mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-18 11:05:48 +08:00
ITS#8114 OpenLDAP WiredTiger Backend
This commit is contained in:
parent
f385fd5ad1
commit
61c95e7669
@ -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
|
||||
|
54
configure.in
54
configure.in
@ -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
90
doc/man/man5/slapd-wt.5
Normal 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>.
|
54
servers/slapd/back-wt/Makefile.in
Normal file
54
servers/slapd/back-wt/Makefile.in
Normal 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
408
servers/slapd/back-wt/add.c
Normal 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:
|
||||
*/
|
388
servers/slapd/back-wt/attr.c
Normal file
388
servers/slapd/back-wt/attr.c
Normal 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:
|
||||
*/
|
99
servers/slapd/back-wt/back-wt.h
Normal file
99
servers/slapd/back-wt/back-wt.h
Normal 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:
|
||||
*/
|
156
servers/slapd/back-wt/bind.c
Normal file
156
servers/slapd/back-wt/bind.c
Normal 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:
|
||||
*/
|
149
servers/slapd/back-wt/compare.c
Normal file
149
servers/slapd/back-wt/compare.c
Normal 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:
|
||||
*/
|
158
servers/slapd/back-wt/config.c
Normal file
158
servers/slapd/back-wt/config.c
Normal 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
142
servers/slapd/back-wt/ctx.c
Normal 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:
|
||||
*/
|
424
servers/slapd/back-wt/delete.c
Normal file
424
servers/slapd/back-wt/delete.c
Normal 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:
|
||||
*/
|
131
servers/slapd/back-wt/dn2entry.c
Normal file
131
servers/slapd/back-wt/dn2entry.c
Normal 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:
|
||||
*/
|
393
servers/slapd/back-wt/dn2id.c
Normal file
393
servers/slapd/back-wt/dn2id.c
Normal 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:
|
||||
*/
|
679
servers/slapd/back-wt/filterindex.c
Normal file
679
servers/slapd/back-wt/filterindex.c
Normal 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:
|
||||
*/
|
241
servers/slapd/back-wt/id2entry.c
Normal file
241
servers/slapd/back-wt/id2entry.c
Normal 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
794
servers/slapd/back-wt/idl.c
Normal 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 */
|
||||
|
80
servers/slapd/back-wt/idl.h
Normal file
80
servers/slapd/back-wt/idl.h
Normal 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
|
391
servers/slapd/back-wt/index.c
Normal file
391
servers/slapd/back-wt/index.c
Normal 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:
|
||||
*/
|
308
servers/slapd/back-wt/init.c
Normal file
308
servers/slapd/back-wt/init.c
Normal 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
152
servers/slapd/back-wt/key.c
Normal 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:
|
||||
*/
|
92
servers/slapd/back-wt/nextid.c
Normal file
92
servers/slapd/back-wt/nextid.c
Normal 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:
|
||||
*/
|
113
servers/slapd/back-wt/operational.c
Normal file
113
servers/slapd/back-wt/operational.c
Normal 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:
|
||||
*/
|
177
servers/slapd/back-wt/proto-wt.h
Normal file
177
servers/slapd/back-wt/proto-wt.h
Normal 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:
|
||||
*/
|
||||
|
709
servers/slapd/back-wt/search.c
Normal file
709
servers/slapd/back-wt/search.c
Normal 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:
|
||||
*/
|
514
servers/slapd/back-wt/tools.c
Normal file
514
servers/slapd/back-wt/tools.c
Normal 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:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user