1 /* tools.cpp - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2008 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 );
127 for ( i=0; i<NDB_MAX_RDNS; i++ ) {
128 if ( myScanDN[i]->isNULL() || !myRdns.nr_buf[i] )
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;
191 if ( BER_BVISEMPTY(dn) )
195 NA.txn = myNdb->startTransaction();
197 snprintf( text, sizeof(text),
198 "startTransaction failed: %s (%d)",
199 myNdb->getNdbError().message, myNdb->getNdbError().code );
200 Debug( LDAP_DEBUG_ANY,
201 "=> " LDAP_XSTRING(ndb_tool_dn2id_get) ": %s\n",
206 ber_bvarray_free( myOcList );
213 rc = ndb_entry_get_info( be, &NA, 0, NULL );
225 Entry* ndb_tool_entry_get( BackendDB *be, ID id )
231 assert( be != NULL );
232 assert( slapMode & SLAP_TOOL_MODE );
234 NA.txn = myNdb->startTransaction();
236 snprintf( text, sizeof(text),
237 "start_transaction failed: %s (%d)",
238 myNdb->getNdbError().message, myNdb->getNdbError().code );
239 Debug( LDAP_DEBUG_ANY,
240 "=> " LDAP_XSTRING(ndb_tool_entry_get) ": %s\n",
245 NA.e = entry_alloc();
247 ber_dupbv( &NA.e->e_name, &myDn );
248 dnNormalize( 0, NULL, NULL, &NA.e->e_name, &NA.e->e_nname, NULL );
253 rc = ndb_entry_get_data( be, &NA, 0 );
264 static struct berval glueval[] = {
269 static int ndb_dnid_cmp( const void *v1, const void *v2 )
271 struct dn_id *dn1 = (struct dn_id *)v1,
272 *dn2 = (struct dn_id *)v2;
273 return ber_bvcmp( &dn1->dn, &dn2->dn );
276 static int ndb_tool_next_id(
282 struct berval ndn = NA->e->e_nname;
285 if (ndn.bv_len == 0) {
290 rc = ndb_entry_get_info( be, NA, 0, NULL );
292 Attribute *a, tmp = {0};
293 if ( !be_issuffix( be, &ndn ) ) {
296 dnParent( &ndn, &npdn );
297 NA->e->e_nname = npdn;
299 rc = ndb_tool_next_id( be, NA, text, 1 );
300 NA->e->e_nname = ndn;
305 /* If parent didn't exist, it was created just now
306 * and its ID is now in e->e_id.
308 dptr = (struct dn_id *)ch_malloc( sizeof( struct dn_id ) + npdn.bv_len + 1);
309 dptr->id = NA->e->e_id;
310 dptr->dn.bv_val = (char *)(dptr+1);
311 strcpy(dptr->dn.bv_val, npdn.bv_val );
312 dptr->dn.bv_len = npdn.bv_len;
313 if ( avl_insert( &myParents, dptr, ndb_dnid_cmp, avl_dup_error )) {
317 rc = ndb_next_id( be, myNdb, &NA->e->e_id );
319 snprintf( text->bv_val, text->bv_len,
320 "next_id failed: %s (%d)",
321 myNdb->getNdbError().message, myNdb->getNdbError().code );
322 Debug( LDAP_DEBUG_ANY,
323 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
328 NA->e->e_attrs = &tmp;
329 tmp.a_desc = slap_schema.si_ad_objectClass;
330 tmp.a_vals = glueval;
331 tmp.a_nvals = tmp.a_vals;
334 rc = ndb_entry_put_info( be, NA, 0 );
339 snprintf( text->bv_val, text->bv_len,
340 "ndb_entry_put_info failed: %s (%d)",
341 myNdb->getNdbError().message, myNdb->getNdbError().code );
342 Debug( LDAP_DEBUG_ANY,
343 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
345 if ( nholes == nhmax - 1 ) {
346 if ( holes == hbuf ) {
347 holes = (dn_id *)ch_malloc( nhmax * sizeof(dn_id) * 2 );
348 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
350 holes = (dn_id *)ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
354 ber_dupbv( &holes[nholes].dn, &ndn );
355 holes[nholes++].id = NA->e->e_id;
357 } else if ( !hole ) {
360 for ( i=0; i<nholes; i++) {
361 if ( holes[i].id == NA->e->e_id ) {
363 free(holes[i].dn.bv_val);
364 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
367 rc = ndb_entry_put_info( be, NA, 1 );
369 } else if ( holes[i].id > NA->e->e_id ) {
378 ID ndb_tool_entry_put(
381 struct berval *text )
383 struct ndb_info *ni = (struct ndb_info *) be->be_private;
384 struct dn_id dtmp, *dptr;
389 assert( be != NULL );
390 assert( slapMode & SLAP_TOOL_MODE );
392 assert( text != NULL );
393 assert( text->bv_val != NULL );
394 assert( text->bv_val[0] == '\0' ); /* overconservative? */
396 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(ndb_tool_entry_put)
397 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
399 if ( !be_issuffix( be, &e->e_nname )) {
400 dnParent( &e->e_nname, &dtmp.dn );
401 dptr = (struct dn_id *)avl_find( myParents, &dtmp, ndb_dnid_cmp );
409 rc = ndb_next_id( be, myNdb, &e->e_id );
411 snprintf( text->bv_val, text->bv_len,
412 "next_id failed: %s (%d)",
413 myNdb->getNdbError().message, myNdb->getNdbError().code );
414 Debug( LDAP_DEBUG_ANY,
415 "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
421 myPutTxn = myNdb->startTransaction();
423 snprintf( text->bv_val, text->bv_len,
424 "start_transaction failed: %s (%d)",
425 myNdb->getNdbError().message, myNdb->getNdbError().code );
426 Debug( LDAP_DEBUG_ANY,
427 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
428 text->bv_val, 0, 0 );
432 /* add dn2id indices */
433 ndb_dn2rdns( &e->e_name, &rdns );
439 rc = ndb_tool_next_id( be, &NA, text, 0 );
444 rc = ndb_entry_put_info( be, &NA, 0 );
451 rc = ndb_entry_put_data( be, &NA, 0 );
453 snprintf( text->bv_val, text->bv_len,
454 "ndb_entry_put_data failed: %s (%d)",
455 myNdb->getNdbError().message, myNdb->getNdbError().code );
456 Debug( LDAP_DEBUG_ANY,
457 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
458 text->bv_val, 0, 0 );
465 if ( !( myPutCnt & 0x0f )) {
466 rc = myPutTxn->execute(NdbTransaction::Commit);
468 snprintf( text->bv_val, text->bv_len,
469 "txn_commit failed: %s (%d)",
470 myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
471 Debug( LDAP_DEBUG_ANY,
472 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
473 text->bv_val, 0, 0 );
480 snprintf( text->bv_val, text->bv_len,
481 "txn_aborted! %s (%d)",
482 myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
483 Debug( LDAP_DEBUG_ANY,
484 "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
485 text->bv_val, 0, 0 );
494 int ndb_tool_entry_reindex(
497 AttributeDescription **adv )
499 struct ndb_info *ni = (struct ndb_info *) be->be_private;
501 Debug( LDAP_DEBUG_ARGS,
502 "=> " LDAP_XSTRING(ndb_tool_entry_reindex) "( %ld )\n",
509 ID ndb_tool_entry_modify(
512 struct berval *text )
514 struct ndb_info *ni = (struct ndb_info *) be->be_private;
517 Debug( LDAP_DEBUG_TRACE,
518 "=> " LDAP_XSTRING(ndb_tool_entry_modify) "( %ld, \"%s\" )\n",
519 (long) e->e_id, e->e_dn, 0 );