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