diff options
Diffstat (limited to '')
-rw-r--r-- | servers/slapd/back-ndb/tools.cpp | 544 |
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; +} + |