From 0a2cf7e69db6e53a7e89964199b492b8f181da76 Mon Sep 17 00:00:00 2001 From: HAMANO Tsukasa Date: Wed, 10 Feb 2021 22:56:09 +0900 Subject: [PATCH] ITS#9463 cumulative fix for back-wt - LDAP MODRDN handling - support paged response - add wt_extended - add config emit - wt_key_read() return WT_NOTFOUND if not found key. - add ext_candidates() - fix idlcache session name - fix warning - don't reuse idlcache cursor - set correct pid when modrdn with newsuperior - fix condition bug - fix send_search_entry() error handling - fix for referral handling - fix for readonly mode - fix sizelimit response - support modrdn - improve modify handling - clear ancestor idlcache - fix for multi-DIT - IMPORTANT CHANGES: Compatibility is broken with previous database table, please restore database from LDIF. - checking for scope=children - sort dn2idl result - fix cursor leak - support db_open with readonly mode - add wt_tool_entry_delete - initialize comp variable - support referrals - implement wt_tool_dn2id_get() and wt_tool_entry_modify() for slapadd -w - skip redundant scan, and more debug message - fix OID conflict with back-passwd - no need to close session, It may cause SEGV. - fixed wt_dn2entry for empty DN - support multiple database - Construct wiredtiger's config parameter. It allow multi line wtconfig settings - add idlcache - fix concurrent modification to a entry with multi values - prevent to add duplicate dn entry - suppress error message "search_near failed: WT_NOTFOUND" - update Debug statements - back-wt does not support subtree rename - fix for @ondra review - update slapd-wt.5 and warning for mode option - add back-wt test into test target - add scope checking --- doc/man/man5/slapd-wt.5 | 32 +- servers/slapd/back-wt/Makefile.in | 12 +- servers/slapd/back-wt/add.c | 80 ++-- servers/slapd/back-wt/attr.c | 43 +- servers/slapd/back-wt/back-wt.h | 25 +- servers/slapd/back-wt/bind.c | 7 +- servers/slapd/back-wt/cache.c | 231 +++++++++++ servers/slapd/back-wt/compare.c | 72 ++-- servers/slapd/back-wt/config.c | 77 +++- servers/slapd/back-wt/ctx.c | 91 ++--- servers/slapd/back-wt/delete.c | 128 +++--- servers/slapd/back-wt/dn2entry.c | 79 +++- servers/slapd/back-wt/dn2id.c | 354 ++++++++++------- servers/slapd/back-wt/extended.c | 58 +++ servers/slapd/back-wt/filterindex.c | 93 +++-- servers/slapd/back-wt/id2entry.c | 197 +++++++-- servers/slapd/back-wt/idl.c | 22 +- servers/slapd/back-wt/idl.h | 2 +- servers/slapd/back-wt/index.c | 52 ++- servers/slapd/back-wt/init.c | 177 ++++++--- servers/slapd/back-wt/key.c | 52 ++- servers/slapd/back-wt/modify.c | 210 ++++++---- servers/slapd/back-wt/modrdn.c | 552 ++++++++++++++++++++++++++ servers/slapd/back-wt/nextid.c | 12 +- servers/slapd/back-wt/operational.c | 8 +- servers/slapd/back-wt/proto-wt.h | 98 ++++- servers/slapd/back-wt/search.c | 181 ++++++--- servers/slapd/back-wt/tools.c | 315 ++++++++++++--- tests/Makefile.in | 10 + tests/README | 1 + tests/run.in | 2 + tests/scripts/test023-refint | 7 +- tests/scripts/test040-subtree-rename | 5 + tests/scripts/test057-memberof-refint | 9 +- 34 files changed, 2480 insertions(+), 814 deletions(-) create mode 100644 servers/slapd/back-wt/cache.c create mode 100644 servers/slapd/back-wt/extended.c create mode 100644 servers/slapd/back-wt/modrdn.c diff --git a/doc/man/man5/slapd-wt.5 b/doc/man/man5/slapd-wt.5 index d820f2cb97..d207374ff7 100644 --- a/doc/man/man5/slapd-wt.5 +++ b/doc/man/man5/slapd-wt.5 @@ -33,6 +33,25 @@ A separate directory must be specified for each database. The default is .BR LOCALSTATEDIR/openldap\-data . .TP +.BI idlcache \ +Use the in-memory idlcache. The default is true. +.TP +\fBindex \fR{\fI\fR|\fBdefault\fR} [\fBpres\fR,\fBeq\fR,\fBapprox\fR,\fBsub\fR,\fI\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\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. +.TP +.BI mode \ +back-wt does not support mode option. use umask instead. +.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). @@ -52,19 +71,6 @@ maximum heap memory to allocate for the cache. asynchronous operations configuration options. disabled by default. .RE .RS -.TP -\fBindex \fR{\fI\fR|\fBdefault\fR} [\fBpres\fR,\fBeq\fR,\fBapprox\fR,\fBsub\fR,\fI\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\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 diff --git a/servers/slapd/back-wt/Makefile.in b/servers/slapd/back-wt/Makefile.in index 4f1f33bcc2..3f7e2b761e 100644 --- a/servers/slapd/back-wt/Makefile.in +++ b/servers/slapd/back-wt/Makefile.in @@ -14,18 +14,18 @@ ## . SRCS = init.c tools.c config.c \ - add.c bind.c compare.c delete.c modify.c search.c \ - operational.c \ + add.c bind.c compare.c delete.c modify.c modrdn.c search.c \ + extended.c operational.c \ attr.c index.c key.c filterindex.c \ dn2entry.c dn2id.c id2entry.c idl.c \ - nextid.c ctx.c + nextid.c ctx.c cache.c OBJS = init.lo tools.lo config.lo \ - add.lo bind.lo compare.lo delete.lo modify.lo search.lo \ - operational.lo \ + add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \ + extended.lo operational.lo \ attr.lo index.lo key.lo filterindex.lo \ dn2entry.lo dn2id.lo id2entry.lo idl.lo \ - nextid.lo ctx.lo + nextid.lo ctx.lo cache.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-wt/add.c b/servers/slapd/back-wt/add.c index 5b9e83da3e..5613be2bef 100644 --- a/servers/slapd/back-wt/add.c +++ b/servers/slapd/back-wt/add.c @@ -34,20 +34,17 @@ wt_add( Operation *op, SlapReply *rs ) 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; + ID eid = NOID; 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; + ID pid = NOID; int rc; - Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_add) ": %s\n", - op->ora_e->e_name.bv_val ); + Debug( LDAP_DEBUG_ARGS, "==> wt_add: %s\n", op->ora_e->e_name.bv_val ); ctrls[num_ctrls] = 0; @@ -57,8 +54,7 @@ wt_add( Operation *op, SlapReply *rs ) 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", + "wt_add: entry failed schema check: %s (%d)\n", rs->sr_text, rs->sr_err ); goto return_results; } @@ -68,8 +64,7 @@ wt_add( Operation *op, SlapReply *rs ) 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", + "wt_add: entry failed op attrs add: %s (%d)\n", rs->sr_text, rs->sr_err ); goto return_results; } @@ -97,9 +92,7 @@ wt_add( Operation *op, SlapReply *rs ) wc = wt_ctx_get(op, wi); if( !wc ){ - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_add) - ": wt_ctx_get failed\n" ); + Debug( LDAP_DEBUG_ANY, "wt_add: wt_ctx_get failed\n" ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; send_ldap_result( op, rs ); @@ -117,9 +110,7 @@ wt_add( Operation *op, SlapReply *rs ) default: /* TODO: retry handling */ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_add) - ": error at wt_dn2entry() rc=%d\n", - rc ); + "wt_add: error at wt_dn2entry() rc=%d\n", rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; @@ -133,9 +124,7 @@ wt_add( Operation *op, SlapReply *rs ) break; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_add) - ": error at wt_dn2pentry() rc=%d\n", - rc ); + "wt_add: error at wt_dn2pentry() rc=%d\n", rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; @@ -156,9 +145,7 @@ wt_add( Operation *op, SlapReply *rs ) rs->sr_ref = NULL; } p = NULL; - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": parent " - "does not exist\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: parent does not exist\n" ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; goto return_results; @@ -173,8 +160,7 @@ wt_add( Operation *op, SlapReply *rs ) */ p = NULL; - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": no write access to parent\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: no write access to parent\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results;; @@ -185,8 +171,7 @@ wt_add( Operation *op, SlapReply *rs ) 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" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: parent is subentry\n" ); rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "parent is a subentry"; goto return_results;; @@ -196,8 +181,7 @@ wt_add( Operation *op, SlapReply *rs ) 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" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: parent is alias\n" ); rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "parent is an alias"; goto return_results;; @@ -213,8 +197,7 @@ wt_add( Operation *op, SlapReply *rs ) ber_bvarray_free( ref ); wt_entry_return( p ); p = NULL; - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": parent is referral\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: parent is referral\n" ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; @@ -261,8 +244,7 @@ wt_add( Operation *op, SlapReply *rs ) entry, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": no write access to entry\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: no write access to entry\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to entry"; goto return_results; @@ -272,33 +254,29 @@ wt_add( Operation *op, SlapReply *rs ) * 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" ); + Debug( LDAP_DEBUG_TRACE, "wt_add: no write access to attribute\n" ); 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); + rc = wc->session->begin_transaction(wc->session, "isolation=read-uncommitted"); if( rc ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n", + Debug( LDAP_DEBUG_TRACE, "wt_add: begin_transaction failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); 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 ); + Debug( LDAP_DEBUG_TRACE, "wt_add: session id: %p\n", wc->session ); wt_next_id( op->o_bd, &eid ); op->ora_e->e_id = eid; - rc = wt_dn2id_add( op, wc->session, pid, op->ora_e ); + rc = wt_dn2id_add( op, wc, pid, op->ora_e ); if( rc ){ Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) - ": dn2id_add failed: %s (%d)\n", + "wt_add: dn2id_add failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); switch( rc ) { case WT_DUPLICATE_KEY: @@ -311,11 +289,10 @@ wt_add( Operation *op, SlapReply *rs ) goto return_results; } - rc = wt_id2entry_add( op, wc->session, op->ora_e ); + rc = wt_id2entry_add( op, wc, op->ora_e ); if ( rc ) { Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) - ": id2entry_add failed: %s (%d)\n", + "wt_add: id2entry_add failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); if ( rc == LDAP_ADMINLIMIT_EXCEEDED ) { rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; @@ -332,8 +309,7 @@ wt_add( Operation *op, SlapReply *rs ) 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", + "<== wt_add: index add failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "index add failed"; @@ -344,8 +320,7 @@ wt_add( Operation *op, SlapReply *rs ) rc = wc->session->commit_transaction(wc->session, NULL); if( rc ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_add) - ": commit_transaction failed: %s (%d)\n", + "<== wt_add: commit_transaction failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "commit_transaction failed"; @@ -363,9 +338,7 @@ wt_add( Operation *op, SlapReply *rs ) 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" ); + Debug( LDAP_DEBUG_TRACE, "<=- wt_add: post-read failed!\n" ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ @@ -375,12 +348,11 @@ wt_add( Operation *op, SlapReply *rs ) } Debug(LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": added%s id=%08lx dn=\"%s\"\n", + "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 ); diff --git a/servers/slapd/back-wt/attr.c b/servers/slapd/back-wt/attr.c index 3aac12ff5e..58a5e15701 100644 --- a/servers/slapd/back-wt/attr.c +++ b/servers/slapd/back-wt/attr.c @@ -21,6 +21,7 @@ #include "back-wt.h" #include "slap-config.h" +#include "lutil.h" /* Find the ad, return -1 if not found, * set point for insertion if ins is non-NULL @@ -57,7 +58,7 @@ wt_attr_slot( struct wt_info *wi, AttributeDescription *ad, int *ins ) static int ainfo_insert( struct wt_info *wi, AttrInfo *a ) { - int x; + int x = INT_MAX; int i = wt_attr_slot( wi, a->ai_desc, &x ); /* Is it a dup? */ @@ -357,6 +358,44 @@ done: return rc; } +static int +wt_attr_index_unparser( void *v1, void *v2 ) +{ + AttrInfo *ai = v1; + BerVarray *bva = v2; + struct berval bv; + char *ptr; + + slap_index2bvlen( ai->ai_indexmask, &bv ); + if ( bv.bv_len ) { + bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1; + ptr = ch_malloc( bv.bv_len+1 ); + bv.bv_val = lutil_strcopy(ptr, + (const char*)ai->ai_desc->ad_cname.bv_val ); + *bv.bv_val++ = ' '; + slap_index2bv( ai->ai_indexmask, &bv ); + bv.bv_val = ptr; + ber_bvarray_add( bva, &bv ); + } + return 0; +} + +static AttributeDescription addef = { NULL, NULL, BER_BVC("default") }; +static AttrInfo aidef = { &addef }; + +void +wt_attr_index_unparse( struct wt_info *wi, BerVarray *bva ) +{ + int i; + + if ( wi->wi_defaultmask ) { + aidef.ai_indexmask = wi->wi_defaultmask; + wt_attr_index_unparser( &aidef, bva ); + } + for ( i=0; iwi_nattrs; i++ ) + wt_attr_index_unparser( wi->wi_attrs[i], bva ); +} + void wt_attr_info_free( AttrInfo *ai ) { @@ -377,8 +416,6 @@ wt_attr_index_destroy( struct wt_info *wi ) free( wi->wi_attrs ); } - - /* * Local variables: * indent-tabs-mode: t diff --git a/servers/slapd/back-wt/back-wt.h b/servers/slapd/back-wt/back-wt.h index 87ee7357e5..121463afb3 100644 --- a/servers/slapd/back-wt/back-wt.h +++ b/servers/slapd/back-wt/back-wt.h @@ -33,10 +33,13 @@ /* The default search IDL stack cache depth */ #define DEFAULT_SEARCH_STACK_DEPTH 16 +#define WT_CONFIG_MAX 2048 + struct wt_info { WT_CONNECTION *wi_conn; - char *wi_dbenv_home; - char *wi_dbenv_config; + WT_CONNECTION *wi_cache; + char *wi_home; + char *wi_config; ID wi_lastid; slap_mask_t wi_defaultmask; @@ -53,23 +56,41 @@ struct wt_info { #define WT_DEL_INDEX 0x08 #define WT_RE_OPEN 0x10 #define WT_NEED_UPGRADE 0x20 +#define WT_USE_IDLCACHE 0x40 }; #define WT_TABLE_ID2ENTRY "table:id2entry" #define WT_TABLE_DN2ID "table:dn2id" #define WT_INDEX_DN "index:id2entry:dn" +#define WT_INDEX_NDN "index:dn2id:ndn" #define WT_INDEX_PID "index:dn2id:pid" +/* Currently, revdn is primary key, the revdn index is obsolete. */ #define WT_INDEX_REVDN "index:dn2id:revdn" +/* table for cache */ +#define WT_TABLE_IDLCACHE "table:idlcache" + #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 ) +#define WT_INDEX_CACHE_SIZE 1024 + typedef struct { WT_SESSION *session; + int is_begin_transaction; + WT_CURSOR *dn2id; + WT_CURSOR *dn2id_w; + WT_CURSOR *dn2id_ndn; + WT_CURSOR *dn2entry; + WT_CURSOR *id2entry; + WT_CURSOR *id2entry_add; + WT_CURSOR *id2entry_update; + WT_SESSION *idlcache_session; + WT_CURSOR *index_pid; } wt_ctx; /* for the cache of attribute information (which are indexed, etc.) */ diff --git a/servers/slapd/back-wt/bind.c b/servers/slapd/back-wt/bind.c index c3908a161c..5c283f27bc 100644 --- a/servers/slapd/back-wt/bind.c +++ b/servers/slapd/back-wt/bind.c @@ -29,15 +29,13 @@ 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", + Debug( LDAP_DEBUG_ARGS, "==> wt_bind: dn: %s\n", op->o_req_dn.bv_val ); /* allow noauth binds */ @@ -59,8 +57,7 @@ wt_bind( Operation *op, SlapReply *rs ) wc = wt_ctx_get(op, wi); if( !wc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_bind) - ": wt_ctx_get failed\n" ); + "wt_bind: wt_ctx_get failed\n" ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; send_ldap_result( op, rs ); diff --git a/servers/slapd/back-wt/cache.c b/servers/slapd/back-wt/cache.c new file mode 100644 index 0000000000..eeced86a41 --- /dev/null +++ b/servers/slapd/back-wt/cache.c @@ -0,0 +1,231 @@ +/* OpenLDAP WiredTiger backend */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2002-2017 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was developed by HAMANO Tsukasa + * based on back-bdb for inclusion in OpenLDAP Software. + * WiredTiger is a product of MongoDB Inc. + */ + +#include "portable.h" + +#include +#include +#include "back-wt.h" +#include "slap-config.h" +#include "idl.h" + +int wt_idlcache_get(wt_ctx *wc, struct berval *ndn, int scope, ID *ids) +{ + int rc = 0; + WT_ITEM item; + WT_SESSION *session = wc->idlcache_session; + WT_CURSOR *cursor = NULL; + + Debug( LDAP_DEBUG_TRACE, + "=> wt_idlcache_get(\"%s\", %d)\n", + ndn->bv_val, scope ); + + rc = session->open_cursor(session, WT_TABLE_IDLCACHE, NULL, + NULL, &cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_get: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + cursor->set_key(cursor, ndn->bv_val, (int8_t)scope); + rc = cursor->search(cursor); + switch( rc ){ + case 0: + break; + case WT_NOTFOUND: + Debug(LDAP_DEBUG_TRACE, "<= wt_idlcache_get: miss\n" ); + goto done; + default: + Debug( LDAP_DEBUG_ANY, "<= wt_idlcache_get: search failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rc = 0; + goto done; + } + rc = cursor->get_value(cursor, &item); + if (rc) { + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_get: get_value failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + if (item.size == 0) { + Debug(LDAP_DEBUG_TRACE, "<= wt_idlcache_get: updating\n"); + rc = WT_NOTFOUND; + goto done; + } + memcpy(ids, item.data, item.size); + + Debug(LDAP_DEBUG_TRACE, + "<= wt_idlcache_get: hit id=%ld first=%ld last=%ld\n", + (long)ids[0], + (long)WT_IDL_FIRST(ids), + (long)WT_IDL_LAST(ids)); +done: + if(cursor) { + cursor->close(cursor); + } + return rc; +} + +int wt_idlcache_set(wt_ctx *wc, struct berval *ndn, int scope, ID *ids) +{ + int rc = 0; + WT_ITEM item; + WT_SESSION *session = wc->idlcache_session; + WT_CURSOR *cursor = NULL; + + Debug( LDAP_DEBUG_TRACE, + "=> wt_idlcache_set(\"%s\", %d)\n", + ndn->bv_val, scope ); + + item.size = WT_IDL_SIZEOF(ids); + item.data = ids; + + rc = session->open_cursor(session, WT_TABLE_IDLCACHE, NULL, + "overwrite=false", &cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_set: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + cursor->set_key(cursor, ndn->bv_val, (int8_t)scope); + cursor->set_value(cursor, &item); + rc = cursor->update(cursor); + switch( rc ){ + case 0: + break; + case WT_NOTFOUND: + // updating cache by another thread + goto done; + default: + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_set: update failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + + Debug(LDAP_DEBUG_TRACE, + "<= wt_idlcache_set: set idl size=%ld\n", + (long)ids[0]); +done: + if(cursor) { + cursor->close(cursor); + } + return rc; +} + +int wt_idlcache_begin(wt_ctx *wc, struct berval *ndn, int scope) +{ + int rc = 0; + WT_ITEM item; + WT_SESSION *session = wc->idlcache_session; + WT_CURSOR *cursor = NULL; + + Debug( LDAP_DEBUG_TRACE, + "=> wt_idlcache_begin(\"%s\", %d)\n", + ndn->bv_val, scope ); + + item.size = 0; + item.data = ""; + + rc = session->open_cursor(session, WT_TABLE_IDLCACHE, NULL, + "overwrite=true", &cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_begin: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + cursor->set_key(cursor, ndn->bv_val, (int8_t)scope); + cursor->set_value(cursor, &item); + rc = cursor->update(cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_begin: update failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + + Debug(LDAP_DEBUG_TRACE, + "<= wt_idlcache_begin: set updating\n" ); + +done: + if(cursor) { + cursor->close(cursor); + } + return rc; +} + +int wt_idlcache_clear(Operation *op, wt_ctx *wc, struct berval *ndn) +{ + BackendDB *be = op->o_bd; + int rc = 0; + struct berval pdn = *ndn; + WT_SESSION *session = wc->idlcache_session; + WT_CURSOR *cursor = NULL; + int level = 0; + + Debug( LDAP_DEBUG_TRACE, + "=> wt_idlcache_clear(\"%s\")\n", + ndn->bv_val ); + + if (be_issuffix( be, ndn )) { + return 0; + } + + rc = session->open_cursor(session, WT_TABLE_IDLCACHE, NULL, + NULL, &cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_idlcache_clear: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + + do { + dnParent( &pdn, &pdn ); + if (level == 0) { + /* clear only parent level cache */ + cursor->set_key(cursor, pdn.bv_val, (int8_t)LDAP_SCOPE_ONE); + cursor->remove(cursor); + } + cursor->set_key(cursor, pdn.bv_val, (int8_t)LDAP_SCOPE_SUB); + cursor->remove(cursor); + cursor->set_key(cursor, pdn.bv_val, (int8_t)LDAP_SCOPE_CHILDREN); + cursor->remove(cursor); + level++; + }while(!be_issuffix( be, &pdn )); + + if(cursor) { + cursor->close(cursor); + } + return 0; +} + +/* + * Local variables: + * indent-tabs-mode: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/servers/slapd/back-wt/compare.c b/servers/slapd/back-wt/compare.c index 1d13af7406..d34bf68075 100644 --- a/servers/slapd/back-wt/compare.c +++ b/servers/slapd/back-wt/compare.c @@ -36,22 +36,20 @@ wt_compare( Operation *op, SlapReply *rs ) int rc; wt_ctx *wc = NULL; - Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_compare) ": %s\n", + Debug( LDAP_DEBUG_ARGS, "==> wt_compare: %s\n", op->o_req_dn.bv_val ); wc = wt_ctx_get(op, wi); if( !wc ){ - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_compare) - ": wt_ctx_get failed\n" ); + Debug( LDAP_DEBUG_ANY, "wt_compare: wt_ctx_get failed\n" ); 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 ) { + rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { case 0: case WT_NOTFOUND: break; @@ -61,37 +59,45 @@ wt_compare( Operation *op, SlapReply *rs ) 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 ) ) - { + if ( rc == WT_NOTFOUND || + (!manageDSAit && e && is_entry_glue( e ) )) { + + if ( !e ) { + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: 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; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, "wt_compare: wt_dn2aentry failed (%d)\n", + rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; } - 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; } + /* 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; + } rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; send_ldap_result( op, rs ); goto done; diff --git a/servers/slapd/back-wt/config.c b/servers/slapd/back-wt/config.c index ed8ef395c0..79442ea3c2 100644 --- a/servers/slapd/back-wt/config.c +++ b/servers/slapd/back-wt/config.c @@ -35,6 +35,8 @@ enum { WT_DIRECTORY = 1, WT_CONFIG, WT_INDEX, + WT_MODE, + WT_IDLCACHE, }; static ConfigTable wtcfg[] = { @@ -43,27 +45,35 @@ static ConfigTable wtcfg[] = { "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 }, + { "mode", "mode", 2, 2, 0, ARG_MAGIC|WT_MODE, + wt_cf_gen, "( OLcfgDbAt:0.3 NAME 'olcDbMode' " + "DESC 'Unix permissions of database files' " + "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 }, + { "idlcache", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|WT_IDLCACHE, + wt_cf_gen, "( OLcfgDbAt:13.2 NAME 'olcIDLcache' " + "DESC 'enable IDL cache' " + "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL } }; static ConfigOCs wtocs[] = { - { "( OLcfgDbOc:9.1 " + { "( OLcfgDbOc:13.1 " "NAME 'olcWtConfig' " "DESC 'Wt backend configuration' " "SUP olcDatabaseConfig " "MUST olcDbDirectory " - "MAY ( olcWtConfig $ olcDbIndex ) )", + "MAY ( olcWtConfig $ olcDbIndex $ olcDbMode $ olcIDLcache) )", Cft_Database, wtcfg }, { NULL, 0, NULL } }; @@ -73,6 +83,7 @@ static void * wt_online_index( void *ctx, void *arg ) { // Not implement yet + return NULL; } /* Cleanup loose ends after Modify completes */ @@ -89,20 +100,47 @@ wt_cf_gen( ConfigArgs *c ) struct wt_info *wi = (struct wt_info *) c->be->be_private; int rc; - if(c->op == SLAP_CONFIG_EMIT) { + if( c->op == SLAP_CONFIG_EMIT ) { + rc = 0; + switch( c->type ) { + case WT_DIRECTORY: + if ( wi->wi_home ) { + c->value_string = ch_strdup( wi->wi_home ); + } else { + rc = 1; + } + break; + case WT_INDEX: + wt_attr_index_unparse( wi, &c->rvalue_vals ); + if ( !c->rvalue_vals ) rc = 1; + break; + case WT_IDLCACHE: + if ( wi->wi_flags & WT_USE_IDLCACHE) { + c->value_int = 1; + } + break; + } + return rc; + } else if ( c->op == LDAP_MOD_DELETE ) { 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; + ch_free( wi->wi_home ); + wi->wi_home = c->value_string; break; case WT_CONFIG: - ch_free( wi->wi_dbenv_config ); - wi->wi_dbenv_config = c->value_string; + if(strlen(wi->wi_config) + 1 + strlen(c->value_string) > WT_CONFIG_MAX){ + fprintf( stderr, "%s: " + "\"wtconfig\" are too long. Increase WT_CONFIG_MAX or you may realloc the buffer.\n", + c->log ); + return 1; + } + /* size of wi->wi_config is WT_CONFIG_MAX + 1, it's guaranteed with NUL-terminate. */ + strcat(wi->wi_config, ","); + strcat(wi->wi_config, c->value_string); break; case WT_INDEX: @@ -135,6 +173,19 @@ wt_cf_gen( ConfigArgs *c ) } break; + case WT_MODE: + fprintf( stderr, "%s: " + "back-wt does not support \"mode\" option. use umask instead.\n", + c->log ); + return 1; + + case WT_IDLCACHE: + if ( c->value_int ) { + wi->wi_flags |= WT_USE_IDLCACHE; + } else { + wi->wi_flags &= ~WT_USE_IDLCACHE; + } + break; } return LDAP_SUCCESS; } diff --git a/servers/slapd/back-wt/ctx.c b/servers/slapd/back-wt/ctx.c index 6f09801d1e..a9a32c730c 100644 --- a/servers/slapd/back-wt/ctx.c +++ b/servers/slapd/back-wt/ctx.c @@ -30,24 +30,32 @@ wt_ctx_init(struct wt_info *wi) wc = ch_malloc( sizeof( wt_ctx ) ); if( !wc ) { - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_ctx_init) - ": cannot allocate memory\n" ); + Debug( LDAP_DEBUG_ANY, "wt_ctx_init: cannot allocate memory\n" ); 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 ); - return NULL; - } + rc = wi->wi_conn->open_session(wi->wi_conn, NULL, NULL, &wc->session); + if( rc ) { + Debug( LDAP_DEBUG_ANY, "wt_ctx_init: open_session error %s(%d)\n", + wiredtiger_strerror(rc), rc ); + return NULL; } + + /* readonly mode */ + if (!wi->wi_cache) { + return wc; + } + + rc = wi->wi_cache->open_session(wi->wi_cache, NULL, NULL, &wc->idlcache_session); + if( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_ctx_init: cannot open idlcache session %s(%d)\n", + wiredtiger_strerror(rc), rc ); + return NULL; + } + return wc; } @@ -57,9 +65,19 @@ wt_ctx_free( void *key, void *data ) wt_ctx *wc = data; if(wc->session){ - wc->session->close(wc->session, NULL); + /* + * The session will close automatically when db closing. + * We can close session here, but it's require to check db + * status, otherwise it will cause SEGV. + */ + /* + if(IS_DB_OPEN) { + wc->session->close(wc->session, NULL); + } + */ wc->session = NULL; } + ch_free(wc); } @@ -70,17 +88,15 @@ wt_ctx_get(Operation *op, struct wt_info *wi){ wt_ctx *wc = NULL; rc = ldap_pvt_thread_pool_getkey(op->o_threadctx, - wt_ctx_get, &data, NULL ); + wi, &data, NULL ); if( rc ){ wc = wt_ctx_init(wi); if( !wc ) { - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_ctx) - ": wt_ctx_init failed\n" ); + Debug( LDAP_DEBUG_ANY, "wt_ctx: wt_ctx_init failed\n" ); return NULL; } rc = ldap_pvt_thread_pool_setkey( op->o_threadctx, - wt_ctx_get, wc, wt_ctx_free, + wi, wc, wt_ctx_free, NULL, NULL ); if( rc ) { Debug( LDAP_DEBUG_ANY, "wt_ctx: setkey error(%d)\n", @@ -92,45 +108,6 @@ wt_ctx_get(Operation *op, struct wt_info *wi){ 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 ); - return NULL; - } - - return cursor; -} - /* * Local variables: * indent-tabs-mode: t diff --git a/servers/slapd/back-wt/delete.c b/servers/slapd/back-wt/delete.c index 20f06b2f15..5a9e1b3ff6 100644 --- a/servers/slapd/back-wt/delete.c +++ b/servers/slapd/back-wt/delete.c @@ -44,12 +44,11 @@ wt_delete( Operation *op, SlapReply *rs ) 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", + Debug( LDAP_DEBUG_ARGS, "==> wt_delete: %s\n", op->o_req_dn.bv_val ); if( op->o_txnSpec && txn_preop( op, rs )) @@ -60,9 +59,7 @@ wt_delete( Operation *op, SlapReply *rs ) wc = wt_ctx_get(op, wi); if( !wc ){ - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_delete) - ": wt_ctx_get failed\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_delete: wt_ctx_get failed\n" ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; @@ -89,26 +86,37 @@ wt_delete( Operation *op, SlapReply *rs ) 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 ); + "wt_delete: error at wt_dn2entry() rc=%d\n", rc ); 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 ); + "<== wt_delete: parent not found %s\n", op->o_req_dn.bv_val ); + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); + Debug( LDAP_DEBUG_ARGS, "<== wt_delete: rc=%d\n", rc ); - 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, + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, "wt_delete: wt_dn2aentry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + + if ( e && !BER_BVISEMPTY( &e->e_name )) { + rs->sr_matched = ch_strdup( e->e_name.bv_val ); + 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 { @@ -130,30 +138,36 @@ wt_delete( Operation *op, SlapReply *rs ) 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 ); - rs->sr_err = LDAP_REFERRAL; - rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; - goto return_results; + 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 ); + "wt_delete: error at wt_dn2entry() rc=%d\n", rc ); 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 ); + if (rc == WT_NOTFOUND || + ( !manageDSAit && e && is_entry_glue( e ) )) { + if ( !e ) { + Debug( LDAP_DEBUG_ARGS, + "<== wt_delete: no such object %s\n", + op->o_req_dn.bv_val); + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, "wt_delete: wt_dn2aentry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + } rs->sr_matched = ch_strdup( e->e_dn ); if ( is_entry_referral( e )) { @@ -177,8 +191,7 @@ wt_delete( Operation *op, SlapReply *rs ) if ( !rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) ": no write " - "access to parent\n" ); + "<== wt_delete: no write access to parent\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results; @@ -199,8 +212,7 @@ wt_delete( Operation *op, SlapReply *rs ) if ( !rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": no access to parent\n" ); + "<== wt_delete: no access to parent\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results; @@ -208,8 +220,7 @@ wt_delete( Operation *op, SlapReply *rs ) } else { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": no parent and not root\n" ); + "<== wt_delete: no parent and not root\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } @@ -227,8 +238,7 @@ wt_delete( Operation *op, SlapReply *rs ) entry, NULL, ACL_WDEL, NULL ); if ( !rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) ": no write access " - "to entry\n" ); + "<== wt_delete: no write access to entry\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to entry"; goto return_results; @@ -238,8 +248,7 @@ wt_delete( Operation *op, SlapReply *rs ) /* 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" ); + Debug( LDAP_DEBUG_TRACE, "wt_delete: entry is referral\n" ); rs->sr_err = LDAP_REFERRAL; rs->sr_matched = ch_strdup( e->e_name.bv_val ); @@ -257,8 +266,7 @@ wt_delete( Operation *op, SlapReply *rs ) &slap_pre_read_bv, preread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) ": pre-read " - "failed!\n" ); + "<== wt_delete: pre-read failed!\n" ); if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ @@ -268,21 +276,18 @@ wt_delete( Operation *op, SlapReply *rs ) } /* Can't do it if we have kids */ - rc = wt_dn2id_has_children( op, wc->session, e->e_id ); + rc = wt_dn2id_has_children( op, wc, 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 ); + "<== wt_delete: non-leaf %s\n", op->o_req_dn.bv_val ); 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", + "<== wt_delete: has_children failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; @@ -294,7 +299,7 @@ wt_delete( Operation *op, SlapReply *rs ) rc = wc->session->begin_transaction(wc->session, NULL); if( rc ) { Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n", + "wt_delete: begin_transaction failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "begin_transaction failed"; @@ -302,11 +307,10 @@ wt_delete( Operation *op, SlapReply *rs ) } /* delete from dn2id */ - rc = wt_dn2id_delete( op, wc->session, &e->e_nname); + rc = wt_dn2id_delete( op, wc, &op->o_req_ndn); if ( rc ) { Debug(LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": dn2id failed: %s (%d)\n", + "<== wt_delete: dn2id failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "dn2id delete failed"; @@ -318,8 +322,7 @@ wt_delete( Operation *op, SlapReply *rs ) rc = wt_index_entry_del( op, wc, e ); if ( rc ) { Debug(LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": index delete failed: %s (%d)\n", + "<== wt_delete: index delete failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "index delete failed"; @@ -334,7 +337,7 @@ wt_delete( Operation *op, SlapReply *rs ) 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, + rs->sr_err = wt_index_values( op, wc, slap_schema.si_ad_entryCSN, vals, 0, SLAP_INDEX_ADD_OP ); if ( rs->sr_err != LDAP_SUCCESS ) { rs->sr_text = "entryCSN index update failed"; @@ -345,11 +348,10 @@ wt_delete( Operation *op, SlapReply *rs ) } /* delete from id2entry */ - rc = wt_id2entry_delete( op, wc->session, e ); + rc = wt_id2entry_delete( op, wc, e ); if ( rc ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": id2entry failed: %s (%d)\n", + "<== wt_delete: id2entry failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "entry delete failed"; @@ -364,8 +366,7 @@ wt_delete( Operation *op, SlapReply *rs ) rc = wc->session->commit_transaction(wc->session, NULL); if( rc ) { Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_delete) - ": commit_transaction failed: %s (%d)\n", + "<== wt_delete: commit_transaction failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "commit_transaction failed"; @@ -373,8 +374,7 @@ wt_delete( Operation *op, SlapReply *rs ) } Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_delete) - ": deleted%s id=%08lx dn=\"%s\"\n", + "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; diff --git a/servers/slapd/back-wt/dn2entry.c b/servers/slapd/back-wt/dn2entry.c index c180e44596..6e6e08a02b 100644 --- a/servers/slapd/back-wt/dn2entry.c +++ b/servers/slapd/back-wt/dn2entry.c @@ -35,28 +35,33 @@ int wt_dn2entry( BackendDB *be, 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; + WT_CURSOR *cursor = wc->dn2entry; if( ndn->bv_len == 0 ){ - /* parent of root dn */ - return WT_NOTFOUND; + /* empty dn */ + e = entry_alloc(); + ber_dupbv(&e->e_nname, ndn); + *ep = e; + return LDAP_SUCCESS; } - 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 ); - goto done; + if(!cursor){ + rc = session->open_cursor(session, + WT_INDEX_DN"(id, entry)", + NULL, NULL, &cursor); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_dn2entry: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->dn2entry = cursor; } cursor->set_key(cursor, ndn->bv_val); @@ -68,8 +73,7 @@ int wt_dn2entry( BackendDB *be, goto done; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2entry) - ": search failed: %s (%d)\n", + "wt_dn2entry: search failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } @@ -86,9 +90,7 @@ int wt_dn2entry( BackendDB *be, rc = entry_decode( &eh, &e ); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2entry) - ": entry decode error: %d\n", - rc ); + "wt_dn2entry: entry decode error: %d\n", rc ); goto done; } @@ -96,9 +98,17 @@ int wt_dn2entry( BackendDB *be, *ep = e; done: + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->dn2entry = NULL; } +#endif return rc; } @@ -122,6 +132,41 @@ int wt_dn2pentry( BackendDB *be, return rc; } +/* dn2aentry - return ancestor entry */ +int wt_dn2aentry( 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 0; + } + + dnParent( ndn, &pdn ); + rc = wt_dn2entry(be, wc, &pdn, &e); + switch( rc ) { + case 0: + *ep = e; + break; + case WT_NOTFOUND: + rc = wt_dn2aentry(be, wc, &pdn, &e); + if (rc != 0 && rc != WT_NOTFOUND) { + return rc; + } + *ep = e; + break; + default: + Debug( LDAP_DEBUG_ANY, + "wt_dn2aentry: failed %s (%d)\n", + wiredtiger_strerror(rc), rc ); + } + return rc; +} + /* * Local variables: * indent-tabs-mode: t diff --git a/servers/slapd/back-wt/dn2id.c b/servers/slapd/back-wt/dn2id.c index 5251203a0c..58d98d9866 100644 --- a/servers/slapd/back-wt/dn2id.c +++ b/servers/slapd/back-wt/dn2id.c @@ -26,7 +26,7 @@ #include "slap-config.h" #include "idl.h" -char * +static char * mkrevdn(struct berval src){ char *dst, *p; char *rdn; @@ -46,7 +46,7 @@ mkrevdn(struct berval src){ rdn = src.bv_val; src.bv_len = 0; } - AC_MEMCPY( p, rdn, rdn_len ); + memcpy( p, rdn, rdn_len ); p += rdn_len; *p++ = ','; } @@ -57,12 +57,14 @@ mkrevdn(struct berval src){ int wt_dn2id_add( Operation *op, - WT_SESSION *session, + wt_ctx *wc, ID pid, Entry *e) { + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; int rc; - WT_CURSOR *cursor = NULL; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->dn2id_w; char *revdn = NULL; Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_add 0x%lx: \"%s\"\n", @@ -72,33 +74,47 @@ wt_dn2id_add( /* 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 ); - goto done; - } - cursor->set_key(cursor, e->e_ndn); - cursor->set_value(cursor, e->e_id, pid, revdn); + if(!cursor){ + rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL, + "overwrite=false", &cursor); + if(rc){ + Debug( LDAP_DEBUG_ANY, + "wt_dn2id_add: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->dn2id_w = cursor; + } + cursor->set_key(cursor, revdn); + cursor->set_value(cursor, e->e_ndn, e->e_id, pid); rc = cursor->insert(cursor); if(rc){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2id_add) - ": insert failed: %s (%d)\n", + "wt_dn2id_add: insert failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } + if (wi->wi_flags & WT_USE_IDLCACHE) { + wt_idlcache_clear(op, wc, &e->e_nname); + } + done: if(revdn){ ch_free(revdn); } + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->dn2id_w = NULL; } +#endif + Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id_add 0x%lx: %d\n", e->e_id, rc ); return rc; } @@ -106,73 +122,94 @@ done: int wt_dn2id_delete( Operation *op, - WT_SESSION *session, + wt_ctx *wc, struct berval *ndn) { + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; int rc = 0; - WT_CURSOR *cursor = NULL; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->dn2id_w; + char *revdn = NULL; Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id_delete %s\n", ndn->bv_val ); - 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 ); - goto done; + /* make reverse dn */ + revdn = mkrevdn(*ndn); + + if(!cursor){ + rc = session->open_cursor(session, WT_TABLE_DN2ID, NULL, + "overwrite=false", &cursor); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_dn2id_delete: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->dn2id_w = cursor; } - cursor->set_key(cursor, ndn->bv_val); + cursor->set_key(cursor, revdn); rc = cursor->remove(cursor); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2id_delete) - ": remove failed: %s (%d)\n", + "wt_dn2id_delete: remove failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } + if (wi->wi_flags & WT_USE_IDLCACHE) { + wt_idlcache_clear(op, wc, ndn); + } + Debug( LDAP_DEBUG_TRACE, - "<= wt_dn2id_delete %s: %d\n", - ndn->bv_val, rc ); + "<= wt_dn2id_delete %s: %d\n", ndn->bv_val, rc ); done: + if(revdn){ + ch_free(revdn); + } + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->dn2id_w = NULL; } +#endif return rc; } int wt_dn2id( Operation *op, - WT_SESSION *session, + wt_ctx *wc, 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; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->dn2id_ndn; + int rc = LDAP_SUCCESS; - Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id(\"%s\")\n", - ndn->bv_val ); + Debug( LDAP_DEBUG_TRACE, "=> wt_dn2id(\"%s\")\n", ndn->bv_val ); 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 ); - goto done; + if(!cursor){ + rc = session->open_cursor(session, WT_INDEX_NDN + "(id)", + NULL, NULL, &cursor); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_dn2id: cursor open failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->dn2id_ndn = cursor; } cursor->set_key(cursor, ndn->bv_val); @@ -184,24 +221,30 @@ wt_dn2id( goto done; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2id) - ": search failed: %s (%d)\n", + "wt_dn2id: search failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } rc = cursor->get_value(cursor, id); if( rc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2id) - ": get_value failed: %s (%d)\n", + "wt_dn2id: get_value failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } done: + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->dn2id_ndn = NULL; } +#endif if( rc ) { Debug( LDAP_DEBUG_TRACE, "<= wt_dn2id: get failed: %s (%d)\n", @@ -217,47 +260,56 @@ done: int wt_dn2id_has_children( Operation *op, - WT_SESSION *session, + wt_ctx *wc, ID id ) { - struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; - WT_CURSOR *cursor = NULL; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->index_pid; 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 ); - goto done; + if(!cursor){ + rc = session->open_cursor(session, WT_INDEX_PID, + NULL, NULL, &cursor); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_dn2id_has_children: cursor open failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->index_pid = cursor; } cursor->set_key(cursor, key); rc = cursor->search(cursor); done: + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->index_pid = NULL; } +#endif return rc; } int -wt_dn2idl( +wt_dn2idl_db( Operation *op, - WT_SESSION *session, + wt_ctx *wc, 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; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->dn2id; int rc; char *revdn = NULL; size_t revdn_len; @@ -268,73 +320,58 @@ wt_dn2idl( "=> wt_dn2idl(\"%s\")\n", ndn->bv_val ); - 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 ( !cursor ) { + rc = session->open_cursor(session, WT_TABLE_DN2ID"(id, pid)", + NULL, NULL, &cursor); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_dn2idl: cursor open failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->dn2id = cursor; + } + cursor->set_key(cursor, revdn); + rc = cursor->search(cursor); if( rc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2idl) - ": cursor open failed: %s (%d)\n", + "wt_dn2idl: search failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); 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 ); - goto done; + + if( op->ors_scope == LDAP_SCOPE_CHILDREN ) { + cursor->next(cursor); } do { rc = cursor->get_key(cursor, &key); if( rc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_dn2idl) - ": get_key failed: %s (%d)\n", + "wt_dn2idl: get_key failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + rc = cursor->get_value(cursor, &id, &pid); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_dn2id: get_value failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); 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 ); - 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); + + if( op->ors_scope == LDAP_SCOPE_ONELEVEL && e->e_id != pid ){ + goto next; } + wt_idl_append_one(ids, id); + next: rc = cursor->next(cursor); }while(rc == 0); @@ -342,47 +379,70 @@ wt_dn2idl( rc = LDAP_SUCCESS; } + wt_idl_sort(ids, stack); + Debug( LDAP_DEBUG_TRACE, + "<= wt_dn2idl_db: size=%ld first=%ld last=%ld\n", + (long) ids[0], + (long) WT_IDL_FIRST(ids), + (long) WT_IDL_LAST(ids) ); + done: if(revdn){ ch_free(revdn); } +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->dn2id = NULL; } - 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 ); - - 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 ); - 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 + return rc; +} + +int +wt_dn2idl( + Operation *op, + wt_ctx *wc, + struct berval *ndn, + Entry *e, + ID *ids, + ID *stack) +{ + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; + int rc; + + Debug( LDAP_DEBUG_TRACE, + "=> wt_dn2idl(\"%s\")\n", ndn->bv_val ); + + if(op->ors_scope != LDAP_SCOPE_ONELEVEL && + be_issuffix( op->o_bd, &e->e_nname )){ + WT_IDL_ALL(wi, ids); + return 0; + } + + if (wi->wi_flags & WT_USE_IDLCACHE) { + rc = wt_idlcache_get(wc, ndn, op->ors_scope, ids); + if (rc == 0) { + /* cache hit */ + return rc; + } + /* cache miss */ + } + + if ( wi->wi_flags & WT_USE_IDLCACHE ) { + wt_idlcache_begin(wc, ndn, op->ors_scope); + } + rc = wt_dn2idl_db(op, wc, ndn, e, ids, stack); + if ( rc == 0 && wi->wi_flags & WT_USE_IDLCACHE ) { + wt_idlcache_set(wc, ndn, op->ors_scope, ids); + } + + return rc; +} /* * Local variables: diff --git a/servers/slapd/back-wt/extended.c b/servers/slapd/back-wt/extended.c new file mode 100644 index 0000000000..306c34e5a1 --- /dev/null +++ b/servers/slapd/back-wt/extended.c @@ -0,0 +1,58 @@ +/* OpenLDAP WiredTiger backend */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was developed by HAMANO Tsukasa + * based on back-bdb for inclusion in OpenLDAP Software. + * WiredTiger is a product of MongoDB Inc. + */ + +#include "portable.h" + +#include +#include + +#include "back-wt.h" +#include "lber_pvt.h" + +static struct exop { + struct berval *oid; + BI_op_extended *extended; +} exop_table[] = { + { NULL, NULL } +}; + +int +wt_extended( Operation *op, SlapReply *rs ) +{ + int i; + + for( i=0; exop_table[i].extended != NULL; i++ ) { + if( ber_bvcmp( exop_table[i].oid, &op->oq_extended.rs_reqoid ) == 0 ) { + return (exop_table[i].extended)( op, rs ); + } + } + + rs->sr_text = "not supported within naming context"; + return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; +} + +/* + * Local variables: + * indent-tabs-mode: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/servers/slapd/back-wt/filterindex.c b/servers/slapd/back-wt/filterindex.c index d2cdbc8346..a9d95f6b31 100644 --- a/servers/slapd/back-wt/filterindex.c +++ b/servers/slapd/back-wt/filterindex.c @@ -75,7 +75,7 @@ presence_candidates( } /* open index cursor */ - cursor = wt_ctx_index_cursor(wc, &desc->ad_type->sat_cname, 0); + cursor = wt_index_open(wc, &desc->ad_type->sat_cname, 0); if( !cursor ) { Debug( LDAP_DEBUG_ANY, "<= wt_presence_candidates: open index cursor failed: %s\n", @@ -85,9 +85,7 @@ presence_candidates( rc = wt_key_read( op->o_bd, cursor, &prefix, ids, NULL, 0 ); - if(cursor){ - cursor->close(cursor); - } + cursor->close(cursor); Debug(LDAP_DEBUG_TRACE, "<= wt_presence_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], @@ -114,12 +112,12 @@ equality_candidates( MatchingRule *mr; WT_CURSOR *cursor = NULL; - Debug( LDAP_DEBUG_TRACE, "=> wt_equality_candidates (%s)\n", - ava->aa_desc->ad_cname.bv_val ); + Debug( LDAP_DEBUG_TRACE, "=> wt_equality_candidates (%s=%s)\n", + ava->aa_desc->ad_cname.bv_val, ava->aa_value.bv_val ); if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { ID id = NOID; - rc = wt_dn2id(op, wc->session, &ava->aa_value, &id); + rc = wt_dn2id(op, wc, &ava->aa_value, &id); if( rc == 0 ){ wt_idl_append_one(ids, id); }else if ( rc == WT_NOTFOUND ) { @@ -182,7 +180,7 @@ equality_candidates( } /* open index cursor */ - cursor = wt_ctx_index_cursor(wc, &ava->aa_desc->ad_type->sat_cname, 0); + cursor = wt_index_open(wc, &ava->aa_desc->ad_type->sat_cname, 0); if( !cursor ) { Debug( LDAP_DEBUG_ANY, "<= wt_equality_candidates: open index cursor failed: %s\n", @@ -198,8 +196,7 @@ equality_candidates( break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "<= wt_equality_candidates: (%s) " - "key read failed (%d)\n", + "<= wt_equality_candidates: (%s) key read failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc ); break; } @@ -215,9 +212,7 @@ equality_candidates( ber_bvarray_free_x( keys, op->o_tmpmemctx ); - if(cursor){ - cursor->close(cursor); - } + cursor->close(cursor); Debug( LDAP_DEBUG_TRACE, "<= wt_equality_candidates: id=%ld, first=%ld, last=%ld\n", @@ -305,7 +300,7 @@ approx_candidates( } /* open index cursor */ - cursor = wt_ctx_index_cursor(wc, &ava->aa_desc->ad_type->sat_cname, 0); + cursor = wt_index_open(wc, &ava->aa_desc->ad_type->sat_cname, 0); if( !cursor ) { Debug( LDAP_DEBUG_ANY, "<= wt_approx_candidates: open index cursor failed: %s\n", @@ -346,9 +341,7 @@ approx_candidates( ber_bvarray_free_x( keys, op->o_tmpmemctx ); - if(cursor){ - cursor->close(cursor); - } + cursor->close(cursor); Debug( LDAP_DEBUG_TRACE, "<= wt_approx_candidates %ld, first=%ld, last=%ld\n", @@ -393,8 +386,7 @@ substring_candidates( if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "<= wt_substring_candidates: (%s) " - "index_param failed (%d)\n", + "<= wt_substring_candidates: (%s) index_param failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc ); return 0; } @@ -433,7 +425,7 @@ substring_candidates( } /* open index cursor */ - cursor = wt_ctx_index_cursor(wc, &sub->sa_desc->ad_cname, 0); + cursor = wt_index_open(wc, &sub->sa_desc->ad_cname, 0); if( !cursor ) { Debug( LDAP_DEBUG_ANY, "<= wt_substring_candidates: open index cursor failed: %s\n", @@ -475,9 +467,7 @@ substring_candidates( ber_bvarray_free_x( keys, op->o_tmpmemctx ); - if(cursor){ - cursor->close(cursor); - } + cursor->close(cursor); Debug( LDAP_DEBUG_TRACE, "<= wt_substring_candidates: %ld, first=%ld, last=%ld\n", @@ -487,6 +477,56 @@ substring_candidates( return rc; } +#ifdef LDAP_COMP_MATCH +static int +comp_candidates ( + Operation *op, + wt_ctx *wc, + MatchingRuleAssertion *mra, + ComponentFilter *f, + ID *ids, + ID *tmp, + ID *stack) +{ + int rc = 0; + + if ( !f ) return LDAP_PROTOCOL_ERROR; + + Debug( LDAP_DEBUG_FILTER, "comp_candidates\n" ); + /* TODO: */ + Debug( LDAP_DEBUG_FILTER, "=> not implement yet\n" ); + return( rc ); +} + +#endif + +static int +ext_candidates( + Operation *op, + wt_ctx *wc, + MatchingRuleAssertion *mra, + ID *ids, + ID *tmp, + ID *stack ) +{ + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; + +#ifdef LDAP_COMP_MATCH + /* + * Currently Only Component Indexing for componentFilterMatch is supported + * Indexing for an extensible filter is not supported yet + */ + if ( mra->ma_cf ) { + return comp_candidates ( op, wc, mra, mra->ma_cf, ids, tmp, stack); + } +#endif + if ( mra->ma_desc == slap_schema.si_ad_entryDN ) { + /* TODO: */ + Debug( LDAP_DEBUG_FILTER, "=> not implement yet.\n" ); + } + WT_IDL_ALL( wi, ids ); + return 0; +} static int list_candidates( @@ -569,7 +609,7 @@ wt_filter_candidates( ID *stack ) { struct wt_info *wi = (struct wt_info *)op->o_bd->be_private; - int rc = 0; + int rc = LDAP_SUCCESS; Debug( LDAP_DEBUG_FILTER, "=> wt_filter_candidates\n" ); if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { @@ -649,9 +689,8 @@ wt_filter_candidates( break; case LDAP_FILTER_EXT: - /* TODO: not implement yet */ Debug( LDAP_DEBUG_FILTER, "\tEXT\n" ); - rc = presence_candidates( op, wc, f->f_ava->aa_desc, ids ); + rc = ext_candidates( op, wc, f->f_mra, ids, tmp, stack); break; default: @@ -667,7 +706,7 @@ done: (long) ids[0], (long) WT_IDL_FIRST( ids ), (long) WT_IDL_LAST( ids ) ); - return 0; + return rc; } /* diff --git a/servers/slapd/back-wt/id2entry.c b/servers/slapd/back-wt/id2entry.c index 4240ac90a9..0fda2a9fb8 100644 --- a/servers/slapd/back-wt/id2entry.c +++ b/servers/slapd/back-wt/id2entry.c @@ -24,12 +24,11 @@ static int wt_id2entry_put( Operation *op, - WT_SESSION *session, + wt_ctx *wc, Entry *e, - const char *config ) + WT_CURSOR *cursor) { struct berval bv; - WT_CURSOR *cursor = NULL; WT_ITEM item; int rc; @@ -40,63 +39,108 @@ static int wt_id2entry_put( 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 ); - 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", + "wt_id2entry_put: insert failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } done: ch_free( bv.bv_val ); - if(cursor){ - cursor->close(cursor); - } + return rc; } int wt_id2entry_add( Operation *op, - WT_SESSION *session, + wt_ctx *wc, Entry *e ) { - return wt_id2entry_put(op, session, e, "overwrite=false"); + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->id2entry_add; + int rc; + + if(!cursor){ + rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL, + "overwrite=false", &cursor); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_id2entry_put: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + wc->id2entry_add = cursor; + } + + rc = wt_id2entry_put(op, wc, e, cursor); + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else + if(cursor){ + cursor->close(cursor); + wc->id2entry_add = NULL; + } +#endif + + return rc; } int wt_id2entry_update( Operation *op, - WT_SESSION *session, + wt_ctx *wc, Entry *e ) { - return wt_id2entry_put(op, session, e, "overwrite=true"); + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->id2entry_update; + int rc; + + if(!cursor){ + rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL, + "overwrite=true", &cursor); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_id2entry_put: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return rc; + } + wc->id2entry_update = cursor; + } + rc = wt_id2entry_put(op, wc, e, cursor); + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else + if(cursor){ + cursor->close(cursor); + wc->id2entry_update = NULL; + } +#endif + return rc; } int wt_id2entry_delete( Operation *op, - WT_SESSION *session, + wt_ctx *wc, Entry *e ) { int rc; + WT_SESSION *session = wc->session; 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", + "wt_id2entry_delete: open_cursor failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } @@ -104,8 +148,7 @@ int wt_id2entry_delete( rc = cursor->remove(cursor); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_id2entry_delete) - ": remove failed: %s (%d)\n", + "wt_id2entry_delete: remove failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } @@ -118,24 +161,27 @@ done: } int wt_id2entry( BackendDB *be, - WT_SESSION *session, + wt_ctx *wc, ID id, Entry **ep ){ int rc; - WT_CURSOR *cursor = NULL; + WT_SESSION *session = wc->session; + WT_CURSOR *cursor = wc->id2entry; 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 ); - goto done; + if(!cursor){ + rc = session->open_cursor(session, WT_TABLE_ID2ENTRY"(entry)", NULL, + NULL, &cursor); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_id2entry: open_cursor failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + wc->id2entry = cursor; } cursor->set_key(cursor, id); @@ -156,18 +202,25 @@ int wt_id2entry( BackendDB *be, rc = entry_decode( &eh, &e ); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_id2entry) - ": entry decode error: %d\n", - rc ); + "wt_id2entry: entry decode error: %s (%d)\n", + wiredtiger_strerror(rc), rc ); goto done; } e->e_id = id; *ep = e; done: + +#ifdef WT_CURSOR_CACHE + if(cursor){ + cursor->reset(cursor); + } +#else if(cursor){ cursor->close(cursor); + wc->id2entry = NULL; } +#endif return rc; } @@ -210,7 +263,6 @@ int wt_entry_release( Entry *e, int rw ) { - struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; return wt_entry_return( e ); } @@ -225,7 +277,70 @@ int wt_entry_get( int rw, Entry **ent ) { - return 0; + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; + wt_ctx *wc; + Entry *e = NULL; + int rc; + const char *at_name = at ? at->ad_cname.bv_val : "(null)"; + + Debug( LDAP_DEBUG_ARGS, + "wt_entry_get: ndn: \"%s\"\n", ndn->bv_val ); + Debug( LDAP_DEBUG_ARGS, + "wt_entry_get: oc: \"%s\", at: \"%s\"\n", + oc ? oc->soc_cname.bv_val : "(null)", at_name ); + + wc = wt_ctx_get(op, wi); + if( !wc ){ + Debug( LDAP_DEBUG_ANY, + "wt_entry_get: wt_ctx_get failed\n" ); + return LDAP_OTHER; + } + rc = wt_dn2entry(op->o_bd, wc, ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + Debug( LDAP_DEBUG_ACL, + "wt_entry_get: cannot find entry: \"%s\"\n", + ndn->bv_val ); + return LDAP_NO_SUCH_OBJECT; + default: + Debug( LDAP_DEBUG_ANY, + "wt_entry_get: wt_dn2entry failed %s rc=%d\n", + wiredtiger_strerror(rc), rc ); + rc = LDAP_OTHER; + } + + Debug( LDAP_DEBUG_ACL, + "wt_entry_get: found entry: \"%s\"\n", ndn->bv_val ); + + if ( oc && !is_entry_objectclass( e, oc, 0 )) { + Debug( LDAP_DEBUG_ACL, + "wt_entry_get: failed to find objectClass %s\n", + oc->soc_cname.bv_val ); + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_results; + } + + /* NOTE: attr_find() or attrs_find()? */ + if ( at && attr_find( e->e_attrs, at ) == NULL ) { + Debug( LDAP_DEBUG_ACL, + "wt_entry_get: failed to find attribute %s\n", + at->ad_cname.bv_val ); + rc = LDAP_NO_SUCH_ATTRIBUTE; + goto return_results; + } + +return_results: + if( rc != LDAP_SUCCESS ) { + wt_entry_return( e ); + }else{ + *ent = e; + } + + Debug( LDAP_DEBUG_TRACE, "wt_entry_get: rc=%d\n", rc ); + + return rc; } /* diff --git a/servers/slapd/back-wt/idl.c b/servers/slapd/back-wt/idl.c index db83f1b33e..0004ae63de 100644 --- a/servers/slapd/back-wt/idl.c +++ b/servers/slapd/back-wt/idl.c @@ -31,8 +31,7 @@ #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 ) +void wt_idl_check( ID *ids ) { if( WT_IDL_IS_RANGE( ids ) ) { assert( WT_IDL_RANGE_FIRST(ids) <= WT_IDL_RANGE_LAST(ids) ); @@ -44,8 +43,7 @@ static void idl_check( ID *ids ) } } -#if IDL_DEBUG > 1 -static void idl_dump( ID *ids ) +void wt_idl_dump( ID *ids ) { if( WT_IDL_IS_RANGE( ids ) ) { Debug( LDAP_DEBUG_ANY, @@ -67,10 +65,8 @@ static void idl_dump( ID *ids ) Debug( LDAP_DEBUG_ANY, "\n" ); } - idl_check( ids ); + wt_idl_check( ids ); } -#endif /* IDL_DEBUG > 1 */ -#endif /* IDL_DEBUG > 0 */ unsigned wt_idl_search( ID *ids, ID id ) { @@ -138,7 +134,7 @@ int wt_idl_insert( ID *ids, ID id ) Debug( LDAP_DEBUG_ANY, "insert: %04lx at %d\n", (long) id, x ); idl_dump( ids ); #elif IDL_DEBUG > 0 - idl_check( ids ); + wt_idl_check( ids ); #endif if (WT_IDL_IS_RANGE( ids )) { @@ -183,9 +179,9 @@ int wt_idl_insert( ID *ids, ID id ) } #if IDL_DEBUG > 1 - idl_dump( ids ); + wt_idl_dump( ids ); #elif IDL_DEBUG > 0 - idl_check( ids ); + wt_idl_check( ids ); #endif return 0; @@ -199,7 +195,7 @@ static int wt_idl_delete( ID *ids, ID id ) Debug( LDAP_DEBUG_ANY, "delete: %04lx at %d\n", (long) id, x ); idl_dump( ids ); #elif IDL_DEBUG > 0 - idl_check( ids ); + wt_idl_check( ids ); #endif if (WT_IDL_IS_RANGE( ids )) { @@ -240,9 +236,9 @@ static int wt_idl_delete( ID *ids, ID id ) } #if IDL_DEBUG > 1 - idl_dump( ids ); + wt_idl_dump( ids ); #elif IDL_DEBUG > 0 - idl_check( ids ); + wt_idl_check( ids ); #endif return 0; diff --git a/servers/slapd/back-wt/idl.h b/servers/slapd/back-wt/idl.h index e8eb853dc1..bcaf62cd57 100644 --- a/servers/slapd/back-wt/idl.h +++ b/servers/slapd/back-wt/idl.h @@ -19,7 +19,7 @@ * WiredTiger is a product of MongoDB Inc. */ -#ifndef _WI_IDL_H_ +#ifndef _WT_IDL_H_ #define _WT_IDL_H_ /* IDL sizes - likely should be even bigger diff --git a/servers/slapd/back-wt/index.c b/servers/slapd/back-wt/index.c index 06624591d3..e5365fe1c5 100644 --- a/servers/slapd/back-wt/index.c +++ b/servers/slapd/back-wt/index.c @@ -22,6 +22,7 @@ #include "portable.h" #include +#include #include "back-wt.h" #include "slap-config.h" @@ -80,7 +81,6 @@ int wt_index_param( struct berval *prefixp ) { AttrInfo *ai; - int rc; slap_mask_t mask, type = 0; ai = wt_index_mask( be, desc, prefixp ); @@ -148,17 +148,15 @@ static int indexer( int opid, slap_mask_t mask ) { - int rc, i; + int rc = LDAP_SUCCESS, i; struct berval *keys; WT_CURSOR *cursor = NULL; - WT_SESSION *session = wc->session; assert( mask != 0 ); - cursor = wt_ctx_index_cursor(wc, atname, 1); + cursor = wt_index_open(wc, atname, 1); if( !cursor ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(indexer) - ": open index cursor failed: %s\n", + "indexer: open index cursor failed: %s\n", atname->bv_val ); goto done; } @@ -236,9 +234,7 @@ static int indexer( } done: - if(cursor){ - cursor->close(cursor); - } + cursor->close(cursor); return rc; } @@ -252,7 +248,7 @@ static int index_at_values( ID id, int opid ) { - int rc; + int rc = LDAP_SUCCESS; slap_mask_t mask = 0; int ixop = opid; AttrInfo *ai = NULL; @@ -382,6 +378,42 @@ wt_index_entry( Operation *op, wt_ctx *wc, int opid, Entry *e ) return 0; } +WT_CURSOR * +wt_index_open(wt_ctx *wc, struct berval *name, int create) +{ + WT_CURSOR *cursor = NULL; + WT_SESSION *session = wc->session; + char uri[1024]; + int rc; + + snprintf(uri, sizeof(uri), "table:%s", name->bv_val); + + rc = session->open_cursor(session, uri, NULL, "overwrite=false", &cursor); + if (rc == ENOENT && create) { + rc = session->create(session, uri, + "key_format=uQ," + "value_format=x," + "columns=(key, id, none)"); + if( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_index_open: table \"%s\": " + "cannot create index table: %s (%d)\n", + uri, wiredtiger_strerror(rc), rc); + return NULL; + } + rc = session->open_cursor(session, uri, NULL, + "overwrite=false", &cursor); + } + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_index_open: table \"%s\": " + ": open cursor failed: %s (%d)\n", + uri, wiredtiger_strerror(rc), rc); + return NULL; + } + return cursor; +} + /* * Local variables: * indent-tabs-mode: t diff --git a/servers/slapd/back-wt/init.c b/servers/slapd/back-wt/init.c index 015d8566a9..ba828bf109 100644 --- a/servers/slapd/back-wt/init.c +++ b/servers/slapd/back-wt/init.c @@ -31,17 +31,21 @@ wt_db_init( BackendDB *be, ConfigReply *cr ) { struct wt_info *wi; - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_db_init) ": Initializing wt backend\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_db_init: Initializing wt backend\n" ); /* 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 = ch_calloc( 1, sizeof(struct wt_info) ); + wi->wi_home = ch_strdup( SLAPD_DEFAULT_DB_DIR ); + wi->wi_config = ch_calloc( 1, WT_CONFIG_MAX + 1); + if ( slapMode & SLAP_TOOL_READONLY ) { + strcpy(wi->wi_config, "readonly"); + } else { + strcpy(wi->wi_config, "create"); + } wi->wi_lastid = 0; wi->wi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH; wi->wi_search_stack = NULL; + wi->wi_flags = WT_USE_IDLCACHE; be->be_private = wi; be->be_cf_ocs = be->bd_info->bi_cf_ocs; @@ -55,51 +59,65 @@ 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; + WT_SESSION *session = NULL; + WT_SESSION *cache_session = NULL; if ( be->be_suffix == NULL ) { - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": need suffix.\n" ); + Debug( LDAP_DEBUG_ANY, "wt_db_open: need suffix.\n" ); return -1; } Debug( LDAP_DEBUG_ARGS, - LDAP_XSTRING(wt_db_open) ": \"%s\"\n", - be->be_suffix[0].bv_val ); + "wt_db_open: \"%s\", home=%s, config=%s\n", + be->be_suffix[0].bv_val, wi->wi_home, wi->wi_config ); /* Check existence of home. Any error means trouble */ - rc = stat( wi->wi_dbenv_home, &st ); + rc = stat( wi->wi_home, &st ); if( rc ) { int saved_errno = errno; Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot access database directory \"%s\" (%d).\n", - be->be_suffix[0].bv_val, wi->wi_dbenv_home, saved_errno ); + be->be_suffix[0].bv_val, wi->wi_home, saved_errno ); return -1; } /* Open and create database */ - rc = wiredtiger_open(wi->wi_dbenv_home, NULL, - wi->wi_dbenv_config, &conn); + rc = wiredtiger_open(wi->wi_home, NULL, + wi->wi_config, &wi->wi_conn); if( rc ) { int saved_errno = errno; Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot open database \"%s\" (%d).\n", - be->be_suffix[0].bv_val, wi->wi_dbenv_home, saved_errno ); + be->be_suffix[0].bv_val, wi->wi_home, saved_errno ); return -1; } - rc = conn->open_session(conn, NULL, NULL, &session); + rc = wi->wi_conn->open_session(wi->wi_conn, NULL, NULL, &session); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot open session: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; } + if ( slapMode & SLAP_TOOL_READONLY ) { + goto readonly; + } + + /* checking for obsolete table */ + rc = session->verify(session, WT_INDEX_REVDN, NULL); + if ( !rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_db_open: database \"%s\": " + "incompatible wiredtiger table, please restore from LDIF.\n", + be->be_suffix[0].bv_val ); + return -1; + } + + /* create tables and indexes */ rc = session->create(session, WT_TABLE_ID2ENTRY, "key_format=Q," @@ -107,7 +125,7 @@ wt_db_open( BackendDB *be, ConfigReply *cr ) "columns=(id,dn,entry)"); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot create entry table: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; @@ -116,11 +134,11 @@ wt_db_open( BackendDB *be, ConfigReply *cr ) rc = session->create(session, WT_TABLE_DN2ID, "key_format=S," - "value_format=QQS," - "columns=(ndn,id,pid,revdn)"); + "value_format=SQQ," + "columns=(revdn,ndn,id,pid)"); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot create entry table: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; @@ -130,7 +148,7 @@ wt_db_open( BackendDB *be, ConfigReply *cr ) rc = session->create(session, WT_INDEX_DN, "columns=(dn)"); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot create dn index: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; @@ -139,36 +157,72 @@ wt_db_open( BackendDB *be, ConfigReply *cr ) rc = session->create(session, WT_INDEX_PID, "columns=(pid)"); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " + "wt_db_open: database \"%s\": " "cannot create pid index: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; } - rc = session->create(session, WT_INDEX_REVDN, "columns=(revdn)"); + rc = session->create(session, WT_INDEX_NDN, "columns=(ndn)"); if( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_open) ": database \"%s\": " - "cannot create revdn index: \"%s\"\n", + "wt_db_open: database \"%s\": " + "cannot create ndn index: \"%s\"\n", be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); return -1; } + /* open in-memory database for idlcache */ + rc = wiredtiger_open(be->be_suffix[0].bv_val, NULL, + "in_memory=true", &wi->wi_cache); + if( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_db_open: database \"%s\": " + "cannot open database for cache (%s).\n", + be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); + return -1; + } + + rc = wi->wi_cache->open_session(wi->wi_cache, NULL, NULL, &cache_session); + if( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_db_open: database \"%s\": " + "cannot open session for cache: \"%s\"\n", + be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); + return -1; + } + + rc = cache_session->create(cache_session, + WT_TABLE_IDLCACHE, + "key_format=Sb," + "value_format=u," + "columns=(ndn,scope,idl)"); + if( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_db_open: database \"%s\": " + "cannot create idlcache table: \"%s\"\n", + be->be_suffix[0].bv_val, wiredtiger_strerror(rc) ); + return -1; + } + +readonly: 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 ); + Debug( LDAP_DEBUG_ANY, "wt_db_open: %s\n", cr->msg ); return rc; } - session->close(session, NULL); - wi->wi_conn = conn; - wi->wi_flags |= WT_IS_OPEN; + if (session) { + session->close(session, NULL); + } + if (cache_session) { + cache_session->close(cache_session, NULL); + } + wi->wi_flags |= WT_IS_OPEN; return LDAP_SUCCESS; } @@ -178,13 +232,15 @@ wt_db_close( BackendDB *be, ConfigReply *cr ) struct wt_info *wi = (struct wt_info *) be->be_private; int rc; + if ( !wi->wi_conn ) { + return -1; + } + rc = wi->wi_conn->close(wi->wi_conn, NULL); if( rc ) { int saved_errno = errno; Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_db_close) - ": cannot close database (%d).\n", - saved_errno ); + "wt_db_close: cannot close database (%d).\n", saved_errno ); return -1; } @@ -198,13 +254,14 @@ 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_home ) { + ch_free( wi->wi_home ); + wi->wi_home = NULL; } - if( wi->wi_dbenv_config ) { - ch_free( wi->wi_dbenv_config ); - wi->wi_dbenv_config = NULL; + + if( wi->wi_config ) { + ch_free( wi->wi_config ); + wi->wi_config = NULL; } wt_attr_index_destroy( wi ); @@ -217,7 +274,7 @@ wt_db_destroy( Backend *be, ConfigReply *cr ) int wt_back_initialize( BackendInfo *bi ) { - static char *controls[] = { + static const char *controls[] = { LDAP_CONTROL_ASSERT, LDAP_CONTROL_MANAGEDSAIT, LDAP_CONTROL_NOOP, @@ -226,13 +283,15 @@ wt_back_initialize( BackendInfo *bi ) LDAP_CONTROL_POST_READ, LDAP_CONTROL_SUBENTRIES, LDAP_CONTROL_X_PERMISSIVE_MODIFY, +#ifdef LDAP_X_TXN + LDAP_CONTROL_X_TXN_SPEC, +#endif NULL }; /* initialize the database system */ Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_back_initialize) - ": initialize WiredTiger backend\n" ); + "wt_back_initialize: initialize WiredTiger backend\n" ); bi->bi_flags |= SLAP_BFLAG_INCREMENT | @@ -240,10 +299,11 @@ wt_back_initialize( BackendInfo *bi ) SLAP_BFLAG_ALIASES | SLAP_BFLAG_REFERRALS; - bi->bi_controls = controls; -/* version check */ + bi->bi_controls = (char **)controls; + + /* version check */ Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_back_initialize) ": %s\n", + "wt_back_initialize: %s\n", wiredtiger_version(NULL, NULL, NULL) ); bi->bi_open = 0; @@ -263,15 +323,19 @@ wt_back_initialize( BackendInfo *bi ) bi->bi_op_search = wt_search; bi->bi_op_compare = wt_compare; bi->bi_op_modify = wt_modify; - bi->bi_op_modrdn = 0; + bi->bi_op_modrdn = wt_modrdn; bi->bi_op_delete = wt_delete; bi->bi_op_abandon = 0; - bi->bi_extended = 0; + bi->bi_extended = wt_extended; +#ifdef LDAP_X_TXN + bi->bi_op_txn = 0; +#endif bi->bi_chk_referrals = 0; bi->bi_operational = wt_operational; + bi->bi_has_subordinates = wt_hasSubordinates; bi->bi_entry_release_rw = wt_entry_release; bi->bi_entry_get_rw = wt_entry_get; @@ -283,6 +347,13 @@ wt_back_initialize( BackendInfo *bi ) 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_tool_sync = 0; + bi->bi_tool_dn2id_get = wt_tool_dn2id_get; + bi->bi_tool_entry_modify = wt_tool_entry_modify; + +#if LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= 5 + bi->bi_tool_entry_delete = wt_tool_entry_delete; +#endif bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; diff --git a/servers/slapd/back-wt/key.c b/servers/slapd/back-wt/key.c index 4b5fd8d184..eb931917e5 100644 --- a/servers/slapd/back-wt/key.c +++ b/servers/slapd/back-wt/key.c @@ -32,7 +32,7 @@ int wt_key_read( Backend *be, WT_CURSOR *cursor, - struct berval *k, + struct berval *bkey, ID *ids, WT_CURSOR **saved_cursor, int get_flag @@ -43,33 +43,42 @@ wt_key_read( int exact; WT_ITEM key2; ID id; + int comp; + long scanned = 0; Debug( LDAP_DEBUG_TRACE, "=> key_read\n" ); WT_IDL_ZERO(ids); - - bv2ITEM(k, &key); + bv2ITEM(bkey, &key); cursor->set_key(cursor, &key, 0); rc = cursor->search_near(cursor, &exact); - if( rc ){ + switch( rc ){ + case 0: + break; + case WT_NOTFOUND: + rc = LDAP_SUCCESS; + goto done; + default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_key_read) - ": search_near failed: %s (%d)\n", - wiredtiger_strerror(rc), rc ); + "wt_key_read: search_near failed: %s (%d)\n", + wiredtiger_strerror(rc), rc); goto done; } - do { + scanned++; rc = cursor->get_key(cursor, &key2, &id); if( rc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_key_read) - ": get_key failed: %s (%d)\n", + "wt_key_read: get_key failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); break; } - - if (key.size != key2.size || memcmp(key.data, key2.data, key.size)) { + comp = 0; + if (key.size != key2.size || + (comp = memcmp(key2.data, key.data, key.size))) { + if(comp > 0){ + break; + } if(exact < 0){ rc = cursor->next(cursor); if (rc) { @@ -85,17 +94,17 @@ wt_key_read( rc = cursor->next(cursor); } while(rc == 0); - if (rc == WT_NOTFOUND ) { + if ( rc == WT_NOTFOUND && exact == 0 ) { rc = LDAP_SUCCESS; } done: if( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "<= wt_key_read: failed (%d)\n", - rc ); + Debug( LDAP_DEBUG_TRACE, "<= wt_key_read: failed (%d) %ld scanned\n", + rc, scanned ); } else { - Debug( LDAP_DEBUG_TRACE, "<= wt_key_read %ld candidates\n", - (long) WT_IDL_N(ids) ); + Debug( LDAP_DEBUG_TRACE, "<= wt_key_read %ld candidates %ld scanned\n", + (long) WT_IDL_N(ids), scanned ); } return rc; @@ -131,10 +140,11 @@ wt_key_change( 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 ); + if ( rc != WT_ROLLBACK ) { + Debug( LDAP_DEBUG_ANY, + "wt_key_change: error: %s (%d)\n", + wiredtiger_strerror(rc), rc); + } return rc; } diff --git a/servers/slapd/back-wt/modify.c b/servers/slapd/back-wt/modify.c index 3fa687a473..12bfd03e09 100644 --- a/servers/slapd/back-wt/modify.c +++ b/servers/slapd/back-wt/modify.c @@ -10,7 +10,7 @@ * Public License. * * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at +B * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: @@ -21,6 +21,7 @@ #include "portable.h" #include +#include #include "back-wt.h" #include "slap-config.h" @@ -150,7 +151,7 @@ int wt_modify_internal( break; } - Debug(LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "wt_modify_internal: delete %s\n", mod->sm_desc->ad_cname.bv_val ); err = modify_delete_values( e, mod, get_permissiveModify(op), @@ -164,7 +165,7 @@ int wt_modify_internal( break; case LDAP_MOD_REPLACE: - Debug(LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "wt_modify_internal: replace %s\n", mod->sm_desc->ad_cname.bv_val ); err = modify_replace_values( e, mod, get_permissiveModify(op), @@ -178,22 +179,21 @@ int wt_modify_internal( break; case LDAP_MOD_INCREMENT: - Debug(LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "wt_modify_internal: increment %s\n", mod->sm_desc->ad_cname.bv_val ); err = modify_increment_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( err != LDAP_SUCCESS ) { - Debug(LDAP_DEBUG_ARGS, - "wt_modify_internal: %d %s\n", - err, *text ); + Debug( LDAP_DEBUG_ARGS, + "wt_modify_internal: %d %s\n", err, *text ); } else { got_delete = 1; } break; case SLAP_MOD_SOFTADD: - Debug(LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "wt_modify_internal: softadd %s\n", mod->sm_desc->ad_cname.bv_val ); /* Avoid problems in index_add_mods() @@ -217,7 +217,7 @@ int wt_modify_internal( break; case SLAP_MOD_SOFTDEL: - Debug(LDAP_DEBUG_ARGS, + Debug( LDAP_DEBUG_ARGS, "wt_modify_internal: softdel %s\n", mod->sm_desc->ad_cname.bv_val ); /* Avoid problems in index_delete_mods() @@ -314,8 +314,7 @@ int wt_modify_internal( if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "entry failed schema check: %s\n", - *text ); + "entry failed schema check: %s\n", *text ); } /* if NOOP then silently revert to saved attrs */ @@ -447,7 +446,7 @@ wt_modify( Operation *op, SlapReply *rs ) { struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; wt_ctx *wc = NULL; - Entry *e = NULL; + Entry *e = NULL; int manageDSAit = get_manageDSAit( op ); char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; @@ -460,19 +459,18 @@ wt_modify( Operation *op, SlapReply *rs ) int rc; - Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(wt_modify) ": %s\n", - op->o_req_dn.bv_val ); + Debug( LDAP_DEBUG_ARGS, "wt_modify: %s\n", op->o_req_dn.bv_val ); +#ifdef LDAP_X_TXN if( op->o_txnSpec && txn_preop( op, rs )) return rs->sr_err; +#endif ctrls[num_ctrls] = NULL; wc = wt_ctx_get(op, wi); if( !wc ){ - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_add) - ": wt_ctx_get failed\n" ); + Debug( LDAP_DEBUG_ANY, "wt_modify: wt_ctx_get failed\n" ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; send_ldap_result( op, rs ); @@ -487,35 +485,75 @@ wt_modify( Operation *op, SlapReply *rs ) slap_mods_opattrs( op, &op->orm_modlist, 1 ); } +retry: + /* begin transaction */ + wc->is_begin_transaction = 0; + rc = wc->session->begin_transaction(wc->session, "isolation=snapshot"); + if( rc ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modify: begin_transaction failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "begin_transaction failed"; + goto return_results; + } + wc->is_begin_transaction = 1; + Debug( LDAP_DEBUG_TRACE, "wt_modify: session id: %p\n", wc->session ); + /* 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 ); - /* TODO: lookup referrals */ - rs->sr_err = LDAP_NO_SUCH_OBJECT; - goto return_results; + break; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_modify) - ": wt_dn2entry failed (%d)\n", - rc ); + "<== wt_modify: wt_dn2entry failed (%d)\n", rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } + if ( rc == WT_NOTFOUND || + ( !manageDSAit && e && is_entry_glue( e ))) { + if ( !e ) { + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, "wt_modify: wt_dna2entry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + } + + 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_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; + rs->sr_err = LDAP_REFERRAL; + send_ldap_result( op, rs ); + goto done; + } + if ( !manageDSAit && is_entry_referral( e ) ) { /* entry is a referral, don't allow modify */ rs->sr_ref = get_entry_referrals( op, e ); - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_modify) ": entry is referral\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_modify: entry is referral\n" ); rs->sr_err = LDAP_REFERRAL; rs->sr_matched = e->e_name.bv_val; @@ -541,8 +579,7 @@ wt_modify( Operation *op, SlapReply *rs ) &slap_pre_read_bv, preread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, - "<=- " LDAP_XSTRING(wt_modify) ": pre-read " - "failed!\n" ); + "<=- wt_modify: pre-read failed!\n" ); if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ @@ -551,72 +588,46 @@ wt_modify( Operation *op, SlapReply *rs ) } } - /* begin 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 ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "begin_transaction failed"; - goto return_results; - } - Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(wt_modify) ": session id: %p\n", - wc->session ); - /* Modify the entry */ dummy = *e; rs->sr_err = wt_modify_internal( op, wc, op->orm_modlist, &dummy, &rs->sr_text, textbuf, textlen ); - if( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_modify) ": modify failed (%d)\n", - rs->sr_err ); + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + break; + case WT_ROLLBACK: + Debug (LDAP_DEBUG_TRACE, "wt_modify: rollback wt_modify_internal failed.\n" ); + wc->session->rollback_transaction(wc->session, NULL); + goto retry; + default: + Debug( LDAP_DEBUG_ANY, "wt_modify: modify failed (%d)\n", rs->sr_err ); /* Only free attrs if they were dup'd. */ if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; goto return_results; } /* change the entry itself */ - rs->sr_err = wt_id2entry_update( op, wc->session, &dummy ); - if ( rs->sr_err != 0 ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_modify) ": id2entry update failed " "(%d)\n", - rs->sr_err ); - if ( rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ) { - rs->sr_text = "entry too big"; - } else { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "entry update failed"; - } - goto return_results; - } - - if( op->o_noop ) { + rs->sr_err = wt_id2entry_update( op, wc, &dummy ); + switch ( rs->sr_err ) { + case 0: + break; + case WT_ROLLBACK: + Debug (LDAP_DEBUG_TRACE, "wt_modify: rollback wt_id2entry_update failed.\n"); wc->session->rollback_transaction(wc->session, NULL); - rs->sr_err = LDAP_X_NO_OPERATION; + goto retry; + case LDAP_ADMINLIMIT_EXCEEDED: + Debug( LDAP_DEBUG_ANY, "wt_modify: id2entry update failed (%d)\n", + rs->sr_err); + rs->sr_text = "entry too big"; goto return_results; - } - - /* Only free attrs if they were dup'd. */ - if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; - - rc = wc->session->commit_transaction(wc->session, NULL); - if( rc ) { - Debug( LDAP_DEBUG_TRACE, - "<== " LDAP_XSTRING(wt_modify) - ": commit failed: %s (%d)\n", - wiredtiger_strerror(rc), rc ); + default: + Debug( LDAP_DEBUG_ANY, "wt_modify: id2entry update failed (%d)\n", + rs->sr_err); rs->sr_err = LDAP_OTHER; - rs->sr_text = "commit failed"; + rs->sr_text = "entry update failed"; goto return_results; } - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_modify) ": updated%s id=%08lx dn=\"%s\"\n", - op->o_noop ? " (no-op)" : "", - dummy.e_id, op->o_req_dn.bv_val ); - if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; @@ -626,8 +637,7 @@ wt_modify( Operation *op, SlapReply *rs ) &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, - "<=- " LDAP_XSTRING(wt_modify) - ": post-read failed!\n" ); + "<== wt_modify: post-read failed!\n"); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ @@ -635,10 +645,34 @@ wt_modify( Operation *op, SlapReply *rs ) } } } - if( num_ctrls ) rs->sr_ctrls = ctrls; + + if( op->o_noop ) { + rs->sr_err = LDAP_X_NO_OPERATION; + goto return_results; + } + + /* Only free attrs if they were dup'd. */ + if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; + + rc = wc->session->commit_transaction(wc->session, NULL); + wc->is_begin_transaction = 0; + if( rc ) { + Debug( LDAP_DEBUG_TRACE, + "<== wt_modify: commit failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "commit failed"; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "wt_modify: updated%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", + dummy.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( dummy.e_attrs ) { @@ -649,6 +683,12 @@ return_results: done: slap_graduate_commit_csn( op ); + if( wc && wc->is_begin_transaction ){ + Debug( LDAP_DEBUG_TRACE, "wt_modify: rollback transaction\n" ); + wc->session->rollback_transaction(wc->session, NULL); + wc->is_begin_transaction = 0; + } + if( e != NULL ) { wt_entry_return( e ); } @@ -662,8 +702,6 @@ done: slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } - rs->sr_text = NULL; - return rs->sr_err; } diff --git a/servers/slapd/back-wt/modrdn.c b/servers/slapd/back-wt/modrdn.c new file mode 100644 index 0000000000..990d56cc36 --- /dev/null +++ b/servers/slapd/back-wt/modrdn.c @@ -0,0 +1,552 @@ +/* OpenLDAP WiredTiger backend */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was developed by HAMANO Tsukasa + * based on back-bdb for inclusion in OpenLDAP Software. + * WiredTiger is a product of MongoDB Inc. + */ + +#include "portable.h" + +#include +#include "back-wt.h" +#include "slap-config.h" + +int +wt_modrdn( Operation *op, SlapReply *rs ) +{ + struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; + AttributeDescription *children = slap_schema.si_ad_children; + AttributeDescription *entry = slap_schema.si_ad_entry; + wt_ctx *wc = NULL; + Entry *e = NULL; + Entry *p = NULL; + Entry *ne = NULL; + Entry dummy = {0}; + + struct berval p_dn, p_ndn; + struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; + + Entry *np = NULL; /* newSuperior Entry */ + struct berval *np_dn = NULL; /* newSuperior dn */ + struct berval *np_ndn = NULL; /* newSuperior ndn */ + struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ + + int manageDSAit = get_manageDSAit( op ); + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + LDAPControl **preread_ctrl = NULL; + LDAPControl **postread_ctrl = NULL; + LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; + int num_ctrls = 0; + + int rc; + + int parent_is_glue = 0; + int parent_is_leaf = 0; + + Debug( LDAP_DEBUG_TRACE, "==> wt_modrdn(%s -> newrdn=%s - newsup=%s)\n", + op->o_req_dn.bv_val, + op->oq_modrdn.rs_newrdn.bv_val, + op->oq_modrdn.rs_newSup?op->oq_modrdn.rs_newSup->bv_val:"NULL" ); + + ctrls[num_ctrls] = NULL; + + slap_mods_opattrs( op, &op->orr_modlist, 1 ); + + wc = wt_ctx_get(op, wi); + if( !wc ){ + Debug( LDAP_DEBUG_ANY, "wt_modrdn: wt_ctx_get failed\n"); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + send_ldap_result( op, rs ); + return rs->sr_err; + } + + /* get parent entry */ + if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) { + rs->sr_err = LDAP_NAMING_VIOLATION; + rs->sr_text = "cannot rename suffix entry"; + goto return_results; + } else { + dnParent( &op->o_req_ndn, &p_ndn ); + } + + rc = wt_dn2entry(op->o_bd, wc, &p_ndn, &p); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + Debug( LDAP_DEBUG_ARGS, + "<== wt_modrdn: parent does not exist %s\n", p_ndn.bv_val); + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, + "<== wt_modrdn: wt_dn2entry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + + /* check parent for "children" acl */ + rc = access_allowed( op, p, children, NULL, + op->oq_modrdn.rs_newSup == NULL ? + ACL_WRITE : ACL_WDEL, NULL ); + + if ( !rc ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: no access to parent\n"); + rs->sr_text = "no write access to old parent's children"; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: wr to children of entry %s OK\n", p_ndn.bv_val ); + + if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { + p_dn = slap_empty_bv; + } else { + dnParent( &op->o_req_dn, &p_dn ); + } + + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: parent dn=%s\n", p_dn.bv_val ); + + /* get entry */ + rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + break; + default: + Debug( LDAP_DEBUG_ANY, + "<== wt_modrdn: wt_dn2entry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + + if ( rc == WT_NOTFOUND || + ( !manageDSAit && e && is_entry_glue( e ) )) { + + if ( !e ) { + Debug( LDAP_DEBUG_ARGS, + "<== wt_modrdn: no such object %s\n", op->o_req_dn.bv_val); + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, "wt_modrdn: wt_dn2aentry failed (%d)\n", rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + } + + 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_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; + rs->sr_err = LDAP_REFERRAL; + send_ldap_result( op, rs ); + goto done; + } + + if ( get_assert( op ) && + ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + goto return_results; + } + + /* check write on old entry */ + rc = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ); + if ( !rc ) { + Debug( LDAP_DEBUG_TRACE, "wt_modrdn: no access to entry\n"); + rs->sr_text = "no write access to old entry"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + /* Can't do it if we have kids */ + rc = wt_dn2id_has_children( op, wc, e->e_id ); + if( rc != WT_NOTFOUND ) { + switch( rc ) { + case 0: + Debug(LDAP_DEBUG_ARGS, "<== wt_modrdn: non-leaf %s\n", op->o_req_dn.bv_val); + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subtree rename not supported"; + break; + default: + Debug(LDAP_DEBUG_ARGS, + "<== wt_modrdn: has_children failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + } + goto return_results; + } + + if (!manageDSAit && is_entry_referral( e ) ) { + /* parent is a referral, don't allow add */ + rs->sr_ref = get_entry_referrals( op, e ); + + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: entry %s is referral\n", e->e_dn ); + + rs->sr_err = LDAP_REFERRAL, + rs->sr_matched = e->e_name.bv_val; + send_ldap_result( op, rs ); + + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + rs->sr_matched = NULL; + goto done; + } + + new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ + if ( op->oq_modrdn.rs_newSup != NULL ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: new parent \"%s\" requested...\n", + op->oq_modrdn.rs_newSup->bv_val ); + + /* newSuperior == oldParent? */ + if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: new parent \"%s\" same as the old parent \"%s\"\n", + op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val ); + op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ + } + } + + if ( op->oq_modrdn.rs_newSup != NULL ) { + if ( op->oq_modrdn.rs_newSup->bv_len ) { + np_dn = op->oq_modrdn.rs_newSup; + np_ndn = op->oq_modrdn.rs_nnewSup; + + /* newSuperior == oldParent? - checked above */ + /* newSuperior == entry being moved?, if so ==> ERROR */ + if ( dnIsSuffix( np_ndn, &e->e_nname )) { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = "new superior not found"; + goto return_results; + } + /* Get Entry with dn=newSuperior. Does newSuperior exist? */ + rc = wt_dn2entry(op->o_bd, wc, np_ndn, &np); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + Debug( LDAP_DEBUG_ANY, + "<== wt_modrdn: new superior not found: %s\n", + np_ndn->bv_val ); + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = "new superior not found"; + goto return_results; + default: + Debug( LDAP_DEBUG_ANY, + "<== wt_modrdn: wt_dn2entry failed %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: wr to new parent OK np=%p, id=%ld\n", + (void *) np, (long) np->e_id ); + rs->sr_err = access_allowed( op, np, children, + NULL, ACL_WADD, NULL ); + if( ! rs->sr_err ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: no wr to newSup children\n" ); + rs->sr_text = "no write access to new superior's children"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + if ( is_entry_alias( np ) ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: entry is alias\n" ); + rs->sr_text = "new superior is an alias"; + rs->sr_err = LDAP_ALIAS_PROBLEM; + goto return_results; + } + if ( is_entry_referral( np ) ) { + /* parent is a referral, don't allow add */ + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: entry is referral\n" ); + rs->sr_text = "new superior is a referral"; + rs->sr_err = LDAP_OTHER; + goto return_results; + } + } else { + /* no parent, modrdn entry directly under root */ + /* TODO: */ + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: no parent, not implement yet\n" ); + rs->sr_text = "not implement yet"; + rs->sr_err = LDAP_OTHER; + goto return_results; + } + + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: wr to new parent's children OK\n" ); + new_parent_dn = np_dn; + } + + /* Build target dn and make sure target entry doesn't exist already. */ + if (!new_dn.bv_val) { + build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL ); + } + + if (!new_ndn.bv_val) { + struct berval bv = {0, NULL}; + dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx ); + ber_dupbv( &new_ndn, &bv ); + /* FIXME: why not call dnNormalize() w/o ctx? */ + op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); + } + + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: new ndn=%s\n", new_ndn.bv_val ); + + /* check new entry */ + rc = wt_dn2entry(op->o_bd, wc, &new_ndn, &ne); + switch( rc ) { + case 0: + /* Allow rename to same DN */ + if(e->e_id == ne->e_id){ + break; + } + rs->sr_err = LDAP_ALREADY_EXISTS; + goto return_results; + break; + case WT_NOTFOUND: + break; + default: + Debug( LDAP_DEBUG_ANY, + "<== wt_modrdn: wt_dn2entry failed %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } + + assert( op->orr_modlist != NULL ); + + 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, + "<== wt_modrdn: pre-read failed!\n" ); + if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { + /* FIXME: is it correct to abort + * operation if control fails? */ + goto return_results; + } + } + } + + /* begin transaction */ + rc = wc->session->begin_transaction(wc->session, NULL); + if( rc ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: begin_transaction failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "begin_transaction failed"; + goto return_results; + } + wc->is_begin_transaction = 1; + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: session id: %p\n", wc->session ); + + /* delete old DN */ + rc = wt_dn2id_delete( op, wc, &e->e_nname); + if ( rc ) { + Debug(LDAP_DEBUG_TRACE, + "<== wt_modrdn: delete failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "dn2id delete failed"; + goto return_results; + } + + /* copy the entry, then override some fields */ + dummy = *e; + dummy.e_name = new_dn; + dummy.e_nname = new_ndn; + dummy.e_attrs = NULL; + + /* add new DN */ + rc = wt_dn2id_add( op, wc, np?np->e_id:p->e_id, &dummy ); + if ( rc ) { + Debug(LDAP_DEBUG_TRACE, + "<== wt_modrdn: add failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "DN add failed"; + goto return_results; + } + dummy.e_attrs = e->e_attrs; + + rc = wt_modify_internal( op, wc, op->orm_modlist, + &dummy, &rs->sr_text, textbuf, textlen ); + if( rc != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_TRACE, + "<== wt_modrdn: modify failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; + goto return_results; + } + + /* update entry */ + rc = wt_id2entry_update( op, wc, &dummy ); + if ( rc != 0 ) { + Debug( LDAP_DEBUG_TRACE, + "wt_modrdn: id2entry update failed(%d)\n", rc ); + if ( rc == LDAP_ADMINLIMIT_EXCEEDED ) { + rs->sr_text = "entry too big"; + } else { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "entry update failed"; + } + goto return_results; + } + + if ( p_ndn.bv_len != 0 ) { + parent_is_glue = is_entry_glue(p); + /* TODO: glue entry handling */ + } + + if( op->o_postread ) { + if( postread_ctrl == NULL ) { + postread_ctrl = &ctrls[num_ctrls++]; + ctrls[num_ctrls] = NULL; + } + if( slap_read_controls( op, rs, &dummy, + &slap_post_read_bv, postread_ctrl ) ) + { + Debug( LDAP_DEBUG_TRACE, + "<== wt_modrdn: post-read failed!\n" ); + if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { + /* FIXME: is it correct to abort + * operation if control fails? */ + goto return_results; + } + } + } + + if( op->o_noop ) { + rs->sr_err = LDAP_X_NO_OPERATION; + goto return_results; + } + + rc = wc->session->commit_transaction(wc->session, NULL); + wc->is_begin_transaction = 0; + if( rc ) { + Debug( LDAP_DEBUG_TRACE, + "<== wt_modrdn: commit failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "commit failed"; + goto return_results; + } + + Debug(LDAP_DEBUG_TRACE, + "wt_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", + op->o_noop ? " (no-op)" : "", + dummy.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 ( dummy.e_attrs ) { + attrs_free( dummy.e_attrs ); + } + send_ldap_result( op, rs ); + + if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) { + op->o_delete_glue_parent = 1; + } + +done: + if( wc && wc->is_begin_transaction ){ + Debug( LDAP_DEBUG_TRACE, "wt_modrdn: rollback transaction\n" ); + wc->session->rollback_transaction(wc->session, NULL); + wc->is_begin_transaction = 0; + } + + slap_graduate_commit_csn( op ); + + if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); + if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); + + /* free entry */ + if( e != NULL ) { + wt_entry_return( e ); + } + /* free parent entry */ + if( p != NULL ) { + wt_entry_return( p ); + } + /* free new entry */ + if( ne != NULL ) { + wt_entry_return( ne ); + } + /* free new parent entry */ + if( np != NULL ) { + wt_entry_return( np ); + } + + 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 ); + } + 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: + */ diff --git a/servers/slapd/back-wt/nextid.c b/servers/slapd/back-wt/nextid.c index e2ae082654..be0d5f5ae8 100644 --- a/servers/slapd/back-wt/nextid.c +++ b/servers/slapd/back-wt/nextid.c @@ -41,8 +41,7 @@ int wt_last_id( BackendDB *be, WT_SESSION *session, ID *out ) 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", + "wt_last_id: open_cursor failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return rc; } @@ -53,8 +52,7 @@ int wt_last_id( BackendDB *be, WT_SESSION *session, ID *out ) rc = cursor->get_key(cursor, &id); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_last_id) - ": get_key failed: %s (%d)\n", + "wt_last_id: get_key failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return rc; } @@ -66,16 +64,14 @@ int wt_last_id( BackendDB *be, WT_SESSION *session, ID *out ) break; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_last_id) - ": prev failed: %s (%d)\n", + "wt_last_id: prev failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); } rc = cursor->close(cursor); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_last_id) - ": close failed: %s (%d)\n", + "wt_last_id: close failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return rc; } diff --git a/servers/slapd/back-wt/operational.c b/servers/slapd/back-wt/operational.c index c5e8438471..780f39ddcc 100644 --- a/servers/slapd/back-wt/operational.c +++ b/servers/slapd/back-wt/operational.c @@ -42,12 +42,11 @@ wt_hasSubordinates( wc = wt_ctx_get(op, wi); if( !wc ){ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_compare) - ": wt_ctx_get failed\n" ); + "wt_hasSubordinates: wt_ctx_get failed\n" ); return LDAP_OTHER; } - rc = wt_dn2id_has_children(op, wc->session, e->e_id); + rc = wt_dn2id_has_children(op, wc, e->e_id); switch(rc){ case 0: *hasSubordinates = LDAP_COMPARE_TRUE; @@ -58,8 +57,7 @@ wt_hasSubordinates( break; default: Debug(LDAP_DEBUG_ANY, - "<=- " LDAP_XSTRING(wt_hasSubordinates) - ": has_children failed: %s (%d)\n", + "<=- wt_hasSubordinates: has_children failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); rc = LDAP_OTHER; } diff --git a/servers/slapd/back-wt/proto-wt.h b/servers/slapd/back-wt/proto-wt.h index a218b428ea..1d7c2824c3 100644 --- a/servers/slapd/back-wt/proto-wt.h +++ b/servers/slapd/back-wt/proto-wt.h @@ -26,15 +26,29 @@ LDAP_BEGIN_DECL #define WT_UCTYPE "WT" +/* + * attr.c + */ + AttrInfo *wt_attr_mask( struct wt_info *wi, AttributeDescription *desc ); void wt_attr_flush( struct wt_info *wi ); +void wt_attr_index_unparse( struct wt_info *wi, BerVarray *bva ); +int wt_attr_index_config( + struct wt_info *wi, + const char *fname, + int lineno, + int argc, + char **argv, + struct config_reply_s *c_reply); +void wt_attr_index_destroy( 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 ); +int wt_id2entry(BackendDB *be, wt_ctx *wc, ID id, Entry **ep ); +int wt_id2entry_add(Operation *op, wt_ctx *wc, Entry *e ); +int wt_id2entry_update(Operation *op, wt_ctx *wc, Entry *e ); +int wt_id2entry_delete(Operation *op, wt_ctx *wc, Entry *e ); BI_entry_release_rw wt_entry_release; BI_entry_get_rw wt_entry_get; @@ -50,12 +64,47 @@ unsigned wt_idl_search( ID *ids, ID id ); ID wt_idl_first( ID *ids, ID *cursor ); ID wt_idl_next( ID *ids, ID *cursor ); - +int wt_idl_append_one( ID *ids, ID id ); +void wt_idl_sort( ID *ids, ID *tmp ); +int wt_idl_intersection( ID *a, ID *b ); +int wt_filter_candidates( + Operation *op, + wt_ctx *wc, + Filter *f, + ID *ids, + ID *tmp, + ID *stack ); +int +wt_idl_union( + ID *a, + ID *b ); /* * index.c */ + +extern AttrInfo * +wt_index_mask LDAP_P(( + Backend *be, + AttributeDescription *desc, + struct berval *atname )); + int wt_index_entry LDAP_P(( Operation *op, wt_ctx *wc, int r, Entry *e )); +int wt_index_values( + Operation *op, + wt_ctx *wc, + AttributeDescription *desc, + BerVarray vals, + ID id, + int opid ); +int wt_index_param( + Backend *be, + AttributeDescription *desc, + int ftype, + slap_mask_t *maskp, + struct berval *prefixp ); + +WT_CURSOR *wt_index_open(wt_ctx *wc, struct berval *name, int create); #define wt_index_entry_add(op,t,e) \ wt_index_entry((op),(t),SLAP_INDEX_ADD_OP,(e)) @@ -110,23 +159,38 @@ int wt_back_init_cf( BackendInfo *bi ); int wt_dn2id( Operation *op, - WT_SESSION *session, + wt_ctx *wc, struct berval *ndn, ID *id); int wt_dn2id_add( Operation *op, - WT_SESSION *session, + wt_ctx *wc, ID pid, Entry *e); +int +wt_dn2idl( + Operation *op, + wt_ctx *wc, + struct berval *ndn, + Entry *e, + ID *ids, + ID *stack); + int wt_dn2id_delete( Operation *op, - WT_SESSION *session, + wt_ctx *wc, struct berval *ndn); +int +wt_dn2id_has_children( + Operation *op, + wt_ctx *wc, + ID id ); + /* * dn2entry.c */ @@ -139,6 +203,10 @@ int wt_dn2pentry( BackendDB *be, wt_ctx *wc, struct berval *ndn, Entry **ep ); +int wt_dn2aentry( BackendDB *be, + wt_ctx *wc, + struct berval *ndn, + Entry **ep ); /* * former ctx.c @@ -146,8 +214,14 @@ int wt_dn2pentry( BackendDB *be, 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 cache.c + */ +int wt_idlcache_get(wt_ctx *wc, struct berval *ndn, int scope, ID *ids); +int wt_idlcache_set(wt_ctx *wc, struct berval *ndn, int scope, ID *ids); +int wt_idlcache_begin(wt_ctx *wc, struct berval *ndn, int scope); +int wt_idlcache_clear(Operation *op, wt_ctx *wc, struct berval *ndn); /* * former external.h @@ -159,13 +233,16 @@ 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_delete wt_modify; - +extern BI_op_modify wt_modify; +extern BI_op_modrdn wt_modrdn; extern BI_op_search wt_search; +extern BI_op_extended wt_extended; extern BI_operational wt_operational; +extern BI_has_subordinates wt_hasSubordinates; /* tools.c */ +int wt_entry_header(WT_ITEM *item, EntryHeader *eh); 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; @@ -175,6 +252,7 @@ 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; +extern BI_tool_entry_delete wt_tool_entry_delete; LDAP_END_DECL diff --git a/servers/slapd/back-wt/search.c b/servers/slapd/back-wt/search.c index 3d4e6d7e14..ddd77cdc59 100644 --- a/servers/slapd/back-wt/search.c +++ b/servers/slapd/back-wt/search.c @@ -47,8 +47,7 @@ static int base_candidate( ID *ids ) { Debug(LDAP_DEBUG_ARGS, - LDAP_XSTRING(base_candidate) - ": base: \"%s\" (0x%08lx)\n", + "base_candidate: base: \"%s\" (0x%08lx)\n", e->e_nname.bv_val, (long) e->e_id ); ids[0] = 1; @@ -138,8 +137,7 @@ static int search_candidates( AttributeAssertion aa_subentry = ATTRIBUTEASSERTION_INIT; Debug(LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search_candidates) - ": base=\"%s\" (0x%08lx) scope=%d\n", + "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; @@ -195,9 +193,9 @@ static int search_candidates( 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 ); + rc = wt_dn2idl( op, wc, &e->e_nname, e, ids, stack ); } else { - rc = wt_dn2idl(op, wc->session, &e->e_nname, e, ids, stack ); + rc = wt_dn2idl(op, wc, &e->e_nname, e, ids, stack ); } if ( rc == LDAP_SUCCESS ) { @@ -211,14 +209,11 @@ static int search_candidates( if( rc ) { Debug(LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search_candidates) - ": failed (rc=%d)\n", - rc ); + "wt_search_candidates: failed (rc=%d)\n", rc ); } else { Debug(LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search_candidates) - ": id=%ld first=%ld last=%ld\n", + "wt_search_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) WT_IDL_FIRST(ids), (long) WT_IDL_LAST(ids)); @@ -247,7 +242,7 @@ parse_paged_cookie( Operation *op, SlapReply *rs ) goto done; } - AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); + memcpy( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); if ( reqcookie > ps->ps_cookie ) { /* bad cookie */ @@ -285,8 +280,7 @@ send_paged_response( struct berval cookie; Debug(LDAP_DEBUG_ARGS, - LDAP_XSTRING(send_paged_response) - ": lastid=0x%08lx nentries=%d\n", + "send_paged_response: lastid=0x%08lx nentries=%d\n", lastid ? *lastid : 0, rs->sr_nentries ); ctrls[1] = NULL; @@ -333,34 +327,28 @@ 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; + int rc = LDAP_OTHER; Entry *e = NULL; + Entry *ae = 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 ); - attrs = op->oq_search.rs_attrs; + Debug( LDAP_DEBUG_ARGS, "==> wt_search: %s\n", op->o_req_dn.bv_val ); 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 ); + "wt_search: wt_ctx_get failed: %d\n", rc ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rc; } @@ -371,20 +359,12 @@ wt_search( Operation *op, SlapReply *rs ) 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 ); - rs->sr_err = LDAP_REFERRAL; - rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; - send_ldap_result( op, rs ); - goto done; + rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &ae); + break; default: /* TODO: error handling */ Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_delete) - ": error at wt_dn2entry() rc=%d\n", - rc ); + "<== wt_search: error at wt_dn2entry() rc=%d\n", rc ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); goto done; } @@ -394,7 +374,37 @@ wt_search( Operation *op, SlapReply *rs ) } if ( e == NULL ) { - // TODO + if ( ae ) { + struct berval matched_dn = BER_BVNULL; + /* found ancestor entry */ + if ( access_allowed( op, ae, + slap_schema.si_ad_entry, + NULL, ACL_DISCLOSE, NULL ) ) { + BerVarray erefs = NULL; + ber_dupbv( &matched_dn, &ae->e_name ); + erefs = is_entry_referral( ae ) + ? get_entry_referrals( op, ae ) + : NULL; + rs->sr_err = LDAP_REFERRAL; + rs->sr_matched = matched_dn.bv_val; + if ( erefs ) { + rs->sr_ref = referral_rewrite( erefs, &matched_dn, + &op->o_req_dn, op->oq_search.rs_scope ); + ber_bvarray_free( erefs ); + } + Debug( LDAP_DEBUG_ARGS, + "wt_search: ancestor is referral\n"); + rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; + send_ldap_result( op, rs ); + goto done; + } + } + Debug( LDAP_DEBUG_ARGS, + "wt_search: no such object %s\n", + op->o_req_dn.bv_val); + rs->sr_err = LDAP_NO_SUCH_OBJECT; + send_ldap_result( op, rs ); + goto done; } /* NOTE: __NEW__ "search" access is required @@ -413,8 +423,27 @@ wt_search( Operation *op, SlapReply *rs ) } if ( !manageDSAit && is_entry_referral( e ) ) { - /* entry is a referral */ - /* TODO: */ + struct berval matched_dn = BER_BVNULL; + BerVarray erefs = NULL; + ber_dupbv( &matched_dn, &e->e_name ); + erefs = get_entry_referrals( op, e ); + rs->sr_err = LDAP_REFERRAL; + if ( erefs ) { + rs->sr_ref = referral_rewrite( erefs, &matched_dn, + &op->o_req_dn, op->oq_search.rs_scope ); + ber_bvarray_free( erefs ); + if ( !rs->sr_ref ) { + rs->sr_text = "bad_referral object"; + } + } + Debug( LDAP_DEBUG_ARGS, "wt_search: entry is referral\n"); + rs->sr_matched = matched_dn.bv_val; + send_ldap_result( op, rs ); + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + ber_memfree( matched_dn.bv_val ); + rs->sr_matched = NULL; + goto done; } if ( get_assert( op ) && @@ -445,8 +474,7 @@ wt_search( Operation *op, SlapReply *rs ) case WT_NOTFOUND: break; default: - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_search) ": error search_candidates\n" ); + Debug( LDAP_DEBUG_ANY, "wt_search: error search_candidates\n" ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); goto done; } @@ -457,8 +485,7 @@ wt_search( Operation *op, SlapReply *rs ) cursor = 0; if ( candidates[0] == 0 ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search) ": no candidates\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_search: no candidates\n" ); goto nochange; } @@ -497,9 +524,7 @@ wt_search( Operation *op, SlapReply *rs ) } id = wt_idl_first( candidates, &cursor ); if ( id == NOID ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search) - ": no paged results candidates\n" ); + Debug( LDAP_DEBUG_TRACE, "wt_search: no paged results candidates\n" ); send_paged_response( op, rs, &lastid, 0 ); rs->sr_err = LDAP_OTHER; @@ -549,7 +574,7 @@ loop_begin: fetch_entry_retry: - rc = wt_id2entry(op->o_bd, wc->session, id, &e); + rc = wt_id2entry(op->o_bd, wc, id, &e); /* TODO: error handling */ if ( e == NULL ) { /* TODO: */ @@ -583,8 +608,11 @@ loop_begin: case LDAP_SCOPE_ONELEVEL: scopeok = 1; break; + case LDAP_SCOPE_CHILDREN: + if ( id == base->e_id ) break; + /* Fall-thru */ case LDAP_SCOPE_SUBTREE: - scopeok = 1; + scopeok = dnIsSuffix(&e->e_nname, &base->e_nname); break; } @@ -605,9 +633,7 @@ loop_begin: /* Not in scope, ignore it */ if ( !scopeok ) { - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search) - ": %ld scope not okay\n", + Debug( LDAP_DEBUG_TRACE, "wt_search: %ld scope not okay\n", (long) id ); goto loop_continue; } @@ -620,7 +646,16 @@ loop_begin: if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE && is_entry_referral( e ) ) { - /* TODO: referral */ + BerVarray erefs = get_entry_referrals( op, e ); + rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL, + op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL + ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); + rs->sr_entry = e; + send_search_reference( op, rs ); + rs->sr_entry = NULL; + ber_bvarray_free( rs->sr_ref ); + ber_bvarray_free( erefs ); + goto loop_continue; } if ( !manageDSAit && is_entry_glue( e )) { @@ -632,7 +667,13 @@ loop_begin: if ( rs->sr_err == LDAP_COMPARE_TRUE ) { /* check size limit */ if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { - /* TODO: */ + if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) { + wt_entry_return( e ); + e = NULL; + send_paged_response( op, rs, &lastid, tentries ); + goto done; + } + lastid = id; } if (e) { @@ -648,19 +689,28 @@ loop_begin: 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; + + switch ( rs->sr_err ) { + case LDAP_SUCCESS: /* entry sent ok */ + break; + default: /* entry not sent */ + break; + case LDAP_BUSY: + send_ldap_result( op, rs ); + goto done; + case LDAP_UNAVAILABLE: + rs->sr_err = LDAP_OTHER; + goto done; + case LDAP_SIZELIMIT_EXCEEDED: + rs->sr_ref = rs->sr_v2ref; + send_ldap_result( op, rs ); + rs->sr_err = LDAP_SUCCESS; + goto done; + } } } else { Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(wt_search) - ": %ld does not match filter\n", - (long) id ); + "wt_search: %ld does not match filter\n", (long) id ); } loop_continue: @@ -676,8 +726,7 @@ nochange: 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 ); */ + send_paged_response( op, rs, NULL, 0 ); } else { send_ldap_result( op, rs ); } @@ -694,6 +743,10 @@ done: wt_entry_return( e ); } + if( ae ) { + wt_entry_return( ae ); + } + return rs->sr_err; } diff --git a/servers/slapd/back-wt/tools.c b/servers/slapd/back-wt/tools.c index 846edc091a..63b63bef89 100644 --- a/servers/slapd/back-wt/tools.c +++ b/servers/slapd/back-wt/tools.c @@ -33,15 +33,11 @@ typedef struct 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; @@ -51,14 +47,12 @@ 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\n" ); + "wt_tool_entry_open: wt_ctx_get failed\n" ); return -1; } @@ -66,8 +60,7 @@ wt_tool_entry_open( BackendDB *be, int mode ) ,NULL, NULL, &reader); if ( rc ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_tool_entry_open) - ": cursor open failed: %s (%d)\n", + "wt_tool_entry_open: cursor open failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return -1; } @@ -78,8 +71,6 @@ wt_tool_entry_open( BackendDB *be, int mode ) int wt_tool_entry_close( BackendDB *be ) { - int rc; - if( reader ) { reader->close(reader); reader = NULL; @@ -127,8 +118,7 @@ wt_tool_entry_next( BackendDB *be ) return NOID; default: Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_tool_entry_next) - ": next failed: %s (%d)\n", + "wt_tool_entry_next: next failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return NOID; } @@ -136,16 +126,7 @@ wt_tool_entry_next( BackendDB *be ) 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 ); - } - - rc = reader->get_value(reader, &item); - if( rc ){ - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_tool_entry_next) - ": get_value failed: %s (%d)\n", + "wt_tool_entry_next: get_key failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); } return id; @@ -169,7 +150,8 @@ entry_getlen(unsigned char **buf) return len; } -int wt_entry_header(WT_ITEM *item, EntryHeader *eh){ +int wt_entry_header(WT_ITEM *item, EntryHeader *eh) +{ unsigned char *ptr = (unsigned char *)item->data; /* Some overlays can create empty entries @@ -191,6 +173,22 @@ wt_tool_entry_get( BackendDB *be, ID id ) assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); + reader->set_key(reader, id); + rc = reader->search(reader); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "wt_tool_entry_get: search failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + rc = reader->get_value(reader, &item); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_tool_entry_get: get_value failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + rc = wt_entry_header( &item, &eh ); assert( rc == 0 ); eoff = eh.data - (char *)item.data; @@ -209,6 +207,7 @@ wt_tool_entry_get( BackendDB *be, ID id ) e->e_id = id; } +done: return e; } @@ -218,7 +217,6 @@ static int wt_tool_next_id( 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; @@ -231,7 +229,7 @@ static int wt_tool_next_id( return 0; } - rc = wt_dn2id(op, wc->session, &ndn, &id); + rc = wt_dn2id(op, wc, &ndn, &id); if(rc == 0){ e->e_id = id; }else if( rc == WT_NOTFOUND ){ @@ -258,7 +256,7 @@ static int wt_tool_next_id( pid = id; } wt_next_id( op->o_bd, &e->e_id ); - rc = wt_dn2id_add(op, wc->session, pid, e); + rc = wt_dn2id_add(op, wc, pid, e); if( rc ){ snprintf( text->bv_val, text->bv_len, "wt_dn2id_add failed: %s (%d)", @@ -298,11 +296,9 @@ wt_tool_index_add( 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}; + Operation op = {0}; + Opheader ohdr = {0}; assert( slapMode & SLAP_TOOL_MODE ); assert( text != NULL ); @@ -310,14 +306,12 @@ wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) assert( text->bv_val[0] == '\0' ); /* overconservative? */ Debug( LDAP_DEBUG_TRACE, - "=> " LDAP_XSTRING(wt_tool_entry_put) - ": ( \"%s\" )\n", e->e_dn ); + "=> wt_tool_entry_put: ( \"%s\" )\n", e->e_dn ); 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", + "wt_dn2id_add: begin_transaction failed: %s (%d)\n", wiredtiger_strerror(rc), rc ); return NOID; } @@ -333,18 +327,17 @@ wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) "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 ); + "=> wt_tool_entry_put: %s\n", text->bv_val ); goto done; } - rc = wt_id2entry_add( &op, wc->session, e ); + rc = wt_id2entry_add( &op, wc, 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", + "=> wt_tool_entry_put: %s\n", text->bv_val ); goto done; } @@ -356,8 +349,7 @@ wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) rc == LDAP_OTHER ? "Internal error" : wiredtiger_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, - "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n", - text->bv_val ); + "=> wt_tool_entry_put: %s\n", text->bv_val ); goto done; } @@ -369,8 +361,7 @@ done: "txn_commit failed: %s (%d)", wiredtiger_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, - "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n", - text->bv_val ); + "=> wt_tool_entry_put: %s\n", text->bv_val ); e->e_id = NOID; } }else{ @@ -380,8 +371,7 @@ done: rc == LDAP_OTHER ? "Internal error" : wiredtiger_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, - "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n", - text->bv_val ); + "=> wt_tool_entry_put: %s\n", text->bv_val ); e->e_id = NOID; } @@ -400,8 +390,7 @@ int wt_tool_entry_reindex( Opheader ohdr = {0}; Debug( LDAP_DEBUG_ARGS, - "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld )\n", - (long) id ); + "=> wt_tool_entry_reindex( %ld )\n", (long) id ); assert( tool_base == NULL ); assert( tool_filter == NULL ); @@ -443,8 +432,7 @@ int wt_tool_entry_reindex( } if ( j == wi->wi_nattrs ) { Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_tool_entry_reindex) - ": no index configured for %s\n", + "wt_tool_entry_reindex: no index configured for %s\n", adv[i]->ad_cname.bv_val ); return -1; } @@ -456,8 +444,7 @@ int wt_tool_entry_reindex( e = wt_tool_entry_get( be, id ); if( e == NULL ) { - Debug( LDAP_DEBUG_ANY, - LDAP_XSTRING(wt_tool_entry_reindex) + Debug( LDAP_DEBUG_ANY, "=> wt_tool_entry_reindex" ": could not locate id=%ld\n", (long) id ); return -1; @@ -471,13 +458,12 @@ int wt_tool_entry_reindex( 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", + "wt_tool_entry_reindex: begin_transaction failed %s (%d)\n", wiredtiger_strerror(rc), rc ); goto done; } Debug( LDAP_DEBUG_TRACE, - "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld, \"%s\" )\n", + "=> wt_tool_entry_reindex( %ld, \"%s\" )\n", (long) id, e->e_dn ); rc = wt_tool_index_add( &op, wc, e ); @@ -487,15 +473,13 @@ done: 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", + "=> wt_tool_entry_reindex: commit_transaction failed %s (%d)\n", wiredtiger_strerror(rc), rc ); } }else{ rc = wc->session->rollback_transaction(wc->session, NULL); Debug( LDAP_DEBUG_ANY, - "=> " LDAP_XSTRING(wt_tool_entry_reindex) - ": rollback transaction %s (%d)\n", + "=> wt_tool_entry_reindex: rollback transaction %s (%d)\n", wiredtiger_strerror(rc), rc ); } @@ -504,6 +488,221 @@ done: return rc; } +ID wt_tool_dn2id_get( + Backend *be, + struct berval *dn +) +{ + Operation op = {0}; + Opheader ohdr = {0}; + ID id; + int rc; + + if ( BER_BVISEMPTY(dn) ) + return 0; + + op.o_hdr = &ohdr; + op.o_bd = be; + op.o_tmpmemctx = NULL; + op.o_tmpmfuncs = &ch_mfuncs; + + rc = wt_dn2id(&op, wc, dn, &id); + switch( rc ){ + case 0: + break; + case WT_NOTFOUND: + return NOID; + default: + Debug( LDAP_DEBUG_ANY, + "wt_tool_entry_get: entry get failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return NOID; + } + return id; +} + +ID wt_tool_entry_modify( + BackendDB *be, + Entry *e, + struct berval *text ) +{ + int rc; + Operation op = {0}; + Opheader ohdr = {0}; + + assert( be != NULL ); + assert( slapMode & SLAP_TOOL_MODE ); + + assert( text != NULL ); + assert( text->bv_val != NULL ); + assert( text->bv_val[0] == '\0' ); /* overconservative? */ + + assert ( e->e_id != NOID ); + + Debug( LDAP_DEBUG_TRACE, + "=> wt_tool_entry_modify( %ld, \"%s\" )\n", + (long) e->e_id, e->e_dn ); + + rc = wc->session->begin_transaction(wc->session, NULL); + if( rc ){ + Debug( LDAP_DEBUG_ANY, "=> wt_tool_entry_modify" + ": begin_transaction failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + return NOID; + } + + op.o_hdr = &ohdr; + op.o_bd = be; + op.o_tmpmemctx = NULL; + op.o_tmpmfuncs = &ch_mfuncs; + + rc = wt_id2entry_update( &op, wc, e ); + if( rc != 0 ) { + snprintf( text->bv_val, text->bv_len, + "id2entry_update failed: %s (%d)", + wiredtiger_strerror(rc), rc ); + Debug( LDAP_DEBUG_ANY, "=> wt_tool_entry_modify: %s\n", + text->bv_val ); + 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, "=> wt_tool_entry_modify: %s\n", + text->bv_val ); + 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, "=> wt_tool_entry_modify: %s\n", + text->bv_val ); + e->e_id = NOID; + } + + return e->e_id; +} + +int wt_tool_entry_delete( + BackendDB *be, + struct berval *ndn, + struct berval *text ) +{ + struct wt_info *wi = (struct wt_info *) be->be_private; + int rc; + Operation op = {0}; + Opheader ohdr = {0}; + Entry *e = NULL; + + assert( be != NULL ); + assert( slapMode & SLAP_TOOL_MODE ); + + assert( text != NULL ); + assert( text->bv_val != NULL ); + assert( text->bv_val[0] == '\0' ); /* overconservative? */ + + assert ( ndn != NULL ); + assert ( ndn->bv_val != NULL ); + + Debug( LDAP_DEBUG_TRACE, + "=> wt_tool_entry_delete( %s )\n", + ndn->bv_val ); + + op.o_hdr = &ohdr; + op.o_bd = be; + op.o_tmpmemctx = NULL; + op.o_tmpmfuncs = &ch_mfuncs; + + /* get entry */ + rc = wt_dn2entry(op.o_bd, wc, ndn, &e); + switch( rc ) { + case 0: + break; + case WT_NOTFOUND: + Debug( LDAP_DEBUG_ARGS, + "<== wt_tool_entry_delete: no such object %s\n", + ndn->bv_val); + goto done; + default: + Debug( LDAP_DEBUG_ANY, + "wt_tool_entry_delete: error at wt_dn2entry() rc=%d\n", + rc ); + goto done; + } + + rc = wt_dn2id_has_children( &op, wc, e->e_id ); + if( rc != WT_NOTFOUND ) { + /* subordinate objects must be deleted first */ + rc = -1; + goto done; + } + + rc = wc->session->begin_transaction(wc->session, NULL); + if( rc ){ + Debug( LDAP_DEBUG_ANY, + "wt_tool_entry_delete: begin_transaction failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + goto done; + } + + /* delete from dn2id */ + rc = wt_dn2id_delete( &op, wc, &e->e_nname); + if ( rc ) { + Debug( LDAP_DEBUG_TRACE, + "<== wt_tool_entry_delete: dn2id failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + wc->session->rollback_transaction(wc->session, NULL); + goto done; + } + + /* delete indices for old attributes */ + rc = wt_index_entry_del( &op, wc, e ); + if ( rc ) { + Debug( LDAP_DEBUG_TRACE, + "<== wt_tool_entry_delete: index delete failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + wc->session->rollback_transaction(wc->session, NULL); + goto done; + } + + /* delete from id2entry */ + rc = wt_id2entry_delete( &op, wc, e ); + if ( rc ) { + Debug( LDAP_DEBUG_TRACE, + "<== wt_tool_entry_delete: id2entry failed: %s (%d)\n", + wiredtiger_strerror(rc), rc ); + wc->session->rollback_transaction(wc->session, NULL); + goto done; + } + + 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, + "=> wt_tool_entry_delete: %s\n", + text->bv_val ); + goto done; + } + +done: + /* free entry */ + if( e != NULL ) { + wt_entry_return( e ); + } + return rc; +} + + /* * Local variables: * indent-tabs-mode: t diff --git a/tests/Makefile.in b/tests/Makefile.in index d4abff7f09..606229315d 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -20,16 +20,19 @@ BUILD_MDB=@BUILD_MDB@ BUILD_SQL=@BUILD_SQL@ BUILD_SLAPD=@BUILD_SLAPD@ BUILD_BALANCER=@BUILD_BALANCER@ +BUILD_WT=@BUILD_WT@ # test primary backends (default) test tests: @$(MAKE) mdb @$(MAKE) lloadd + @$(MAKE) wt # test all backends alltests: tests @$(MAKE) sql @$(MAKE) ldif + @$(MAKE) wt mdb test-mdb: mdb-$(BUILD_MDB) mdb-no: @@ -51,6 +54,13 @@ ldif test-ldif: FORCE @echo "Initiating LDAP tests for LDIF..." @$(RUN) -b ldif all +wt test-wt: wt-$(BUILD_WT) +wt-no: + @echo "run configure with --enable-wt to run back-wt tests" + +wt-yes wt-mod: FORCE + @$(RUN) -b wt all + lloadd test-lloadd: lloadd-$(BUILD_BALANCER) lloadd-no: @echo "run configure with --enable-balancer to run the Load Balancer tests" diff --git a/tests/README b/tests/README index a3b5d2f304..e7a8a921d6 100644 --- a/tests/README +++ b/tests/README @@ -6,6 +6,7 @@ verify basic functionality of the LDAP libraries and slapd. To run SQL tests, define SLAPD_USE_SQL= and type "make sql"; define SLAPD_USE_SQLWRITE=yes to enable write tests as well. + To run WT tests, type "make wt". To run regression tests, type "make regressions" The test scripts depends on a number of tools commonly available on diff --git a/tests/run.in b/tests/run.in index 0afeca07b5..8df8c4c238 100644 --- a/tests/run.in +++ b/tests/run.in @@ -38,6 +38,7 @@ AC_asyncmeta=asyncmeta@BUILD_ASYNCMETA@ AC_perl=perl@BUILD_PERL@ AC_relay=relay@BUILD_RELAY@ AC_sql=sql@BUILD_SQL@ +AC_wt=@BUILD_WT@ # overlays AC_accesslog=accesslog@BUILD_ACCESSLOG@ @@ -188,6 +189,7 @@ INDEXDB=noindexdb MAINDB=nomaindb case $BACKEND in mdb) INDEXDB=indexdb MAINDB=maindb ;; ndb) INDEXDB=indexdb ;; + wt) INDEXDB=indexdb ;; esac export BACKEND BACKENDTYPE INDEXDB MAINDB \ diff --git a/tests/scripts/test023-refint b/tests/scripts/test023-refint index 61a6833dcc..dc1a1b4a17 100755 --- a/tests/scripts/test023-refint +++ b/tests/scripts/test023-refint @@ -19,7 +19,12 @@ echo "running defines.sh" if test $REFINT = refintno; then echo "Referential Integrity overlay not available, test skipped" exit 0 -fi +fi + +if test $BACKEND = wt ; then + echo "back-wt does not support subtree rename" + exit 0 +fi mkdir -p $TESTDIR $DBDIR1 diff --git a/tests/scripts/test040-subtree-rename b/tests/scripts/test040-subtree-rename index 98022348bb..f250c40aad 100755 --- a/tests/scripts/test040-subtree-rename +++ b/tests/scripts/test040-subtree-rename @@ -16,6 +16,11 @@ echo "running defines.sh" . $SRCDIR/scripts/defines.sh +if test $BACKEND = wt ; then + echo "back-wt does not support subtree rename" + exit 0 +fi + mkdir -p $TESTDIR $DBDIR1 echo "Starting slapd on TCP/IP port $PORT1..." diff --git a/tests/scripts/test057-memberof-refint b/tests/scripts/test057-memberof-refint index 6ad1bface5..c1e0eb58cd 100755 --- a/tests/scripts/test057-memberof-refint +++ b/tests/scripts/test057-memberof-refint @@ -20,12 +20,17 @@ echo "running defines.sh" if test $MEMBEROF = memberofno; then echo "Memberof overlay not available, test skipped" exit 0 -fi +fi if test $REFINT = refintno; then echo "Referential Integrity overlay not available, test skipped" exit 0 -fi +fi + +if test $BACKEND = wt ; then + echo "back-wt does not support subtree rename" + exit 0 +fi mkdir -p $TESTDIR $DBDIR1 $TESTDIR/confdir