summaryrefslogtreecommitdiffstats
path: root/servers/slapd/back-wt/tools.c
diff options
context:
space:
mode:
Diffstat (limited to 'servers/slapd/back-wt/tools.c')
-rw-r--r--servers/slapd/back-wt/tools.c712
1 files changed, 712 insertions, 0 deletions
diff --git a/servers/slapd/back-wt/tools.c b/servers/slapd/back-wt/tools.c
new file mode 100644
index 0000000..658837f
--- /dev/null
+++ b/servers/slapd/back-wt/tools.c
@@ -0,0 +1,712 @@
+/* OpenLDAP WiredTiger backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2022 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
+ * based on back-bdb for inclusion in OpenLDAP Software.
+ * WiredTiger is a product of MongoDB Inc.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include "back-wt.h"
+#include "slap-config.h"
+
+typedef struct dn_id {
+ ID id;
+ struct berval dn;
+} dn_id;
+
+#define HOLE_SIZE 4096
+static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
+static unsigned nholes;
+
+static struct berval *tool_base;
+static int tool_scope;
+static Filter *tool_filter;
+
+static wt_ctx *wc;
+static WT_CURSOR *reader;
+static WT_ITEM item;
+
+int
+wt_tool_entry_open( BackendDB *be, int mode )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+
+ wc = wt_ctx_init(wi);
+ if( !wc ){
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_open: wt_ctx_get failed\n" );
+ return -1;
+ }
+
+ rc = wc->session->open_cursor(wc->session, WT_TABLE_ID2ENTRY"(entry)"
+ ,NULL, NULL, &reader);
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_open: cursor open failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc );
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+wt_tool_entry_close( BackendDB *be )
+{
+ if( reader ) {
+ reader->close(reader);
+ reader = NULL;
+ }
+
+ wt_ctx_free(NULL, wc);
+
+ if( nholes ) {
+ unsigned i;
+ fprintf( stderr, "Error, entries missing!\n");
+ for (i=0; i<nholes; i++) {
+ fprintf(stderr, " entry %ld: %s\n",
+ holes[i].id, holes[i].dn.bv_val);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+ID
+wt_tool_entry_first_x( BackendDB *be,
+ struct berval *base,
+ int scope,
+ Filter *f )
+{
+ tool_base = base;
+ tool_scope = scope;
+ tool_filter = f;
+
+ return wt_tool_entry_next( be );
+}
+
+ID
+wt_tool_entry_next( BackendDB *be )
+{
+ int rc;
+ ID id;
+
+ rc = reader->next(reader);
+ switch( rc ){
+ case 0:
+ break;
+ case WT_NOTFOUND:
+ return NOID;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_next: next failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc );
+ return NOID;
+ }
+
+ rc = reader->get_key(reader, &id);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_next: get_key failed: %s (%d)\n",
+ wiredtiger_strerror(rc), rc );
+ }
+ return id;
+}
+
+static ber_len_t
+entry_getlen(unsigned char **buf)
+{
+ ber_len_t len;
+ int i;
+
+ len = *(*buf)++;
+ if (len <= 0x7f)
+ return len;
+ i = len & 0x7f;
+ len = 0;
+ for (;i > 0; i--) {
+ len <<= 8;
+ len |= *(*buf)++;
+ }
+ return len;
+}
+
+int wt_entry_header(WT_ITEM *item, EntryHeader *eh)
+{
+ unsigned char *ptr = (unsigned char *)item->data;
+
+ /* Some overlays can create empty entries
+ * so don't check for zeros here.
+ */
+ eh->nattrs = entry_getlen(&ptr);
+ eh->nvals = entry_getlen(&ptr);
+ eh->data = (char *)ptr;
+ return LDAP_SUCCESS;
+}
+
+Entry *
+wt_tool_entry_get( BackendDB *be, ID id )
+{
+ Entry *e = NULL;
+ static EntryHeader eh;
+ int rc, eoff;
+
+ assert( be != NULL );
+ assert( slapMode & SLAP_TOOL_MODE );
+
+ 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;
+
+ eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
+ eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
+ memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
+ eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
+ memcpy(eh.data, item.data, item.size);
+ eh.data += eoff;
+
+ rc = entry_decode( &eh, &e );
+ assert( rc == 0 );
+
+ if( rc == LDAP_SUCCESS ) {
+ e->e_id = id;
+ }
+
+done:
+ return e;
+}
+
+static int wt_tool_next_id(
+ Operation *op,
+ Entry *e,
+ struct berval *text,
+ int hole )
+{
+ struct berval dn = e->e_name;
+ struct berval ndn = e->e_nname;
+ struct berval pdn, npdn;
+ int rc;
+ ID id = 0;
+ ID pid = 0;
+
+ if(ndn.bv_len == 0){
+ e->e_id = 0;
+ return 0;
+ }
+
+ rc = wt_dn2id(op, wc, &ndn, &id);
+ if(rc == 0){
+ e->e_id = id;
+ }else if( rc == WT_NOTFOUND ){
+ if ( !be_issuffix( op->o_bd, &ndn ) ) {
+ ID eid = e->e_id;
+ dnParent( &dn, &pdn );
+ dnParent( &ndn, &npdn );
+ e->e_name = pdn;
+ e->e_nname = npdn;
+ rc = wt_tool_next_id( op, e, text, 1 );
+ e->e_name = dn;
+ e->e_nname = ndn;
+ if ( rc ) {
+ return rc;
+ }
+ /* If parent didn't exist, it was created just now
+ * and its ID is now in e->e_id. Make sure the current
+ * entry gets added under the new parent ID.
+ */
+ if ( eid != e->e_id ) {
+ pid = e->e_id;
+ }
+ }else{
+ pid = id;
+ }
+ wt_next_id( op->o_bd, &e->e_id );
+ rc = wt_dn2id_add(op, wc, pid, e);
+ if( rc ){
+ snprintf( text->bv_val, text->bv_len,
+ "wt_dn2id_add failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> wt_tool_next_id: %s\n", text->bv_val );
+ }
+
+ }else if ( !hole ) {
+ unsigned i, j;
+ e->e_id = id;
+
+ for ( i=0; i<nholes; i++) {
+ if ( holes[i].id == e->e_id ) {
+ free(holes[i].dn.bv_val);
+ for (j=i;j<nholes;j++) holes[j] = holes[j+1];
+ holes[j].id = 0;
+ nholes--;
+ break;
+ } else if ( holes[i].id > e->e_id ) {
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+static int
+wt_tool_index_add(
+ Operation *op,
+ wt_ctx *wc,
+ Entry *e )
+{
+ return wt_index_entry_add( op, wc, e );
+}
+
+ID
+wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
+{
+ int rc;
+ Operation op = {0};
+ Opheader ohdr = {0};
+
+ assert( slapMode & SLAP_TOOL_MODE );
+ assert( text != NULL );
+ assert( text->bv_val != NULL );
+ assert( text->bv_val[0] == '\0' ); /* overconservative? */
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> wt_tool_entry_put: ( \"%s\" )\n", e->e_dn );
+
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ "wt_dn2id_add: 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_tool_next_id( &op, e, text, 0 );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "wt_tool_next_id failed: %s (%d)",
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> wt_tool_entry_put: %s\n", text->bv_val );
+ goto done;
+ }
+
+ 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,
+ "=> wt_tool_entry_put: %s\n",
+ text->bv_val );
+ goto done;
+ }
+
+ rc = wt_tool_index_add( &op, wc, e );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "index_entry_add failed: %s (%d)",
+ rc == LDAP_OTHER ? "Internal error" :
+ wiredtiger_strerror(rc), rc );
+ Debug( LDAP_DEBUG_ANY,
+ "=> wt_tool_entry_put: %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_put: %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_put: %s\n", text->bv_val );
+ e->e_id = NOID;
+ }
+
+ return e->e_id;
+}
+
+int wt_tool_entry_reindex(
+ BackendDB *be,
+ ID id,
+ AttributeDescription **adv )
+{
+ struct wt_info *wi = (struct wt_info *) be->be_private;
+ int rc;
+ Entry *e;
+ Operation op = {0};
+ Opheader ohdr = {0};
+
+ Debug( LDAP_DEBUG_ARGS,
+ "=> wt_tool_entry_reindex( %ld )\n", (long) id );
+ assert( tool_base == NULL );
+ assert( tool_filter == NULL );
+
+ /* No indexes configured, nothing to do. Could return an
+ * error here to shortcut things.
+ */
+ if (!wi->wi_attrs) {
+ return 0;
+ }
+
+ /* Check for explicit list of attrs to index */
+ if ( adv ) {
+ int i, j, n;
+
+ if ( wi->wi_attrs[0]->ai_desc != adv[0] ) {
+ /* count */
+ for ( n = 0; adv[n]; n++ ) ;
+
+ /* insertion sort */
+ for ( i = 0; i < n; i++ ) {
+ AttributeDescription *ad = adv[i];
+ for ( j = i-1; j>=0; j--) {
+ if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
+ adv[j+1] = adv[j];
+ }
+ adv[j+1] = ad;
+ }
+ }
+
+ for ( i = 0; adv[i]; i++ ) {
+ if ( wi->wi_attrs[i]->ai_desc != adv[i] ) {
+ for ( j = i+1; j < wi->wi_nattrs; j++ ) {
+ if ( wi->wi_attrs[j]->ai_desc == adv[i] ) {
+ AttrInfo *ai = wi->wi_attrs[i];
+ wi->wi_attrs[i] = wi->wi_attrs[j];
+ wi->wi_attrs[j] = ai;
+ break;
+ }
+ }
+ if ( j == wi->wi_nattrs ) {
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_reindex: no index configured for %s\n",
+ adv[i]->ad_cname.bv_val );
+ return -1;
+ }
+ }
+ }
+ wi->wi_nattrs = i;
+ }
+
+ e = wt_tool_entry_get( be, id );
+
+ if( e == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "=> wt_tool_entry_reindex"
+ ": could not locate id=%ld\n",
+ (long) id );
+ return -1;
+ }
+
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ rc = wc->session->begin_transaction(wc->session, NULL);
+ if( rc ){
+ Debug( LDAP_DEBUG_ANY,
+ "wt_tool_entry_reindex: begin_transaction failed %s (%d)\n",
+ wiredtiger_strerror(rc), rc );
+ goto done;
+ }
+ Debug( LDAP_DEBUG_TRACE,
+ "=> wt_tool_entry_reindex( %ld, \"%s\" )\n",
+ (long) id, e->e_dn );
+
+ rc = wt_tool_index_add( &op, wc, e );
+
+done:
+ if ( rc == 0 ){
+ rc = wc->session->commit_transaction(wc->session, NULL);
+ if( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "=> 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,
+ "=> wt_tool_entry_reindex: rollback transaction %s (%d)\n",
+ wiredtiger_strerror(rc), rc );
+ }
+
+ wt_entry_release( &op, e, 0 );
+
+ 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
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */