summaryrefslogtreecommitdiffstats
path: root/servers/slapd/back-ndb/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--servers/slapd/back-ndb/tools.cpp544
1 files changed, 544 insertions, 0 deletions
diff --git a/servers/slapd/back-ndb/tools.cpp b/servers/slapd/back-ndb/tools.cpp
new file mode 100644
index 0000000..13ea7c3
--- /dev/null
+++ b/servers/slapd/back-ndb/tools.cpp
@@ -0,0 +1,544 @@
+/* tools.cpp - tools for slap tools */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2008-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 initially developed by Howard Chu for inclusion
+ * in OpenLDAP Software. This work was sponsored by MySQL.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include <ac/errno.h>
+
+#include "lutil.h"
+
+#include "back-ndb.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 Avlnode *myParents;
+
+static Ndb *myNdb;
+static NdbTransaction *myScanTxn;
+static NdbIndexScanOperation *myScanOp;
+
+static NdbRecAttr *myScanID, *myScanOC;
+static NdbRecAttr *myScanDN[NDB_MAX_RDNS];
+static char myDNbuf[2048];
+static char myIdbuf[2*sizeof(ID)];
+static char myOcbuf[NDB_OC_BUFLEN];
+static NdbRdns myRdns;
+
+static NdbTransaction *myPutTxn;
+static int myPutCnt;
+
+static struct berval *myOcList;
+static struct berval myDn;
+
+extern "C"
+int ndb_tool_entry_open(
+ BackendDB *be, int mode )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+
+ myNdb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
+ return myNdb->init(1024);
+}
+
+extern "C"
+int ndb_tool_entry_close(
+ BackendDB *be )
+{
+ if ( myPutTxn ) {
+ int rc = myPutTxn->execute(NdbTransaction::Commit);
+ if( rc != 0 ) {
+ char text[1024];
+ snprintf( text, sizeof(text),
+ "txn_commit failed: %s (%d)",
+ myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
+ text, 0, 0 );
+ }
+ myPutTxn->close();
+ myPutTxn = NULL;
+ }
+ myPutCnt = 0;
+
+ 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;
+}
+
+extern "C"
+ID ndb_tool_entry_next(
+ BackendDB *be )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+ char *ptr;
+ ID id;
+ int i;
+
+ assert( be != NULL );
+ assert( slapMode & SLAP_TOOL_MODE );
+
+ if ( myScanOp->nextResult() ) {
+ myScanOp->close();
+ myScanOp = NULL;
+ myScanTxn->close();
+ myScanTxn = NULL;
+ return NOID;
+ }
+ id = myScanID->u_64_value();
+
+ if ( myOcList ) {
+ ber_bvarray_free( myOcList );
+ }
+ myOcList = ndb_ref2oclist( myOcbuf, NULL );
+ for ( i=0; i<NDB_MAX_RDNS; i++ ) {
+ if ( myScanDN[i]->isNULL() || !myRdns.nr_buf[i][0] )
+ break;
+ }
+ myRdns.nr_num = i;
+ ptr = myDNbuf;
+ for ( --i; i>=0; i-- ) {
+ char *buf;
+ int len;
+ buf = myRdns.nr_buf[i];
+ len = *buf++;
+ ptr = lutil_strncopy( ptr, buf, len );
+ if ( i )
+ *ptr++ = ',';
+ }
+ *ptr = '\0';
+ myDn.bv_val = myDNbuf;
+ myDn.bv_len = ptr - myDNbuf;
+
+ return id;
+}
+
+extern "C"
+ID ndb_tool_entry_first(
+ BackendDB *be )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+ int i;
+
+ myScanTxn = myNdb->startTransaction();
+ if ( !myScanTxn )
+ return NOID;
+
+ myScanOp = myScanTxn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
+ if ( !myScanOp )
+ return NOID;
+
+ if ( myScanOp->readTuples( NdbOperation::LM_CommittedRead, NdbScanOperation::SF_KeyInfo ))
+ return NOID;
+
+ myScanID = myScanOp->getValue( EID_COLUMN, myIdbuf );
+ myScanOC = myScanOp->getValue( OCS_COLUMN, myOcbuf );
+ for ( i=0; i<NDB_MAX_RDNS; i++ ) {
+ myScanDN[i] = myScanOp->getValue( i+RDN_COLUMN, myRdns.nr_buf[i] );
+ }
+ if ( myScanTxn->execute( NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1 ))
+ return NOID;
+
+ return ndb_tool_entry_next( be );
+}
+
+extern "C"
+ID ndb_tool_dn2id_get(
+ Backend *be,
+ struct berval *dn
+)
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+ NdbArgs NA;
+ NdbRdns rdns;
+ Entry e;
+ char text[1024];
+ Operation op = {0};
+ Opheader ohdr = {0};
+ int rc;
+
+ if ( BER_BVISEMPTY(dn) )
+ return 0;
+
+ NA.ndb = myNdb;
+ NA.txn = myNdb->startTransaction();
+ if ( !NA.txn ) {
+ snprintf( text, sizeof(text),
+ "startTransaction failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_dn2id_get) ": %s\n",
+ text, 0, 0 );
+ return NOID;
+ }
+ if ( myOcList ) {
+ ber_bvarray_free( myOcList );
+ myOcList = NULL;
+ }
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ NA.e = &e;
+ e.e_name = *dn;
+ NA.rdns = &rdns;
+ NA.ocs = NULL;
+ rc = ndb_entry_get_info( &op, &NA, 0, NULL );
+ myOcList = NA.ocs;
+ NA.txn->close();
+ if ( rc )
+ return NOID;
+
+ myDn = *dn;
+
+ return e.e_id;
+}
+
+extern "C"
+Entry* ndb_tool_entry_get( BackendDB *be, ID id )
+{
+ NdbArgs NA;
+ int rc;
+ char text[1024];
+ Operation op = {0};
+ Opheader ohdr = {0};
+
+ assert( be != NULL );
+ assert( slapMode & SLAP_TOOL_MODE );
+
+ NA.txn = myNdb->startTransaction();
+ if ( !NA.txn ) {
+ snprintf( text, sizeof(text),
+ "start_transaction failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_get) ": %s\n",
+ text, 0, 0 );
+ return NULL;
+ }
+
+ NA.e = entry_alloc();
+ NA.e->e_id = id;
+ ber_dupbv( &NA.e->e_name, &myDn );
+ dnNormalize( 0, NULL, NULL, &NA.e->e_name, &NA.e->e_nname, NULL );
+
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ NA.ndb = myNdb;
+ NA.ocs = myOcList;
+ rc = ndb_entry_get_data( &op, &NA, 0 );
+
+ if ( rc ) {
+ entry_free( NA.e );
+ NA.e = NULL;
+ }
+ NA.txn->close();
+
+ return NA.e;
+}
+
+static struct berval glueval[] = {
+ BER_BVC("glue"),
+ BER_BVNULL
+};
+
+static int ndb_dnid_cmp( const void *v1, const void *v2 )
+{
+ struct dn_id *dn1 = (struct dn_id *)v1,
+ *dn2 = (struct dn_id *)v2;
+ return ber_bvcmp( &dn1->dn, &dn2->dn );
+}
+
+static int ndb_tool_next_id(
+ Operation *op,
+ NdbArgs *NA,
+ struct berval *text,
+ int hole )
+{
+ struct berval ndn = NA->e->e_nname;
+ int rc;
+
+ if (ndn.bv_len == 0) {
+ NA->e->e_id = 0;
+ return 0;
+ }
+
+ rc = ndb_entry_get_info( op, NA, 0, NULL );
+ if ( rc ) {
+ Attribute *a, tmp = {0};
+ if ( !be_issuffix( op->o_bd, &ndn ) ) {
+ struct dn_id *dptr;
+ struct berval npdn;
+ dnParent( &ndn, &npdn );
+ NA->e->e_nname = npdn;
+ NA->rdns->nr_num--;
+ rc = ndb_tool_next_id( op, NA, text, 1 );
+ NA->e->e_nname = ndn;
+ NA->rdns->nr_num++;
+ if ( rc ) {
+ return rc;
+ }
+ /* If parent didn't exist, it was created just now
+ * and its ID is now in e->e_id.
+ */
+ dptr = (struct dn_id *)ch_malloc( sizeof( struct dn_id ) + npdn.bv_len + 1);
+ dptr->id = NA->e->e_id;
+ dptr->dn.bv_val = (char *)(dptr+1);
+ strcpy(dptr->dn.bv_val, npdn.bv_val );
+ dptr->dn.bv_len = npdn.bv_len;
+ if ( avl_insert( &myParents, dptr, ndb_dnid_cmp, avl_dup_error )) {
+ ch_free( dptr );
+ }
+ }
+ rc = ndb_next_id( op->o_bd, myNdb, &NA->e->e_id );
+ if ( rc ) {
+ snprintf( text->bv_val, text->bv_len,
+ "next_id failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ return rc;
+ }
+ if ( hole ) {
+ a = NA->e->e_attrs;
+ NA->e->e_attrs = &tmp;
+ tmp.a_desc = slap_schema.si_ad_objectClass;
+ tmp.a_vals = glueval;
+ tmp.a_nvals = tmp.a_vals;
+ tmp.a_numvals = 1;
+ }
+ rc = ndb_entry_put_info( op->o_bd, NA, 0 );
+ if ( hole ) {
+ NA->e->e_attrs = a;
+ }
+ if ( rc ) {
+ snprintf( text->bv_val, text->bv_len,
+ "ndb_entry_put_info failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ } else if ( hole ) {
+ if ( nholes == nhmax - 1 ) {
+ if ( holes == hbuf ) {
+ holes = (dn_id *)ch_malloc( nhmax * sizeof(dn_id) * 2 );
+ AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
+ } else {
+ holes = (dn_id *)ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
+ }
+ nhmax *= 2;
+ }
+ ber_dupbv( &holes[nholes].dn, &ndn );
+ holes[nholes++].id = NA->e->e_id;
+ }
+ } else if ( !hole ) {
+ unsigned i;
+
+ for ( i=0; i<nholes; i++) {
+ if ( holes[i].id == NA->e->e_id ) {
+ int j;
+ free(holes[i].dn.bv_val);
+ for (j=i;j<nholes;j++) holes[j] = holes[j+1];
+ holes[j].id = 0;
+ nholes--;
+ rc = ndb_entry_put_info( op->o_bd, NA, 1 );
+ break;
+ } else if ( holes[i].id > NA->e->e_id ) {
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+extern "C"
+ID ndb_tool_entry_put(
+ BackendDB *be,
+ Entry *e,
+ struct berval *text )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+ struct dn_id dtmp, *dptr;
+ NdbArgs NA;
+ NdbRdns rdns;
+ int rc, slow = 0;
+ 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? */
+
+ Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(ndb_tool_entry_put)
+ "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
+
+ if ( !be_issuffix( be, &e->e_nname )) {
+ dnParent( &e->e_nname, &dtmp.dn );
+ dptr = (struct dn_id *)avl_find( myParents, &dtmp, ndb_dnid_cmp );
+ if ( !dptr )
+ slow = 1;
+ }
+
+ rdns.nr_num = 0;
+
+ op.o_hdr = &ohdr;
+ op.o_bd = be;
+ op.o_tmpmemctx = NULL;
+ op.o_tmpmfuncs = &ch_mfuncs;
+
+ if ( !slow ) {
+ rc = ndb_next_id( be, myNdb, &e->e_id );
+ if ( rc ) {
+ snprintf( text->bv_val, text->bv_len,
+ "next_id failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
+ return rc;
+ }
+ }
+
+ if ( !myPutTxn )
+ myPutTxn = myNdb->startTransaction();
+ if ( !myPutTxn ) {
+ snprintf( text->bv_val, text->bv_len,
+ "start_transaction failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ return NOID;
+ }
+
+ /* add dn2id indices */
+ ndb_dn2rdns( &e->e_name, &rdns );
+ NA.rdns = &rdns;
+ NA.e = e;
+ NA.ndb = myNdb;
+ NA.txn = myPutTxn;
+ if ( slow ) {
+ rc = ndb_tool_next_id( &op, &NA, text, 0 );
+ if( rc != 0 ) {
+ goto done;
+ }
+ } else {
+ rc = ndb_entry_put_info( be, &NA, 0 );
+ if ( rc != 0 ) {
+ goto done;
+ }
+ }
+
+ /* id2entry index */
+ rc = ndb_entry_put_data( be, &NA );
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "ndb_entry_put_data failed: %s (%d)",
+ myNdb->getNdbError().message, myNdb->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ goto done;
+ }
+
+done:
+ if( rc == 0 ) {
+ myPutCnt++;
+ if ( !( myPutCnt & 0x0f )) {
+ rc = myPutTxn->execute(NdbTransaction::Commit);
+ if( rc != 0 ) {
+ snprintf( text->bv_val, text->bv_len,
+ "txn_commit failed: %s (%d)",
+ myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ e->e_id = NOID;
+ }
+ myPutTxn->close();
+ myPutTxn = NULL;
+ }
+ } else {
+ snprintf( text->bv_val, text->bv_len,
+ "txn_aborted! %s (%d)",
+ myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
+ Debug( LDAP_DEBUG_ANY,
+ "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
+ text->bv_val, 0, 0 );
+ e->e_id = NOID;
+ myPutTxn->close();
+ }
+
+ return e->e_id;
+}
+
+extern "C"
+int ndb_tool_entry_reindex(
+ BackendDB *be,
+ ID id,
+ AttributeDescription **adv )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "=> " LDAP_XSTRING(ndb_tool_entry_reindex) "( %ld )\n",
+ (long) id, 0, 0 );
+
+ return 0;
+}
+
+extern "C"
+ID ndb_tool_entry_modify(
+ BackendDB *be,
+ Entry *e,
+ struct berval *text )
+{
+ struct ndb_info *ni = (struct ndb_info *) be->be_private;
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> " LDAP_XSTRING(ndb_tool_entry_modify) "( %ld, \"%s\" )\n",
+ (long) e->e_id, e->e_dn, 0 );
+
+done:
+ return e->e_id;
+}
+