BDB_LIBS = @BDB_LIBS@
SLAPD_NDB_LIBS = @SLAPD_NDB_LIBS@
+WT_LIBS = @WT_LIBS@
LDAP_LIBLBER_LA = $(LDAP_LIBDIR)/liblber/liblber.la
LDAP_LIBLDAP_LA = $(LDAP_LIBDIR)/libldap/libldap.la
relay \
shell \
sock \
- sql"
+ sql \
+ wt"
AC_ARG_ENABLE(xxslapbackends,[
SLAPD Backend Options:])
no, [no yes mod], ol_enable_backends)dnl
OL_ARG_ENABLE(sql,[ --enable-sql enable sql backend],
no, [no yes mod], ol_enable_backends)dnl
+OL_ARG_ENABLE(wt,[ --enable-wt enable WiredTiger backend],
+ no, [no yes mod], ol_enable_backends)dnl
dnl ----------------------------------------------------------------
dnl SLAPD Overlay Options
test $ol_enable_relay = no &&
test $ol_enable_shell = no &&
test $ol_enable_sock = no &&
- test $ol_enable_sql = no ; then
+ test $ol_enable_sql = no &&
+ test $ol_enable_wt = no ; then
dnl no slapd backend
if test $ol_enable_slapd = yes ; then
BUILD_SHELL=no
BUILD_SOCK=no
BUILD_SQL=no
+BUILD_WT=no
BUILD_ACCESSLOG=no
BUILD_AUDITLOG=no
fi
fi
+dnl ----------------------------------------------------------------
+dnl WiredTiger
+ol_link_wt=no
+if test $ol_enable_wt != no ; then
+ AC_CHECK_PROG(PKGCONFIG,pkg-config,yes)
+ if test "$PKGCONFIG" != yes ; then
+ AC_MSG_ERROR([could not locate pkg-config])
+ fi
+ WT_INCS=`pkg-config --cflags wiredtiger`
+ WT_LIBS=`pkg-config --libs wiredtiger`
+
+ save_CFLAGS="$CFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ CFLAGS="$WT_INCS"
+ CPPFLAGS="$WT_INCS"
+ LDFLAGS="$WT_LIBS"
+ AC_CHECK_HEADERS([wiredtiger.h])
+ AC_CHECK_LIB(wiredtiger,wiredtiger_version,[: ok],[
+ AC_MSG_ERROR([could not locate wiredtiger library])
+ ])
+ CFLAGS="$save_CFLAGS"
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ SLAPD_LIBS="$SLAPD_LIBS \$(WT_LIBS)"
+ ol_link_wt=yes
+fi
+
dnl ----------------------------------------------------------------
dnl International Components for Unicode
OL_ICU
AC_DEFINE_UNQUOTED(SLAPD_SQL,$MFLAG,[define to support SQL backend])
fi
+if test "$ol_link_wt" != no ; then
+ BUILD_SLAPD=yes
+ BUILD_WT=$ol_enable_wt
+ if test "$ol_enable_wt" = mod; then
+ SLAPD_DYNAMIC_BACKENDS="$SLAPD_DYNAMIC_BACKENDS back-wt"
+ MFLAG=SLAPD_MOD_DYNAMIC
+ else
+ SLAPD_STATIC_BACKENDS="$SLAPD_STATIC_BACKENDS back-wt"
+ MFLAG=SLAPD_MOD_STATIC
+ fi
+ AC_DEFINE_UNQUOTED(SLAPD_WT,$MFLAG,[define to support WiredTiger backend])
+fi
+
if test "$ol_enable_accesslog" != no ; then
BUILD_ACCESSLOG=$ol_enable_accesslog
if test "$ol_enable_accesslog" = mod ; then
AC_SUBST(BUILD_SHELL)
AC_SUBST(BUILD_SOCK)
AC_SUBST(BUILD_SQL)
+ AC_SUBST(BUILD_WT)
dnl overlays
AC_SUBST(BUILD_ACCESSLOG)
AC_SUBST(BUILD_AUDITLOG)
AC_SUBST(SLAPD_SQL_LIBS)
AC_SUBST(SLAPD_SQL_INCLUDES)
+AC_SUBST(WT_INCS)
+AC_SUBST(WT_LIBS)
+
dnl ----------------------------------------------------------------
dnl final help output
AC_ARG_WITH(xxinstall,[
[servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk]
[servers/slapd/back-sock/Makefile:build/top.mk:servers/slapd/back-sock/Makefile.in:build/mod.mk]
[servers/slapd/back-sql/Makefile:build/top.mk:servers/slapd/back-sql/Makefile.in:build/mod.mk]
+[servers/slapd/back-wt/Makefile:build/top.mk:servers/slapd/back-wt/Makefile.in:build/mod.mk]
[servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk]
[servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk]
[servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk]
--- /dev/null
+.TH SLAPD-WT 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2011-2015 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
+.\" $OpenLDAP$
+.SH NAME
+slapd\-wt \- WiredTiger backend to slapd
+.SH SYNOPSIS
+.B ETCDIR/slapd.conf
+.SH DESCRIPTION
+The \fBwt\fP backend to
+.BR slapd (8)
+uses WiredTiger database library to store data.
+.LP
+The \fBwt\fP backend is experimental module that have potential high
+write performance and high concurrency performance.
+This backend have not some basic feature yet. Please backup data using
+slapcat before update the module.
+
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the \fBwt\fP backend database.
+That is, they must follow a "database wt" line and
+come before any subsequent "backend" or "database" lines.
+Other database options are described in the
+.BR slapd.conf (5)
+manual page.
+.TP
+.BI directory \ <directory>
+Specify WiredTiger home directory that containing this database and
+associated indexes live.
+A separate directory must be specified for each database.
+The default is
+.BR LOCALSTATEDIR/openldap\-data .
+.TP
+\fBwtconfig \fR{\fBcreate\fR,\fBcache_size=512M\fR,\fBasync=(enabled)\fR}
+Specify configuration for wiredtiger, This parameter is pass to
+.BR wiredtiger_open (3).
+.RS
+.TP
+.B create
+create the database if it does not exist.
+.RE
+.RS
+.TP
+.B cache_size
+maximum heap memory to allocate for the cache.
+.RE
+.RS
+.TP
+.B async
+asynchronous operations configuration options. disabled by default.
+.RE
+.RS
+.TP
+\fBindex \fR{\fI<attrlist>\fR|\fBdefault\fR} [\fBpres\fR,\fBeq\fR,\fBapprox\fR,\fBsub\fR,\fI<special>\fR]
+Specify the indexes to maintain for the given attribute (or
+list of attributes).
+Some attributes only support a subset of indexes.
+If only an \fI<attr>\fP is given, the indices specified for \fBdefault\fR
+are maintained.
+Note that setting a default does not imply that all attributes will be
+indexed. Also, for best performance, an
+.B eq
+index should always be configured for the
+.B objectClass
+attribute.
+
+.SH ACCESS CONTROL
+The
+.B wt
+backend honors access control semantics as indicated in
+.BR slapd.access (5).
+.SH FILES
+.TP
+.B ETCDIR/slapd.conf
+default
+.B slapd
+configuration file
+.SH SEE ALSO
+.BR slapd.conf (5),
+.BR slapd\-config (5),
+.BR slapd (8),
+.BR slapadd (8),
+.BR slapcat (8),
+.BR slapindex (8),
+WiredTiger documentation.
+.SH ACKNOWLEDGEMENTS
+.so ../Project
+Written by HAMANO Tsukasa <hamano@osstech.co.jp>.
--- /dev/null
+# Makefile.in for back-wt
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2015 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+SRCS = init.c tools.c config.c \
+ add.c bind.c compare.c delete.c search.c \
+ operational.c \
+ attr.c index.c key.c filterindex.c \
+ dn2entry.c dn2id.c id2entry.c idl.c \
+ nextid.c ctx.c
+
+OBJS = init.lo tools.lo config.lo \
+ add.lo bind.lo compare.lo delete.lo search.lo \
+ operational.lo \
+ attr.lo index.lo key.lo filterindex.lo \
+ dn2entry.lo dn2id.lo id2entry.lo idl.lo \
+ nextid.lo ctx.lo
+
+LDAP_INCDIR= ../../../include
+LDAP_LIBDIR= ../../../libraries
+
+BUILD_OPT = "--enable-wt"
+BUILD_MOD = @BUILD_WT@
+
+mod_DEFS = -DSLAPD_IMPORT
+MOD_DEFS = @WT_INCS@
+MOD_LIBS = @WT_LIBS@
+
+
+shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
+NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+
+LIBBASE = back_wt
+
+XINCPATH = -I.. -I$(srcdir)/..
+XDEFS = $(MODULES_CPPFLAGS)
+
+all-local-lib: ../.backend
+
+../.backend: lib$(LIBBASE).a
+ @touch $@
+
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "back-wt.h"
+#include "config.h"
+
+int
+wt_add( Operation *op, SlapReply *rs )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ struct berval pdn;
+ char textbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof textbuf;
+ AttributeDescription *children = slap_schema.si_ad_children;
+ AttributeDescription *entry = slap_schema.si_ad_entry;
+ ID eid;
+ int num_retries = 0;
+ int success;
+ LDAPControl **postread_ctrl = NULL;
+ LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
+ int num_ctrls = 0;
+ wt_ctx *wc;
+ Entry *e = NULL;
+ Entry *p = NULL;
+ ID pid;
+ int rc;
+
+ Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_add) ": %s\n",
+ op->ora_e->e_name.bv_val, 0, 0);
+
+ ctrls[num_ctrls] = 0;
+
+ /* check entry's schema */
+ rs->sr_err = entry_schema_check(
+ op, op->ora_e, NULL,
+ get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add)
+ ": entry failed schema check: %s (%d)\n",
+ rs->sr_text, rs->sr_err, 0 );
+ goto return_results;
+ }
+
+ /* add opattrs to shadow as well, only missing attrs will actually
+ * be added; helps compatibility with older OL versions */
+ rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add)
+ ": entry failed op attrs add: %s (%d)\n",
+ rs->sr_text, rs->sr_err, 0 );
+ goto return_results;
+ }
+
+ if ( get_assert( op ) &&
+ ( test_filter( op, op->ora_e, get_assertion( op ))
+ != LDAP_COMPARE_TRUE ))
+ {
+ rs->sr_err = LDAP_ASSERTION_FAILED;
+ goto return_results;
+ }
+
+ /* Not used
+ * subentry = is_entry_subentry( op->ora_e );
+ */
+
+ /*
+ * Get the parent dn and see if the corresponding entry exists.
+ */
+ if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
+ pdn = slap_empty_bv;
+ } else {
+ dnParent( &op->ora_e->e_nname, &pdn );
+ }
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_add)
+ ": wt_ctx_get failed\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ send_ldap_result( op, rs );
+ return rs->sr_err;
+ }
+
+ rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
+ switch( rc ) {
+ case 0:
+ rs->sr_err = LDAP_ALREADY_EXISTS;
+ goto return_results;
+ break;
+ case WT_NOTFOUND:
+ break;
+ default:
+ /* TODO: retry handling */
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_add)
+ ": error at wt_dn2entry() rc=%d\n",
+ rc, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ goto return_results;
+ }
+
+ /* get parent entry */
+ rc = wt_dn2pentry(op->o_bd, wc, &op->o_req_ndn, &p);
+ switch( rc ){
+ case 0:
+ case WT_NOTFOUND:
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_add)
+ ": error at wt_dn2pentry() rc=%d\n",
+ rc, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ goto return_results;
+ }
+
+ if ( !p )
+ p = (Entry *)&slap_entry_root;
+
+ if ( !bvmatch( &pdn, &p->e_nname ) ) {
+ rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
+ op->o_tmpmemctx );
+ if ( p != (Entry *)&slap_entry_root ) {
+ rs->sr_ref = is_entry_referral( p )
+ ? get_entry_referrals( op, p )
+ : NULL;
+ wt_entry_return( p );
+ } else {
+ rs->sr_ref = NULL;
+ }
+ p = NULL;
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": parent "
+ "does not exist\n", 0, 0, 0 );
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ }
+
+ rs->sr_err = access_allowed( op, p,
+ children, NULL, ACL_WADD, NULL );
+ if ( ! rs->sr_err ) {
+ /*
+ if ( p != (Entry *)&slap_entry_root )
+ wt_entry_return( op, p );
+ */
+ p = NULL;
+
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": no write access to parent\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to parent";
+ goto return_results;;
+ }
+
+ if ( p != (Entry *)&slap_entry_root ) {
+ if ( is_entry_subentry( p ) ) {
+ wt_entry_return( p );
+ p = NULL;
+ /* parent is a subentry, don't allow add */
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": parent is subentry\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
+ rs->sr_text = "parent is a subentry";
+ goto return_results;;
+ }
+
+ if ( is_entry_alias( p ) ) {
+ wt_entry_return( p );
+ p = NULL;
+ /* parent is an alias, don't allow add */
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": parent is alias\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_ALIAS_PROBLEM;
+ rs->sr_text = "parent is an alias";
+ goto return_results;;
+ }
+
+ if ( is_entry_referral( p ) ) {
+ BerVarray ref = get_entry_referrals( op, p );
+ /* parent is a referral, don't allow add */
+ rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
+ op->o_tmpmemctx );
+ rs->sr_ref = referral_rewrite( ref, &p->e_name,
+ &op->o_req_dn, LDAP_SCOPE_DEFAULT );
+ ber_bvarray_free( ref );
+ wt_entry_return( p );
+ p = NULL;
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": parent is referral\n",
+ 0, 0, 0 );
+
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ }
+ }
+
+#if 0
+ if ( subentry ) {
+ /* FIXME: */
+ /* parent must be an administrative point of the required kind */
+ }
+#endif
+
+ /* free parent */
+ if ( p != (Entry *)&slap_entry_root ) {
+ pid = p->e_id;
+ if ( p->e_nname.bv_len ) {
+ struct berval ppdn;
+
+ /* ITS#5326: use parent's DN if differs from provided one */
+ dnParent( &op->ora_e->e_name, &ppdn );
+ if ( !dn_match( &p->e_name, &ppdn ) ) {
+ struct berval rdn;
+ struct berval newdn;
+
+ dnRdn( &op->ora_e->e_name, &rdn );
+
+ build_new_dn( &newdn, &p->e_name, &rdn, NULL );
+ if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
+ ber_memfree( op->ora_e->e_name.bv_val );
+ op->ora_e->e_name = newdn;
+
+ /* FIXME: should check whether
+ * dnNormalize(newdn) == e->e_nname ... */
+ }
+ }
+
+ wt_entry_return( p );
+ }
+ p = NULL;
+
+ rs->sr_err = access_allowed( op, op->ora_e,
+ entry, NULL, ACL_WADD, NULL );
+
+ if ( ! rs->sr_err ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": no write access to entry\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to entry";
+ goto return_results;
+ }
+
+ /*
+ * Check ACL for attribute write access
+ */
+ if (!acl_check_modlist(op, op->ora_e, op->ora_modlist)) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": no write access to attribute\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to attribute";
+ goto return_results;
+ }
+
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "begin_transaction failed";
+ goto return_results;
+ }
+ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(wt_add) ": session id: %p\n",
+ wc->session, 0, 0 );
+
+ wt_next_id( op->o_bd, &eid );
+ op->ora_e->e_id = eid;
+
+ rc = wt_dn2id_add( op, wc->session, pid, op->ora_e );
+ if( rc ){
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add)
+ ": dn2id_add failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ switch( rc ) {
+ case WT_DUPLICATE_KEY:
+ rs->sr_err = LDAP_ALREADY_EXISTS;
+ break;
+ default:
+ rs->sr_err = LDAP_OTHER;
+ }
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ rc = wt_id2entry_add( op, wc->session, op->ora_e );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add)
+ ": id2entry_add failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ if ( rc == LDAP_ADMINLIMIT_EXCEEDED ) {
+ rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
+ rs->sr_text = "entry is too big";
+ } else {
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "entry store failed";
+ }
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ /* add indices */
+ rc = wt_index_entry_add( op, wc, op->ora_e );
+ if ( rc ) {
+ Debug(LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_add)
+ ": index add failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "index add failed";
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ rc = wc->session->commit_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_add)
+ ": commit_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "commit_transaction failed";
+ goto return_results;
+ }
+
+ rs->sr_err = LDAP_SUCCESS;
+
+ /* post-read */
+ if( op->o_postread ) {
+ if( postread_ctrl == NULL ) {
+ postread_ctrl = &ctrls[num_ctrls++];
+ ctrls[num_ctrls] = NULL;
+ }
+ if ( slap_read_controls( op, rs, op->ora_e,
+ &slap_post_read_bv, postread_ctrl ) )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- " LDAP_XSTRING(wt_add) ": post-read "
+ "failed!\n", 0, 0, 0 );
+ if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
+ /* FIXME: is it correct to abort
+ * operation if control fails? */
+ goto return_results;
+ }
+ }
+ }
+
+ Debug(LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": added%s id=%08lx dn=\"%s\"\n",
+ op->o_noop ? " (no-op)" : "",
+ op->ora_e->e_id, op->ora_e->e_dn );
+
+return_results:
+ success = rs->sr_err;
+ send_ldap_result( op, rs );
+
+ slap_graduate_commit_csn( op );
+
+ if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
+ slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
+ slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
+ }
+ return rs->sr_err;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "back-wt.h"
+#include "config.h"
+
+/* Find the ad, return -1 if not found,
+ * set point for insertion if ins is non-NULL
+ */
+int
+wt_attr_slot( struct wt_info *wi, AttributeDescription *ad, int *ins )
+{
+ unsigned base = 0, cursor = 0;
+ unsigned n = wi->wi_nattrs;
+ int val = 0;
+
+ while ( 0 < n ) {
+ unsigned pivot = n >> 1;
+ cursor = base + pivot;
+
+ val = SLAP_PTRCMP( ad, wi->wi_attrs[cursor]->ai_desc );
+ if ( val < 0 ) {
+ n = pivot;
+ } else if ( val > 0 ) {
+ base = cursor + 1;
+ n -= pivot + 1;
+ } else {
+ return cursor;
+ }
+ }
+ if ( ins ) {
+ if ( val > 0 )
+ ++cursor;
+ *ins = cursor;
+ }
+ return -1;
+}
+
+static int
+ainfo_insert( struct wt_info *wi, AttrInfo *a )
+{
+ int x;
+ int i = wt_attr_slot( wi, a->ai_desc, &x );
+
+ /* Is it a dup? */
+ if ( i >= 0 )
+ return -1;
+
+ wi->wi_attrs = ch_realloc( wi->wi_attrs, ( wi->wi_nattrs+1 ) *
+ sizeof( AttrInfo * ));
+ if ( x < wi->wi_nattrs )
+ AC_MEMCPY( &wi->wi_attrs[x+1], &wi->wi_attrs[x],
+ ( wi->wi_nattrs - x ) * sizeof( AttrInfo *));
+ wi->wi_attrs[x] = a;
+ wi->wi_nattrs++;
+ return 0;
+}
+
+AttrInfo *
+wt_attr_mask(
+ struct wt_info *wi,
+ AttributeDescription *desc )
+{
+ int i = wt_attr_slot( wi, desc, NULL );
+ return i < 0 ? NULL : wi->wi_attrs[i];
+}
+
+int
+wt_attr_index_config(
+ struct wt_info *wi,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv,
+ struct config_reply_s *c_reply)
+{
+ int rc = 0;
+ int i;
+ slap_mask_t mask;
+ char **attrs;
+ char **indexes = NULL;
+
+ attrs = ldap_str2charray( argv[0], "," );
+
+ if( attrs == NULL ) {
+ fprintf( stderr, "%s: line %d: "
+ "no attributes specified: %s\n",
+ fname, lineno, argv[0] );
+ return LDAP_PARAM_ERROR;
+ }
+
+ if ( argc > 1 ) {
+ indexes = ldap_str2charray( argv[1], "," );
+
+ if( indexes == NULL ) {
+ fprintf( stderr, "%s: line %d: "
+ "no indexes specified: %s\n",
+ fname, lineno, argv[1] );
+ rc = LDAP_PARAM_ERROR;
+ goto done;
+ }
+ }
+
+ if( indexes == NULL ) {
+ mask = wi->wi_defaultmask;
+
+ } else {
+ mask = 0;
+
+ for ( i = 0; indexes[i] != NULL; i++ ) {
+ slap_mask_t index;
+
+ rc = slap_str2index( indexes[i], &index );
+
+ if( rc != LDAP_SUCCESS ) {
+ if ( c_reply )
+ {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "index type \"%s\" undefined", indexes[i] );
+
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_PARAM_ERROR;
+ goto done;
+ }
+
+ mask |= index;
+ }
+ }
+
+ if( !mask ) {
+ if ( c_reply )
+ {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "no indexes selected" );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_PARAM_ERROR;
+ goto done;
+ }
+
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ AttrInfo *a;
+ AttributeDescription *ad;
+ const char *text;
+#ifdef LDAP_COMP_MATCH
+ ComponentReference* cr = NULL;
+ AttrInfo *a_cr = NULL;
+#endif
+
+ if( strcasecmp( attrs[i], "default" ) == 0 ) {
+ wi->wi_defaultmask |= mask;
+ continue;
+ }
+
+#ifdef LDAP_COMP_MATCH
+ if ( is_component_reference( attrs[i] ) ) {
+ rc = extract_component_reference( attrs[i], &cr );
+ if ( rc != LDAP_SUCCESS ) {
+ if ( c_reply )
+ {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "index component reference\"%s\" undefined",
+ attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ goto done;
+ }
+ cr->cr_indexmask = mask;
+ /*
+ * After extracting a component reference
+ * only the name of a attribute will be remaining
+ */
+ } else {
+ cr = NULL;
+ }
+#endif
+ ad = NULL;
+ rc = slap_str2ad( attrs[i], &ad, &text );
+
+ if( rc != LDAP_SUCCESS ) {
+ if ( c_reply )
+ {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "index attribute \"%s\" undefined",
+ attrs[i] );
+
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+fail:
+#ifdef LDAP_COMP_MATCH
+ ch_free( cr );
+#endif
+ goto done;
+ }
+
+ if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
+ if (c_reply) {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "index of attribute \"%s\" disallowed", attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto fail;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
+ ad->ad_type->sat_approx
+ && ad->ad_type->sat_approx->smr_indexer
+ && ad->ad_type->sat_approx->smr_filter ) )
+ {
+ if (c_reply) {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "approx index of attribute \"%s\" disallowed", attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_INAPPROPRIATE_MATCHING;
+ goto fail;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
+ ad->ad_type->sat_equality
+ && ad->ad_type->sat_equality->smr_indexer
+ && ad->ad_type->sat_equality->smr_filter ) )
+ {
+ if (c_reply) {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "equality index of attribute \"%s\" disallowed", attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_INAPPROPRIATE_MATCHING;
+ goto fail;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
+ ad->ad_type->sat_substr
+ && ad->ad_type->sat_substr->smr_indexer
+ && ad->ad_type->sat_substr->smr_filter ) )
+ {
+ if (c_reply) {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "substr index of attribute \"%s\" disallowed", attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+ rc = LDAP_INAPPROPRIATE_MATCHING;
+ goto fail;
+ }
+
+ Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
+ ad->ad_cname.bv_val, mask, 0 );
+
+ a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
+
+#ifdef LDAP_COMP_MATCH
+ a->ai_cr = NULL;
+#endif
+ a->ai_desc = ad;
+
+ if ( wi->wi_flags & WT_IS_OPEN ) {
+ a->ai_indexmask = 0;
+ a->ai_newmask = mask;
+ } else {
+ a->ai_indexmask = mask;
+ a->ai_newmask = 0;
+ }
+
+#ifdef LDAP_COMP_MATCH
+ if ( cr ) {
+ a_cr = wt_attr_mask( wi, ad );
+ if ( a_cr ) {
+ /*
+ * AttrInfo is already in AVL
+ * just add the extracted component reference
+ * in the AttrInfo
+ */
+ ch_free( a );
+ rc = insert_component_reference( cr, &a_cr->ai_cr );
+ if ( rc != LDAP_SUCCESS) {
+ fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
+ rc = LDAP_PARAM_ERROR;
+ goto fail;
+ }
+ continue;
+ } else {
+ rc = insert_component_reference( cr, &a->ai_cr );
+ if ( rc != LDAP_SUCCESS) {
+ fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
+ rc = LDAP_PARAM_ERROR;
+ ch_free( a );
+ goto fail;
+ }
+ }
+ }
+#endif
+ rc = ainfo_insert( wi, a );
+ if( rc ) {
+ if ( wi->wi_flags & WT_IS_OPEN ) {
+ AttrInfo *b = wt_attr_mask( wi, ad );
+ /* If there is already an index defined for this attribute
+ * it must be replaced. Otherwise we end up with multiple
+ * olcIndex values for the same attribute */
+ if ( b->ai_indexmask & WT_INDEX_DELETING ) {
+ /* If we were editing this attr, reset it */
+ b->ai_indexmask &= ~WT_INDEX_DELETING;
+ /* If this is leftover from a previous add, commit it */
+ if ( b->ai_newmask )
+ b->ai_indexmask = b->ai_newmask;
+ b->ai_newmask = a->ai_newmask;
+ ch_free( a );
+ rc = 0;
+ continue;
+ }
+ }
+ if (c_reply) {
+ snprintf(c_reply->msg, sizeof(c_reply->msg),
+ "duplicate index definition for attr \"%s\"",
+ attrs[i] );
+ fprintf( stderr, "%s: line %d: %s\n",
+ fname, lineno, c_reply->msg );
+ }
+
+ rc = LDAP_PARAM_ERROR;
+ goto done;
+ }
+ }
+
+done:
+ ldap_charray_free( attrs );
+ if ( indexes != NULL ) ldap_charray_free( indexes );
+
+ return rc;
+}
+
+void
+wt_attr_info_free( AttrInfo *ai )
+{
+#ifdef LDAP_COMP_MATCH
+ free( ai->ai_cr );
+#endif
+ free( ai );
+}
+
+void
+wt_attr_index_destroy( struct wt_info *wi )
+{
+ int i;
+
+ for ( i=0; i<wi->wi_nattrs; i++ )
+ wt_attr_info_free( wi->wi_attrs[i] );
+
+ free( wi->wi_attrs );
+}
+
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#ifndef _BACK_WT_H_
+#define _BACK_WT_H_
+
+#include <portable.h>
+
+#include <ac/errno.h>
+#include <sys/stat.h>
+
+#include "slap.h"
+#include "wiredtiger.h"
+
+/* The default search IDL stack cache depth */
+#define DEFAULT_SEARCH_STACK_DEPTH 16
+
+struct wt_info {
+ WT_CONNECTION *wi_conn;
+ char *wi_dbenv_home;
+ char *wi_dbenv_config;
+ ID wi_lastid;
+
+ slap_mask_t wi_defaultmask;
+ int wi_nattrs;
+ struct wt_attrinfo **wi_attrs;
+ void *wi_search_stack;
+ int wi_search_stack_depth;
+
+ struct re_s *wi_index_task;
+
+ int wi_flags;
+#define WT_IS_OPEN 0x01
+#define WT_OPEN_INDEX 0x02
+#define WT_DEL_INDEX 0x08
+#define WT_RE_OPEN 0x10
+#define WT_NEED_UPGRADE 0x20
+};
+
+#define WT_TABLE_ID2ENTRY "table:id2entry"
+#define WT_TABLE_DN2ID "table:dn2id"
+
+#define WT_INDEX_DN "index:id2entry:dn"
+#define WT_INDEX_PID "index:dn2id:pid"
+#define WT_INDEX_REVDN "index:dn2id:revdn"
+
+#define ITEMzero(item) (memset((item), 0, sizeof(WT_ITEM)))
+#define ITEM2bv(item,bv) ((bv)->bv_val = (item)->data, \
+ (bv)->bv_len = (item)->size)
+#define bv2ITEM(bv,item) ((item)->data = (bv)->bv_val, \
+ (item)->size = (bv)->bv_len )
+
+typedef struct {
+ WT_SESSION *session;
+} wt_ctx;
+
+/* for the cache of attribute information (which are indexed, etc.) */
+typedef struct wt_attrinfo {
+ AttributeDescription *ai_desc; /* attribute description cn;lang-en */
+ slap_mask_t ai_indexmask; /* how the attr is indexed */
+ slap_mask_t ai_newmask; /* new settings to replace old mask */
+ #ifdef LDAP_COMP_MATCH
+ ComponentReference* ai_cr; /*component indexing*/
+ #endif
+} AttrInfo;
+
+/* These flags must not clash with SLAP_INDEX flags or ops in slap.h! */
+#define WT_INDEX_DELETING 0x8000U /* index is being modified */
+#define WT_INDEX_UPDATE_OP 0x03 /* performing an index update */
+
+#include "proto-wt.h"
+
+#endif /* _BACK_WT_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "back-wt.h"
+#include "config.h"
+
+int
+wt_bind( Operation *op, SlapReply *rs )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ WT_SESSION *session;
+ wt_ctx *wc;
+ int rc;
+ Entry *e = NULL;
+ Attribute *a;
+ AttributeDescription *password = slap_schema.si_ad_userPassword;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "==> " LDAP_XSTRING(wt_bind) ": dn: %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+
+ /* allow noauth binds */
+ switch ( be_rootdn_bind( op, NULL ) ) {
+ case LDAP_SUCCESS:
+ /* frontend will send result */
+ return rs->sr_err = LDAP_SUCCESS;
+
+ default:
+ /* give the database a chance */
+ /* NOTE: this behavior departs from that of other backends,
+ * since the others, in case of password checking failure
+ * do not give the database a chance. If an entry with
+ * rootdn's name does not exist in the database the result
+ * will be the same. See ITS#4962 for discussion. */
+ break;
+ }
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_bind)
+ ": wt_ctx_get failed\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ send_ldap_result( op, rs );
+ return rs->sr_err;
+ }
+
+ /* get entry */
+ rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
+ switch( rc ) {
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ send_ldap_result( op, rs );
+ return rs->sr_err;
+ default:
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ send_ldap_result( op, rs );
+ return rs->sr_err;
+ }
+
+ ber_dupbv( &op->oq_bind.rb_edn, &e->e_name );
+
+ /* check for deleted */
+ if ( is_entry_subentry( e ) ) {
+ /* entry is an subentry, don't allow bind */
+ Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0,
+ 0, 0 );
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto done;
+ }
+
+ if ( is_entry_alias( e ) ) {
+ /* entry is an alias, don't allow bind */
+ Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto done;
+ }
+
+ if ( is_entry_referral( e ) ) {
+ Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+ 0, 0 );
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto done;
+ }
+
+ switch ( op->oq_bind.rb_method ) {
+ case LDAP_AUTH_SIMPLE:
+ a = attr_find( e->e_attrs, password );
+ if ( a == NULL ) {
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto done;
+ }
+
+ if ( slap_passwd_check( op, e, a, &op->oq_bind.rb_cred,
+ &rs->sr_text ) != 0 )
+ {
+ /* failure; stop front end from sending result */
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto done;
+ }
+ rs->sr_err = 0;
+ break;
+
+ default:
+ rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED;
+ rs->sr_text = "authentication method not supported";
+ }
+
+done:
+ /* free entry */
+ if (e) {
+ wt_entry_return(e);
+ }
+ if (rs->sr_err) {
+ send_ldap_result( op, rs );
+ if ( rs->sr_ref ) {
+ ber_bvarray_free( rs->sr_ref );
+ rs->sr_ref = NULL;
+ }
+ }
+ return rs->sr_err;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-wt.h"
+#include "config.h"
+
+int
+wt_compare( Operation *op, SlapReply *rs )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ Entry *e = NULL;
+ int manageDSAit = get_manageDSAit( op );
+ int rc;
+ wt_ctx *wc = NULL;
+
+ Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_compare) ": %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_compare)
+ ": wt_ctx_get failed\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ send_ldap_result( op, rs );
+ return rs->sr_err;
+ }
+
+ rs->sr_err = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
+ switch( rs->sr_err ) {
+ case 0:
+ case WT_NOTFOUND:
+ break;
+ default:
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ goto return_results;
+ }
+
+ if ( rs->sr_err == WT_NOTFOUND ) {
+ if ( e != NULL ) {
+ /* return referral only if "disclose" is granted on the object */
+ if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL ) )
+ {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ } else {
+ rs->sr_matched = ch_strdup( e->e_dn );
+ if ( is_entry_referral( e )) {
+ BerVarray ref = get_entry_referrals( op, e );
+ rs->sr_ref = referral_rewrite( ref,
+ &e->e_name,
+ &op->o_req_dn,
+ LDAP_SCOPE_DEFAULT );
+ ber_bvarray_free( ref );
+ } else {
+ rs->sr_ref = NULL;
+ }
+ rs->sr_err = LDAP_REFERRAL;
+ }
+ wt_entry_return( e );
+ e = NULL;
+ } else {
+ rs->sr_ref = referral_rewrite( default_referral,
+ NULL,
+ &op->o_req_dn,
+ LDAP_SCOPE_DEFAULT );
+ rs->sr_err = rs->sr_ref ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
+ }
+
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ send_ldap_result( op, rs );
+ goto done;
+ }
+
+ if (!manageDSAit && is_entry_referral( e ) ) {
+ /* return referral only if "disclose" is granted on the object */
+ if ( !access_allowed( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_DISCLOSE, NULL ) )
+ {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ } else {
+ /* entry is a referral, don't allow compare */
+ rs->sr_ref = get_entry_referrals( op, e );
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_matched = e->e_name.bv_val;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
+
+ send_ldap_result( op, rs );
+
+ ber_bvarray_free( rs->sr_ref );
+ rs->sr_ref = NULL;
+ rs->sr_matched = NULL;
+ goto done;
+ }
+
+ rs->sr_err = slap_compare_entry( op, e, op->orc_ava );
+
+return_results:
+ send_ldap_result( op, rs );
+
+ switch ( rs->sr_err ) {
+ case LDAP_COMPARE_FALSE:
+ case LDAP_COMPARE_TRUE:
+ rs->sr_err = LDAP_SUCCESS;
+ break;
+ }
+
+done:
+ if ( e != NULL ) {
+ wt_entry_return( e );
+ }
+ return rs->sr_err;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+
+#include "lutil.h"
+#include "ldap_rq.h"
+
+static ConfigDriver wt_cf_gen;
+
+enum {
+ WT_DIRECTORY = 1,
+ WT_CONFIG,
+ WT_INDEX,
+};
+
+static ConfigTable wtcfg[] = {
+ { "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|WT_DIRECTORY,
+ wt_cf_gen, "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
+ "DESC 'Directory for database content' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { "wtconfig", "config", 2, 2, 0, ARG_STRING|ARG_MAGIC|WT_CONFIG,
+ wt_cf_gen, "( OLcfgDbAt:13.1 NAME 'olcWtConfig' "
+ "DESC 'Configuration for WiredTiger' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { "index", "attr> <[pres,eq,approx,sub]", 2, 3, 0, ARG_MAGIC|WT_INDEX,
+ wt_cf_gen, "( OLcfgDbAt:0.2 NAME 'olcDbIndex' "
+ "DESC 'Attribute index parameters' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString )", NULL, NULL },
+ { NULL, NULL, 0, 0, 0, ARG_IGNORED,
+ NULL, NULL, NULL, NULL }
+};
+
+static ConfigOCs wtocs[] = {
+ { "( OLcfgDbOc:9.1 "
+ "NAME 'olcWtConfig' "
+ "DESC 'Wt backend ocnfiguration' "
+ "SUP olcDatabaseConfig "
+ "MUST olcDbDirectory "
+ "MAY ( olcWtConfig $ olcDbIndex ) )",
+ Cft_Database, wtcfg },
+ { NULL, 0, NULL }
+};
+
+/* reindex entries on the fly */
+static void *
+wt_online_index( void *ctx, void *arg )
+{
+ // Not implement yet
+}
+
+/* Cleanup loose ends after Modify completes */
+static int
+wt_cf_cleanup( ConfigArgs *c )
+{
+ // Not implement yet
+ return 0;
+}
+
+static int
+wt_cf_gen( ConfigArgs *c )
+{
+ struct wt_info *wi = (struct wt_info *) c->be->be_private;
+ int rc;
+
+ if(c->op == SLAP_CONFIG_EMIT) {
+ rc = 0;
+ // not implement yet
+ return rc;
+ }
+
+ switch( c->type ) {
+ case WT_DIRECTORY:
+ ch_free( wi->wi_dbenv_home );
+ wi->wi_dbenv_home = c->value_string;
+ break;
+ case WT_CONFIG:
+ ch_free( wi->wi_dbenv_config );
+ wi->wi_dbenv_config = c->value_string;
+ break;
+
+ case WT_INDEX:
+ rc = wt_attr_index_config( wi, c->fname, c->lineno,
+ c->argc - 1, &c->argv[1], &c->reply);
+
+ if( rc != LDAP_SUCCESS ) return 1;
+ wi->wi_flags |= WT_OPEN_INDEX;
+
+ if ( wi->wi_flags & WT_IS_OPEN ) {
+ c->cleanup = wt_cf_cleanup;
+
+ if ( !wi->wi_index_task ) {
+ /* Start the task as soon as we finish here. Set a long
+ * interval (10 hours) so that it only gets scheduled once.
+ */
+ if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
+ fprintf( stderr, "%s: "
+ "\"index\" must occur after \"suffix\".\n",
+ c->log );
+ return 1;
+ }
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ wi->wi_index_task = ldap_pvt_runqueue_insert(&slapd_rq, 36000,
+ wt_online_index, c->be,
+ LDAP_XSTRING(wt_online_index),
+ c->be->be_suffix[0].bv_val );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+ }
+ }
+ break;
+
+ }
+ return LDAP_SUCCESS;
+}
+
+int wt_back_init_cf( BackendInfo *bi )
+{
+ int rc;
+ bi->bi_cf_ocs = wtocs;
+
+ rc = config_register_schema( wtcfg, wtocs );
+ if ( rc ) return rc;
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "back-wt.h"
+#include "config.h"
+
+wt_ctx *
+wt_ctx_init(struct wt_info *wi)
+{
+ int rc;
+ wt_ctx *wc;
+
+ wc = ch_malloc( sizeof( wt_ctx ) );
+ if( !wc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_ctx_init)
+ ": cannot allocate memory\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ memset(wc, 0, sizeof(wt_ctx));
+
+ if(!wc->session){
+ rc = wi->wi_conn->open_session(wi->wi_conn, NULL, NULL, &wc->session);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_ctx_session)
+ ": open_session error %s(%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return NULL;
+ }
+ }
+ return wc;
+}
+
+void
+wt_ctx_free( void *key, void *data )
+{
+ wt_ctx *wc = data;
+
+ if(wc->session){
+ wc->session->close(wc->session, NULL);
+ wc->session = NULL;
+ }
+ ch_free(wc);
+}
+
+wt_ctx *
+wt_ctx_get(Operation *op, struct wt_info *wi){
+ int rc;
+ void *data;
+ wt_ctx *wc = NULL;
+
+ rc = ldap_pvt_thread_pool_getkey(op->o_threadctx,
+ wt_ctx_get, &data, NULL );
+ if( rc ){
+ wc = wt_ctx_init(wi);
+ if( !wc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_ctx)
+ ": wt_ctx_init failed\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+ rc = ldap_pvt_thread_pool_setkey( op->o_threadctx,
+ wt_ctx_get, wc, wt_ctx_free,
+ NULL, NULL );
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY, "wt_ctx: setkey error(%d)\n",
+ rc, 0, 0 );
+ return NULL;
+ }
+ return wc;
+ }
+ return (wt_ctx *)data;
+}
+
+WT_CURSOR *
+wt_ctx_index_cursor(wt_ctx *wc, struct berval *name, int create)
+{
+ WT_CURSOR *cursor = NULL;
+ WT_SESSION *session = wc->session;
+ char tablename[1024];
+ int rc;
+
+ snprintf(tablename, sizeof(tablename), "table:%s", name->bv_val);
+
+ rc = session->open_cursor(session, tablename, NULL,
+ "overwrite=false", &cursor);
+ if (rc == ENOENT && create) {
+ rc = session->create(session,
+ tablename,
+ "key_format=uQ,"
+ "value_format=x,"
+ "columns=(key, id, none)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(indexer) ": table \"%s\": "
+ "cannot create idnex table: %s (%d)\n",
+ tablename, wiredtiger_strerror(rc), rc);
+ return NULL;
+ }
+ rc = session->open_cursor(session, tablename, NULL,
+ "overwrite=false", &cursor);
+ }
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry_put)
+ ": open cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return NULL;
+ }
+
+ return cursor;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-wt.h"
+#include "config.h"
+
+int
+wt_delete( Operation *op, SlapReply *rs )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ struct berval pdn = {0, NULL};
+ Entry *e = NULL;
+ Entry *p = NULL;
+ int manageDSAit = get_manageDSAit( op );
+ AttributeDescription *children = slap_schema.si_ad_children;
+ AttributeDescription *entry = slap_schema.si_ad_entry;
+
+ LDAPControl **preread_ctrl = NULL;
+ LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
+ int num_ctrls = 0;
+
+ wt_ctx *wc;
+ int rc;
+ WT_CURSOR *cursor = NULL;
+
+ int parent_is_glue = 0;
+ int parent_is_leaf = 0;
+
+ Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_delete) ": %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+
+#ifdef LDAP_X_TXN
+ if( op->o_txnSpec && txn_preop( op, rs ))
+ return rs->sr_err;
+#endif
+
+ ctrls[num_ctrls] = 0;
+ rs->sr_text = NULL;
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_delete)
+ ": wt_ctx_get failed\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ goto return_results;
+ }
+
+/* allocate CSN */
+ if ( BER_BVISNULL( &op->o_csn ) ) {
+ struct berval csn;
+ char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
+
+ csn.bv_val = csnbuf;
+ csn.bv_len = sizeof(csnbuf);
+ slap_get_csn( op, &csn, 1 );
+ }
+
+ if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
+ dnParent( &op->o_req_ndn, &pdn );
+ }
+
+ /* get parent */
+ rc = wt_dn2entry(op->o_bd, wc, &pdn, &p);
+ switch( rc ) {
+ case 0:
+ case WT_NOTFOUND:
+ break;
+ default:
+ /* TODO: error handling */
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_delete)
+ ": error at wt_dn2entry() rc=%d\n",
+ rc, 0, 0 );
+ goto return_results;
+ }
+
+ if ( rc == WT_NOTFOUND && pdn.bv_len != 0 ) {
+ Debug( LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_delete) ": no such object %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+
+ if ( p && !BER_BVISEMPTY( &p->e_name )) {
+ rs->sr_matched = ch_strdup( p->e_name.bv_val );
+ if ( is_entry_referral( p )) {
+ BerVarray ref = get_entry_referrals( op, p );
+ rs->sr_ref = referral_rewrite( ref, &p->e_name,
+ &op->o_req_dn, LDAP_SCOPE_DEFAULT );
+ ber_bvarray_free( ref );
+ } else {
+ rs->sr_ref = NULL;
+ }
+ } else {
+ rs->sr_ref = referral_rewrite( default_referral, NULL,
+ &op->o_req_dn, LDAP_SCOPE_DEFAULT );
+ }
+
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ }
+
+ /* get entry */
+ rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
+ switch( rc ) {
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ Debug( LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": no such object %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ default:
+ /* TODO: error handling */
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_delete)
+ ": error at wt_dn2entry() rc=%d\n",
+ rc, 0, 0 );
+ goto return_results;
+ }
+
+ /* FIXME : dn2entry() should return non-glue entry */
+ if ( !manageDSAit && is_entry_glue( e ) ) {
+ Debug( LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": glue entry %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+
+ rs->sr_matched = ch_strdup( e->e_dn );
+ if ( is_entry_referral( e )) {
+ BerVarray ref = get_entry_referrals( op, e );
+ rs->sr_ref = referral_rewrite( ref, &e->e_name,
+ &op->o_req_dn, LDAP_SCOPE_DEFAULT );
+ ber_bvarray_free( ref );
+ } else {
+ rs->sr_ref = NULL;
+ }
+
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ }
+
+ if ( pdn.bv_len != 0 ) {
+ /* check parent for "children" acl */
+ rs->sr_err = access_allowed( op, p,
+ children, NULL, ACL_WDEL, NULL );
+
+ if ( !rs->sr_err ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete) ": no write "
+ "access to parent\n", 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to parent";
+ goto return_results;
+ }
+
+ } else {
+ /* no parent, must be root to delete */
+ if( ! be_isroot( op ) ) {
+ if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
+ || be_shadow_update( op ) ) {
+ p = (Entry *)&slap_entry_root;
+
+ /* check parent for "children" acl */
+ rs->sr_err = access_allowed( op, p,
+ children, NULL, ACL_WDEL, NULL );
+
+ p = NULL;
+
+ if ( !rs->sr_err ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": no access to parent\n",
+ 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to parent";
+ goto return_results;
+ }
+
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": no parent and not root\n", 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ goto return_results;
+ }
+ }
+ }
+
+ if ( get_assert( op ) &&
+ ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
+ {
+ rs->sr_err = LDAP_ASSERTION_FAILED;
+ goto return_results;
+ }
+
+ rs->sr_err = access_allowed( op, e,
+ entry, NULL, ACL_WDEL, NULL );
+ if ( !rs->sr_err ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete) ": no write access "
+ "to entry\n", 0, 0, 0 );
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "no write access to entry";
+ goto return_results;
+ }
+
+ if ( !manageDSAit && is_entry_referral( e ) ) {
+ /* entry is a referral, don't allow delete */
+ rs->sr_ref = get_entry_referrals( op, e );
+
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(tw_delete) ": entry is referral\n",
+ 0, 0, 0 );
+
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_matched = ch_strdup( e->e_name.bv_val );
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ goto return_results;
+ }
+
+ /* pre-read */
+ if( op->o_preread ) {
+ if( preread_ctrl == NULL ) {
+ preread_ctrl = &ctrls[num_ctrls++];
+ ctrls[num_ctrls] = NULL;
+ }
+ if( slap_read_controls( op, rs, e,
+ &slap_pre_read_bv, preread_ctrl ) )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete) ": pre-read "
+ "failed!\n", 0, 0, 0 );
+ if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
+ /* FIXME: is it correct to abort
+ * operation if control fails? */
+ goto return_results;
+ }
+ }
+ }
+
+ /* Can't do it if we have kids */
+ rc = wt_dn2id_has_children( op, wc->session, e->e_id );
+ if( rc != WT_NOTFOUND ) {
+ switch( rc ) {
+ case 0:
+ Debug(LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": non-leaf %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+ rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
+ rs->sr_text = "subordinate objects must be deleted first";
+ break;
+ default:
+ Debug(LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": has_children failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "internal error";
+ }
+ goto return_results;
+ }
+
+ /* begen transaction */
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "begin_transaction failed";
+ goto return_results;
+ }
+
+ /* delete from dn2id */
+ rc = wt_dn2id_delete( op, wc->session, &e->e_nname);
+ if ( rc ) {
+ Debug(LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": dn2id failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "dn2id delete failed";
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ /* delete indices for old attributes */
+ rc = wt_index_entry_del( op, wc, e );
+ if ( rc ) {
+ Debug(LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": index delete failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "index delete failed";
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ /* fixup delete CSN */
+ if ( !SLAP_SHADOW( op->o_bd )) {
+ struct berval vals[2];
+
+ assert( !BER_BVISNULL( &op->o_csn ) );
+ vals[0] = op->o_csn;
+ BER_BVZERO( &vals[1] );
+ rs->sr_err = wt_index_values( op, wc->session, slap_schema.si_ad_entryCSN,
+ vals, 0, SLAP_INDEX_ADD_OP );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ rs->sr_text = "entryCSN index update failed";
+ rs->sr_err = LDAP_OTHER;
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+ }
+
+ /* delete from id2entry */
+ rc = wt_id2entry_delete( op, wc->session, e );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": id2entry failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "entry delete failed";
+ wc->session->rollback_transaction(wc->session, NULL);
+ goto return_results;
+ }
+
+ if ( pdn.bv_len != 0 ) {
+ // TODO: glue entry
+ }
+
+ rc = wc->session->commit_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<== " LDAP_XSTRING(wt_delete)
+ ": commit_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "commit_transaction failed";
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_delete)
+ ": deleted%s id=%08lx dn=\"%s\"\n",
+ op->o_noop ? " (no-op)" : "", e->e_id, op->o_req_dn.bv_val );
+
+ rs->sr_err = LDAP_SUCCESS;
+ rs->sr_text = NULL;
+ if( num_ctrls ) {
+ rs->sr_ctrls = ctrls;
+ }
+
+return_results:
+ if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
+ op->o_delete_glue_parent = 1;
+ }
+
+ if ( p != NULL ) {
+ wt_entry_return( p );
+ }
+
+ /* free entry */
+ if( e != NULL ) {
+ wt_entry_return( e );
+ }
+
+ send_ldap_result( op, rs );
+ slap_graduate_commit_csn( op );
+
+ if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
+ slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
+ slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
+ }
+
+ /* TODO: checkpoint */
+
+ return rs->sr_err;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+
+/*
+ * dn2entry - look up dn in the db and return the corresponding entry.
+ * No longer return closest ancestor, see wt_dn2pentry().
+ */
+int wt_dn2entry( BackendDB *be,
+ wt_ctx *wc,
+ struct berval *ndn,
+ Entry **ep ){
+ uint64_t id;
+ WT_CURSOR *cursor = NULL;
+ WT_ITEM item;
+ EntryHeader eh;
+ int rc;
+ int eoff;
+ Entry *e = NULL;
+ WT_SESSION *session = wc->session;
+
+ if( ndn->bv_len == 0 ){
+ /* parent of root dn */
+ return WT_NOTFOUND;
+ }
+
+ rc = session->open_cursor(session,
+ WT_INDEX_DN"(id, entry)",
+ NULL, NULL, &cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2entry)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->set_key(cursor, ndn->bv_val);
+ rc = cursor->search(cursor);
+ switch( rc ){
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ goto done;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2entry)
+ ": search failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ cursor->get_value(cursor, &id, &item);
+ rc = wt_entry_header( &item, &eh );
+
+ eoff = eh.data - (char *)item.data;
+ eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
+ eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
+ memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
+ eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
+ memcpy(eh.data, item.data, item.size);
+ eh.data += eoff;
+ rc = entry_decode( &eh, &e );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2entry)
+ ": entry decode error: %s (%d)\n",
+ rc, 0, 0 );
+ goto done;
+ }
+
+ e->e_id = id;
+ *ep = e;
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+/* dn2pentry - return parent entry */
+int wt_dn2pentry( BackendDB *be,
+ wt_ctx *wc,
+ struct berval *ndn,
+ Entry **ep ){
+ Entry *e = NULL;
+ struct berval pdn;
+ int rc;
+
+ if (be_issuffix( be, ndn )) {
+ *ep = NULL;
+ return WT_NOTFOUND;
+ }
+
+ dnParent( ndn, &pdn );
+ rc = wt_dn2entry(be, wc, &pdn, &e);
+ *ep = e;
+ return rc;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "back-wt.h"
+#include "config.h"
+#include "idl.h"
+
+char *
+mkrevdn(struct berval src){
+ char *dst, *p;
+ char *rdn;
+ size_t rdn_len;
+
+ p = dst = ch_malloc(src.bv_len + 2);
+ while(src.bv_len){
+ rdn = ber_bvrchr( &src, ',' );
+ if (rdn) {
+ rdn_len = src.bv_len;
+ src.bv_len = rdn - src.bv_val;
+ rdn_len -= src.bv_len + 1;
+ rdn++;
+ }else{
+ /* first rdn */
+ rdn_len = src.bv_len;
+ rdn = src.bv_val;
+ src.bv_len = 0;
+ }
+ AC_MEMCPY( p, rdn, rdn_len );
+ p += rdn_len;
+ *p++ = ',';
+ }
+ *p = '\0';
+ return dst;
+}
+
+int
+wt_dn2id_add(
+ Operation *op,
+ WT_SESSION *session,
+ ID pid,
+ Entry *e)
+{
+ int rc;
+ WT_CURSOR *cursor = NULL;
+ char *revdn = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_add 0x%lx: \"%s\"\n",
+ e->e_id, e->e_ndn, 0 );
+ assert( e->e_id != NOID );
+
+ /* make reverse dn */
+ revdn = mkrevdn(e->e_nname);
+
+ rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL,
+ NULL, &cursor);
+ if(rc){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_add)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ cursor->set_key(cursor, e->e_ndn);
+ cursor->set_value(cursor, e->e_id, pid, revdn);
+ rc = cursor->insert(cursor);
+ if(rc){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_add)
+ ": insert failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+done:
+ if(revdn){
+ ch_free(revdn);
+ }
+ if(cursor){
+ cursor->close(cursor);
+ }
+ Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 );
+ return rc;
+}
+
+int
+wt_dn2id_delete(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *ndn)
+{
+ int rc = 0;
+ WT_CURSOR *cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_delete %s\n", ndn->bv_val, 0, 0 );
+
+ rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL,
+ NULL, &cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_delete)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->set_key(cursor, ndn->bv_val);
+ rc = cursor->remove(cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_delete)
+ ": remove failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_dn2id_delete %s: %d\n",
+ ndn->bv_val, rc, 0 );
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+int
+wt_dn2id(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *ndn,
+ ID *id)
+{
+ WT_CURSOR *cursor = NULL;
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ int rc;
+ ID nid;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id(\"%s\")\n",
+ ndn->bv_val, 0, 0 );
+
+ if ( ndn->bv_len == 0 ) {
+ *id = 0;
+ goto done;
+ }
+
+ rc = session->open_cursor(session, WT_TABLE_DN2ID
+ "(id)",
+ NULL, NULL, &cursor);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id)
+ ": cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->set_key(cursor, ndn->bv_val);
+ rc = cursor->search(cursor);
+ switch( rc ){
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ goto done;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id)
+ ": search failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ rc = cursor->get_value(cursor, id);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id)
+ ": get_value failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+
+ if( rc ) {
+ Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id: get failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ } else {
+ Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id: got id=0x%lx\n",
+ *id, 0, 0 );
+ }
+
+ return rc;
+}
+
+int
+wt_dn2id_has_children(
+ Operation *op,
+ WT_SESSION *session,
+ ID id )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ WT_CURSOR *cursor = NULL;
+ int rc;
+ uint64_t key = id;
+
+ rc = session->open_cursor(session, WT_INDEX_PID,
+ NULL, NULL, &cursor);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_has_children)
+ ": cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->set_key(cursor, key);
+ rc = cursor->search(cursor);
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+
+ return rc;
+}
+
+int
+wt_dn2idl(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *ndn,
+ Entry *e,
+ ID *ids,
+ ID *stack)
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ WT_CURSOR *cursor = NULL;
+ int exact = 0;
+ int rc;
+ char *revdn = NULL;
+ size_t revdn_len;
+ char *key;
+ ID id, pid;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> wt_dn2idl(\"%s\")\n",
+ ndn->bv_val, 0, 0 );
+
+ if(op->ors_scope != LDAP_SCOPE_ONELEVEL &&
+ be_issuffix( op->o_bd, &e->e_nname )){
+ WT_IDL_ALL(wi, ids);
+ return 0;
+ }
+
+ revdn = mkrevdn(*ndn);
+ revdn_len = strlen(revdn);
+ rc = session->open_cursor(session, WT_INDEX_REVDN"(id, pid)",
+ NULL, NULL, &cursor);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2idl)
+ ": cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ cursor->set_key(cursor, revdn);
+ rc = cursor->search_near(cursor, &exact);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2idl)
+ ": search failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ do {
+ rc = cursor->get_key(cursor, &key);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2idl)
+ ": get_key failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ if( strncmp(revdn, key, revdn_len) ){
+ if(exact < 0){
+ rc = cursor->next(cursor);
+ if (rc) {
+ break;
+ }else{
+ continue;
+ }
+ }
+ break;
+ }
+ exact = 0;
+ rc = cursor->get_value(cursor, &id, &pid);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id)
+ ": get_value failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ if( op->ors_scope == LDAP_SCOPE_ONELEVEL &&
+ e->e_id != pid){
+ rc = cursor->next(cursor);
+ if ( rc ) {
+ break;
+ }
+ continue;
+ }else{
+ wt_idl_append_one(ids, id);
+ }
+ rc = cursor->next(cursor);
+ }while(rc == 0);
+
+ if (rc == WT_NOTFOUND ) {
+ rc = LDAP_SUCCESS;
+ }
+
+done:
+ if(revdn){
+ ch_free(revdn);
+ }
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+#if 0
+int
+wt_dn2id(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *dn,
+ ID *id)
+{
+ struct wt_info *wi = (struct wy_info *) op->o_bd->be_private;
+ WT_CURSOR *cursor = NULL;
+ int rc;
+ Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id(\"%s\")\n", dn->bv_val, 0, 0 );
+
+ rc = session->open_cursor(session, WT_INDEX_DN"(id)",
+ NULL, NULL, &cursor);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id)
+ ": cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return rc;
+ }
+ cursor->set_key(cursor, dn->bv_val);
+ rc = cursor->search(cursor);
+ if( !rc ){
+ cursor->get_key(cursor, &id);
+ }
+ cursor->close(cursor);
+ return rc;
+}
+#endif
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "idl.h"
+
+static int
+presence_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeDescription *desc,
+ ID *ids )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ slap_mask_t mask;
+ struct berval prefix = {0, NULL};
+ int rc;
+ WT_CURSOR *cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_presence_candidates (%s)\n",
+ desc->ad_cname.bv_val, 0, 0 );
+
+ WT_IDL_ALL( wi, ids );
+
+ if( desc == slap_schema.si_ad_objectClass ) {
+ return 0;
+ }
+
+ rc = wt_index_param( op->o_bd, desc, LDAP_FILTER_PRESENT,
+ &mask, &prefix );
+
+ if( rc == LDAP_INAPPROPRIATE_MATCHING ) {
+ /* not indexed */
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_presence_candidates: (%s) not indexed\n",
+ desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_presence_candidates: (%s) index_param "
+ "returned=%d\n",
+ desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ if( prefix.bv_val == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_presence_candidates: (%s) no prefix\n",
+ desc->ad_cname.bv_val, 0, 0 );
+ return -1;
+ }
+
+ /* open index cursor */
+ cursor = wt_ctx_index_cursor(wc, &desc->ad_type->sat_cname, 0);
+ if( !cursor ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_presence_candidates: open index cursor failed: %s\n",
+ desc->ad_type->sat_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ rc = wt_key_read( op->o_bd, cursor, &prefix, ids, NULL, 0 );
+
+ if(cursor){
+ cursor->close(cursor);
+ }
+ Debug(LDAP_DEBUG_TRACE,
+ "<= wt_presence_candidates: id=%ld first=%ld last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids) );
+
+ return 0;
+}
+
+static int
+equality_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeAssertion *ava,
+ ID *ids,
+ ID *tmp)
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ slap_mask_t mask;
+ struct berval prefix = {0, NULL};
+ struct berval *keys = NULL;
+ int i;
+ int rc;
+ MatchingRule *mr;
+ WT_CURSOR *cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_equality_candidates (%s)\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+
+ if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
+ ID id = NOID;
+ rc = wt_dn2id(op, wc->session, &ava->aa_value, &id);
+ if( rc == 0 ){
+ wt_idl_append_one(ids, id);
+ }else if ( rc == WT_NOTFOUND ) {
+ WT_IDL_ZERO( ids );
+ rc = 0;
+ }
+ return rc;
+ }
+
+ WT_IDL_ALL( wi, ids );
+
+ rc = wt_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
+ &mask, &prefix );
+
+ if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_equality_candidates: (%s) not indexed\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_equality_candidates: (%s) index_param failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ mr = ava->aa_desc->ad_type->sat_equality;
+ if( !mr ) {
+ return 0;
+ }
+
+ if( !mr->smr_filter ) {
+ return 0;
+ }
+
+ rc = (mr->smr_filter)(
+ LDAP_FILTER_EQUALITY,
+ mask,
+ ava->aa_desc->ad_type->sat_syntax,
+ mr,
+ &prefix,
+ &ava->aa_value,
+ &keys, op->o_tmpmemctx );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_equality_candidates: (%s, %s) "
+ "MR filter failed (%d)\n",
+ prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
+ return 0;
+ }
+
+ if( keys == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_equality_candidates: (%s) no keys\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ /* open index cursor */
+ cursor = wt_ctx_index_cursor(wc, &ava->aa_desc->ad_type->sat_cname, 0);
+ if( !cursor ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_equality_candidates: open index cursor failed: %s\n",
+ ava->aa_desc->ad_type->sat_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ for ( i= 0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_read( op->o_bd, cursor, &keys[i], tmp, NULL, 0 );
+ if( rc == WT_NOTFOUND ) {
+ WT_IDL_ZERO( ids );
+ rc = 0;
+ break;
+ } else if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_equality_candidates: (%s) "
+ "key read failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ break;
+ }
+ if ( i == 0 ) {
+ WT_IDL_CPY( ids, tmp );
+ } else {
+ wt_idl_intersection( ids, tmp );
+ }
+
+ if( WT_IDL_IS_ZERO( ids ) )
+ break;
+ }
+
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+
+ if(cursor){
+ cursor->close(cursor);
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_equality_candidates: id=%ld, first=%ld, last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids) );
+
+ return rc;
+}
+
+static int
+approx_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeAssertion *ava,
+ ID *ids,
+ ID *tmp )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ int i;
+ int rc;
+ slap_mask_t mask;
+ struct berval prefix = {0, NULL};
+ struct berval *keys = NULL;
+ MatchingRule *mr;
+ WT_CURSOR *cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_approx_candidates (%s)\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+
+ WT_IDL_ALL( wi, ids );
+
+ rc = wt_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_APPROX,
+ &mask, &prefix );
+
+ if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_approx_candidates: (%s) not indexed\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_approx_candidates: (%s) index_param failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ mr = ava->aa_desc->ad_type->sat_approx;
+ if( !mr ) {
+ /* no approx matching rule, try equality matching rule */
+ mr = ava->aa_desc->ad_type->sat_equality;
+ }
+
+ if( !mr ) {
+ return 0;
+ }
+
+ if( !mr->smr_filter ) {
+ return 0;
+ }
+
+ rc = (mr->smr_filter)(
+ LDAP_FILTER_APPROX,
+ mask,
+ ava->aa_desc->ad_type->sat_syntax,
+ mr,
+ &prefix,
+ &ava->aa_value,
+ &keys, op->o_tmpmemctx );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_approx_candidates: (%s, %s) MR filter failed (%d)\n",
+ prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
+ return 0;
+ }
+
+ if( keys == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_approx_candidates: (%s) no keys (%s)\n",
+ prefix.bv_val, ava->aa_desc->ad_cname.bv_val, 0 );
+ return 0;
+ }
+
+ /* open index cursor */
+ cursor = wt_ctx_index_cursor(wc, &ava->aa_desc->ad_type->sat_cname, 0);
+ if( !cursor ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_approx_candidates: open index cursor failed: %s\n",
+ ava->aa_desc->ad_type->sat_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ for ( i= 0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_read( op->o_bd, cursor, &keys[i], tmp, NULL, 0 );
+ if( rc == WT_NOTFOUND ) {
+ WT_IDL_ZERO( ids );
+ rc = 0;
+ break;
+ } else if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_approx_candidates: (%s) key read failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ break;
+ }
+
+ if( WT_IDL_IS_ZERO( tmp ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_approx_candidates: (%s) NULL\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ WT_IDL_ZERO( ids );
+ break;
+ }
+
+ if ( i == 0 ) {
+ WT_IDL_CPY( ids, tmp );
+ } else {
+ wt_idl_intersection( ids, tmp );
+ }
+
+ if( WT_IDL_IS_ZERO( ids ) )
+ break;
+ }
+
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+
+ if(cursor){
+ cursor->close(cursor);
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_approx_candidates %ld, first=%ld, last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids) );
+
+ return rc;
+}
+
+static int
+substring_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ SubstringsAssertion *sub,
+ ID *ids,
+ ID *tmp )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ int i;
+ int rc;
+ slap_mask_t mask;
+ struct berval prefix = {0, NULL};
+ struct berval *keys = NULL;
+ MatchingRule *mr;
+ WT_CURSOR *cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> wt_substring_candidates (%s)\n",
+ sub->sa_desc->ad_cname.bv_val, 0, 0 );
+
+ WT_IDL_ALL( wi, ids );
+
+ rc = wt_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS,
+ &mask, &prefix );
+
+ if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_substring_candidates: (%s) not indexed\n",
+ sub->sa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_substring_candidates: (%s) "
+ "index_param failed (%d)\n",
+ sub->sa_desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ mr = sub->sa_desc->ad_type->sat_substr;
+
+ if( !mr ) {
+ return 0;
+ }
+
+ if( !mr->smr_filter ) {
+ return 0;
+ }
+
+ rc = (mr->smr_filter)(
+ LDAP_FILTER_SUBSTRINGS,
+ mask,
+ sub->sa_desc->ad_type->sat_syntax,
+ mr,
+ &prefix,
+ sub,
+ &keys, op->o_tmpmemctx );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_substring_candidates: (%s) MR filter failed (%d)\n",
+ sub->sa_desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ if( keys == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_substring_candidates: (0x%04lx) no keys (%s)\n",
+ mask, sub->sa_desc->ad_cname.bv_val, 0 );
+ return 0;
+ }
+
+ /* open index cursor */
+ cursor = wt_ctx_index_cursor(wc, &sub->sa_desc->ad_cname, 0);
+ if( !cursor ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= wt_substring_candidates: open index cursor failed: %s\n",
+ sub->sa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ for ( i= 0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_read( op->o_bd, cursor, &keys[i], tmp, NULL, 0 );
+
+ if( rc == WT_NOTFOUND ) {
+ WT_IDL_ZERO( ids );
+ rc = 0;
+ break;
+ } else if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_substring_candidates: (%s) key read failed (%d)\n",
+ sub->sa_desc->ad_cname.bv_val, rc, 0 );
+ break;
+ }
+
+ if( WT_IDL_IS_ZERO( tmp ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_substring_candidates: (%s) NULL\n",
+ sub->sa_desc->ad_cname.bv_val, 0, 0 );
+ WT_IDL_ZERO( ids );
+ break;
+ }
+
+ if ( i == 0 ) {
+ WT_IDL_CPY( ids, tmp );
+ } else {
+ wt_idl_intersection( ids, tmp );
+ }
+
+ if( WT_IDL_IS_ZERO( ids ) )
+ break;
+ }
+
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+
+ if(cursor){
+ cursor->close(cursor);
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= wt_substring_candidates: %ld, first=%ld, last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids));
+ return rc;
+}
+
+
+static int
+list_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ Filter *flist,
+ int ftype,
+ ID *ids,
+ ID *tmp,
+ ID *save )
+{
+ int rc = 0;
+ Filter *f;
+
+ Debug( LDAP_DEBUG_FILTER, "=> wt_list_candidates 0x%x\n", ftype, 0, 0 );
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ /* ignore precomputed scopes */
+ if ( f->f_choice == SLAPD_FILTER_COMPUTED &&
+ f->f_result == LDAP_SUCCESS ) {
+ continue;
+ }
+ WT_IDL_ZERO( save );
+ rc = wt_filter_candidates( op, wc, f, save, tmp,
+ save+WT_IDL_UM_SIZE );
+
+ if ( rc != 0 ) {
+ /* TODO: error handling */
+ /*
+ if ( rc == DB_LOCK_DEADLOCK )
+ return rc;
+ */
+ if ( ftype == LDAP_FILTER_AND ) {
+ rc = 0;
+ continue;
+ }
+ break;
+ }
+
+
+ if ( ftype == LDAP_FILTER_AND ) {
+ if ( f == flist ) {
+ WT_IDL_CPY( ids, save );
+ } else {
+ wt_idl_intersection( ids, save );
+ }
+ if( WT_IDL_IS_ZERO( ids ) )
+ break;
+ } else {
+ if ( f == flist ) {
+ WT_IDL_CPY( ids, save );
+ } else {
+ wt_idl_union( ids, save );
+ }
+ }
+ }
+
+ if( rc == LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_FILTER,
+ "<= wt_list_candidates: id=%ld first=%ld last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids) );
+
+ } else {
+ Debug( LDAP_DEBUG_FILTER,
+ "<= wt_list_candidates: undefined rc=%d\n",
+ rc, 0, 0 );
+ }
+
+ return 0;
+}
+
+int
+wt_filter_candidates(
+ Operation *op,
+ wt_ctx *wc,
+ Filter *f,
+ ID *ids,
+ ID *tmp,
+ ID *stack )
+{
+ struct wt_info *wi = (struct wt_info *)op->o_bd->be_private;
+ int rc = 0;
+ Debug( LDAP_DEBUG_FILTER, "=> wt_filter_candidates\n", 0, 0, 0 );
+
+ if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
+ WT_IDL_ZERO( ids );
+ goto done;
+ }
+
+ switch ( f->f_choice ) {
+ case SLAPD_FILTER_COMPUTED:
+ switch( f->f_result ) {
+ case SLAPD_COMPARE_UNDEFINED:
+ /* This technically is not the same as FALSE, but it
+ * certainly will produce no matches.
+ */
+ /* FALL THRU */
+ case LDAP_COMPARE_FALSE:
+ WT_IDL_ZERO( ids );
+ break;
+ case LDAP_COMPARE_TRUE: {
+
+ WT_IDL_ALL( wi, ids );
+ } break;
+ case LDAP_SUCCESS:
+ /* this is a pre-computed scope, leave it alone */
+ break;
+ }
+ break;
+ case LDAP_FILTER_PRESENT:
+ Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
+ rc = presence_candidates( op, wc, f->f_desc, ids );
+ break;
+
+ case LDAP_FILTER_EQUALITY:
+ Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
+ rc = equality_candidates( op, wc, f->f_ava, ids, tmp );
+ break;
+
+ case LDAP_FILTER_APPROX:
+ Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
+ rc = approx_candidates( op, wc, f->f_ava, ids, tmp );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
+ rc = substring_candidates( op, wc, f->f_sub, ids, tmp );
+ break;
+
+ case LDAP_FILTER_GE:
+ /* if no GE index, use pres */
+ /* TODO: not implement yet */
+ rc = presence_candidates( op, wc, f->f_ava->aa_desc, ids );
+ break;
+
+ case LDAP_FILTER_LE:
+ /* if no LE index, use pres */
+ /* TODO: not implement yet */
+ Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
+ rc = presence_candidates( op, wc, f->f_ava->aa_desc, ids );
+ break;
+
+ case LDAP_FILTER_NOT:
+ /* no indexing to support NOT filters */
+ Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
+ WT_IDL_ALL( wi, ids );
+ break;
+
+ case LDAP_FILTER_AND:
+ Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
+ rc = list_candidates( op, wc,
+ f->f_and, LDAP_FILTER_AND, ids, tmp, stack );
+ break;
+
+ case LDAP_FILTER_OR:
+ Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
+ rc = list_candidates( op, wc,
+ f->f_or, LDAP_FILTER_OR, ids, tmp, stack );
+ break;
+
+ case LDAP_FILTER_EXT:
+ /* TODO: not implement yet */
+ Debug( LDAP_DEBUG_FILTER, "\tEXT\n", 0, 0, 0 );
+ rc = presence_candidates( op, wc, f->f_ava->aa_desc, ids );
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_FILTER, "\tUNKNOWN %lu\n",
+ (unsigned long) f->f_choice, 0, 0 );
+ /* Must not return NULL, otherwise extended filters break */
+ WT_IDL_ALL( wi, ids );
+ }
+
+done:
+ Debug( LDAP_DEBUG_FILTER,
+ "<= wt_filter_candidates: id=%ld first=%ld last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST( ids ),
+ (long) WT_IDL_LAST( ids ) );
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "back-wt.h"
+#include "config.h"
+
+static int wt_id2entry_put(
+ Operation *op,
+ WT_SESSION *session,
+ Entry *e,
+ const char *config )
+{
+ struct berval bv;
+ WT_CURSOR *cursor = NULL;
+ WT_ITEM item;
+ int rc;
+
+ rc = entry_encode( e, &bv );
+ if(rc != LDAP_SUCCESS){
+ return -1;
+ }
+ item.size = bv.bv_len;
+ item.data = bv.bv_val;
+
+ rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL,
+ config, &cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry_put)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ cursor->set_key(cursor, e->e_id);
+ cursor->set_value(cursor, e->e_ndn, &item);
+ rc = cursor->insert(cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry_put)
+ ": insert failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+done:
+ ch_free( bv.bv_val );
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+int wt_id2entry_add(
+ Operation *op,
+ WT_SESSION *session,
+ Entry *e )
+{
+ return wt_id2entry_put(op, session, e, "overwrite=false");
+}
+
+int wt_id2entry_update(
+ Operation *op,
+ WT_SESSION *session,
+ Entry *e )
+{
+ return wt_id2entry_put(op, session, e, "overwrite=true");
+}
+
+int wt_id2entry_delete(
+ Operation *op,
+ WT_SESSION *session,
+ Entry *e )
+{
+ int rc;
+ WT_CURSOR *cursor = NULL;
+ rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL,
+ NULL, &cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry_delete)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ cursor->set_key(cursor, e->e_id);
+ rc = cursor->remove(cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry_delete)
+ ": remove failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+int wt_id2entry( BackendDB *be,
+ WT_SESSION *session,
+ ID id,
+ Entry **ep ){
+ int rc;
+ WT_CURSOR *cursor = NULL;
+ WT_ITEM item;
+ EntryHeader eh;
+ int eoff;
+ Entry *e = NULL;
+
+ rc = session->open_cursor(session, WT_TABLE_ID2ENTRY"(entry)", NULL,
+ NULL, &cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->set_key(cursor, id);
+ rc = cursor->search(cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry)
+ ": search failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ cursor->get_value(cursor, &item);
+ rc = wt_entry_header( &item, &eh );
+ eoff = eh.data - (char *)item.data;
+ eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
+ eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
+ memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
+ eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
+ memcpy(eh.data, item.data, item.size);
+ eh.data += eoff;
+ rc = entry_decode( &eh, &e );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_id2entry)
+ ": entry decode error: %s (%d)\n",
+ rc, 0, 0 );
+ goto done;
+ }
+ e->e_id = id;
+ *ep = e;
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+int wt_entry_return(
+ Entry *e
+ )
+{
+ if ( !e ) {
+ return 0;
+ }
+
+ /* Our entries are allocated in two blocks; the data comes from
+ * the db itself and the Entry structure and associated pointers
+ * are allocated in entry_decode. The db data pointer is saved
+ * in e_bv.
+ */
+ if ( e->e_bv.bv_val ) {
+#if 0
+ /* See if the DNs were changed by modrdn */
+ if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val >
+ e->e_bv.bv_val + e->e_bv.bv_len ) {
+ ch_free(e->e_name.bv_val);
+ ch_free(e->e_nname.bv_val);
+ }
+#endif
+ e->e_name.bv_val = NULL;
+ e->e_nname.bv_val = NULL;
+ /* In tool mode the e_bv buffer is realloc'd, leave it alone */
+ if( !(slapMode & SLAP_TOOL_MODE) ) {
+ free( e->e_bv.bv_val );
+ }
+ BER_BVZERO( &e->e_bv );
+ }
+
+ entry_free( e );
+}
+
+int wt_entry_release(
+ Operation *op,
+ Entry *e,
+ int rw )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ return wt_entry_return( e );
+}
+
+/*
+ * return LDAP_SUCCESS IFF we can retrieve the specified entry.
+ */
+int wt_entry_get(
+ Operation *op,
+ struct berval *ndn,
+ ObjectClass *oc,
+ AttributeDescription *at,
+ int rw,
+ Entry **ent )
+{
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-wt.h"
+#include "idl.h"
+
+#define IDL_MAX(x,y) ( (x) > (y) ? (x) : (y) )
+#define IDL_MIN(x,y) ( (x) < (y) ? (x) : (y) )
+#define IDL_CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
+
+#if IDL_DEBUG > 0
+static void idl_check( ID *ids )
+{
+ if( WT_IDL_IS_RANGE( ids ) ) {
+ assert( WT_IDL_RANGE_FIRST(ids) <= WT_IDL_RANGE_LAST(ids) );
+ } else {
+ ID i;
+ for( i=1; i < ids[0]; i++ ) {
+ assert( ids[i+1] > ids[i] );
+ }
+ }
+}
+
+#if IDL_DEBUG > 1
+static void idl_dump( ID *ids )
+{
+ if( WT_IDL_IS_RANGE( ids ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "IDL: range ( %ld - %ld )\n",
+ (long) WT_IDL_RANGE_FIRST( ids ),
+ (long) WT_IDL_RANGE_LAST( ids ),
+ 0);
+
+ } else {
+ ID i;
+ Debug( LDAP_DEBUG_ANY, "IDL: size %ld", (long) ids[0], 0, 0 );
+
+ for( i=1; i<=ids[0]; i++ ) {
+ if( i % 16 == 1 ) {
+ Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 );
+ }
+ Debug( LDAP_DEBUG_ANY, " %02lx", (long) ids[i], 0, 0 );
+ }
+
+ Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 );
+ }
+
+ idl_check( ids );
+}
+#endif /* IDL_DEBUG > 1 */
+#endif /* IDL_DEBUG > 0 */
+
+unsigned wt_idl_search( ID *ids, ID id )
+{
+#define IDL_BINARY_SEARCH 1
+#ifdef IDL_BINARY_SEARCH
+ /*
+ * binary search of id in ids
+ * if found, returns position of id
+ * if not found, returns first postion greater than id
+ */
+ unsigned base = 0;
+ unsigned cursor = 1;
+ int val = 0;
+ unsigned n = ids[0];
+
+#if IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ while( 0 < n ) {
+ unsigned pivot = n >> 1;
+ cursor = base + pivot + 1;
+ val = IDL_CMP( id, ids[cursor] );
+
+ if( val < 0 ) {
+ n = pivot;
+
+ } else if ( val > 0 ) {
+ base = cursor;
+ n -= pivot + 1;
+
+ } else {
+ return cursor;
+ }
+ }
+
+ if( val > 0 ) {
+ ++cursor;
+ }
+ return cursor;
+
+#else
+ /* (reverse) linear search */
+ int i;
+
+#if IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ for( i=ids[0]; i; i-- ) {
+ if( id > ids[i] ) {
+ break;
+ }
+ }
+
+ return i+1;
+#endif
+}
+
+int wt_idl_insert( ID *ids, ID id )
+{
+ unsigned x;
+
+#if IDL_DEBUG > 1
+ Debug( LDAP_DEBUG_ANY, "insert: %04lx at %d\n", (long) id, x, 0 );
+ idl_dump( ids );
+#elif IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ if (WT_IDL_IS_RANGE( ids )) {
+ /* if already in range, treat as a dup */
+ if (id >= WT_IDL_RANGE_FIRST(ids) && id <= WT_IDL_RANGE_LAST(ids))
+ return -1;
+ if (id < WT_IDL_RANGE_FIRST(ids))
+ ids[1] = id;
+ else if (id > WT_IDL_RANGE_LAST(ids))
+ ids[2] = id;
+ return 0;
+ }
+
+ x = wt_idl_search( ids, id );
+ assert( x > 0 );
+
+ if( x < 1 ) {
+ /* internal error */
+ return -2;
+ }
+
+ if ( x <= ids[0] && ids[x] == id ) {
+ /* duplicate */
+ return -1;
+ }
+
+ if ( ++ids[0] >= WT_IDL_DB_MAX ) {
+ if( id < ids[1] ) {
+ ids[1] = id;
+ ids[2] = ids[ids[0]-1];
+ } else if ( ids[ids[0]-1] < id ) {
+ ids[2] = id;
+ } else {
+ ids[2] = ids[ids[0]-1];
+ }
+ ids[0] = NOID;
+
+ } else {
+ /* insert id */
+ AC_MEMCPY( &ids[x+1], &ids[x], (ids[0]-x) * sizeof(ID) );
+ ids[x] = id;
+ }
+
+#if IDL_DEBUG > 1
+ idl_dump( ids );
+#elif IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ return 0;
+}
+
+static int wt_idl_delete( ID *ids, ID id )
+{
+ unsigned x;
+
+#if IDL_DEBUG > 1
+ Debug( LDAP_DEBUG_ANY, "delete: %04lx at %d\n", (long) id, x, 0 );
+ idl_dump( ids );
+#elif IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ if (WT_IDL_IS_RANGE( ids )) {
+ /* If deleting a range boundary, adjust */
+ if ( ids[1] == id )
+ ids[1]++;
+ else if ( ids[2] == id )
+ ids[2]--;
+ /* deleting from inside a range is a no-op */
+
+ /* If the range has collapsed, re-adjust */
+ if ( ids[1] > ids[2] )
+ ids[0] = 0;
+ else if ( ids[1] == ids[2] )
+ ids[1] = 1;
+ return 0;
+ }
+
+ x = wt_idl_search( ids, id );
+ assert( x > 0 );
+
+ if( x <= 0 ) {
+ /* internal error */
+ return -2;
+ }
+
+ if( x > ids[0] || ids[x] != id ) {
+ /* not found */
+ return -1;
+
+ } else if ( --ids[0] == 0 ) {
+ if( x != 1 ) {
+ return -3;
+ }
+
+ } else {
+ AC_MEMCPY( &ids[x], &ids[x+1], (1+ids[0]-x) * sizeof(ID) );
+ }
+
+#if IDL_DEBUG > 1
+ idl_dump( ids );
+#elif IDL_DEBUG > 0
+ idl_check( ids );
+#endif
+
+ return 0;
+}
+
+static char *
+wt_show_key(
+ char *buf,
+ void *val,
+ size_t len )
+{
+ if ( len == 4 /* LUTIL_HASH_BYTES */ ) {
+ unsigned char *c = val;
+ sprintf( buf, "[%02x%02x%02x%02x]", c[0], c[1], c[2], c[3] );
+ return buf;
+ } else {
+ return val;
+ }
+}
+
+/*
+ * idl_intersection - return a = a intersection b
+ */
+int
+wt_idl_intersection(
+ ID *a,
+ ID *b )
+{
+ ID ida, idb;
+ ID idmax, idmin;
+ ID cursora = 0, cursorb = 0, cursorc;
+ int swap = 0;
+
+ if ( WT_IDL_IS_ZERO( a ) || WT_IDL_IS_ZERO( b ) ) {
+ a[0] = 0;
+ return 0;
+ }
+
+ idmin = IDL_MAX( WT_IDL_FIRST(a), WT_IDL_FIRST(b) );
+ idmax = IDL_MIN( WT_IDL_LAST(a), WT_IDL_LAST(b) );
+ if ( idmin > idmax ) {
+ a[0] = 0;
+ return 0;
+ } else if ( idmin == idmax ) {
+ a[0] = 1;
+ a[1] = idmin;
+ return 0;
+ }
+
+ if ( WT_IDL_IS_RANGE( a ) ) {
+ if ( WT_IDL_IS_RANGE(b) ) {
+ /* If both are ranges, just shrink the boundaries */
+ a[1] = idmin;
+ a[2] = idmax;
+ return 0;
+ } else {
+ /* Else swap so that b is the range, a is a list */
+ ID *tmp = a;
+ a = b;
+ b = tmp;
+ swap = 1;
+ }
+ }
+
+ /* If a range completely covers the list, the result is
+ * just the list. If idmin to idmax is contiguous, just
+ * turn it into a range.
+ */
+ if ( WT_IDL_IS_RANGE( b )
+ && WT_IDL_RANGE_FIRST( b ) <= WT_IDL_FIRST( a )
+ && WT_IDL_RANGE_LAST( b ) >= WT_IDL_LLAST( a ) ) {
+ if (idmax - idmin + 1 == a[0])
+ {
+ a[0] = NOID;
+ a[1] = idmin;
+ a[2] = idmax;
+ }
+ goto done;
+ }
+
+ /* Fine, do the intersection one element at a time.
+ * First advance to idmin in both IDLs.
+ */
+ cursora = cursorb = idmin;
+ ida = wt_idl_first( a, &cursora );
+ idb = wt_idl_first( b, &cursorb );
+ cursorc = 0;
+
+ while( ida <= idmax || idb <= idmax ) {
+ if( ida == idb ) {
+ a[++cursorc] = ida;
+ ida = wt_idl_next( a, &cursora );
+ idb = wt_idl_next( b, &cursorb );
+ } else if ( ida < idb ) {
+ ida = wt_idl_next( a, &cursora );
+ } else {
+ idb = wt_idl_next( b, &cursorb );
+ }
+ }
+ a[0] = cursorc;
+done:
+ if (swap)
+ WT_IDL_CPY( b, a );
+
+ return 0;
+}
+
+
+/*
+ * idl_union - return a = a union b
+ */
+int
+wt_idl_union(
+ ID *a,
+ ID *b )
+{
+ ID ida, idb;
+ ID cursora = 0, cursorb = 0, cursorc;
+
+ if ( WT_IDL_IS_ZERO( b ) ) {
+ return 0;
+ }
+
+ if ( WT_IDL_IS_ZERO( a ) ) {
+ WT_IDL_CPY( a, b );
+ return 0;
+ }
+
+ if ( WT_IDL_IS_RANGE( a ) || WT_IDL_IS_RANGE(b) ) {
+over: ida = IDL_MIN( WT_IDL_FIRST(a), WT_IDL_FIRST(b) );
+ idb = IDL_MAX( WT_IDL_LAST(a), WT_IDL_LAST(b) );
+ a[0] = NOID;
+ a[1] = ida;
+ a[2] = idb;
+ return 0;
+ }
+
+ ida = wt_idl_first( a, &cursora );
+ idb = wt_idl_first( b, &cursorb );
+
+ cursorc = b[0];
+
+ /* The distinct elements of a are cat'd to b */
+ while( ida != NOID || idb != NOID ) {
+ if ( ida < idb ) {
+ if( ++cursorc > WT_IDL_UM_MAX ) {
+ goto over;
+ }
+ b[cursorc] = ida;
+ ida = wt_idl_next( a, &cursora );
+
+ } else {
+ if ( ida == idb )
+ ida = wt_idl_next( a, &cursora );
+ idb = wt_idl_next( b, &cursorb );
+ }
+ }
+
+ /* b is copied back to a in sorted order */
+ a[0] = cursorc;
+ cursora = 1;
+ cursorb = 1;
+ cursorc = b[0]+1;
+ while (cursorb <= b[0] || cursorc <= a[0]) {
+ if (cursorc > a[0])
+ idb = NOID;
+ else
+ idb = b[cursorc];
+ if (cursorb <= b[0] && b[cursorb] < idb)
+ a[cursora++] = b[cursorb++];
+ else {
+ a[cursora++] = idb;
+ cursorc++;
+ }
+ }
+
+ return 0;
+}
+
+
+#if 0
+/*
+ * wt_idl_notin - return a intersection ~b (or a minus b)
+ */
+int
+wt_idl_notin(
+ ID *a,
+ ID *b,
+ ID *ids )
+{
+ ID ida, idb;
+ ID cursora = 0, cursorb = 0;
+
+ if( WT_IDL_IS_ZERO( a ) ||
+ WT_IDL_IS_ZERO( b ) ||
+ WT_IDL_IS_RANGE( b ) )
+ {
+ WT_IDL_CPY( ids, a );
+ return 0;
+ }
+
+ if( WT_IDL_IS_RANGE( a ) ) {
+ WT_IDL_CPY( ids, a );
+ return 0;
+ }
+
+ ida = wt_idl_first( a, &cursora ),
+ idb = wt_idl_first( b, &cursorb );
+
+ ids[0] = 0;
+
+ while( ida != NOID ) {
+ if ( idb == NOID ) {
+ /* we could shortcut this */
+ ids[++ids[0]] = ida;
+ ida = wt_idl_next( a, &cursora );
+
+ } else if ( ida < idb ) {
+ ids[++ids[0]] = ida;
+ ida = wt_idl_next( a, &cursora );
+
+ } else if ( ida > idb ) {
+ idb = wt_idl_next( b, &cursorb );
+
+ } else {
+ ida = wt_idl_next( a, &cursora );
+ idb = wt_idl_next( b, &cursorb );
+ }
+ }
+
+ return 0;
+}
+#endif
+
+ID wt_idl_first( ID *ids, ID *cursor )
+{
+ ID pos;
+
+ if ( ids[0] == 0 ) {
+ *cursor = NOID;
+ return NOID;
+ }
+
+ if ( WT_IDL_IS_RANGE( ids ) ) {
+ if( *cursor < ids[1] ) {
+ *cursor = ids[1];
+ }
+ return *cursor;
+ }
+
+ if ( *cursor == 0 )
+ pos = 1;
+ else
+ pos = wt_idl_search( ids, *cursor );
+
+ if( pos > ids[0] ) {
+ return NOID;
+ }
+
+ *cursor = pos;
+ return ids[pos];
+}
+
+ID wt_idl_next( ID *ids, ID *cursor )
+{
+ if ( WT_IDL_IS_RANGE( ids ) ) {
+ if( ids[2] < ++(*cursor) ) {
+ return NOID;
+ }
+ return *cursor;
+ }
+
+ if ( ++(*cursor) <= ids[0] ) {
+ return ids[*cursor];
+ }
+
+ return NOID;
+}
+
+/* Add one ID to an unsorted list. We ensure that the first element is the
+ * minimum and the last element is the maximum, for fast range compaction.
+ * this means IDLs up to length 3 are always sorted...
+ */
+int wt_idl_append_one( ID *ids, ID id )
+{
+ if (WT_IDL_IS_RANGE( ids )) {
+ /* if already in range, treat as a dup */
+ if (id >= WT_IDL_RANGE_FIRST(ids) && id <= WT_IDL_RANGE_LAST(ids))
+ return -1;
+ if (id < WT_IDL_RANGE_FIRST(ids))
+ ids[1] = id;
+ else if (id > WT_IDL_RANGE_LAST(ids))
+ ids[2] = id;
+ return 0;
+ }
+ if ( ids[0] ) {
+ ID tmp;
+
+ if (id < ids[1]) {
+ tmp = ids[1];
+ ids[1] = id;
+ id = tmp;
+ }
+ if ( ids[0] > 1 && id < ids[ids[0]] ) {
+ tmp = ids[ids[0]];
+ ids[ids[0]] = id;
+ id = tmp;
+ }
+ }
+ ids[0]++;
+ if ( ids[0] >= WT_IDL_UM_MAX ) {
+ ids[0] = NOID;
+ ids[2] = id;
+ } else {
+ ids[ids[0]] = id;
+ }
+ return 0;
+}
+
+/* Append sorted list b to sorted list a. The result is unsorted but
+ * a[1] is the min of the result and a[a[0]] is the max.
+ */
+int wt_idl_append( ID *a, ID *b )
+{
+ ID ida, idb, tmp, swap = 0;
+
+ if ( WT_IDL_IS_ZERO( b ) ) {
+ return 0;
+ }
+
+ if ( WT_IDL_IS_ZERO( a ) ) {
+ WT_IDL_CPY( a, b );
+ return 0;
+ }
+
+ ida = WT_IDL_LAST( a );
+ idb = WT_IDL_LAST( b );
+ if ( WT_IDL_IS_RANGE( a ) || WT_IDL_IS_RANGE(b) ||
+ a[0] + b[0] >= WT_IDL_UM_MAX ) {
+ a[2] = IDL_MAX( ida, idb );
+ a[1] = IDL_MIN( a[1], b[1] );
+ a[0] = NOID;
+ return 0;
+ }
+
+ if ( b[0] > 1 && ida > idb ) {
+ swap = idb;
+ a[a[0]] = idb;
+ b[b[0]] = ida;
+ }
+
+ if ( b[1] < a[1] ) {
+ tmp = a[1];
+ a[1] = b[1];
+ } else {
+ tmp = b[1];
+ }
+ a[0]++;
+ a[a[0]] = tmp;
+
+ if ( b[0] > 1 ) {
+ int i = b[0] - 1;
+ AC_MEMCPY(a+a[0]+1, b+2, i * sizeof(ID));
+ a[0] += i;
+ }
+ if ( swap ) {
+ b[b[0]] = swap;
+ }
+ return 0;
+}
+
+#if 1
+
+/* Quicksort + Insertion sort for small arrays */
+
+#define SMALL 8
+#define SWAP(a,b) itmp=(a);(a)=(b);(b)=itmp
+
+void
+wt_idl_sort( ID *ids, ID *tmp )
+{
+ int *istack = (int *)tmp; /* Private stack, not used by caller */
+ int i,j,k,l,ir,jstack;
+ ID a, itmp;
+
+ if ( WT_IDL_IS_RANGE( ids ))
+ return;
+
+ ir = ids[0];
+ l = 1;
+ jstack = 0;
+ for(;;) {
+ if (ir - l < SMALL) { /* Insertion sort */
+ for (j=l+1;j<=ir;j++) {
+ a = ids[j];
+ for (i=j-1;i>=1;i--) {
+ if (ids[i] <= a) break;
+ ids[i+1] = ids[i];
+ }
+ ids[i+1] = a;
+ }
+ if (jstack == 0) break;
+ ir = istack[jstack--];
+ l = istack[jstack--];
+ } else {
+ k = (l + ir) >> 1; /* Choose median of left, center, right */
+ SWAP(ids[k], ids[l+1]);
+ if (ids[l] > ids[ir]) {
+ SWAP(ids[l], ids[ir]);
+ }
+ if (ids[l+1] > ids[ir]) {
+ SWAP(ids[l+1], ids[ir]);
+ }
+ if (ids[l] > ids[l+1]) {
+ SWAP(ids[l], ids[l+1]);
+ }
+ i = l+1;
+ j = ir;
+ a = ids[l+1];
+ for(;;) {
+ do i++; while(ids[i] < a);
+ do j--; while(ids[j] > a);
+ if (j < i) break;
+ SWAP(ids[i],ids[j]);
+ }
+ ids[l+1] = ids[j];
+ ids[j] = a;
+ jstack += 2;
+ if (ir-i+1 >= j-l) {
+ istack[jstack] = ir;
+ istack[jstack-1] = i;
+ ir = j-1;
+ } else {
+ istack[jstack] = j-1;
+ istack[jstack-1] = l;
+ l = i;
+ }
+ }
+ }
+}
+
+#else
+
+/* 8 bit Radix sort + insertion sort
+ *
+ * based on code from http://www.cubic.org/docs/radix.htm
+ * with improvements by ebackes@symas.com and hyc@symas.com
+ *
+ * This code is O(n) but has a relatively high constant factor. For lists
+ * up to ~50 Quicksort is slightly faster; up to ~100 they are even.
+ * Much faster than quicksort for lists longer than ~100. Insertion
+ * sort is actually superior for lists <50.
+ */
+
+#define BUCKETS (1<<8)
+#define SMALL 50
+
+void
+wt_idl_sort( ID *ids, ID *tmp )
+{
+ int count, soft_limit, phase = 0, size = ids[0];
+ ID *idls[2];
+ unsigned char *maxv = (unsigned char *)&ids[size];
+
+ if ( WT_IDL_IS_RANGE( ids ))
+ return;
+
+ /* Use insertion sort for small lists */
+ if ( size <= SMALL ) {
+ int i,j;
+ ID a;
+
+ for (j=1;j<=size;j++) {
+ a = ids[j];
+ for (i=j-1;i>=1;i--) {
+ if (ids[i] <= a) break;
+ ids[i+1] = ids[i];
+ }
+ ids[i+1] = a;
+ }
+ return;
+ }
+
+ tmp[0] = size;
+ idls[0] = ids;
+ idls[1] = tmp;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ for (soft_limit = 0; !maxv[soft_limit]; soft_limit++);
+#else
+ for (soft_limit = sizeof(ID)-1; !maxv[soft_limit]; soft_limit--);
+#endif
+
+ for (
+#if BYTE_ORDER == BIG_ENDIAN
+ count = sizeof(ID)-1; count >= soft_limit; --count
+#else
+ count = 0; count <= soft_limit; ++count
+#endif
+ ) {
+ unsigned int num[BUCKETS], * np, n, sum;
+ int i;
+ ID *sp, *source, *dest;
+ unsigned char *bp, *source_start;
+
+ source = idls[phase]+1;
+ dest = idls[phase^1]+1;
+ source_start = ((unsigned char *) source) + count;
+
+ np = num;
+ for ( i = BUCKETS; i > 0; --i ) *np++ = 0;
+
+ /* count occurences of every byte value */
+ bp = source_start;
+ for ( i = size; i > 0; --i, bp += sizeof(ID) )
+ num[*bp]++;
+
+ /* transform count into index by summing elements and storing
+ * into same array
+ */
+ sum = 0;
+ np = num;
+ for ( i = BUCKETS; i > 0; --i ) {
+ n = *np;
+ *np++ = sum;
+ sum += n;
+ }
+
+ /* fill dest with the right values in the right place */
+ bp = source_start;
+ sp = source;
+ for ( i = size; i > 0; --i, bp += sizeof(ID) ) {
+ np = num + *bp;
+ dest[*np] = *sp++;
+ ++(*np);
+ }
+ phase ^= 1;
+ }
+
+ /* copy back from temp if needed */
+ if ( phase ) {
+ ids++; tmp++;
+ for ( count = 0; count < size; ++count )
+ *ids++ = *tmp++;
+ }
+}
+#endif /* Quick vs Radix */
+
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#ifndef _WI_IDL_H_
+#define _WT_IDL_H_
+
+/* IDL sizes - likely should be even bigger
+ * limiting factors: sizeof(ID), thread stack size
+ */
+#define WT_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
+#define WT_IDL_DB_SIZE (1<<WT_IDL_LOGN)
+#define WT_IDL_UM_SIZE (1<<(WT_IDL_LOGN+1))
+#define WT_IDL_UM_SIZEOF (WT_IDL_UM_SIZE * sizeof(ID))
+
+#define WT_IDL_DB_MAX (WT_IDL_DB_SIZE-1)
+
+#define WT_IDL_UM_MAX (WT_IDL_UM_SIZE-1)
+
+#define WT_IDL_IS_RANGE(ids) ((ids)[0] == NOID)
+#define WT_IDL_RANGE_SIZE (3)
+#define WT_IDL_RANGE_SIZEOF (WT_IDL_RANGE_SIZE * sizeof(ID))
+#define WT_IDL_SIZEOF(ids) ((WT_IDL_IS_RANGE(ids) \
+ ? WT_IDL_RANGE_SIZE : ((ids)[0]+1)) * sizeof(ID))
+
+#define WT_IDL_RANGE_FIRST(ids) ((ids)[1])
+#define WT_IDL_RANGE_LAST(ids) ((ids)[2])
+
+#define WT_IDL_RANGE( ids, f, l ) \
+ do { \
+ (ids)[0] = NOID; \
+ (ids)[1] = (f); \
+ (ids)[2] = (l); \
+ } while(0)
+
+#define WT_IDL_ZERO(ids) \
+ do { \
+ (ids)[0] = 0; \
+ (ids)[1] = 0; \
+ (ids)[2] = 0; \
+ } while(0)
+
+#define WT_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
+#define WT_IDL_IS_ALL( range, ids ) ( (ids)[0] == NOID \
+ && (ids)[1] <= (range)[1] && (range)[2] <= (ids)[2] )
+
+#define WT_IDL_CPY( dst, src ) (AC_MEMCPY( dst, src, WT_IDL_SIZEOF( src ) ))
+
+#define WT_IDL_ID( wi, ids, id ) WT_IDL_RANGE( ids, id, ((wi)->wi_lastid) )
+#define WT_IDL_ALL( wi, ids ) WT_IDL_RANGE( ids, 1, ((wi)->wi_lastid) )
+
+#define WT_IDL_FIRST( ids ) ( (ids)[1] )
+#define WT_IDL_LLAST( ids ) ( (ids)[(ids)[0]] )
+#define WT_IDL_LAST( ids ) ( WT_IDL_IS_RANGE(ids) \
+ ? (ids)[2] : (ids)[(ids)[0]] )
+
+#define WT_IDL_N( ids ) ( WT_IDL_IS_RANGE(ids) \
+ ? ((ids)[2]-(ids)[1])+1 : (ids)[0] )
+
+LDAP_BEGIN_DECL
+LDAP_END_DECL
+
+#endif
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include "back-wt.h"
+#include "config.h"
+
+static char presence_keyval[] = {0,0};
+static struct berval presence_key = BER_BVC(presence_keyval);
+
+AttrInfo *wt_index_mask(
+ Backend *be,
+ AttributeDescription *desc,
+ struct berval *atname )
+{
+ AttributeType *at;
+ AttrInfo *ai = wt_attr_mask( be->be_private, desc );
+
+ if( ai ) {
+ *atname = desc->ad_cname;
+ return ai;
+ }
+
+ /* If there is a tagging option, did we ever index the base
+ * type? If so, check for mask, otherwise it's not there.
+ */
+ if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
+ /* has tagging option */
+ ai = wt_attr_mask( be->be_private, desc->ad_type->sat_ad );
+
+ if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) {
+ *atname = desc->ad_type->sat_cname;
+ return ai;
+ }
+ }
+
+ /* see if supertype defined mask for its subtypes */
+ for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
+ /* If no AD, we've never indexed this type */
+ if ( !at->sat_ad ) continue;
+
+ ai = wt_attr_mask( be->be_private, at->sat_ad );
+
+ if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) {
+ *atname = at->sat_cname;
+ return ai;
+ }
+ }
+
+ return 0;
+}
+
+/* This function is only called when evaluating search filters.
+ */
+int wt_index_param(
+ Backend *be,
+ AttributeDescription *desc,
+ int ftype,
+ slap_mask_t *maskp,
+ struct berval *prefixp )
+{
+ AttrInfo *ai;
+ int rc;
+ slap_mask_t mask, type = 0;
+
+ ai = wt_index_mask( be, desc, prefixp );
+
+ if ( !ai ) {
+ /* TODO: add monitor */
+ return LDAP_INAPPROPRIATE_MATCHING;
+ }
+ mask = ai->ai_indexmask;
+
+ switch( ftype ) {
+ case LDAP_FILTER_PRESENT:
+ type = SLAP_INDEX_PRESENT;
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
+ *prefixp = presence_key;
+ *maskp = mask;
+ return LDAP_SUCCESS;
+ }
+ break;
+
+ case LDAP_FILTER_APPROX:
+ type = SLAP_INDEX_APPROX;
+ if ( desc->ad_type->sat_approx ) {
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
+ *maskp = mask;
+ return LDAP_SUCCESS;
+ }
+ break;
+ }
+
+ /* Use EQUALITY rule and index for approximate match */
+ /* fall thru */
+
+ case LDAP_FILTER_EQUALITY:
+ type = SLAP_INDEX_EQUALITY;
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
+ *maskp = mask;
+ return LDAP_SUCCESS;
+ }
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ type = SLAP_INDEX_SUBSTR;
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
+ *maskp = mask;
+ return LDAP_SUCCESS;
+ }
+ break;
+
+ default:
+ return LDAP_OTHER;
+ }
+
+ /* TODO: add monitor index */
+ return LDAP_INAPPROPRIATE_MATCHING;
+}
+
+static int indexer(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeDescription *ad,
+ struct berval *atname,
+ BerVarray vals,
+ ID id,
+ int opid,
+ slap_mask_t mask )
+{
+ int rc, i;
+ struct berval *keys;
+ WT_CURSOR *cursor = NULL;
+ WT_SESSION *session = wc->session;
+ assert( mask != 0 );
+
+ cursor = wt_ctx_index_cursor(wc, atname, 1);
+ if( !cursor ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(indexer)
+ ": open index cursor failed: %s\n",
+ atname->bv_val, 0, 0 );
+ goto done;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
+ rc = wt_key_change( op->o_bd, cursor, &presence_key, id, opid );
+ if( rc ) {
+ goto done;
+ }
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
+ rc = ad->ad_type->sat_equality->smr_indexer(
+ LDAP_FILTER_EQUALITY,
+ mask,
+ ad->ad_type->sat_syntax,
+ ad->ad_type->sat_equality,
+ atname, vals, &keys, op->o_tmpmemctx );
+
+ if( rc == LDAP_SUCCESS && keys != NULL ) {
+ for( i=0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
+ if( rc ) {
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ goto done;
+ }
+ }
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ }
+ rc = LDAP_SUCCESS;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
+ rc = ad->ad_type->sat_approx->smr_indexer(
+ LDAP_FILTER_APPROX,
+ mask,
+ ad->ad_type->sat_syntax,
+ ad->ad_type->sat_approx,
+ atname, vals, &keys, op->o_tmpmemctx );
+
+ if( rc == LDAP_SUCCESS && keys != NULL ) {
+ for( i=0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
+ if( rc ) {
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ goto done;
+ }
+ }
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ }
+
+ rc = LDAP_SUCCESS;
+ }
+
+ if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
+ rc = ad->ad_type->sat_substr->smr_indexer(
+ LDAP_FILTER_SUBSTRINGS,
+ mask,
+ ad->ad_type->sat_syntax,
+ ad->ad_type->sat_substr,
+ atname, vals, &keys, op->o_tmpmemctx );
+
+ if( rc == LDAP_SUCCESS && keys != NULL ) {
+ for( i=0; keys[i].bv_val != NULL; i++ ) {
+ rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
+ if( rc ) {
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ goto done;
+ }
+ }
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+ }
+
+ rc = LDAP_SUCCESS;
+ }
+
+done:
+ if(cursor){
+ cursor->close(cursor);
+ }
+ return rc;
+}
+
+static int index_at_values(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeDescription *ad,
+ AttributeType *type,
+ struct berval *tags,
+ BerVarray vals,
+ ID id,
+ int opid )
+{
+ int rc;
+ slap_mask_t mask = 0;
+ int ixop = opid;
+ AttrInfo *ai = NULL;
+
+ if ( opid == WT_INDEX_UPDATE_OP )
+ ixop = SLAP_INDEX_ADD_OP;
+
+ if( type->sat_sup ) {
+ /* recurse */
+ rc = index_at_values( op, wc, NULL,
+ type->sat_sup, tags,
+ vals, id, opid );
+
+ if( rc ) return rc;
+ }
+
+ /* If this type has no AD, we've never used it before */
+ if( type->sat_ad ) {
+ ai = wt_attr_mask( op->o_bd->be_private, type->sat_ad );
+ if ( ai ) {
+ #ifdef LDAP_COMP_MATCH
+ /* component indexing */
+ if ( ai->ai_cr ) {
+ ComponentReference *cr;
+ for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
+ rc = indexer( op, wc, cr->cr_ad, &type->sat_cname,
+ cr->cr_nvals, id, ixop,
+ cr->cr_indexmask );
+ }
+ }
+ #endif
+ ad = type->sat_ad;
+ /* If we're updating the index, just set the new bits that aren't
+ * already in the old mask.
+ */
+ if ( opid == WT_INDEX_UPDATE_OP )
+ mask = ai->ai_newmask & ~ai->ai_indexmask;
+ else
+ /* For regular updates, if there is a newmask use it. Otherwise
+ * just use the old mask.
+ */
+ mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
+ if( mask ) {
+ rc = indexer( op, wc, ad, &type->sat_cname,
+ vals, id, ixop, mask );
+ if( rc ) return rc;
+ }
+ }
+ }
+
+ if( tags->bv_len ) {
+ AttributeDescription *desc;
+
+ desc = ad_find_tags( type, tags );
+ if( desc ) {
+ ai = wt_attr_mask( op->o_bd->be_private, desc );
+
+ if( ai ) {
+ if ( opid == WT_INDEX_UPDATE_OP )
+ mask = ai->ai_newmask & ~ai->ai_indexmask;
+ else
+ mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
+ if ( mask ) {
+ rc = indexer( op, wc, desc, &desc->ad_cname,
+ vals, id, ixop, mask );
+
+ if( rc ) {
+ return rc;
+ }
+ }
+ }
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int wt_index_values(
+ Operation *op,
+ wt_ctx *wc,
+ AttributeDescription *desc,
+ BerVarray vals,
+ ID id,
+ int opid )
+{
+ int rc;
+
+ /* Never index ID 0 */
+ if ( id == 0 )
+ return 0;
+
+ rc = index_at_values( op, wc, desc,
+ desc->ad_type, &desc->ad_tags,
+ vals, id, opid );
+
+ return rc;
+}
+
+int
+wt_index_entry( Operation *op, wt_ctx *wc, int opid, Entry *e )
+{
+ int rc;
+ Attribute *ap = e->e_attrs;
+
+ if ( e->e_id == 0 )
+ return 0;
+
+ Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
+ opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
+ (long) e->e_id, e->e_dn ? e->e_dn : "" );
+
+ for ( ; ap != NULL; ap = ap->a_next ) {
+ rc = wt_index_values( op, wc, ap->a_desc,
+ ap->a_nvals, e->e_id, opid );
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= index_entry_%s( %ld, \"%s\" ) failure\n",
+ opid == SLAP_INDEX_ADD_OP ? "add" : "del",
+ (long) e->e_id, e->e_dn );
+ return rc;
+ }
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
+ opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
+ (long) e->e_id, e->e_dn ? e->e_dn : "" );
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+
+static int
+wt_db_init( BackendDB *be, ConfigReply *cr )
+{
+ struct wt_info *wi;
+
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_db_init) ": Initializing wt backend\n",
+ 0, 0, 0 );
+
+ /* allocate backend-database-specific stuff */
+ wi = ch_calloc( 1, sizeof(struct wt_info) );
+
+ wi->wi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
+ wi->wi_dbenv_config = ch_strdup("create");
+ wi->wi_lastid = 0;
+ wi->wi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
+ wi->wi_search_stack = NULL;
+
+ be->be_private = wi;
+ be->be_cf_ocs = be->bd_info->bi_cf_ocs;
+
+ return LDAP_SUCCESS;
+}
+
+static int
+wt_db_open( BackendDB *be, ConfigReply *cr )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+ struct stat st;
+ WT_CONNECTION *conn;
+ WT_SESSION *session;
+
+ if ( be->be_suffix == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": need suffix.\n",
+ 1, 0, 0 );
+ return -1;
+ }
+
+ Debug( LDAP_DEBUG_ARGS,
+ LDAP_XSTRING(wt_db_open) ": \"%s\"\n",
+ be->be_suffix[0].bv_val, 0, 0 );
+
+ /* Check existence of home. Any error means trouble */
+ rc = stat( wi->wi_dbenv_home, &st );
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot access database directory \"%s\" (%d).\n",
+ be->be_suffix[0].bv_val, wi->wi_dbenv_home, errno );
+ return -1;
+ }
+
+ /* Open and create database */
+ rc = wiredtiger_open(wi->wi_dbenv_home, NULL,
+ wi->wi_dbenv_config, &conn);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot open database \"%s\" (%d).\n",
+ be->be_suffix[0].bv_val, wi->wi_dbenv_home, errno );
+ return -1;
+ }
+
+ rc = conn->open_session(conn, NULL, NULL, &session);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot open session: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ rc = session->create(session,
+ WT_TABLE_ID2ENTRY,
+ "key_format=Q,"
+ "value_format=Su,"
+ "columns=(id,dn,entry)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot create entry table: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ rc = session->create(session,
+ WT_TABLE_DN2ID,
+ "key_format=S,"
+ "value_format=QQS,"
+ "columns=(ndn,id,pid,revdn)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot create entry table: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ /* not using dn2id index for id2entry table */
+ rc = session->create(session, WT_INDEX_DN, "columns=(dn)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot create dn index: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ rc = session->create(session, WT_INDEX_PID, "columns=(pid)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot create pid index: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ rc = session->create(session, WT_INDEX_REVDN, "columns=(revdn)");
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": database \"%s\": "
+ "cannot create revdn index: \"%s\"\n",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
+ return -1;
+ }
+
+ rc = wt_last_id( be, session, &wi->wi_lastid);
+ if (rc) {
+ snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
+ "last_id() failed: %s(%d).",
+ be->be_suffix[0].bv_val, wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_open) ": %s\n",
+ cr->msg, 0, 0 );
+ return rc;
+ }
+
+ session->close(session, NULL);
+ wi->wi_conn = conn;
+ wi->wi_flags |= WT_IS_OPEN;
+
+ return LDAP_SUCCESS;
+}
+
+static int
+wt_db_close( BackendDB *be, ConfigReply *cr )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+
+ rc = wi->wi_conn->close(wi->wi_conn, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_db_close)
+ ": cannot close database (%d).\n",
+ errno, 0, 0);
+ return -1;
+ }
+
+ wi->wi_flags &= ~WT_IS_OPEN;
+
+ return LDAP_SUCCESS;
+}
+
+static int
+wt_db_destroy( Backend *be, ConfigReply *cr )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+
+ if( wi->wi_dbenv_home ) {
+ ch_free( wi->wi_dbenv_home );
+ wi->wi_dbenv_home = NULL;
+ }
+ if( wi->wi_dbenv_config ) {
+ ch_free( wi->wi_dbenv_config );
+ wi->wi_dbenv_config = NULL;
+ }
+
+ wt_attr_index_destroy( wi );
+ ch_free( wi );
+ be->be_private = NULL;
+
+ return LDAP_SUCCESS;
+}
+
+int
+wt_back_initialize( BackendInfo *bi )
+{
+ static char *controls[] = {
+ LDAP_CONTROL_ASSERT,
+ LDAP_CONTROL_MANAGEDSAIT,
+ LDAP_CONTROL_NOOP,
+ LDAP_CONTROL_PAGEDRESULTS,
+ LDAP_CONTROL_PRE_READ,
+ LDAP_CONTROL_POST_READ,
+ LDAP_CONTROL_SUBENTRIES,
+ LDAP_CONTROL_X_PERMISSIVE_MODIFY,
+ NULL
+ };
+
+ /* initialize the database system */
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_back_initialize)
+ ": initialize WiredTiger backend\n",
+ 0, 0, 0 );
+
+ bi->bi_flags |=
+ SLAP_BFLAG_INCREMENT |
+ SLAP_BFLAG_SUBENTRIES |
+ SLAP_BFLAG_ALIASES |
+ SLAP_BFLAG_REFERRALS;
+
+ bi->bi_controls = controls;
+
+ { /* version check */
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_back_initialize) ": %s\n",
+ wiredtiger_version(NULL, NULL, NULL), 0, 0 );
+ }
+
+ bi->bi_open = 0;
+ bi->bi_close = 0;
+ bi->bi_config = 0;
+ bi->bi_destroy = 0;
+
+ bi->bi_db_init = wt_db_init;
+ bi->bi_db_config = config_generic_wrapper;
+ bi->bi_db_open = wt_db_open;
+ bi->bi_db_close = wt_db_close;
+ bi->bi_db_destroy = wt_db_destroy;
+
+ bi->bi_op_add = wt_add;
+ bi->bi_op_bind = wt_bind;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = wt_search;
+ bi->bi_op_compare = wt_compare;
+ bi->bi_op_modify = 0;
+ bi->bi_op_modrdn = 0;
+ bi->bi_op_delete = wt_delete;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_chk_referrals = 0;
+ bi->bi_operational = wt_operational;
+
+ bi->bi_entry_release_rw = wt_entry_release;
+ bi->bi_entry_get_rw = wt_entry_get;
+
+ bi->bi_tool_entry_open = wt_tool_entry_open;
+ bi->bi_tool_entry_close = wt_tool_entry_close;
+ bi->bi_tool_entry_first = backend_tool_entry_first;
+ bi->bi_tool_entry_first_x = wt_tool_entry_first_x;
+ bi->bi_tool_entry_next = wt_tool_entry_next;
+ bi->bi_tool_entry_get = wt_tool_entry_get;
+ bi->bi_tool_entry_put = wt_tool_entry_put;
+ bi->bi_tool_entry_reindex = wt_tool_entry_reindex;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = 0;
+
+ return wt_back_init_cf( bi );
+}
+
+#if SLAPD_WT == SLAPD_MOD_DYNAMIC
+
+/* conditionally define the init_module() function */
+SLAP_BACKEND_INIT_MODULE( wt )
+
+#endif /* SLAPD_WT == SLAPD_MOD_DYNAMIC */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+#include "idl.h"
+
+/* read a key */
+int
+wt_key_read(
+ Backend *be,
+ WT_CURSOR *cursor,
+ struct berval *k,
+ ID *ids,
+ WT_CURSOR **saved_cursor,
+ int get_flag
+ )
+{
+ int rc;
+ WT_ITEM key;
+ int exact;
+ WT_ITEM key2;
+ ID id;
+
+ Debug( LDAP_DEBUG_TRACE, "=> key_read\n", 0, 0, 0 );
+
+ WT_IDL_ZERO(ids);
+
+ bv2ITEM(k, &key);
+ cursor->set_key(cursor, &key, 0);
+ rc = cursor->search_near(cursor, &exact);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_key_read)
+ ": search_near failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+
+ do {
+ rc = cursor->get_key(cursor, &key2, &id);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_key_read)
+ ": get_key failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ break;
+ }
+
+ if (key.size != key2.size || memcmp(key.data, key2.data, key.size)) {
+ if(exact < 0){
+ rc = cursor->next(cursor);
+ if (rc) {
+ break;
+ }else{
+ continue;
+ }
+ }
+ break;
+ }
+ exact = 0;
+ wt_idl_append_one(ids, id);
+ rc = cursor->next(cursor);
+ } while(rc == 0);
+
+ if (rc == WT_NOTFOUND ) {
+ rc = LDAP_SUCCESS;
+ }
+
+done:
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE, "<= wt_key_read: failed (%d)\n",
+ rc, 0, 0 );
+ } else {
+ Debug( LDAP_DEBUG_TRACE, "<= wt_key_read %ld candidates\n",
+ (long) WT_IDL_N(ids), 0, 0 );
+ }
+
+ return rc;
+}
+
+/* Add or remove stuff from index files */
+int
+wt_key_change(
+ Backend *be,
+ WT_CURSOR *cursor,
+ struct berval *k,
+ ID id,
+ int op
+)
+{
+ int rc;
+ WT_ITEM item;
+
+ Debug( LDAP_DEBUG_TRACE, "=> key_change(%s,%lx)\n",
+ op == SLAP_INDEX_ADD_OP ? "ADD":"DELETE", (long) id, 0 );
+
+ bv2ITEM(k, &item);
+ cursor->set_key(cursor, &item, id);
+ cursor->set_value(cursor, NULL);
+
+ if (op == SLAP_INDEX_ADD_OP) {
+ /* Add values */
+ rc = cursor->insert(cursor);
+ if ( rc == WT_DUPLICATE_KEY ) rc = 0;
+ } else {
+ /* Delete values */
+ rc = cursor->remove(cursor);
+ if ( rc == WT_NOTFOUND ) rc = 0;
+ }
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_key_change)
+ ": error: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0);
+ return rc;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<= key_change %d\n", rc, 0, 0 );
+
+ return rc;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+
+int wt_next_id(BackendDB *be, ID *out){
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ *out = __sync_add_and_fetch(&wi->wi_lastid, 1);
+ return 0;
+}
+
+int wt_last_id( BackendDB *be, WT_SESSION *session, ID *out )
+{
+ WT_CURSOR *cursor;
+ int rc;
+ uint64_t id;
+
+ rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL, NULL, &cursor);
+ if(rc){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_last_id)
+ ": open_cursor failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return rc;
+ }
+
+ rc = cursor->prev(cursor);
+ switch(rc) {
+ case 0:
+ rc = cursor->get_key(cursor, &id);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_last_id)
+ ": get_key failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return rc;
+ }
+ *out = id;
+ break;
+ case WT_NOTFOUND:
+ /* no entry */
+ *out = 0;
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_last_id)
+ ": prev failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ }
+
+ rc = cursor->close(cursor);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_last_id)
+ ": close failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return rc;
+ }
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-wt.h"
+#include "config.h"
+
+int
+wt_hasSubordinates(
+ Operation *op,
+ Entry *e,
+ int *hasSubordinates )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ wt_ctx *wc = NULL;
+ int rc;
+
+ assert( e != NULL );
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_compare)
+ ": wt_ctx_get failed\n",
+ 0, 0, 0 );
+ return LDAP_OTHER;
+ }
+
+ rc = wt_dn2id_has_children(op, wc->session, e->e_id);
+ switch(rc){
+ case 0:
+ *hasSubordinates = LDAP_COMPARE_TRUE;
+ break;
+ case WT_NOTFOUND:
+ *hasSubordinates = LDAP_COMPARE_FALSE;
+ rc = LDAP_SUCCESS;
+ break;
+ default:
+ Debug(LDAP_DEBUG_ANY,
+ "<=- " LDAP_XSTRING(wt_hasSubordinates)
+ ": has_children failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ }
+ return rc;
+}
+
+/*
+ * sets the supported operational attributes (if required)
+ */
+int
+wt_operational(
+ Operation *op,
+ SlapReply *rs )
+{
+ Attribute **ap;
+
+ assert( rs->sr_entry != NULL );
+
+ for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
+ if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
+ break;
+ }
+ }
+
+ if ( *ap == NULL &&
+ attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
+ ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
+ ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
+ {
+ int hasSubordinates, rc;
+
+ rc = wt_hasSubordinates( op, rs->sr_entry, &hasSubordinates );
+ if ( rc == LDAP_SUCCESS ) {
+ *ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE );
+ assert( *ap != NULL );
+
+ ap = &(*ap)->a_next;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#ifndef _PROTO_WT_H_
+#define _PROTO_WT_H_
+
+LDAP_BEGIN_DECL
+
+#define WT_UCTYPE "WT"
+
+AttrInfo *wt_attr_mask( struct wt_info *wi, AttributeDescription *desc );
+void wt_attr_flush( struct wt_info *wi );
+
+/*
+ * id2entry.c
+ */
+int wt_id2entry_add(Operation *op, WT_SESSION *session, Entry *e );
+int wt_id2entry_update(Operation *op, WT_SESSION *session, Entry *e );
+int wt_id2entry_delete(Operation *op, WT_SESSION *session, Entry *e );
+
+BI_entry_release_rw wt_entry_release;
+BI_entry_get_rw wt_entry_get;
+
+int wt_entry_return(Entry *e);
+int wt_entry_release(Operation *op, Entry *e, int rw);
+
+/*
+ * idl.c
+ */
+
+unsigned wt_idl_search( ID *ids, ID id );
+
+ID wt_idl_first( ID *ids, ID *cursor );
+ID wt_idl_next( ID *ids, ID *cursor );
+
+
+/*
+ * index.c
+ */
+int wt_index_entry LDAP_P(( Operation *op, wt_ctx *wc, int r, Entry *e ));
+
+#define wt_index_entry_add(op,t,e) \
+ wt_index_entry((op),(t),SLAP_INDEX_ADD_OP,(e))
+#define wt_index_entry_del(op,t,e) \
+ wt_index_entry((op),(t),SLAP_INDEX_DELETE_OP,(e))
+
+/*
+ * key.c
+ */
+int
+wt_key_read( Backend *be,
+ WT_CURSOR *cursor,
+ struct berval *k,
+ ID *ids,
+ WT_CURSOR **saved_cursor,
+ int get_flag);
+
+int
+wt_key_change( Backend *be,
+ WT_CURSOR *cursor,
+ struct berval *k,
+ ID id,
+ int op);
+
+/*
+ * nextid.c
+ */
+int wt_next_id(BackendDB *be, ID *out);
+int wt_last_id( BackendDB *be, WT_SESSION *session, ID *out );
+
+/*
+ * config.c
+ */
+int wt_back_init_cf( BackendInfo *bi );
+
+/*
+ * dn2id.c
+ */
+
+int
+wt_dn2id(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *ndn,
+ ID *id);
+
+int
+wt_dn2id_add(
+ Operation *op,
+ WT_SESSION *session,
+ ID pid,
+ Entry *e);
+
+int
+wt_dn2id_delete(
+ Operation *op,
+ WT_SESSION *session,
+ struct berval *ndn);
+
+/*
+ * dn2entry.c
+ */
+int wt_dn2entry( BackendDB *be,
+ wt_ctx *wc,
+ struct berval *ndn,
+ Entry **ep );
+
+int wt_dn2pentry( BackendDB *be,
+ wt_ctx *wc,
+ struct berval *ndn,
+ Entry **ep );
+
+/*
+ * former ctx.c
+ */
+wt_ctx *wt_ctx_init(struct wt_info *wi);
+void wt_ctx_free(void *key, void *data);
+wt_ctx *wt_ctx_get(Operation *op, struct wt_info *wi);
+WT_CURSOR *wt_ctx_index_cursor(wt_ctx *wc, struct berval *name, int create);
+
+
+/*
+ * former external.h
+ */
+
+extern BI_init wt_back_initialize;
+extern BI_db_config wt_db_config;
+extern BI_op_add wt_add;
+extern BI_op_bind wt_bind;
+extern BI_op_compare wt_compare;
+extern BI_op_delete wt_delete;
+
+extern BI_op_search wt_search;
+
+extern BI_operational wt_operational;
+
+/* tools.c */
+extern BI_tool_entry_open wt_tool_entry_open;
+extern BI_tool_entry_close wt_tool_entry_close;
+extern BI_tool_entry_first_x wt_tool_entry_first_x;
+extern BI_tool_entry_next wt_tool_entry_next;
+extern BI_tool_entry_get wt_tool_entry_get;
+extern BI_tool_entry_put wt_tool_entry_put;
+extern BI_tool_entry_reindex wt_tool_entry_reindex;
+extern BI_tool_dn2id_get wt_tool_dn2id_get;
+extern BI_tool_entry_modify wt_tool_entry_modify;
+
+LDAP_END_DECL
+
+#endif /* _PROTO_WT_H */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
+
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-wt.h"
+#include "idl.h"
+
+static int search_aliases(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e,
+ WT_SESSION *session,
+ ID *ids,
+ ID *scopes,
+ ID *stack )
+{
+ /* TODO: search_aliases does not implement yet. */
+ WT_IDL_ZERO( ids );
+ return 0;
+}
+
+static int base_candidate(
+ BackendDB *be,
+ Entry *e,
+ ID *ids )
+{
+ Debug(LDAP_DEBUG_ARGS,
+ LDAP_XSTRING(base_candidate)
+ ": base: \"%s\" (0x%08lx)\n",
+ e->e_nname.bv_val, (long) e->e_id, 0);
+
+ ids[0] = 1;
+ ids[1] = e->e_id;
+ return 0;
+}
+
+/* Look for "objectClass Present" in this filter.
+ * Also count depth of filter tree while we're at it.
+ */
+static int oc_filter(
+ Filter *f,
+ int cur,
+ int *max )
+{
+ int rc = 0;
+
+ assert( f != NULL );
+
+ if( cur > *max ) *max = cur;
+
+ switch( f->f_choice ) {
+ case LDAP_FILTER_PRESENT:
+ if (f->f_desc == slap_schema.si_ad_objectClass) {
+ rc = 1;
+ }
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ cur++;
+ for ( f=f->f_and; f; f=f->f_next ) {
+ (void) oc_filter(f, cur, max);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+static void search_stack_free( void *key, void *data )
+{
+ ber_memfree_x(data, NULL);
+}
+
+static void *search_stack( Operation *op )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ void *ret = NULL;
+
+ if ( op->o_threadctx ) {
+ ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)search_stack,
+ &ret, NULL );
+ } else {
+ ret = wi->wi_search_stack;
+ }
+
+ if ( !ret ) {
+ ret = ch_malloc( wi->wi_search_stack_depth * WT_IDL_UM_SIZE
+ * sizeof( ID ) );
+ if ( op->o_threadctx ) {
+ ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)search_stack,
+ ret, search_stack_free, NULL, NULL );
+ } else {
+ wi->wi_search_stack = ret;
+ }
+ }
+ return ret;
+}
+
+static int search_candidates(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e,
+ wt_ctx *wc,
+ ID *ids,
+ ID *scopes )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ int rc, depth = 1;
+ Filter f, rf, xf, nf;
+ ID *stack;
+ AttributeAssertion aa_ref = ATTRIBUTEASSERTION_INIT;
+ Filter sf;
+ AttributeAssertion aa_subentry = ATTRIBUTEASSERTION_INIT;
+
+ Debug(LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search_candidates)
+ ": base=\"%s\" (0x%08lx) scope=%d\n",
+ e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope );
+
+ xf.f_or = op->oq_search.rs_filter;
+ xf.f_choice = LDAP_FILTER_OR;
+ xf.f_next = NULL;
+
+ /* If the user's filter uses objectClass=*,
+ * these clauses are redundant.
+ */
+ if (!oc_filter(op->oq_search.rs_filter, 1, &depth)
+ && !get_subentries_visibility(op)) {
+ if( !get_manageDSAit(op) && !get_domainScope(op) ) {
+ /* match referral objects */
+ struct berval bv_ref = BER_BVC( "referral" );
+ rf.f_choice = LDAP_FILTER_EQUALITY;
+ rf.f_ava = &aa_ref;
+ rf.f_av_desc = slap_schema.si_ad_objectClass;
+ rf.f_av_value = bv_ref;
+ rf.f_next = xf.f_or;
+ xf.f_or = &rf;
+ depth++;
+ }
+ }
+
+ f.f_next = NULL;
+ f.f_choice = LDAP_FILTER_AND;
+ f.f_and = &nf;
+ /* Dummy; we compute scope separately now */
+ nf.f_choice = SLAPD_FILTER_COMPUTED;
+ nf.f_result = LDAP_SUCCESS;
+ nf.f_next = ( xf.f_or == op->oq_search.rs_filter )
+ ? op->oq_search.rs_filter : &xf ;
+ /* Filter depth increased again, adding dummy clause */
+ depth++;
+
+ if( get_subentries_visibility( op ) ) {
+ struct berval bv_subentry = BER_BVC( "subentry" );
+ sf.f_choice = LDAP_FILTER_EQUALITY;
+ sf.f_ava = &aa_subentry;
+ sf.f_av_desc = slap_schema.si_ad_objectClass;
+ sf.f_av_value = bv_subentry;
+ sf.f_next = nf.f_next;
+ nf.f_next = &sf;
+ }
+
+ /* Allocate IDL stack, plus 1 more for former tmp */
+ if ( depth+1 > wi->wi_search_stack_depth ) {
+ stack = ch_malloc( (depth + 1) * WT_IDL_UM_SIZE * sizeof( ID ) );
+ } else {
+ stack = search_stack( op );
+ }
+
+ if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
+ rc = search_aliases( op, rs, e, wc->session, ids, scopes, stack );
+ if ( WT_IDL_IS_ZERO( ids ) && rc == LDAP_SUCCESS )
+ rc = wt_dn2idl( op, wc->session, &e->e_nname, e, ids, stack );
+ } else {
+ rc = wt_dn2idl(op, wc->session, &e->e_nname, e, ids, stack );
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ rc = wt_filter_candidates( op, wc, &f, ids,
+ stack, stack+WT_IDL_UM_SIZE );
+ }
+
+ if ( depth+1 > wi->wi_search_stack_depth ) {
+ ch_free( stack );
+ }
+
+ if( rc ) {
+ Debug(LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search_candidates)
+ ": failed (rc=%d)\n",
+ rc, NULL, NULL );
+
+ } else {
+ Debug(LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search_candidates)
+ ": id=%ld first=%ld last=%ld\n",
+ (long) ids[0],
+ (long) WT_IDL_FIRST(ids),
+ (long) WT_IDL_LAST(ids));
+ }
+ return 0;
+}
+
+static int
+parse_paged_cookie( Operation *op, SlapReply *rs )
+{
+ int rc = LDAP_SUCCESS;
+ PagedResultsState *ps = op->o_pagedresults_state;
+
+ /* this function must be invoked only if the pagedResults
+ * control has been detected, parsed and partially checked
+ * by the frontend */
+ assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
+
+ /* cookie decoding/checks deferred to backend... */
+ if ( ps->ps_cookieval.bv_len ) {
+ PagedResultsCookie reqcookie;
+ if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) {
+ /* bad cookie */
+ rs->sr_text = "paged results cookie is invalid";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
+ }
+
+ AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie ));
+
+ if ( reqcookie > ps->ps_cookie ) {
+ /* bad cookie */
+ rs->sr_text = "paged results cookie is invalid";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
+
+ } else if ( reqcookie < ps->ps_cookie ) {
+ rs->sr_text = "paged results cookie is invalid or old";
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ } else {
+ /* we're going to use ps_cookie */
+ op->o_conn->c_pagedresults_state.ps_cookie = 0;
+ }
+
+done:;
+
+ return rc;
+}
+
+static void
+send_paged_response(
+ Operation *op,
+ SlapReply *rs,
+ ID *lastid,
+ int tentries )
+{
+ LDAPControl *ctrls[2];
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ PagedResultsCookie respcookie;
+ struct berval cookie;
+
+ Debug(LDAP_DEBUG_ARGS,
+ LDAP_XSTRING(send_paged_response)
+ ": lastid=0x%08lx nentries=%d\n",
+ lastid ? *lastid : 0, rs->sr_nentries, NULL );
+
+ ctrls[1] = NULL;
+
+ ber_init2( ber, NULL, LBER_USE_DER );
+
+ if ( lastid ) {
+ respcookie = ( PagedResultsCookie )(*lastid);
+ cookie.bv_len = sizeof( respcookie );
+ cookie.bv_val = (char *)&respcookie;
+
+ } else {
+ respcookie = ( PagedResultsCookie )0;
+ BER_BVSTR( &cookie, "" );
+ }
+
+ op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
+ op->o_conn->c_pagedresults_state.ps_count =
+ ((PagedResultsState *)op->o_pagedresults_state)->ps_count +
+ rs->sr_nentries;
+
+ /* return size of 0 -- no estimate */
+ ber_printf( ber, "{iO}", 0, &cookie );
+
+ ctrls[0] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
+ if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
+ goto done;
+ }
+
+ ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
+ ctrls[0]->ldctl_iscritical = 0;
+
+ slap_add_ctrls( op, rs, ctrls );
+ rs->sr_err = LDAP_SUCCESS;
+ send_ldap_result( op, rs );
+
+done:
+ (void) ber_free_buf( ber );
+}
+
+int
+wt_search( Operation *op, SlapReply *rs )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ ID id, cursor;
+ ID lastid = NOID;
+ AttributeName *attrs;
+ OpExtra *oex;
+ int manageDSAit;
+ wt_ctx *wc;
+ int rc;
+ Entry *e = NULL;
+ Entry *base = NULL;
+ slap_mask_t mask;
+ time_t stoptime;
+
+ ID candidates[WT_IDL_UM_SIZE];
+ ID iscopes[WT_IDL_DB_SIZE];
+ ID scopes[WT_IDL_DB_SIZE];
+ int tentries = 0;
+ unsigned nentries = 0;
+
+ Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_search) ": %s\n",
+ op->o_req_dn.bv_val, 0, 0 );
+ attrs = op->oq_search.rs_attrs;
+
+ manageDSAit = get_manageDSAit( op );
+
+ wc = wt_ctx_get(op, wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_search)
+ ": wt_ctx_get failed: %d\n",
+ rc, 0, 0 );
+ send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
+ return rc;
+ }
+
+ /* get entry */
+ rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
+ switch( rc ) {
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ Debug( LDAP_DEBUG_ARGS,
+ "<== " LDAP_XSTRING(wt_search)
+ ": no such object %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+ rs->sr_err = LDAP_REFERRAL;
+ rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
+ send_ldap_result( op, rs );
+ goto done;
+ default:
+ /* TODO: error handling */
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_delete)
+ ": error at wt_dn2entry() rc=%d\n",
+ rc, 0, 0 );
+ send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
+ goto done;
+ }
+
+ if ( op->ors_deref & LDAP_DEREF_FINDING ) {
+ /* not implement yet */
+ }
+
+ if ( e == NULL ) {
+ // TODO
+ }
+
+ /* NOTE: __NEW__ "search" access is required
+ * on searchBase object */
+ if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_SEARCH, NULL, &mask ) )
+ {
+ if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ } else {
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ send_ldap_result( op, rs );
+ goto done;
+ }
+
+ if ( !manageDSAit && is_entry_referral( e ) ) {
+ /* entry is a referral */
+ /* TODO: */
+ }
+
+ if ( get_assert( op ) &&
+ ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
+ {
+ rs->sr_err = LDAP_ASSERTION_FAILED;
+ send_ldap_result( op, rs );
+ goto done;
+ }
+
+ /* compute it anyway; root does not use it */
+ stoptime = op->o_time + op->ors_tlimit;
+
+ base = e;
+
+ e = NULL;
+
+ /* select candidates */
+ if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
+ rs->sr_err = base_candidate( op->o_bd, base, candidates );
+ }else{
+ WT_IDL_ZERO( candidates );
+ WT_IDL_ZERO( scopes );
+ rc = search_candidates( op, rs, base,
+ wc, candidates, scopes );
+ switch(rc){
+ case 0:
+ case WT_NOTFOUND:
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_search) ": error search_candidates\n",
+ 0, 0, 0 );
+ send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
+ goto done;
+ }
+ }
+
+ /* start cursor at beginning of candidates.
+ */
+ cursor = 0;
+
+ if ( candidates[0] == 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search) ": no candidates\n",
+ 0, 0, 0 );
+ goto nochange;
+ }
+
+ if ( op->ors_limit &&
+ op->ors_limit->lms_s_unchecked != -1 &&
+ WT_IDL_N(candidates) > (unsigned) op->ors_limit->lms_s_unchecked )
+ {
+ rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
+ send_ldap_result( op, rs );
+ rs->sr_err = LDAP_SUCCESS;
+ goto done;
+ }
+
+ if ( op->ors_limit == NULL /* isroot == TRUE */ ||
+ !op->ors_limit->lms_s_pr_hide )
+ {
+ tentries = WT_IDL_N(candidates);
+ }
+
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+ /* TODO: pageresult */
+ PagedResultsState *ps = op->o_pagedresults_state;
+ /* deferred cookie parsing */
+ rs->sr_err = parse_paged_cookie( op, rs );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ send_ldap_result( op, rs );
+ goto done;
+ }
+
+ cursor = (ID) ps->ps_cookie;
+ if ( cursor && ps->ps_size == 0 ) {
+ rs->sr_err = LDAP_SUCCESS;
+ rs->sr_text = "search abandoned by pagedResult size=0";
+ send_ldap_result( op, rs );
+ goto done;
+ }
+ id = wt_idl_first( candidates, &cursor );
+ if ( id == NOID ) {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search)
+ ": no paged results candidates\n",
+ 0, 0, 0 );
+ send_paged_response( op, rs, &lastid, 0 );
+
+ rs->sr_err = LDAP_OTHER;
+ goto done;
+ }
+ nentries = ps->ps_count;
+ if ( id == (ID)ps->ps_cookie )
+ id = wt_idl_next( candidates, &cursor );
+ goto loop_begin;
+ }
+
+ for ( id = wt_idl_first( candidates, &cursor );
+ id != NOID ; id = wt_idl_next( candidates, &cursor ) )
+ {
+ int scopeok;
+
+loop_begin:
+
+ /* check for abandon */
+ if ( op->o_abandon ) {
+ rs->sr_err = SLAPD_ABANDON;
+ send_ldap_result( op, rs );
+ goto done;
+ }
+
+ /* mostly needed by internal searches,
+ * e.g. related to syncrepl, for whom
+ * abandon does not get set... */
+ if ( slapd_shutdown ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ send_ldap_disconnect( op, rs );
+ goto done;
+ }
+
+ /* check time limit */
+ if ( op->ors_tlimit != SLAP_NO_LIMIT
+ && slap_get_time() > stoptime )
+ {
+ rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
+ rs->sr_ref = rs->sr_v2ref;
+ send_ldap_result( op, rs );
+ rs->sr_err = LDAP_SUCCESS;
+ goto done;
+ }
+
+ nentries++;
+
+ fetch_entry_retry:
+
+ rc = wt_id2entry(op->o_bd, wc->session, id, &e);
+ /* TODO: error handling */
+ if ( e == NULL ) {
+ /* TODO: */
+ goto loop_continue;
+ }
+ if ( is_entry_subentry( e ) ) {
+ if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
+ if(!get_subentries_visibility( op )) {
+ /* only subentries are visible */
+ goto loop_continue;
+ }
+
+ } else if ( get_subentries( op ) &&
+ !get_subentries_visibility( op ))
+ {
+ /* only subentries are visible */
+ goto loop_continue;
+ }
+
+ } else if ( get_subentries_visibility( op )) {
+ /* only subentries are visible */
+ goto loop_continue;
+ }
+
+ scopeok = 0;
+ switch( op->ors_scope ) {
+ case LDAP_SCOPE_BASE:
+ /* This is always true, yes? */
+ if ( id == base->e_id ) scopeok = 1;
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ scopeok = 1;
+ break;
+ case LDAP_SCOPE_SUBTREE:
+ scopeok = 1;
+ break;
+ }
+
+ /* aliases were already dereferenced in candidate list */
+ if ( op->ors_deref & LDAP_DEREF_SEARCHING ) {
+ /* but if the search base is an alias, and we didn't
+ * deref it when finding, return it.
+ */
+ if ( is_entry_alias(e) &&
+ ((op->ors_deref & LDAP_DEREF_FINDING) ||
+ !bvmatch(&e->e_nname, &op->o_req_ndn)))
+ {
+ goto loop_continue;
+ }
+ /* TODO: alias handling */
+ }
+
+ /* Not in scope, ignore it */
+ if ( !scopeok )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search)
+ ": %ld scope not okay\n",
+ (long) id, 0, 0 );
+ goto loop_continue;
+ }
+
+ /*
+ * if it's a referral, add it to the list of referrals. only do
+ * this for non-base searches, and don't check the filter
+ * explicitly here since it's only a candidate anyway.
+ */
+ if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE
+ && is_entry_referral( e ) )
+ {
+ /* TODO: referral */
+ }
+
+ if ( !manageDSAit && is_entry_glue( e )) {
+ goto loop_continue;
+ }
+
+ /* if it matches the filter and scope, send it */
+ rs->sr_err = test_filter( op, e, op->oq_search.rs_filter );
+ if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
+ /* check size limit */
+ if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
+ /* TODO: */
+ }
+
+ if (e) {
+ /* safe default */
+ rs->sr_attrs = op->oq_search.rs_attrs;
+ rs->sr_operational_attrs = NULL;
+ rs->sr_ctrls = NULL;
+ rs->sr_entry = e;
+ RS_ASSERT( e->e_private != NULL );
+ rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+ rs->sr_err = LDAP_SUCCESS;
+ rs->sr_err = send_search_entry( op, rs );
+ rs->sr_attrs = NULL;
+ rs->sr_entry = NULL;
+ e = NULL;
+ }
+ switch ( rs->sr_err ) {
+ case LDAP_SUCCESS: /* entry sent ok */
+ break;
+ default:
+ /* TODO: error handling */
+ break;
+ }
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ LDAP_XSTRING(wt_search)
+ ": %ld does not match filter\n",
+ (long) id, 0, 0 );
+ }
+
+ loop_continue:
+ if( e ) {
+ wt_entry_return( e );
+ e = NULL;
+ }
+ }
+
+nochange:
+ rs->sr_ctrls = NULL;
+ rs->sr_ref = rs->sr_v2ref;
+ rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL;
+ rs->sr_rspoid = NULL;
+ if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
+ /* not implement yet */
+ /* send_paged_response( op, rs, NULL, 0 ); */
+ } else {
+ send_ldap_result( op, rs );
+ }
+
+ rs->sr_err = LDAP_SUCCESS;
+
+done:
+
+ if( base ) {
+ wt_entry_return( base );
+ }
+
+ if( e ) {
+ wt_entry_return( e );
+ }
+
+ return rs->sr_err;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
--- /dev/null
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2015 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "config.h"
+
+typedef struct dn_id {
+ ID id;
+ struct berval dn;
+} dn_id;
+
+#define HOLE_SIZE 4096
+static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
+static unsigned nhmax = HOLE_SIZE;
+static unsigned nholes;
+
+static int index_nattrs;
+
+static struct berval *tool_base;
+static int tool_scope;
+static Filter *tool_filter;
+static Entry *tool_next_entry;
+
+static wt_ctx *wc;
+static WT_CURSOR *reader;
+static WT_ITEM item;
+
+int
+wt_tool_entry_open( BackendDB *be, int mode )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ WT_CONNECTION *conn = wi->wi_conn;
+ int rc;
+
+ wc = wt_ctx_init(wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_open)
+ ": wt_ctx_get failed: %s (%d)\n",
+ 0, 0, 0 );
+ return -1;
+ }
+
+ rc = wc->session->open_cursor(wc->session, WT_TABLE_ID2ENTRY"(entry)"
+ ,NULL, NULL, &reader);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_open)
+ ": cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+wt_tool_entry_close( BackendDB *be )
+{
+ int rc;
+
+ if( reader ) {
+ reader->close(reader);
+ reader = NULL;
+ }
+
+ wt_ctx_free(NULL, wc);
+
+ if( nholes ) {
+ unsigned i;
+ fprintf( stderr, "Error, entries missing!\n");
+ for (i=0; i<nholes; i++) {
+ fprintf(stderr, " entry %ld: %s\n",
+ holes[i].id, holes[i].dn.bv_val);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+ID
+wt_tool_entry_first_x( BackendDB *be,
+ struct berval *base,
+ int scope,
+ Filter *f )
+{
+ tool_base = base;
+ tool_scope = scope;
+ tool_filter = f;
+
+ return wt_tool_entry_next( be );
+}
+
+ID
+wt_tool_entry_next( BackendDB *be )
+{
+ int rc;
+ ID id;
+
+ rc = reader->next(reader);
+ switch( rc ){
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ return NOID;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_next)
+ ": next failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return NOID;
+ }
+
+ rc = reader->get_key(reader, &id);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_next)
+ ": get_key failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ }
+
+ rc = reader->get_value(reader, &item);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_next)
+ ": get_value failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ }
+ return id;
+}
+
+static ber_len_t
+entry_getlen(unsigned char **buf)
+{
+ ber_len_t len;
+ int i;
+
+ len = *(*buf)++;
+ if (len <= 0x7f)
+ return len;
+ i = len & 0x7f;
+ len = 0;
+ for (;i > 0; i--) {
+ len <<= 8;
+ len |= *(*buf)++;
+ }
+ return len;
+}
+
+int wt_entry_header(WT_ITEM *item, EntryHeader *eh){
+ unsigned char *ptr = (unsigned char *)item->data;
+
+ /* Some overlays can create empty entries
+ * so don't check for zeros here.
+ */
+ eh->nattrs = entry_getlen(&ptr);
+ eh->nvals = entry_getlen(&ptr);
+ eh->data = (char *)ptr;
+ return LDAP_SUCCESS;
+}
+
+Entry *
+wt_tool_entry_get( BackendDB *be, ID id )
+{
+ Entry *e = NULL;
+ static EntryHeader eh;
+ int rc, eoff;
+
+ assert( be != NULL );
+ assert( slapMode & SLAP_TOOL_MODE );
+
+ rc = wt_entry_header( &item, &eh );
+ assert( rc == 0 );
+ eoff = eh.data - (char *)item.data;
+
+ eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
+ eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
+ memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
+ eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
+ memcpy(eh.data, item.data, item.size);
+ eh.data += eoff;
+
+ rc = entry_decode( &eh, &e );
+ assert( rc == 0 );
+
+ if( rc == LDAP_SUCCESS ) {
+ e->e_id = id;
+ }
+
+ return e;
+}
+
+static int wt_tool_next_id(
+ Operation *op,
+ Entry *e,
+ struct berval *text,
+ int hole )
+{
+ struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
+ struct berval dn = e->e_name;
+ struct berval ndn = e->e_nname;
+ struct berval pdn, npdn;
+ int rc;
+ ID id = 0;
+ ID pid = 0;
+
+ if(ndn.bv_len == 0){
+ e->e_id = 0;
+ return 0;
+ }
+
+ rc = wt_dn2id(op, wc->session, &ndn, &id);
+ if(rc == 0){
+ e->e_id = id;
+ }else if( rc == WT_NOTFOUND ){
+ if ( !be_issuffix( op->o_bd, &ndn ) ) {
+ ID eid = e->e_id;
+ dnParent( &dn, &pdn );
+ dnParent( &ndn, &npdn );
+ e->e_name = pdn;
+ e->e_nname = npdn;
+ rc = wt_tool_next_id( op, e, text, 1 );
+ e->e_name = dn;
+ e->e_nname = ndn;
+ if ( rc ) {
+ return rc;
+ }
+ /* If parent didn't exist, it was created just now
+ * and its ID is now in e->e_id. Make sure the current
+ * entry gets added under the new parent ID.
+ */
+ if ( eid != e->e_id ) {
+ pid = e->e_id;
+ }
+ }else{
+ pid = id;
+ }
+ wt_next_id( op->o_bd, &e->e_id );
+ rc = wt_dn2id_add(op, wc->session, pid, e);
+ if( rc ){
+ snprintf( text->bv_val, text->bv_len,
+ "wt_dn2id_add failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> wt_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ }
+
+ }else if ( !hole ) {
+ unsigned i, j;
+ e->e_id = id;
+
+ for ( i=0; i<nholes; i++) {
+ if ( holes[i].id == e->e_id ) {
+ free(holes[i].dn.bv_val);
+ for (j=i;j<nholes;j++) holes[j] = holes[j+1];
+ holes[j].id = 0;
+ nholes--;
+ break;
+ } else if ( holes[i].id > e->e_id ) {
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+static int
+wt_tool_index_add(
+ Operation *op,
+ wt_ctx *wc,
+ Entry *e )
+{
+ return wt_index_entry_add( op, wc, e );
+}
+
+ID
+wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+
+ Operation op = {0};
+ Opheader ohdr = {0};
+
+ assert( slapMode & SLAP_TOOL_MODE );
+ assert( text != NULL );
+ assert( text->bv_val != NULL );
+ assert( text->bv_val[0] == '\0' ); /* overconservative? */
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> " LDAP_XSTRING(wt_tool_entry_put)
+ ": ( \"%s\" )\n", e->e_dn, 0, 0);
+
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_add)
+ ": begin_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ return NOID;
+ }
+
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ rc = wt_tool_next_id( &op, e, text, 0 );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "wt_tool_next_id failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ goto done;
+ }
+
+ rc = wt_id2entry_add( &op, wc->session, e );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "id2entry_add failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ goto done;
+ }
+
+ rc = wt_tool_index_add( &op, wc, e );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "index_entry_add failed: %s (%d)",
+ rc == LDAP_OTHER ? "Internal error" :
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ goto done;
+ }
+
+done:
+ if ( rc == 0 ){
+ rc = wc->session->commit_transaction(wc->session, NULL);
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "txn_commit failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ e->e_id = NOID;
+ }
+ }else{
+ rc = wc->session->rollback_transaction(wc->session, NULL);
+ snprintf( text->bv_val, text->bv_len,
+ "txn_aborted! %s (%d)",
+ rc == LDAP_OTHER ? "Internal error" :
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ e->e_id = NOID;
+ }
+
+ return e->e_id;
+}
+
+int wt_tool_entry_reindex(
+ BackendDB *be,
+ ID id,
+ AttributeDescription **adv )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+ Entry *e;
+ Operation op = {0};
+ Opheader ohdr = {0};
+
+ Debug( LDAP_DEBUG_ARGS,
+ "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld )\n",
+ (long) id, 0, 0 );
+ assert( tool_base == NULL );
+ assert( tool_filter == NULL );
+
+ /* No indexes configured, nothing to do. Could return an
+ * error here to shortcut things.
+ */
+ if (!wi->wi_attrs) {
+ return 0;
+ }
+
+ /* Check for explicit list of attrs to index */
+ if ( adv ) {
+ int i, j, n;
+
+ if ( wi->wi_attrs[0]->ai_desc != adv[0] ) {
+ /* count */
+ for ( n = 0; adv[n]; n++ ) ;
+
+ /* insertion sort */
+ for ( i = 0; i < n; i++ ) {
+ AttributeDescription *ad = adv[i];
+ for ( j = i-1; j>=0; j--) {
+ if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
+ adv[j+1] = adv[j];
+ }
+ adv[j+1] = ad;
+ }
+ }
+
+ for ( i = 0; adv[i]; i++ ) {
+ if ( wi->wi_attrs[i]->ai_desc != adv[i] ) {
+ for ( j = i+1; j < wi->wi_nattrs; j++ ) {
+ if ( wi->wi_attrs[j]->ai_desc == adv[i] ) {
+ AttrInfo *ai = wi->wi_attrs[i];
+ wi->wi_attrs[i] = wi->wi_attrs[j];
+ wi->wi_attrs[j] = ai;
+ break;
+ }
+ }
+ if ( j == wi->wi_nattrs ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_reindex)
+ ": no index configured for %s\n",
+ adv[i]->ad_cname.bv_val, 0, 0 );
+ return -1;
+ }
+ }
+ }
+ wi->wi_nattrs = i;
+ }
+
+ e = wt_tool_entry_get( be, id );
+
+ if( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_tool_entry_reindex)
+ ": could not locate id=%ld\n",
+ (long) id, 0, 0 );
+ return -1;
+ }
+
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ LDAP_XSTRING(wt_dn2id_add)
+ ": begin_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ goto done;
+ }
+ Debug( LDAP_DEBUG_TRACE,
+ "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld, \"%s\" )\n",
+ (long) id, e->e_dn, 0 );
+
+ rc = wt_tool_index_add( &op, wc, e );
+
+done:
+ if ( rc == 0 ){
+ rc = wc->session->commit_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_reindex)
+ "commit_transaction failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ }
+ }else{
+ rc = wc->session->rollback_transaction(wc->session, NULL);
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(wt_tool_entry_reindex)
+ ": rollback transaction %s\n",
+ wiredtiger_strerror(rc), rc, 0 );
+ }
+
+ wt_entry_release( &op, e, 0 );
+
+ return rc;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */