ITS#8114 OpenLDAP WiredTiger Backend

This commit is contained in:
HAMANO Tsukasa 2015-04-27 10:27:58 +09:00 committed by Howard Chu
parent f385fd5ad1
commit 61c95e7669
26 changed files with 6895 additions and 2 deletions

View File

@ -161,6 +161,7 @@ LTHREAD_LIBS = @LTHREAD_LIBS@
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

View File

@ -296,7 +296,8 @@ Backends="bdb \
relay \
shell \
sock \
sql"
sql \
wt"
AC_ARG_ENABLE(xxslapbackends,[
SLAPD Backend Options:])
@ -333,6 +334,8 @@ OL_ARG_ENABLE(sock,[ --enable-sock enable sock backend],
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
@ -485,7 +488,8 @@ elif test $ol_enable_modules != yes &&
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
@ -548,6 +552,7 @@ BUILD_RELAY=no
BUILD_SHELL=no
BUILD_SOCK=no
BUILD_SQL=no
BUILD_WT=no
BUILD_ACCESSLOG=no
BUILD_AUDITLOG=no
@ -2082,6 +2087,33 @@ if test $ol_enable_ndb != no ; then
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
@ -2811,6 +2843,19 @@ if test "$ol_link_sql" != no ; then
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
@ -3106,6 +3151,7 @@ dnl backends
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)
@ -3169,6 +3215,9 @@ AC_SUBST(SLAPD_SQL_LDFLAGS)
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,[
@ -3213,6 +3262,7 @@ AC_CONFIG_FILES([Makefile:build/top.mk:Makefile.in:build/dir.mk]
[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]

90
doc/man/man5/slapd-wt.5 Normal file
View File

@ -0,0 +1,90 @@
.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>.

View File

@ -0,0 +1,54 @@
# 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 $@

408
servers/slapd/back-wt/add.c Normal file
View File

@ -0,0 +1,408 @@
/* 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:
*/

View File

@ -0,0 +1,388 @@
/* 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:
*/

View File

@ -0,0 +1,99 @@
/* 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:
*/

View File

@ -0,0 +1,156 @@
/* 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:
*/

View File

@ -0,0 +1,149 @@
/* 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:
*/

View File

@ -0,0 +1,158 @@
/* 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:
*/

142
servers/slapd/back-wt/ctx.c Normal file
View File

@ -0,0 +1,142 @@
/* 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:
*/

View File

@ -0,0 +1,424 @@
/* 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:
*/

View File

@ -0,0 +1,131 @@
/* 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:
*/

View File

@ -0,0 +1,393 @@
/* 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:
*/

View File

@ -0,0 +1,679 @@
/* 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:
*/

View File

@ -0,0 +1,241 @@
/* 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:
*/

794
servers/slapd/back-wt/idl.c Normal file
View File

@ -0,0 +1,794 @@
/* 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 */

View File

@ -0,0 +1,80 @@
/* 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

View File

@ -0,0 +1,391 @@
/* 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:
*/

View File

@ -0,0 +1,308 @@
/* 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:
*/

152
servers/slapd/back-wt/key.c Normal file
View File

@ -0,0 +1,152 @@
/* 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:
*/

View File

@ -0,0 +1,92 @@
/* 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:
*/

View File

@ -0,0 +1,113 @@
/* 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:
*/

View File

@ -0,0 +1,177 @@
/* 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:
*/

View File

@ -0,0 +1,709 @@
/* 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:
*/

View File

@ -0,0 +1,514 @@
/* 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:
*/