Back to index

openldap  2.4.31
tools.cpp
Go to the documentation of this file.
00001 /* tools.cpp - tools for slap tools */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Howard Chu for inclusion
00018  * in OpenLDAP Software. This work was sponsored by MySQL.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/string.h>
00025 #include <ac/errno.h>
00026 
00027 #include "lutil.h"
00028 
00029 #include "back-ndb.h"
00030 
00031 typedef struct dn_id {
00032        ID id;
00033        struct berval dn;
00034 } dn_id;
00035 
00036 #define       HOLE_SIZE     4096
00037 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
00038 static unsigned nhmax = HOLE_SIZE;
00039 static unsigned nholes;
00040 static Avlnode *myParents;
00041 
00042 static Ndb *myNdb;
00043 static NdbTransaction *myScanTxn;
00044 static NdbIndexScanOperation *myScanOp;
00045 
00046 static NdbRecAttr *myScanID, *myScanOC;
00047 static NdbRecAttr *myScanDN[NDB_MAX_RDNS];
00048 static char myDNbuf[2048];
00049 static char myIdbuf[2*sizeof(ID)];
00050 static char myOcbuf[NDB_OC_BUFLEN];
00051 static NdbRdns myRdns;
00052 
00053 static NdbTransaction *myPutTxn;
00054 static int myPutCnt;
00055 
00056 static struct berval *myOcList;
00057 static struct berval myDn;
00058 
00059 extern "C"
00060 int ndb_tool_entry_open(
00061        BackendDB *be, int mode )
00062 {
00063        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00064 
00065        myNdb = new Ndb( ni->ni_cluster[0], ni->ni_dbname );
00066        return myNdb->init(1024);
00067 }
00068 
00069 extern "C"
00070 int ndb_tool_entry_close(
00071        BackendDB *be )
00072 {
00073        if ( myPutTxn ) {
00074               int rc = myPutTxn->execute(NdbTransaction::Commit);
00075               if( rc != 0 ) {
00076                      char text[1024];
00077                      snprintf( text, sizeof(text),
00078                                    "txn_commit failed: %s (%d)",
00079                                    myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
00080                      Debug( LDAP_DEBUG_ANY,
00081                             "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
00082                             text, 0, 0 );
00083               }
00084               myPutTxn->close();
00085               myPutTxn = NULL;
00086        }
00087        myPutCnt = 0;
00088 
00089        if( nholes ) {
00090               unsigned i;
00091               fprintf( stderr, "Error, entries missing!\n");
00092               for (i=0; i<nholes; i++) {
00093                      fprintf(stderr, "  entry %ld: %s\n",
00094                             holes[i].id, holes[i].dn.bv_val);
00095               }
00096               return -1;
00097        }
00098 
00099        return 0;
00100 }
00101 
00102 extern "C"
00103 ID ndb_tool_entry_next(
00104        BackendDB *be )
00105 {
00106        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00107        char *ptr;
00108        ID id;
00109        int i;
00110 
00111        assert( be != NULL );
00112        assert( slapMode & SLAP_TOOL_MODE );
00113 
00114        if ( myScanOp->nextResult() ) {
00115               myScanOp->close();
00116               myScanOp = NULL;
00117               myScanTxn->close();
00118               myScanTxn = NULL;
00119               return NOID;
00120        }
00121        id = myScanID->u_64_value();
00122 
00123        if ( myOcList ) {
00124               ber_bvarray_free( myOcList );
00125        }
00126        myOcList = ndb_ref2oclist( myOcbuf, NULL );
00127        for ( i=0; i<NDB_MAX_RDNS; i++ ) {
00128               if ( myScanDN[i]->isNULL() || !myRdns.nr_buf[i][0] )
00129                      break;
00130        }
00131        myRdns.nr_num = i;
00132        ptr = myDNbuf;
00133        for ( --i; i>=0; i-- ) {
00134               char *buf;
00135               int len;
00136               buf = myRdns.nr_buf[i];
00137               len = *buf++;
00138               ptr = lutil_strncopy( ptr, buf, len );
00139               if ( i )
00140                      *ptr++ = ',';
00141        }
00142        *ptr = '\0';
00143        myDn.bv_val = myDNbuf;
00144        myDn.bv_len = ptr - myDNbuf;
00145 
00146        return id;
00147 }
00148 
00149 extern "C"
00150 ID ndb_tool_entry_first(
00151        BackendDB *be )
00152 {
00153        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00154        int i;
00155 
00156        myScanTxn = myNdb->startTransaction();
00157        if ( !myScanTxn )
00158               return NOID;
00159 
00160        myScanOp = myScanTxn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
00161        if ( !myScanOp )
00162               return NOID;
00163 
00164        if ( myScanOp->readTuples( NdbOperation::LM_CommittedRead, NdbScanOperation::SF_KeyInfo ))
00165               return NOID;
00166 
00167        myScanID = myScanOp->getValue( EID_COLUMN, myIdbuf );
00168        myScanOC = myScanOp->getValue( OCS_COLUMN, myOcbuf );
00169        for ( i=0; i<NDB_MAX_RDNS; i++ ) {
00170               myScanDN[i] = myScanOp->getValue( i+RDN_COLUMN, myRdns.nr_buf[i] );
00171        }
00172        if ( myScanTxn->execute( NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1 ))
00173               return NOID;
00174 
00175        return ndb_tool_entry_next( be );
00176 }
00177 
00178 extern "C"
00179 ID ndb_tool_dn2id_get(
00180        Backend *be,
00181        struct berval *dn
00182 )
00183 {
00184        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00185        NdbArgs NA;
00186        NdbRdns rdns;
00187        Entry e;
00188        char text[1024];
00189        Operation op = {0};
00190        Opheader ohdr = {0};
00191        int rc;
00192 
00193        if ( BER_BVISEMPTY(dn) )
00194               return 0;
00195 
00196        NA.ndb = myNdb;
00197        NA.txn = myNdb->startTransaction();
00198        if ( !NA.txn ) {
00199               snprintf( text, sizeof(text),
00200                      "startTransaction failed: %s (%d)",
00201                      myNdb->getNdbError().message, myNdb->getNdbError().code );
00202               Debug( LDAP_DEBUG_ANY,
00203                      "=> " LDAP_XSTRING(ndb_tool_dn2id_get) ": %s\n",
00204                       text, 0, 0 );
00205               return NOID;
00206        }
00207        if ( myOcList ) {
00208               ber_bvarray_free( myOcList );
00209               myOcList = NULL;
00210        }
00211        op.o_hdr = &ohdr;
00212        op.o_bd = be;
00213        op.o_tmpmemctx = NULL;
00214        op.o_tmpmfuncs = &ch_mfuncs;
00215 
00216        NA.e = &e;
00217        e.e_name = *dn;
00218        NA.rdns = &rdns;
00219        NA.ocs = NULL;
00220        rc = ndb_entry_get_info( &op, &NA, 0, NULL );
00221        myOcList = NA.ocs;
00222        NA.txn->close();
00223        if ( rc )
00224               return NOID;
00225        
00226        myDn = *dn;
00227 
00228        return e.e_id;
00229 }
00230 
00231 extern "C"
00232 Entry* ndb_tool_entry_get( BackendDB *be, ID id )
00233 {
00234        NdbArgs NA;
00235        int rc;
00236        char text[1024];
00237        Operation op = {0};
00238        Opheader ohdr = {0};
00239 
00240        assert( be != NULL );
00241        assert( slapMode & SLAP_TOOL_MODE );
00242 
00243        NA.txn = myNdb->startTransaction();
00244        if ( !NA.txn ) {
00245               snprintf( text, sizeof(text),
00246                      "start_transaction failed: %s (%d)",
00247                      myNdb->getNdbError().message, myNdb->getNdbError().code );
00248               Debug( LDAP_DEBUG_ANY,
00249                      "=> " LDAP_XSTRING(ndb_tool_entry_get) ": %s\n",
00250                       text, 0, 0 );
00251               return NULL;
00252        }
00253 
00254        NA.e = entry_alloc();
00255        NA.e->e_id = id;
00256        ber_dupbv( &NA.e->e_name, &myDn );
00257        dnNormalize( 0, NULL, NULL, &NA.e->e_name, &NA.e->e_nname, NULL );
00258 
00259        op.o_hdr = &ohdr;
00260        op.o_bd = be;
00261        op.o_tmpmemctx = NULL;
00262        op.o_tmpmfuncs = &ch_mfuncs;
00263 
00264        NA.ndb = myNdb;
00265        NA.ocs = myOcList;
00266        rc = ndb_entry_get_data( &op, &NA, 0 );
00267 
00268        if ( rc ) {
00269               entry_free( NA.e );
00270               NA.e = NULL;
00271        }
00272        NA.txn->close();
00273 
00274        return NA.e;
00275 }
00276 
00277 static struct berval glueval[] = {
00278        BER_BVC("glue"),
00279        BER_BVNULL
00280 };
00281 
00282 static int ndb_dnid_cmp( const void *v1, const void *v2 )
00283 {
00284        struct dn_id *dn1 = (struct dn_id *)v1,
00285               *dn2 = (struct dn_id *)v2;
00286        return ber_bvcmp( &dn1->dn, &dn2->dn );
00287 }
00288 
00289 static int ndb_tool_next_id(
00290        Operation *op,
00291        NdbArgs *NA,
00292        struct berval *text,
00293        int hole )
00294 {
00295        struct berval ndn = NA->e->e_nname;
00296        int rc;
00297 
00298        if (ndn.bv_len == 0) {
00299               NA->e->e_id = 0;
00300               return 0;
00301        }
00302 
00303        rc = ndb_entry_get_info( op, NA, 0, NULL );
00304        if ( rc ) {
00305               Attribute *a, tmp = {0};
00306               if ( !be_issuffix( op->o_bd, &ndn ) ) {
00307                      struct dn_id *dptr;
00308                      struct berval npdn;
00309                      dnParent( &ndn, &npdn );
00310                      NA->e->e_nname = npdn;
00311                      NA->rdns->nr_num--;
00312                      rc = ndb_tool_next_id( op, NA, text, 1 );
00313                      NA->e->e_nname = ndn;
00314                      NA->rdns->nr_num++;
00315                      if ( rc ) {
00316                             return rc;
00317                      }
00318                      /* If parent didn't exist, it was created just now
00319                       * and its ID is now in e->e_id.
00320                       */
00321                      dptr = (struct dn_id *)ch_malloc( sizeof( struct dn_id ) + npdn.bv_len + 1);
00322                      dptr->id = NA->e->e_id;
00323                      dptr->dn.bv_val = (char *)(dptr+1);
00324                      strcpy(dptr->dn.bv_val, npdn.bv_val );
00325                      dptr->dn.bv_len = npdn.bv_len;
00326                      if ( avl_insert( &myParents, dptr, ndb_dnid_cmp, avl_dup_error )) {
00327                             ch_free( dptr );
00328                      }
00329               }
00330               rc = ndb_next_id( op->o_bd, myNdb, &NA->e->e_id );
00331               if ( rc ) {
00332                      snprintf( text->bv_val, text->bv_len,
00333                             "next_id failed: %s (%d)",
00334                             myNdb->getNdbError().message, myNdb->getNdbError().code );
00335                      Debug( LDAP_DEBUG_ANY,
00336                             "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
00337                      return rc;
00338               }
00339               if ( hole ) {
00340                      a = NA->e->e_attrs;
00341                      NA->e->e_attrs = &tmp;
00342                      tmp.a_desc = slap_schema.si_ad_objectClass;
00343                      tmp.a_vals = glueval;
00344                      tmp.a_nvals = tmp.a_vals;
00345                      tmp.a_numvals = 1;
00346               }
00347               rc = ndb_entry_put_info( op->o_bd, NA, 0 );
00348               if ( hole ) {
00349                      NA->e->e_attrs = a;
00350               }
00351               if ( rc ) {
00352                      snprintf( text->bv_val, text->bv_len, 
00353                             "ndb_entry_put_info failed: %s (%d)",
00354                             myNdb->getNdbError().message, myNdb->getNdbError().code );
00355               Debug( LDAP_DEBUG_ANY,
00356                      "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
00357               } else if ( hole ) {
00358                      if ( nholes == nhmax - 1 ) {
00359                             if ( holes == hbuf ) {
00360                                    holes = (dn_id *)ch_malloc( nhmax * sizeof(dn_id) * 2 );
00361                                    AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
00362                             } else {
00363                                    holes = (dn_id *)ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
00364                             }
00365                             nhmax *= 2;
00366                      }
00367                      ber_dupbv( &holes[nholes].dn, &ndn );
00368                      holes[nholes++].id = NA->e->e_id;
00369               }
00370        } else if ( !hole ) {
00371               unsigned i;
00372 
00373               for ( i=0; i<nholes; i++) {
00374                      if ( holes[i].id == NA->e->e_id ) {
00375                             int j;
00376                             free(holes[i].dn.bv_val);
00377                             for (j=i;j<nholes;j++) holes[j] = holes[j+1];
00378                             holes[j].id = 0;
00379                             nholes--;
00380                             rc = ndb_entry_put_info( op->o_bd, NA, 1 );
00381                             break;
00382                      } else if ( holes[i].id > NA->e->e_id ) {
00383                             break;
00384                      }
00385               }
00386        }
00387        return rc;
00388 }
00389 
00390 extern "C"
00391 ID ndb_tool_entry_put(
00392        BackendDB *be,
00393        Entry *e,
00394        struct berval *text )
00395 {
00396        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00397        struct dn_id dtmp, *dptr;
00398        NdbArgs NA;
00399        NdbRdns rdns;
00400        int rc, slow = 0;
00401        Operation op = {0};
00402        Opheader ohdr = {0};
00403 
00404        assert( be != NULL );
00405        assert( slapMode & SLAP_TOOL_MODE );
00406 
00407        assert( text != NULL );
00408        assert( text->bv_val != NULL );
00409        assert( text->bv_val[0] == '\0' ); /* overconservative? */
00410 
00411        Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(ndb_tool_entry_put)
00412               "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
00413 
00414        if ( !be_issuffix( be, &e->e_nname )) {
00415               dnParent( &e->e_nname, &dtmp.dn );
00416               dptr = (struct dn_id *)avl_find( myParents, &dtmp, ndb_dnid_cmp );
00417               if ( !dptr )
00418                      slow = 1;
00419        }
00420 
00421        rdns.nr_num = 0;
00422 
00423        op.o_hdr = &ohdr;
00424        op.o_bd = be;
00425        op.o_tmpmemctx = NULL;
00426        op.o_tmpmfuncs = &ch_mfuncs;
00427 
00428        if ( !slow ) {
00429               rc = ndb_next_id( be, myNdb, &e->e_id );
00430               if ( rc ) {
00431                      snprintf( text->bv_val, text->bv_len,
00432                             "next_id failed: %s (%d)",
00433                             myNdb->getNdbError().message, myNdb->getNdbError().code );
00434                      Debug( LDAP_DEBUG_ANY,
00435                             "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 );
00436                      return rc;
00437               }
00438        }
00439 
00440        if ( !myPutTxn )
00441               myPutTxn = myNdb->startTransaction();
00442        if ( !myPutTxn ) {
00443               snprintf( text->bv_val, text->bv_len,
00444                      "start_transaction failed: %s (%d)",
00445                      myNdb->getNdbError().message, myNdb->getNdbError().code );
00446               Debug( LDAP_DEBUG_ANY,
00447                      "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
00448                       text->bv_val, 0, 0 );
00449               return NOID;
00450        }
00451 
00452        /* add dn2id indices */
00453        ndb_dn2rdns( &e->e_name, &rdns );
00454        NA.rdns = &rdns;
00455        NA.e = e;
00456        NA.ndb = myNdb;
00457        NA.txn = myPutTxn;
00458        if ( slow ) {
00459               rc = ndb_tool_next_id( &op, &NA, text, 0 );
00460               if( rc != 0 ) {
00461                      goto done;
00462               }
00463        } else {
00464               rc = ndb_entry_put_info( be, &NA, 0 );
00465               if ( rc != 0 ) {
00466                      goto done;
00467               }
00468        }
00469 
00470        /* id2entry index */
00471        rc = ndb_entry_put_data( be, &NA );
00472        if( rc != 0 ) {
00473               snprintf( text->bv_val, text->bv_len,
00474                             "ndb_entry_put_data failed: %s (%d)",
00475                             myNdb->getNdbError().message, myNdb->getNdbError().code );
00476               Debug( LDAP_DEBUG_ANY,
00477                      "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
00478                      text->bv_val, 0, 0 );
00479               goto done;
00480        }
00481 
00482 done:
00483        if( rc == 0 ) {
00484               myPutCnt++;
00485               if ( !( myPutCnt & 0x0f )) {
00486                      rc = myPutTxn->execute(NdbTransaction::Commit);
00487                      if( rc != 0 ) {
00488                             snprintf( text->bv_val, text->bv_len,
00489                                    "txn_commit failed: %s (%d)",
00490                                    myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
00491                             Debug( LDAP_DEBUG_ANY,
00492                                    "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
00493                                    text->bv_val, 0, 0 );
00494                             e->e_id = NOID;
00495                      }
00496                      myPutTxn->close();
00497                      myPutTxn = NULL;
00498               }
00499        } else {
00500               snprintf( text->bv_val, text->bv_len,
00501                      "txn_aborted! %s (%d)",
00502                      myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
00503               Debug( LDAP_DEBUG_ANY,
00504                      "=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n",
00505                      text->bv_val, 0, 0 );
00506               e->e_id = NOID;
00507               myPutTxn->close();
00508        }
00509 
00510        return e->e_id;
00511 }
00512 
00513 extern "C"
00514 int ndb_tool_entry_reindex(
00515        BackendDB *be,
00516        ID id,
00517        AttributeDescription **adv )
00518 {
00519        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00520 
00521        Debug( LDAP_DEBUG_ARGS,
00522               "=> " LDAP_XSTRING(ndb_tool_entry_reindex) "( %ld )\n",
00523               (long) id, 0, 0 );
00524 
00525        return 0;
00526 }
00527 
00528 extern "C"
00529 ID ndb_tool_entry_modify(
00530        BackendDB *be,
00531        Entry *e,
00532        struct berval *text )
00533 {
00534        struct ndb_info *ni = (struct ndb_info *) be->be_private;
00535        int rc;
00536 
00537        Debug( LDAP_DEBUG_TRACE,
00538               "=> " LDAP_XSTRING(ndb_tool_entry_modify) "( %ld, \"%s\" )\n",
00539               (long) e->e_id, e->e_dn, 0 );
00540 
00541 done:
00542        return e->e_id;
00543 }
00544