Back to index

openldap  2.4.31
tools.c
Go to the documentation of this file.
00001 /* tools.c - tools for slap tools */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-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 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 #include <ac/errno.h>
00022 
00023 #define AVL_INTERNAL
00024 #include "back-bdb.h"
00025 #include "idl.h"
00026 
00027 static DBC *cursor = NULL;
00028 static DBT key, data;
00029 static EntryHeader eh;
00030 static ID nid, previd = NOID;
00031 static char ehbuf[16];
00032 
00033 typedef struct dn_id {
00034        ID id;
00035        struct berval dn;
00036 } dn_id;
00037 
00038 #define       HOLE_SIZE     4096
00039 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
00040 static unsigned nhmax = HOLE_SIZE;
00041 static unsigned nholes;
00042 
00043 static int index_nattrs;
00044 
00045 static struct berval *tool_base;
00046 static int           tool_scope;
00047 static Filter        *tool_filter;
00048 static Entry         *tool_next_entry;
00049 
00050 #ifdef BDB_TOOL_IDL_CACHING
00051 #define bdb_tool_idl_cmp           BDB_SYMBOL(tool_idl_cmp)
00052 #define bdb_tool_idl_flush_one            BDB_SYMBOL(tool_idl_flush_one)
00053 #define bdb_tool_idl_flush         BDB_SYMBOL(tool_idl_flush)
00054 
00055 static int bdb_tool_idl_flush( BackendDB *be );
00056 
00057 #define       IDBLOCK       1024
00058 
00059 typedef struct bdb_tool_idl_cache_entry {
00060        struct bdb_tool_idl_cache_entry *next;
00061        ID ids[IDBLOCK];
00062 } bdb_tool_idl_cache_entry;
00063  
00064 typedef struct bdb_tool_idl_cache {
00065        struct berval kstr;
00066        bdb_tool_idl_cache_entry *head, *tail;
00067        ID first, last;
00068        int count;
00069 } bdb_tool_idl_cache;
00070 
00071 static bdb_tool_idl_cache_entry *bdb_tool_idl_free_list;
00072 #endif /* BDB_TOOL_IDL_CACHING */
00073 
00074 static ID bdb_tool_ix_id;
00075 static Operation *bdb_tool_ix_op;
00076 static int *bdb_tool_index_threads, bdb_tool_index_tcount;
00077 static void *bdb_tool_index_rec;
00078 static struct bdb_info *bdb_tool_info;
00079 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex;
00080 static ldap_pvt_thread_cond_t bdb_tool_index_cond_main;
00081 static ldap_pvt_thread_cond_t bdb_tool_index_cond_work;
00082 
00083 #if DB_VERSION_FULL >= 0x04060000
00084 #define       USE_TRICKLE   1
00085 #else
00086 /* Seems to slow things down too much in BDB 4.5 */
00087 #undef USE_TRICKLE
00088 #endif
00089 
00090 #ifdef USE_TRICKLE
00091 static ldap_pvt_thread_mutex_t bdb_tool_trickle_mutex;
00092 static ldap_pvt_thread_cond_t bdb_tool_trickle_cond;
00093 static ldap_pvt_thread_cond_t bdb_tool_trickle_cond_end;
00094 
00095 static void * bdb_tool_trickle_task( void *ctx, void *ptr );
00096 static int bdb_tool_trickle_active;
00097 #endif
00098 
00099 static void * bdb_tool_index_task( void *ctx, void *ptr );
00100 
00101 static int
00102 bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
00103 
00104 static int bdb_tool_threads;
00105 
00106 int bdb_tool_entry_open(
00107        BackendDB *be, int mode )
00108 {
00109        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00110 
00111        /* initialize key and data thangs */
00112        DBTzero( &key );
00113        DBTzero( &data );
00114        key.flags = DB_DBT_USERMEM;
00115        key.data = &nid;
00116        key.size = key.ulen = sizeof( nid );
00117        data.flags = DB_DBT_USERMEM;
00118 
00119        if (cursor == NULL) {
00120               int rc = bdb->bi_id2entry->bdi_db->cursor(
00121                      bdb->bi_id2entry->bdi_db, bdb->bi_cache.c_txn, &cursor,
00122                      bdb->bi_db_opflags );
00123               if( rc != 0 ) {
00124                      return -1;
00125               }
00126        }
00127 
00128        /* Set up for threaded slapindex */
00129        if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
00130               if ( !bdb_tool_info ) {
00131 #ifdef USE_TRICKLE
00132                      ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex );
00133                      ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond );
00134                      ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond_end );
00135                      ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_trickle_task, bdb->bi_dbenv );
00136 #endif
00137 
00138                      ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex );
00139                      ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main );
00140                      ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work );
00141                      if ( bdb->bi_nattrs ) {
00142                             int i;
00143                             bdb_tool_threads = slap_tool_thread_max - 1;
00144                             if ( bdb_tool_threads > 1 ) {
00145                                    bdb_tool_index_threads = ch_malloc( bdb_tool_threads * sizeof( int ));
00146                                    bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec ));
00147                                    bdb_tool_index_tcount = bdb_tool_threads - 1;
00148                                    for (i=1; i<bdb_tool_threads; i++) {
00149                                           int *ptr = ch_malloc( sizeof( int ));
00150                                           *ptr = i;
00151                                           ldap_pvt_thread_pool_submit( &connection_pool,
00152                                                  bdb_tool_index_task, ptr );
00153                                    }
00154                             }
00155                      }
00156                      bdb_tool_info = bdb;
00157               }
00158        }
00159 
00160        return 0;
00161 }
00162 
00163 int bdb_tool_entry_close(
00164        BackendDB *be )
00165 {
00166        if ( bdb_tool_info ) {
00167               slapd_shutdown = 1;
00168 #ifdef USE_TRICKLE
00169               ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
00170 
00171               /* trickle thread may not have started yet */
00172               while ( !bdb_tool_trickle_active )
00173                      ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond_end,
00174                                    &bdb_tool_trickle_mutex );
00175 
00176               ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
00177               while ( bdb_tool_trickle_active )
00178                      ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond_end,
00179                                    &bdb_tool_trickle_mutex );
00180               ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
00181 #endif
00182               if ( bdb_tool_threads > 1 ) {
00183                      ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
00184 
00185                      /* There might still be some threads starting */
00186                      while ( bdb_tool_index_tcount > 0 ) {
00187                             ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
00188                                           &bdb_tool_index_mutex );
00189                      }
00190 
00191                      bdb_tool_index_tcount = bdb_tool_threads - 1;
00192                      ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
00193 
00194                      /* Make sure all threads are stopped */
00195                      while ( bdb_tool_index_tcount > 0 ) {
00196                             ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
00197                                    &bdb_tool_index_mutex );
00198                      }
00199                      ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
00200 
00201                      ch_free( bdb_tool_index_threads );
00202                      ch_free( bdb_tool_index_rec );
00203                      bdb_tool_index_tcount = bdb_tool_threads - 1;
00204               }
00205               bdb_tool_info = NULL;
00206               slapd_shutdown = 0;
00207        }
00208 
00209        if( eh.bv.bv_val ) {
00210               ch_free( eh.bv.bv_val );
00211               eh.bv.bv_val = NULL;
00212        }
00213 
00214        if( cursor ) {
00215               cursor->c_close( cursor );
00216               cursor = NULL;
00217        }
00218 
00219 #ifdef BDB_TOOL_IDL_CACHING
00220        bdb_tool_idl_flush( be );
00221 #endif
00222 
00223        if( nholes ) {
00224               unsigned i;
00225               fprintf( stderr, "Error, entries missing!\n");
00226               for (i=0; i<nholes; i++) {
00227                      fprintf(stderr, "  entry %ld: %s\n",
00228                             holes[i].id, holes[i].dn.bv_val);
00229               }
00230               return -1;
00231        }
00232                      
00233        return 0;
00234 }
00235 
00236 ID
00237 bdb_tool_entry_first_x(
00238        BackendDB *be,
00239        struct berval *base,
00240        int scope,
00241        Filter *f )
00242 {
00243        tool_base = base;
00244        tool_scope = scope;
00245        tool_filter = f;
00246        
00247        return bdb_tool_entry_next( be );
00248 }
00249 
00250 ID bdb_tool_entry_next(
00251        BackendDB *be )
00252 {
00253        int rc;
00254        ID id;
00255        struct bdb_info *bdb;
00256 
00257        assert( be != NULL );
00258        assert( slapMode & SLAP_TOOL_MODE );
00259 
00260        bdb = (struct bdb_info *) be->be_private;
00261        assert( bdb != NULL );
00262 
00263 next:;
00264        /* Get the header */
00265        data.ulen = data.dlen = sizeof( ehbuf );
00266        data.data = ehbuf;
00267        data.flags |= DB_DBT_PARTIAL;
00268        rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
00269 
00270        if( rc ) {
00271               /* If we're doing linear indexing and there are more attrs to
00272                * index, and we're at the end of the database, start over.
00273                */
00274               if ( index_nattrs && rc == DB_NOTFOUND ) {
00275                      /* optional - do a checkpoint here? */
00276                      bdb_attr_info_free( bdb->bi_attrs[0] );
00277                      bdb->bi_attrs[0] = bdb->bi_attrs[index_nattrs];
00278                      index_nattrs--;
00279                      rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
00280                      if ( rc ) {
00281                             return NOID;
00282                      }
00283               } else {
00284                      return NOID;
00285               }
00286        }
00287 
00288        BDB_DISK2ID( key.data, &id );
00289        previd = id;
00290 
00291        if ( tool_filter || tool_base ) {
00292               static Operation op = {0};
00293               static Opheader ohdr = {0};
00294 
00295               op.o_hdr = &ohdr;
00296               op.o_bd = be;
00297               op.o_tmpmemctx = NULL;
00298               op.o_tmpmfuncs = &ch_mfuncs;
00299 
00300               if ( tool_next_entry ) {
00301                      bdb_entry_release( &op, tool_next_entry, 0 );
00302                      tool_next_entry = NULL;
00303               }
00304 
00305               rc = bdb_tool_entry_get_int( be, id, &tool_next_entry );
00306               if ( rc == LDAP_NO_SUCH_OBJECT ) {
00307                      goto next;
00308               }
00309 
00310               assert( tool_next_entry != NULL );
00311 
00312 #ifdef BDB_HIER
00313               /* TODO: needed until BDB_HIER is handled accordingly
00314                * in bdb_tool_entry_get_int() */
00315               if ( tool_base && !dnIsSuffixScope( &tool_next_entry->e_nname, tool_base, tool_scope ) )
00316               {
00317                      bdb_entry_release( &op, tool_next_entry, 0 );
00318                      tool_next_entry = NULL;
00319                      goto next;
00320               }
00321 #endif
00322 
00323               if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
00324               {
00325                      bdb_entry_release( &op, tool_next_entry, 0 );
00326                      tool_next_entry = NULL;
00327                      goto next;
00328               }
00329        }
00330 
00331        return id;
00332 }
00333 
00334 ID bdb_tool_dn2id_get(
00335        Backend *be,
00336        struct berval *dn
00337 )
00338 {
00339        Operation op = {0};
00340        Opheader ohdr = {0};
00341        EntryInfo *ei = NULL;
00342        int rc;
00343 
00344        if ( BER_BVISEMPTY(dn) )
00345               return 0;
00346 
00347        op.o_hdr = &ohdr;
00348        op.o_bd = be;
00349        op.o_tmpmemctx = NULL;
00350        op.o_tmpmfuncs = &ch_mfuncs;
00351 
00352        rc = bdb_cache_find_ndn( &op, 0, dn, &ei );
00353        if ( ei ) bdb_cache_entryinfo_unlock( ei );
00354        if ( rc == DB_NOTFOUND )
00355               return NOID;
00356        
00357        return ei->bei_id;
00358 }
00359 
00360 static int
00361 bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
00362 {
00363        Entry *e = NULL;
00364        char *dptr;
00365        int rc, eoff;
00366 
00367        assert( be != NULL );
00368        assert( slapMode & SLAP_TOOL_MODE );
00369 
00370        if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
00371               *ep = tool_next_entry;
00372               tool_next_entry = NULL;
00373               return LDAP_SUCCESS;
00374        }
00375 
00376        if ( id != previd ) {
00377               data.ulen = data.dlen = sizeof( ehbuf );
00378               data.data = ehbuf;
00379               data.flags |= DB_DBT_PARTIAL;
00380 
00381               BDB_ID2DISK( id, &nid );
00382               rc = cursor->c_get( cursor, &key, &data, DB_SET );
00383               if ( rc ) {
00384                      rc = LDAP_OTHER;
00385                      goto done;
00386               }
00387        }
00388 
00389        /* Get the header */
00390        dptr = eh.bv.bv_val;
00391        eh.bv.bv_val = ehbuf;
00392        eh.bv.bv_len = data.size;
00393        rc = entry_header( &eh );
00394        eoff = eh.data - eh.bv.bv_val;
00395        eh.bv.bv_val = dptr;
00396        if ( rc ) {
00397               rc = LDAP_OTHER;
00398               goto done;
00399        }
00400 
00401        /* Get the size */
00402        data.flags &= ~DB_DBT_PARTIAL;
00403        data.ulen = 0;
00404        rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
00405        if ( rc != DB_BUFFER_SMALL ) {
00406               rc = LDAP_OTHER;
00407               goto done;
00408        }
00409 
00410        /* Allocate a block and retrieve the data */
00411        eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size;
00412        eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
00413        eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
00414        data.data = eh.data;
00415        data.ulen = data.size;
00416 
00417        /* Skip past already parsed nattr/nvals */
00418        eh.data += eoff;
00419 
00420        rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
00421        if ( rc ) {
00422               rc = LDAP_OTHER;
00423               goto done;
00424        }
00425 
00426 #ifndef BDB_HIER
00427        /* TODO: handle BDB_HIER accordingly */
00428        if ( tool_base != NULL ) {
00429               struct berval ndn;
00430               entry_decode_dn( &eh, NULL, &ndn );
00431 
00432               if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
00433                      return LDAP_NO_SUCH_OBJECT;
00434               }
00435        }
00436 #endif
00437 
00438 #ifdef SLAP_ZONE_ALLOC
00439        /* FIXME: will add ctx later */
00440        rc = entry_decode( &eh, &e, NULL );
00441 #else
00442        rc = entry_decode( &eh, &e );
00443 #endif
00444 
00445        if( rc == LDAP_SUCCESS ) {
00446               e->e_id = id;
00447 #ifdef BDB_HIER
00448               if ( slapMode & SLAP_TOOL_READONLY ) {
00449                      struct bdb_info *bdb = (struct bdb_info *) be->be_private;
00450                      EntryInfo *ei = NULL;
00451                      Operation op = {0};
00452                      Opheader ohdr = {0};
00453 
00454                      op.o_hdr = &ohdr;
00455                      op.o_bd = be;
00456                      op.o_tmpmemctx = NULL;
00457                      op.o_tmpmfuncs = &ch_mfuncs;
00458 
00459                      rc = bdb_cache_find_parent( &op, bdb->bi_cache.c_txn, id, &ei );
00460                      if ( rc == LDAP_SUCCESS ) {
00461                             bdb_cache_entryinfo_unlock( ei );
00462                             e->e_private = ei;
00463                             ei->bei_e = e;
00464                             bdb_fix_dn( e, 0 );
00465                             ei->bei_e = NULL;
00466                             e->e_private = NULL;
00467                      }
00468               }
00469 #endif
00470        }
00471 done:
00472        if ( e != NULL ) {
00473               *ep = e;
00474        }
00475 
00476        return rc;
00477 }
00478 
00479 Entry*
00480 bdb_tool_entry_get( BackendDB *be, ID id )
00481 {
00482        Entry *e = NULL;
00483 
00484        (void)bdb_tool_entry_get_int( be, id, &e );
00485        return e;
00486 }
00487 
00488 static int bdb_tool_next_id(
00489        Operation *op,
00490        DB_TXN *tid,
00491        Entry *e,
00492        struct berval *text,
00493        int hole )
00494 {
00495        struct berval dn = e->e_name;
00496        struct berval ndn = e->e_nname;
00497        struct berval pdn, npdn;
00498        EntryInfo *ei = NULL, eidummy;
00499        int rc;
00500 
00501        if (ndn.bv_len == 0) {
00502               e->e_id = 0;
00503               return 0;
00504        }
00505 
00506        rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
00507        if ( ei ) bdb_cache_entryinfo_unlock( ei );
00508        if ( rc == DB_NOTFOUND ) {
00509               if ( !be_issuffix( op->o_bd, &ndn ) ) {
00510                      ID eid = e->e_id;
00511                      dnParent( &dn, &pdn );
00512                      dnParent( &ndn, &npdn );
00513                      e->e_name = pdn;
00514                      e->e_nname = npdn;
00515                      rc = bdb_tool_next_id( op, tid, e, text, 1 );
00516                      e->e_name = dn;
00517                      e->e_nname = ndn;
00518                      if ( rc ) {
00519                             return rc;
00520                      }
00521                      /* If parent didn't exist, it was created just now
00522                       * and its ID is now in e->e_id. Make sure the current
00523                       * entry gets added under the new parent ID.
00524                       */
00525                      if ( eid != e->e_id ) {
00526                             eidummy.bei_id = e->e_id;
00527                             ei = &eidummy;
00528                      }
00529               }
00530               rc = bdb_next_id( op->o_bd, &e->e_id );
00531               if ( rc ) {
00532                      snprintf( text->bv_val, text->bv_len,
00533                             "next_id failed: %s (%d)",
00534                             db_strerror(rc), rc );
00535               Debug( LDAP_DEBUG_ANY,
00536                      "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
00537                      return rc;
00538               }
00539               rc = bdb_dn2id_add( op, tid, ei, e );
00540               if ( rc ) {
00541                      snprintf( text->bv_val, text->bv_len, 
00542                             "dn2id_add failed: %s (%d)",
00543                             db_strerror(rc), rc );
00544               Debug( LDAP_DEBUG_ANY,
00545                      "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
00546               } else if ( hole ) {
00547                      if ( nholes == nhmax - 1 ) {
00548                             if ( holes == hbuf ) {
00549                                    holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
00550                                    AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
00551                             } else {
00552                                    holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
00553                             }
00554                             nhmax *= 2;
00555                      }
00556                      ber_dupbv( &holes[nholes].dn, &ndn );
00557                      holes[nholes++].id = e->e_id;
00558               }
00559        } else if ( !hole ) {
00560               unsigned i, j;
00561 
00562               e->e_id = ei->bei_id;
00563 
00564               for ( i=0; i<nholes; i++) {
00565                      if ( holes[i].id == e->e_id ) {
00566                             free(holes[i].dn.bv_val);
00567                             for (j=i;j<nholes;j++) holes[j] = holes[j+1];
00568                             holes[j].id = 0;
00569                             nholes--;
00570                             break;
00571                      } else if ( holes[i].id > e->e_id ) {
00572                             break;
00573                      }
00574               }
00575        }
00576        return rc;
00577 }
00578 
00579 static int
00580 bdb_tool_index_add(
00581        Operation *op,
00582        DB_TXN *txn,
00583        Entry *e )
00584 {
00585        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00586 
00587        if ( !bdb->bi_nattrs )
00588               return 0;
00589 
00590        if ( bdb_tool_threads > 1 ) {
00591               IndexRec *ir;
00592               int i, rc;
00593               Attribute *a;
00594               
00595               ir = bdb_tool_index_rec;
00596               memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
00597 
00598               for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
00599                      rc = bdb_index_recset( bdb, a, a->a_desc->ad_type, 
00600                             &a->a_desc->ad_tags, ir );
00601                      if ( rc )
00602                             return rc;
00603               }
00604               bdb_tool_ix_id = e->e_id;
00605               bdb_tool_ix_op = op;
00606               ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
00607               /* Wait for all threads to be ready */
00608               while ( bdb_tool_index_tcount > 0 ) {
00609                      ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main, 
00610                             &bdb_tool_index_mutex );
00611               }
00612               for ( i=1; i<bdb_tool_threads; i++ )
00613                      bdb_tool_index_threads[i] = LDAP_BUSY;
00614               bdb_tool_index_tcount = bdb_tool_threads - 1;
00615               ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
00616               ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
00617               rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
00618               if ( rc )
00619                      return rc;
00620               ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
00621               for ( i=1; i<bdb_tool_threads; i++ ) {
00622                      if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
00623                             ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main, 
00624                                    &bdb_tool_index_mutex );
00625                             i--;
00626                             continue;
00627                      }
00628                      if ( bdb_tool_index_threads[i] ) {
00629                             rc = bdb_tool_index_threads[i];
00630                             break;
00631                      }
00632               }
00633               ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
00634               return rc;
00635        } else {
00636               return bdb_index_entry_add( op, txn, e );
00637        }
00638 }
00639 
00640 ID bdb_tool_entry_put(
00641        BackendDB *be,
00642        Entry *e,
00643        struct berval *text )
00644 {
00645        int rc;
00646        struct bdb_info *bdb;
00647        DB_TXN *tid = NULL;
00648        Operation op = {0};
00649        Opheader ohdr = {0};
00650 
00651        assert( be != NULL );
00652        assert( slapMode & SLAP_TOOL_MODE );
00653 
00654        assert( text != NULL );
00655        assert( text->bv_val != NULL );
00656        assert( text->bv_val[0] == '\0' ); /* overconservative? */
00657 
00658        Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
00659               "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
00660 
00661        bdb = (struct bdb_info *) be->be_private;
00662 
00663        if (! (slapMode & SLAP_TOOL_QUICK)) {
00664        rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
00665               bdb->bi_db_opflags );
00666        if( rc != 0 ) {
00667               snprintf( text->bv_val, text->bv_len,
00668                      "txn_begin failed: %s (%d)",
00669                      db_strerror(rc), rc );
00670               Debug( LDAP_DEBUG_ANY,
00671                      "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
00672                       text->bv_val, 0, 0 );
00673               return NOID;
00674        }
00675        }
00676 
00677        op.o_hdr = &ohdr;
00678        op.o_bd = be;
00679        op.o_tmpmemctx = NULL;
00680        op.o_tmpmfuncs = &ch_mfuncs;
00681 
00682        /* add dn2id indices */
00683        rc = bdb_tool_next_id( &op, tid, e, text, 0 );
00684        if( rc != 0 ) {
00685               goto done;
00686        }
00687 
00688 #ifdef USE_TRICKLE
00689        if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) {
00690               ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
00691        }
00692 #endif
00693 
00694        if ( !bdb->bi_linear_index )
00695               rc = bdb_tool_index_add( &op, tid, e );
00696        if( rc != 0 ) {
00697               snprintf( text->bv_val, text->bv_len,
00698                             "index_entry_add failed: %s (%d)",
00699                             rc == LDAP_OTHER ? "Internal error" :
00700                             db_strerror(rc), rc );
00701               Debug( LDAP_DEBUG_ANY,
00702                      "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
00703                      text->bv_val, 0, 0 );
00704               goto done;
00705        }
00706 
00707        /* id2entry index */
00708        rc = bdb_id2entry_add( be, tid, e );
00709        if( rc != 0 ) {
00710               snprintf( text->bv_val, text->bv_len,
00711                             "id2entry_add failed: %s (%d)",
00712                             db_strerror(rc), rc );
00713               Debug( LDAP_DEBUG_ANY,
00714                      "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
00715                      text->bv_val, 0, 0 );
00716               goto done;
00717        }
00718 
00719 done:
00720        if( rc == 0 ) {
00721               if ( !( slapMode & SLAP_TOOL_QUICK )) {
00722               rc = TXN_COMMIT( tid, 0 );
00723               if( rc != 0 ) {
00724                      snprintf( text->bv_val, text->bv_len,
00725                                    "txn_commit failed: %s (%d)",
00726                                    db_strerror(rc), rc );
00727                      Debug( LDAP_DEBUG_ANY,
00728                             "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
00729                             text->bv_val, 0, 0 );
00730                      e->e_id = NOID;
00731               }
00732               }
00733 
00734        } else {
00735               if ( !( slapMode & SLAP_TOOL_QUICK )) {
00736               TXN_ABORT( tid );
00737               snprintf( text->bv_val, text->bv_len,
00738                      "txn_aborted! %s (%d)",
00739                      rc == LDAP_OTHER ? "Internal error" :
00740                      db_strerror(rc), rc );
00741               Debug( LDAP_DEBUG_ANY,
00742                      "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
00743                      text->bv_val, 0, 0 );
00744               }
00745               e->e_id = NOID;
00746        }
00747 
00748        return e->e_id;
00749 }
00750 
00751 int bdb_tool_entry_reindex(
00752        BackendDB *be,
00753        ID id,
00754        AttributeDescription **adv )
00755 {
00756        struct bdb_info *bi = (struct bdb_info *) be->be_private;
00757        int rc;
00758        Entry *e;
00759        DB_TXN *tid = NULL;
00760        Operation op = {0};
00761        Opheader ohdr = {0};
00762 
00763        Debug( LDAP_DEBUG_ARGS,
00764               "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
00765               (long) id, 0, 0 );
00766        assert( tool_base == NULL );
00767        assert( tool_filter == NULL );
00768 
00769        /* No indexes configured, nothing to do. Could return an
00770         * error here to shortcut things.
00771         */
00772        if (!bi->bi_attrs) {
00773               return 0;
00774        }
00775 
00776        /* Check for explicit list of attrs to index */
00777        if ( adv ) {
00778               int i, j, n;
00779 
00780               if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
00781                      /* count */
00782                      for ( n = 0; adv[n]; n++ ) ;
00783 
00784                      /* insertion sort */
00785                      for ( i = 0; i < n; i++ ) {
00786                             AttributeDescription *ad = adv[i];
00787                             for ( j = i-1; j>=0; j--) {
00788                                    if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
00789                                    adv[j+1] = adv[j];
00790                             }
00791                             adv[j+1] = ad;
00792                      }
00793               }
00794 
00795               for ( i = 0; adv[i]; i++ ) {
00796                      if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
00797                             for ( j = i+1; j < bi->bi_nattrs; j++ ) {
00798                                    if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
00799                                           AttrInfo *ai = bi->bi_attrs[i];
00800                                           bi->bi_attrs[i] = bi->bi_attrs[j];
00801                                           bi->bi_attrs[j] = ai;
00802                                           break;
00803                                    }
00804                             }
00805                             if ( j == bi->bi_nattrs ) {
00806                                    Debug( LDAP_DEBUG_ANY,
00807                                           LDAP_XSTRING(bdb_tool_entry_reindex)
00808                                           ": no index configured for %s\n",
00809                                           adv[i]->ad_cname.bv_val, 0, 0 );
00810                                    return -1;
00811                             }
00812                      }
00813               }
00814               bi->bi_nattrs = i;
00815        }
00816 
00817        /* Get the first attribute to index */
00818        if (bi->bi_linear_index && !index_nattrs) {
00819               index_nattrs = bi->bi_nattrs - 1;
00820               bi->bi_nattrs = 1;
00821        }
00822 
00823        e = bdb_tool_entry_get( be, id );
00824 
00825        if( e == NULL ) {
00826               Debug( LDAP_DEBUG_ANY,
00827                      LDAP_XSTRING(bdb_tool_entry_reindex)
00828                      ": could not locate id=%ld\n",
00829                      (long) id, 0, 0 );
00830               return -1;
00831        }
00832 
00833        if (! (slapMode & SLAP_TOOL_QUICK)) {
00834        rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
00835        if( rc != 0 ) {
00836               Debug( LDAP_DEBUG_ANY,
00837                      "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
00838                      "txn_begin failed: %s (%d)\n",
00839                      db_strerror(rc), rc, 0 );
00840               goto done;
00841        }
00842        }
00843        
00844        /*
00845         * just (re)add them for now
00846         * assume that some other routine (not yet implemented)
00847         * will zap index databases
00848         *
00849         */
00850 
00851        Debug( LDAP_DEBUG_TRACE,
00852               "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
00853               (long) id, e->e_dn, 0 );
00854 
00855        op.o_hdr = &ohdr;
00856        op.o_bd = be;
00857        op.o_tmpmemctx = NULL;
00858        op.o_tmpmfuncs = &ch_mfuncs;
00859 
00860        rc = bdb_tool_index_add( &op, tid, e );
00861 
00862 done:
00863        if( rc == 0 ) {
00864               if (! (slapMode & SLAP_TOOL_QUICK)) {
00865               rc = TXN_COMMIT( tid, 0 );
00866               if( rc != 0 ) {
00867                      Debug( LDAP_DEBUG_ANY,
00868                             "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
00869                             ": txn_commit failed: %s (%d)\n",
00870                             db_strerror(rc), rc, 0 );
00871                      e->e_id = NOID;
00872               }
00873               }
00874 
00875        } else {
00876               if (! (slapMode & SLAP_TOOL_QUICK)) {
00877               TXN_ABORT( tid );
00878               Debug( LDAP_DEBUG_ANY,
00879                      "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
00880                      ": txn_aborted! %s (%d)\n",
00881                      db_strerror(rc), rc, 0 );
00882               }
00883               e->e_id = NOID;
00884        }
00885        bdb_entry_release( &op, e, 0 );
00886 
00887        return rc;
00888 }
00889 
00890 ID bdb_tool_entry_modify(
00891        BackendDB *be,
00892        Entry *e,
00893        struct berval *text )
00894 {
00895        int rc;
00896        struct bdb_info *bdb;
00897        DB_TXN *tid = NULL;
00898        Operation op = {0};
00899        Opheader ohdr = {0};
00900 
00901        assert( be != NULL );
00902        assert( slapMode & SLAP_TOOL_MODE );
00903 
00904        assert( text != NULL );
00905        assert( text->bv_val != NULL );
00906        assert( text->bv_val[0] == '\0' ); /* overconservative? */
00907 
00908        assert ( e->e_id != NOID );
00909 
00910        Debug( LDAP_DEBUG_TRACE,
00911               "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
00912               (long) e->e_id, e->e_dn, 0 );
00913 
00914        bdb = (struct bdb_info *) be->be_private;
00915 
00916        if (! (slapMode & SLAP_TOOL_QUICK)) {
00917               if( cursor ) {
00918                      cursor->c_close( cursor );
00919                      cursor = NULL;
00920               }
00921               rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
00922                      bdb->bi_db_opflags );
00923               if( rc != 0 ) {
00924                      snprintf( text->bv_val, text->bv_len,
00925                             "txn_begin failed: %s (%d)",
00926                             db_strerror(rc), rc );
00927                      Debug( LDAP_DEBUG_ANY,
00928                             "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
00929                              text->bv_val, 0, 0 );
00930                      return NOID;
00931               }
00932        }
00933 
00934        op.o_hdr = &ohdr;
00935        op.o_bd = be;
00936        op.o_tmpmemctx = NULL;
00937        op.o_tmpmfuncs = &ch_mfuncs;
00938 
00939        /* id2entry index */
00940        rc = bdb_id2entry_update( be, tid, e );
00941        if( rc != 0 ) {
00942               snprintf( text->bv_val, text->bv_len,
00943                             "id2entry_add failed: %s (%d)",
00944                             db_strerror(rc), rc );
00945               Debug( LDAP_DEBUG_ANY,
00946                      "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
00947                      text->bv_val, 0, 0 );
00948               goto done;
00949        }
00950 
00951 done:
00952        if( rc == 0 ) {
00953               if (! (slapMode & SLAP_TOOL_QUICK)) {
00954               rc = TXN_COMMIT( tid, 0 );
00955               if( rc != 0 ) {
00956                      snprintf( text->bv_val, text->bv_len,
00957                                    "txn_commit failed: %s (%d)",
00958                                    db_strerror(rc), rc );
00959                      Debug( LDAP_DEBUG_ANY,
00960                             "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
00961                             "%s\n", text->bv_val, 0, 0 );
00962                      e->e_id = NOID;
00963               }
00964               }
00965 
00966        } else {
00967               if (! (slapMode & SLAP_TOOL_QUICK)) {
00968               TXN_ABORT( tid );
00969               snprintf( text->bv_val, text->bv_len,
00970                      "txn_aborted! %s (%d)",
00971                      db_strerror(rc), rc );
00972               Debug( LDAP_DEBUG_ANY,
00973                      "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
00974                      text->bv_val, 0, 0 );
00975               }
00976               e->e_id = NOID;
00977        }
00978 
00979        return e->e_id;
00980 }
00981 
00982 #ifdef BDB_TOOL_IDL_CACHING
00983 static int
00984 bdb_tool_idl_cmp( const void *v1, const void *v2 )
00985 {
00986        const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
00987        int rc;
00988 
00989        if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
00990        return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
00991 }
00992 
00993 static int
00994 bdb_tool_idl_flush_one( void *v1, void *arg )
00995 {
00996        bdb_tool_idl_cache *ic = v1;
00997        DB *db = arg;
00998        struct bdb_info *bdb = bdb_tool_info;
00999        bdb_tool_idl_cache_entry *ice;
01000        DBC *curs;
01001        DBT key, data;
01002        int i, rc;
01003        ID id, nid;
01004 
01005        /* Freshly allocated, ignore it */
01006        if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
01007               return 0;
01008        }
01009 
01010        rc = db->cursor( db, NULL, &curs, 0 );
01011        if ( rc )
01012               return -1;
01013 
01014        DBTzero( &key );
01015        DBTzero( &data );
01016 
01017        bv2DBT( &ic->kstr, &key );
01018 
01019        data.size = data.ulen = sizeof( ID );
01020        data.flags = DB_DBT_USERMEM;
01021        data.data = &nid;
01022 
01023        rc = curs->c_get( curs, &key, &data, DB_SET );
01024        /* If key already exists and we're writing a range... */
01025        if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
01026               /* If it's not currently a range, must delete old info */
01027               if ( nid ) {
01028                      /* Skip lo */
01029                      while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
01030                             curs->c_del( curs, 0 );
01031 
01032                      nid = 0;
01033                      /* Store range marker */
01034                      curs->c_put( curs, &key, &data, DB_KEYFIRST );
01035               } else {
01036                      
01037                      /* Skip lo */
01038                      rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
01039 
01040                      /* Get hi */
01041                      rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
01042 
01043                      /* Delete hi */
01044                      curs->c_del( curs, 0 );
01045               }
01046               BDB_ID2DISK( ic->last, &nid );
01047               curs->c_put( curs, &key, &data, DB_KEYLAST );
01048               rc = 0;
01049        } else if ( rc && rc != DB_NOTFOUND ) {
01050               rc = -1;
01051        } else if ( ic->count > BDB_IDL_DB_SIZE ) {
01052               /* range, didn't exist before */
01053               nid = 0;
01054               rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
01055               if ( rc == 0 ) {
01056                      BDB_ID2DISK( ic->first, &nid );
01057                      rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
01058                      if ( rc == 0 ) {
01059                             BDB_ID2DISK( ic->last, &nid );
01060                             rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
01061                      }
01062               }
01063               if ( rc ) {
01064                      rc = -1;
01065               }
01066        } else {
01067               int n;
01068 
01069               /* Just a normal write */
01070               rc = 0;
01071               for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
01072                      int end;
01073                      if ( ice->next ) {
01074                             end = IDBLOCK;
01075                      } else {
01076                             end = ic->count & (IDBLOCK-1);
01077                             if ( !end )
01078                                    end = IDBLOCK;
01079                      }
01080                      for ( i=0; i<end; i++ ) {
01081                             if ( !ice->ids[i] ) continue;
01082                             BDB_ID2DISK( ice->ids[i], &nid );
01083                             rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
01084                             if ( rc ) {
01085                                    if ( rc == DB_KEYEXIST ) {
01086                                           rc = 0;
01087                                           continue;
01088                                    }
01089                                    rc = -1;
01090                                    break;
01091                             }
01092                      }
01093                      if ( rc ) {
01094                             rc = -1;
01095                             break;
01096                      }
01097               }
01098               if ( ic->head ) {
01099                      ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
01100                      ic->tail->next = bdb_tool_idl_free_list;
01101                      bdb_tool_idl_free_list = ic->head;
01102                      bdb->bi_idl_cache_size -= n;
01103                      ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
01104               }
01105        }
01106        if ( ic != db->app_private ) {
01107               ch_free( ic );
01108        } else {
01109               ic->head = ic->tail = NULL;
01110        }
01111        curs->c_close( curs );
01112        return rc;
01113 }
01114 
01115 static int
01116 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
01117 {
01118        Avlnode *root = db->app_private;
01119        int rc;
01120 
01121        db->app_private = ic;
01122        rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
01123        avl_free( root, NULL );
01124        db->app_private = NULL;
01125        if ( rc != -1 )
01126               rc = 0;
01127        return rc;
01128 }
01129 
01130 static int
01131 bdb_tool_idl_flush( BackendDB *be )
01132 {
01133        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
01134        DB *db;
01135        Avlnode *root;
01136        int i, rc = 0;
01137 
01138        for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
01139               db = bdb->bi_databases[i]->bdi_db;
01140               if ( !db->app_private ) continue;
01141               rc = bdb_tool_idl_flush_db( db, NULL );
01142               if ( rc )
01143                      break;
01144        }
01145        if ( !rc ) {
01146               bdb->bi_idl_cache_size = 0;
01147        }
01148        return rc;
01149 }
01150 
01151 int bdb_tool_idl_add(
01152        BackendDB *be,
01153        DB *db,
01154        DB_TXN *txn,
01155        DBT *key,
01156        ID id )
01157 {
01158        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
01159        bdb_tool_idl_cache *ic, itmp;
01160        bdb_tool_idl_cache_entry *ice;
01161        int rc;
01162 
01163        if ( !bdb->bi_idl_cache_max_size )
01164               return bdb_idl_insert_key( be, db, txn, key, id );
01165 
01166        DBT2bv( key, &itmp.kstr );
01167 
01168        ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
01169 
01170        /* No entry yet, create one */
01171        if ( !ic ) {
01172               DBC *curs;
01173               DBT data;
01174               ID nid;
01175               int rc;
01176 
01177               ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
01178               ic->kstr.bv_len = itmp.kstr.bv_len;
01179               ic->kstr.bv_val = (char *)(ic+1);
01180               AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
01181               ic->head = ic->tail = NULL;
01182               ic->last = 0;
01183               ic->count = 0;
01184               avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
01185                      avl_dup_error );
01186 
01187               /* load existing key count here */
01188               rc = db->cursor( db, NULL, &curs, 0 );
01189               if ( rc ) return rc;
01190 
01191               data.ulen = sizeof( ID );
01192               data.flags = DB_DBT_USERMEM;
01193               data.data = &nid;
01194               rc = curs->c_get( curs, key, &data, DB_SET );
01195               if ( rc == 0 ) {
01196                      if ( nid == 0 ) {
01197                             ic->count = BDB_IDL_DB_SIZE+1;
01198                      } else {
01199                             db_recno_t count;
01200 
01201                             curs->c_count( curs, &count, 0 );
01202                             ic->count = count;
01203                             BDB_DISK2ID( &nid, &ic->first );
01204                      }
01205               }
01206               curs->c_close( curs );
01207        }
01208        /* are we a range already? */
01209        if ( ic->count > BDB_IDL_DB_SIZE ) {
01210               ic->last = id;
01211               return 0;
01212        /* Are we at the limit, and converting to a range? */
01213        } else if ( ic->count == BDB_IDL_DB_SIZE ) {
01214               int n;
01215               for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
01216                      /* counting */ ;
01217               if ( n ) {
01218                      ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
01219                      ic->tail->next = bdb_tool_idl_free_list;
01220                      bdb_tool_idl_free_list = ic->head;
01221                      bdb->bi_idl_cache_size -= n;
01222                      ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
01223               }
01224               ic->head = ic->tail = NULL;
01225               ic->last = id;
01226               ic->count++;
01227               return 0;
01228        }
01229        /* No free block, create that too */
01230        if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
01231               ice = NULL;
01232               ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
01233               if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
01234                      ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
01235                      rc = bdb_tool_idl_flush_db( db, ic );
01236                      if ( rc )
01237                             return rc;
01238                      avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
01239                             avl_dup_error );
01240                      ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
01241               }
01242               bdb->bi_idl_cache_size++;
01243               if ( bdb_tool_idl_free_list ) {
01244                      ice = bdb_tool_idl_free_list;
01245                      bdb_tool_idl_free_list = ice->next;
01246               }
01247               ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
01248               if ( !ice ) {
01249                      ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
01250               }
01251               memset( ice, 0, sizeof( *ice ));
01252               if ( !ic->head ) {
01253                      ic->head = ice;
01254               } else {
01255                      ic->tail->next = ice;
01256               }
01257               ic->tail = ice;
01258               if ( !ic->count )
01259                      ic->first = id;
01260        }
01261        ice = ic->tail;
01262        ice->ids[ ic->count & (IDBLOCK-1) ] = id;
01263        ic->count++;
01264 
01265        return 0;
01266 }
01267 #endif
01268 
01269 #ifdef USE_TRICKLE
01270 static void *
01271 bdb_tool_trickle_task( void *ctx, void *ptr )
01272 {
01273        DB_ENV *env = ptr;
01274        int wrote;
01275 
01276        ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
01277        bdb_tool_trickle_active = 1;
01278        ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond_end );
01279        while ( 1 ) {
01280               ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond,
01281                      &bdb_tool_trickle_mutex );
01282               if ( slapd_shutdown )
01283                      break;
01284               env->memp_trickle( env, 30, &wrote );
01285        }
01286        bdb_tool_trickle_active = 0;
01287        ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond_end );
01288        ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
01289 
01290        return NULL;
01291 }
01292 #endif
01293 
01294 static void *
01295 bdb_tool_index_task( void *ctx, void *ptr )
01296 {
01297        int base = *(int *)ptr;
01298 
01299        free( ptr );
01300        while ( 1 ) {
01301               ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
01302               bdb_tool_index_tcount--;
01303               if ( !bdb_tool_index_tcount )
01304                      ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
01305               ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work,
01306                      &bdb_tool_index_mutex );
01307               if ( slapd_shutdown ) {
01308                      bdb_tool_index_tcount--;
01309                      if ( !bdb_tool_index_tcount )
01310                             ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
01311                      ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
01312                      break;
01313               }
01314               ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
01315 
01316               bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
01317                      bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );
01318        }
01319 
01320        return NULL;
01321 }