1 /* tools.cpp - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2008-2009 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by Howard Chu for inclusion
18 * in OpenLDAP Software. This work was sponsored by MySQL.
24 #include <ac/string.h>
31 typedef struct dn_id {
36 #define HOLE_SIZE 4096
37 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
38 static unsigned nhmax = HOLE_SIZE;
39 static unsigned nholes;
40 static Avlnode *myParents;
43 static NdbTransaction *myScanTxn;
44 static NdbIndexScanOperation *myScanOp;
46 static NdbRecAttr *myScanID, *myScanOC;
47 static NdbRecAttr *myScanDN[NDB_MAX_RDNS];
48 static char myDNbuf[2048];
49 static char myIdbuf[2*sizeof(ID)];
50 static char myOcbuf[NDB_OC_BUFLEN];
51 static NdbRdns myRdns;
53 static NdbTransaction *myPutTxn;
56 static struct berval *myOcList;
57 static struct berval myDn;
60 int ndb_tool_entry_open(
61 BackendDB *be, int mode )
63 struct ndb_info *ni = (struct ndb_info *) be->be_private;
65 myNdb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
66 return myNdb->init(1024);
70 int ndb_tool_entry_close(
74 int rc = myPutTxn->execute(NdbTransaction::Commit);
77 snprintf( text, sizeof(text),
78 "txn_commit failed: %s (%d)",
79 myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
80 Debug( LDAP_DEBUG_ANY,
81 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
91 fprintf( stderr, "Error, entries missing!\n");
92 for (i=0; i<nholes; i++) {
93 fprintf(stderr, " entry %ld: %s\n",
94 holes[i].id, holes[i].dn.bv_val);
103 ID ndb_tool_entry_next(
106 struct ndb_info *ni = (struct ndb_info *) be->be_private;
111 assert( be != NULL );
112 assert( slapMode & SLAP_TOOL_MODE );
114 if ( myScanOp->nextResult() ) {
121 id = myScanID->u_64_value();
124 ber_bvarray_free( myOcList );
126 myOcList = ndb_ref2oclist( myOcbuf, NULL );
127 for ( i=0; i<NDB_MAX_RDNS; i++ ) {
128 if ( myScanDN[i]->isNULL() || !myRdns.nr_buf[i][0] )
133 for ( --i; i>=0; i-- ) {
136 buf = myRdns.nr_buf[i];
138 ptr = lutil_strncopy( ptr, buf, len );
143 myDn.bv_val = myDNbuf;
144 myDn.bv_len = ptr - myDNbuf;
150 ID ndb_tool_entry_first(
153 struct ndb_info *ni = (struct ndb_info *) be->be_private;
156 myScanTxn = myNdb->startTransaction();
160 myScanOp = myScanTxn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
164 if ( myScanOp->readTuples( NdbOperation::LM_CommittedRead, NdbScanOperation::SF_KeyInfo ))
167 myScanID = myScanOp->getValue( EID_COLUMN, myIdbuf );
168 myScanOC = myScanOp->getValue( OCS_COLUMN, myOcbuf );
169 for ( i=0; i<NDB_MAX_RDNS; i++ ) {
170 myScanDN[i] = myScanOp->getValue( i+RDN_COLUMN, myRdns.nr_buf[i] );
172 if ( myScanTxn->execute( NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1 ))
175 return ndb_tool_entry_next( be );
179 ID ndb_tool_dn2id_get(
184 struct ndb_info *ni = (struct ndb_info *) be->be_private;
193 if ( BER_BVISEMPTY(dn) )
197 NA.txn = myNdb->startTransaction();
199 snprintf( text, sizeof(text),
200 "startTransaction failed: %s (%d)",
201 myNdb->getNdbError().message, myNdb->getNdbError().code );
202 Debug( LDAP_DEBUG_ANY,
203 "=> " LDAP_XSTRING(ndb_tool_dn2id_get) ": %s\n",
208 ber_bvarray_free( myOcList );
213 op.o_tmpmemctx = NULL;
214 op.o_tmpmfuncs = &ch_mfuncs;
220 rc = ndb_entry_get_info( &op, &NA, 0, NULL );
232 Entry* ndb_tool_entry_get( BackendDB *be, ID id )
240 assert( be != NULL );
241 assert( slapMode & SLAP_TOOL_MODE );
243 NA.txn = myNdb->startTransaction();
245 snprintf( text, sizeof(text),
246 "start_transaction failed: %s (%d)",
247 myNdb->getNdbError().message, myNdb->getNdbError().code );
248 Debug( LDAP_DEBUG_ANY,
249 "=> " LDAP_XSTRING(ndb_tool_entry_get) ": %s\n",
254 NA.e = entry_alloc();
256 ber_dupbv( &NA.e->e_name, &myDn );
257 dnNormalize( 0, NULL, NULL, &NA.e->e_name, &NA.e->e_nname, NULL );
261 op.o_tmpmemctx = NULL;
262 op.o_tmpmfuncs = &ch_mfuncs;
266 rc = ndb_entry_get_data( &op, &NA, 0 );
277 static struct berval glueval[] = {
282 static int ndb_dnid_cmp( const void *v1, const void *v2 )
284 struct dn_id *dn1 = (struct dn_id *)v1,
285 *dn2 = (struct dn_id *)v2;
286 return ber_bvcmp( &dn1->dn, &dn2->dn );
289 static int ndb_tool_next_id(
295 struct berval ndn = NA->e->e_nname;
298 if (ndn.bv_len == 0) {
303 rc = ndb_entry_get_info( op, NA, 0, NULL );
305 Attribute *a, tmp = {0};
306 if ( !be_issuffix( op->o_bd, &ndn ) ) {
309 dnParent( &ndn, &npdn );
310 NA->e->e_nname = npdn;
312 rc = ndb_tool_next_id( op, NA, text, 1 );
313 NA->e->e_nname = ndn;
318 /* If parent didn't exist, it was created just now
319 * and its ID is now in e->e_id.
321 dptr = (struct dn_id *)ch_malloc( sizeof( struct dn_id ) + npdn.bv_len + 1);
322 dptr->id = NA->e->e_id;
323 dptr->dn.bv_val = (char *)(dptr+1);
324 strcpy(dptr->dn.bv_val, npdn.bv_val );
325 dptr->dn.bv_len = npdn.bv_len;
326 if ( avl_insert( &myParents, dptr, ndb_dnid_cmp, avl_dup_error )) {
330 rc = ndb_next_id( op->o_bd, myNdb, &NA->e->e_id );
332 snprintf( text->bv_val, text->bv_len,
333 "next_id failed: %s (%d)",
334 myNdb->getNdbError().message, myNdb->getNdbError().code );
335 Debug( LDAP_DEBUG_ANY,
336 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
341 NA->e->e_attrs = &tmp;
342 tmp.a_desc = slap_schema.si_ad_objectClass;
343 tmp.a_vals = glueval;
344 tmp.a_nvals = tmp.a_vals;
347 rc = ndb_entry_put_info( op->o_bd, NA, 0 );
352 snprintf( text->bv_val, text->bv_len,
353 "ndb_entry_put_info failed: %s (%d)",
354 myNdb->getNdbError().message, myNdb->getNdbError().code );
355 Debug( LDAP_DEBUG_ANY,
356 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
358 if ( nholes == nhmax - 1 ) {
359 if ( holes == hbuf ) {
360 holes = (dn_id *)ch_malloc( nhmax * sizeof(dn_id) * 2 );
361 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
363 holes = (dn_id *)ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
367 ber_dupbv( &holes[nholes].dn, &ndn );
368 holes[nholes++].id = NA->e->e_id;
370 } else if ( !hole ) {
373 for ( i=0; i<nholes; i++) {
374 if ( holes[i].id == NA->e->e_id ) {
376 free(holes[i].dn.bv_val);
377 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
380 rc = ndb_entry_put_info( op->o_bd, NA, 1 );
382 } else if ( holes[i].id > NA->e->e_id ) {
391 ID ndb_tool_entry_put(
394 struct berval *text )
396 struct ndb_info *ni = (struct ndb_info *) be->be_private;
397 struct dn_id dtmp, *dptr;
404 assert( be != NULL );
405 assert( slapMode & SLAP_TOOL_MODE );
407 assert( text != NULL );
408 assert( text->bv_val != NULL );
409 assert( text->bv_val[0] == '\0' ); /* overconservative? */
411 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(ndb_tool_entry_put)
412 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
414 if ( !be_issuffix( be, &e->e_nname )) {
415 dnParent( &e->e_nname, &dtmp.dn );
416 dptr = (struct dn_id *)avl_find( myParents, &dtmp, ndb_dnid_cmp );
425 op.o_tmpmemctx = NULL;
426 op.o_tmpmfuncs = &ch_mfuncs;
429 rc = ndb_next_id( be, myNdb, &e->e_id );
431 snprintf( text->bv_val, text->bv_len,
432 "next_id failed: %s (%d)",
433 myNdb->getNdbError().message, myNdb->getNdbError().code );
434 Debug( LDAP_DEBUG_ANY,
435 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
441 myPutTxn = myNdb->startTransaction();
443 snprintf( text->bv_val, text->bv_len,
444 "start_transaction failed: %s (%d)",
445 myNdb->getNdbError().message, myNdb->getNdbError().code );
446 Debug( LDAP_DEBUG_ANY,
447 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
448 text->bv_val, 0, 0 );
452 /* add dn2id indices */
453 ndb_dn2rdns( &e->e_name, &rdns );
459 rc = ndb_tool_next_id( &op, &NA, text, 0 );
464 rc = ndb_entry_put_info( be, &NA, 0 );
471 rc = ndb_entry_put_data( be, &NA );
473 snprintf( text->bv_val, text->bv_len,
474 "ndb_entry_put_data failed: %s (%d)",
475 myNdb->getNdbError().message, myNdb->getNdbError().code );
476 Debug( LDAP_DEBUG_ANY,
477 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
478 text->bv_val, 0, 0 );
485 if ( !( myPutCnt & 0x0f )) {
486 rc = myPutTxn->execute(NdbTransaction::Commit);
488 snprintf( text->bv_val, text->bv_len,
489 "txn_commit failed: %s (%d)",
490 myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
491 Debug( LDAP_DEBUG_ANY,
492 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
493 text->bv_val, 0, 0 );
500 snprintf( text->bv_val, text->bv_len,
501 "txn_aborted! %s (%d)",
502 myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
503 Debug( LDAP_DEBUG_ANY,
504 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
505 text->bv_val, 0, 0 );
514 int ndb_tool_entry_reindex(
517 AttributeDescription **adv )
519 struct ndb_info *ni = (struct ndb_info *) be->be_private;
521 Debug( LDAP_DEBUG_ARGS,
522 "=> " LDAP_XSTRING(ndb_tool_entry_reindex) "( %ld )\n",
529 ID ndb_tool_entry_modify(
532 struct berval *text )
534 struct ndb_info *ni = (struct ndb_info *) be->be_private;
537 Debug( LDAP_DEBUG_TRACE,
538 "=> " LDAP_XSTRING(ndb_tool_entry_modify) "( %ld, \"%s\" )\n",
539 (long) e->e_id, e->e_dn, 0 );