1 /* tools.c - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2005 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>.
20 #include <ac/string.h>
26 static DBC *cursor = NULL;
29 typedef struct dn_id {
34 #define HOLE_SIZE 4096
35 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
36 static unsigned nhmax = HOLE_SIZE;
37 static unsigned nholes;
39 static int index_nattrs;
41 #ifdef BDB_TOOL_IDL_CACHING
42 #define bdb_tool_idl_cmp BDB_SYMBOL(tool_idl_cmp)
43 #define bdb_tool_idl_flush_one BDB_SYMBOL(tool_idl_flush_one)
44 #define bdb_tool_idl_flush BDB_SYMBOL(tool_idl_flush)
46 static int bdb_tool_idl_flush( BackendDB *be );
50 typedef struct bdb_tool_idl_cache_entry {
51 struct bdb_tool_idl_cache_entry *next;
53 } bdb_tool_idl_cache_entry;
55 typedef struct bdb_tool_idl_cache {
57 bdb_tool_idl_cache_entry *head, *tail;
62 static bdb_tool_idl_cache_entry *bdb_tool_idl_free_list;
63 #endif /* BDB_TOOL_IDL_CACHING */
65 static ID bdb_tool_ix_id;
66 static Operation *bdb_tool_ix_op;
67 static volatile int *bdb_tool_index_threads;
68 static void *bdb_tool_index_rec;
69 static struct bdb_info *bdb_tool_info;
70 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex;
71 static ldap_pvt_thread_cond_t bdb_tool_index_cond;
73 static int bdb_tool_ix_rec( int base );
74 static void * bdb_tool_index_task( void *ctx, void *ptr );
76 int bdb_tool_entry_open(
77 BackendDB *be, int mode )
79 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
81 /* initialize key and data thangs */
84 key.flags = DB_DBT_REALLOC;
85 data.flags = DB_DBT_REALLOC;
88 int rc = bdb->bi_id2entry->bdi_db->cursor(
89 bdb->bi_id2entry->bdi_db, NULL, &cursor,
96 /* Set up for slapindex */
97 if ( !(slapMode & SLAP_TOOL_READONLY )) {
99 if ( !bdb_tool_info && ( slapMode & SLAP_TOOL_QUICK )) {
100 ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex );
101 ldap_pvt_thread_cond_init( &bdb_tool_index_cond );
102 bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
103 bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec ));
104 for (i=1; i<slap_tool_thread_max; i++) {
105 int *ptr = ch_malloc( sizeof( int ));
107 ldap_pvt_thread_pool_submit( &connection_pool,
108 bdb_tool_index_task, ptr );
109 ldap_pvt_thread_yield();
118 int bdb_tool_entry_close(
121 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
123 if ( bdb_tool_info ) {
125 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
126 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond );
127 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
135 ch_free( data.data );
140 cursor->c_close( cursor );
144 #ifdef BDB_TOOL_IDL_CACHING
145 bdb_tool_idl_flush( be );
150 fprintf( stderr, "Error, entries missing!\n");
151 for (i=0; i<nholes; i++) {
152 fprintf(stderr, " entry %ld: %s\n",
153 holes[i].id, holes[i].dn.bv_val);
161 ID bdb_tool_entry_next(
166 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
168 assert( be != NULL );
169 assert( slapMode & SLAP_TOOL_MODE );
170 assert( bdb != NULL );
172 rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
175 /* If we're doing linear indexing and there are more attrs to
176 * index, and we're at the end of the database, start over.
178 if ( index_nattrs && rc == DB_NOTFOUND ) {
179 /* optional - do a checkpoint here? */
180 bdb_attr_info_free( bdb->bi_attrs[0] );
181 bdb->bi_attrs[0] = bdb->bi_attrs[index_nattrs];
183 rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
192 if( data.data == NULL ) {
196 BDB_DISK2ID( key.data, &id );
200 ID bdb_tool_dn2id_get(
207 EntryInfo *ei = NULL;
210 if ( BER_BVISEMPTY(dn) )
215 op.o_tmpmemctx = NULL;
216 op.o_tmpmfuncs = &ch_mfuncs;
218 rc = bdb_cache_find_ndn( &op, NULL, dn, &ei );
219 if ( ei ) bdb_cache_entryinfo_unlock( ei );
220 if ( rc == DB_NOTFOUND )
226 int bdb_tool_id2entry_get(
232 int rc = bdb_id2entry( be, NULL, 0, id, e );
234 if ( rc == DB_NOTFOUND && id == 0 ) {
235 Entry *dummy = ch_calloc( 1, sizeof(Entry) );
236 struct berval gluebv = BER_BVC("glue");
237 dummy->e_name.bv_val = ch_strdup( "" );
238 dummy->e_nname.bv_val = ch_strdup( "" );
239 attr_merge_one( dummy, slap_schema.si_ad_objectClass, &gluebv, NULL );
240 attr_merge_one( dummy, slap_schema.si_ad_structuralObjectClass,
248 Entry* bdb_tool_entry_get( BackendDB *be, ID id )
254 assert( be != NULL );
255 assert( slapMode & SLAP_TOOL_MODE );
256 assert( data.data != NULL );
258 DBT2bv( &data, &bv );
260 #ifdef SLAP_ZONE_ALLOC
261 /* FIXME: will add ctx later */
262 rc = entry_decode( &bv, &e, NULL );
264 rc = entry_decode( &bv, &e );
267 if( rc == LDAP_SUCCESS ) {
271 if ( slapMode & SLAP_TOOL_READONLY ) {
272 EntryInfo *ei = NULL;
278 op.o_tmpmemctx = NULL;
279 op.o_tmpmfuncs = &ch_mfuncs;
281 rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei );
282 if ( rc == LDAP_SUCCESS ) {
283 bdb_cache_entryinfo_unlock( ei );
295 static int bdb_tool_next_id(
302 struct berval dn = e->e_name;
303 struct berval ndn = e->e_nname;
304 struct berval pdn, npdn;
305 EntryInfo *ei = NULL, eidummy;
308 if (ndn.bv_len == 0) {
313 rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
314 if ( ei ) bdb_cache_entryinfo_unlock( ei );
315 if ( rc == DB_NOTFOUND ) {
316 if ( !be_issuffix( op->o_bd, &ndn ) ) {
318 dnParent( &dn, &pdn );
319 dnParent( &ndn, &npdn );
322 rc = bdb_tool_next_id( op, tid, e, text, 1 );
328 /* If parent didn't exist, it was created just now
329 * and its ID is now in e->e_id. Make sure the current
330 * entry gets added under the new parent ID.
332 if ( eid != e->e_id ) {
333 eidummy.bei_id = e->e_id;
337 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
339 snprintf( text->bv_val, text->bv_len,
340 "next_id failed: %s (%d)",
341 db_strerror(rc), rc );
342 Debug( LDAP_DEBUG_ANY,
343 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
346 rc = bdb_dn2id_add( op, tid, ei, e );
348 snprintf( text->bv_val, text->bv_len,
349 "dn2id_add failed: %s (%d)",
350 db_strerror(rc), rc );
351 Debug( LDAP_DEBUG_ANY,
352 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
354 if ( nholes == nhmax - 1 ) {
355 if ( holes == hbuf ) {
356 holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
357 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
359 holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
363 ber_dupbv( &holes[nholes].dn, &ndn );
364 holes[nholes++].id = e->e_id;
366 } else if ( !hole ) {
369 e->e_id = ei->bei_id;
371 for ( i=0; i<nholes; i++) {
372 if ( holes[i].id == e->e_id ) {
374 free(holes[i].dn.bv_val);
375 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
379 } else if ( holes[i].id > e->e_id ) {
393 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
395 if ( slapMode & SLAP_TOOL_QUICK ) {
400 ir = bdb_tool_index_rec;
401 memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
403 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
404 rc = bdb_index_recset( bdb, a, a->a_desc->ad_type,
405 &a->a_desc->ad_tags, ir );
409 bdb_tool_ix_id = e->e_id;
411 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
412 for ( i=1; i<slap_tool_thread_max; i++ )
413 bdb_tool_index_threads[i] = LDAP_BUSY;
414 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond );
415 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
416 rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
419 for ( i=1; i<slap_tool_thread_max; i++ ) {
420 if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
421 ldap_pvt_thread_yield();
425 if ( bdb_tool_index_threads[i] )
426 return bdb_tool_index_threads[i];
430 return bdb_index_entry_add( op, txn, e );
434 ID bdb_tool_entry_put(
437 struct berval *text )
440 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
445 assert( be != NULL );
446 assert( slapMode & SLAP_TOOL_MODE );
448 assert( text != NULL );
449 assert( text->bv_val != NULL );
450 assert( text->bv_val[0] == '\0' ); /* overconservative? */
452 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
453 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
455 if (! (slapMode & SLAP_TOOL_QUICK)) {
456 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
457 bdb->bi_db_opflags );
459 snprintf( text->bv_val, text->bv_len,
460 "txn_begin failed: %s (%d)",
461 db_strerror(rc), rc );
462 Debug( LDAP_DEBUG_ANY,
463 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
464 text->bv_val, 0, 0 );
471 op.o_tmpmemctx = NULL;
472 op.o_tmpmfuncs = &ch_mfuncs;
474 /* add dn2id indices */
475 rc = bdb_tool_next_id( &op, tid, e, text, 0 );
481 rc = bdb_id2entry_add( be, tid, e );
483 snprintf( text->bv_val, text->bv_len,
484 "id2entry_add failed: %s (%d)",
485 db_strerror(rc), rc );
486 Debug( LDAP_DEBUG_ANY,
487 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
488 text->bv_val, 0, 0 );
492 if ( !bdb->bi_linear_index )
493 rc = bdb_tool_index_add( &op, tid, e );
495 snprintf( text->bv_val, text->bv_len,
496 "index_entry_add failed: %s (%d)",
497 db_strerror(rc), rc );
498 Debug( LDAP_DEBUG_ANY,
499 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
500 text->bv_val, 0, 0 );
506 if ( !( slapMode & SLAP_TOOL_QUICK )) {
507 rc = TXN_COMMIT( tid, 0 );
509 snprintf( text->bv_val, text->bv_len,
510 "txn_commit failed: %s (%d)",
511 db_strerror(rc), rc );
512 Debug( LDAP_DEBUG_ANY,
513 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
514 text->bv_val, 0, 0 );
520 if ( !( slapMode & SLAP_TOOL_QUICK )) {
522 snprintf( text->bv_val, text->bv_len,
523 "txn_aborted! %s (%d)",
524 db_strerror(rc), rc );
525 Debug( LDAP_DEBUG_ANY,
526 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
527 text->bv_val, 0, 0 );
535 int bdb_tool_entry_reindex(
539 struct bdb_info *bi = (struct bdb_info *) be->be_private;
546 Debug( LDAP_DEBUG_ARGS,
547 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
550 /* No indexes configured, nothing to do. Could return an
551 * error here to shortcut things.
557 /* Get the first attribute to index */
558 if (bi->bi_linear_index && !index_nattrs) {
559 index_nattrs = bi->bi_nattrs - 1;
563 e = bdb_tool_entry_get( be, id );
566 Debug( LDAP_DEBUG_ANY,
567 LDAP_XSTRING(bdb_tool_entry_reindex)
568 ": could not locate id=%ld\n",
573 if (! (slapMode & SLAP_TOOL_QUICK)) {
574 rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
576 Debug( LDAP_DEBUG_ANY,
577 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
578 "txn_begin failed: %s (%d)\n",
579 db_strerror(rc), rc, 0 );
585 * just (re)add them for now
586 * assume that some other routine (not yet implemented)
587 * will zap index databases
591 Debug( LDAP_DEBUG_TRACE,
592 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
593 (long) id, e->e_dn, 0 );
597 op.o_tmpmemctx = NULL;
598 op.o_tmpmfuncs = &ch_mfuncs;
600 rc = bdb_tool_index_add( &op, tid, e );
604 if (! (slapMode & SLAP_TOOL_QUICK)) {
605 rc = TXN_COMMIT( tid, 0 );
607 Debug( LDAP_DEBUG_ANY,
608 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
609 ": txn_commit failed: %s (%d)\n",
610 db_strerror(rc), rc, 0 );
616 if (! (slapMode & SLAP_TOOL_QUICK)) {
618 Debug( LDAP_DEBUG_ANY,
619 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
620 ": txn_aborted! %s (%d)\n",
621 db_strerror(rc), rc, 0 );
625 bdb_entry_release( &op, e, 0 );
630 ID bdb_tool_entry_modify(
633 struct berval *text )
636 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
641 assert( be != NULL );
642 assert( slapMode & SLAP_TOOL_MODE );
644 assert( text != NULL );
645 assert( text->bv_val != NULL );
646 assert( text->bv_val[0] == '\0' ); /* overconservative? */
648 assert ( e->e_id != NOID );
650 Debug( LDAP_DEBUG_TRACE,
651 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
652 (long) e->e_id, e->e_dn, 0 );
654 if (! (slapMode & SLAP_TOOL_QUICK)) {
655 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
656 bdb->bi_db_opflags );
658 snprintf( text->bv_val, text->bv_len,
659 "txn_begin failed: %s (%d)",
660 db_strerror(rc), rc );
661 Debug( LDAP_DEBUG_ANY,
662 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
663 text->bv_val, 0, 0 );
670 op.o_tmpmemctx = NULL;
671 op.o_tmpmfuncs = &ch_mfuncs;
674 rc = bdb_id2entry_update( be, tid, e );
676 snprintf( text->bv_val, text->bv_len,
677 "id2entry_add failed: %s (%d)",
678 db_strerror(rc), rc );
679 Debug( LDAP_DEBUG_ANY,
680 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
681 text->bv_val, 0, 0 );
686 /* FIXME: this is bogus, we don't have the old values to delete
687 * from the index because the given entry has already been modified.
689 rc = bdb_index_entry_del( &op, tid, e );
691 snprintf( text->bv_val, text->bv_len,
692 "index_entry_del failed: %s (%d)",
693 db_strerror(rc), rc );
694 Debug( LDAP_DEBUG_ANY,
695 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
696 text->bv_val, 0, 0 );
701 rc = bdb_index_entry_add( &op, tid, e );
703 snprintf( text->bv_val, text->bv_len,
704 "index_entry_add failed: %s (%d)",
705 db_strerror(rc), rc );
706 Debug( LDAP_DEBUG_ANY,
707 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
708 text->bv_val, 0, 0 );
714 if (! (slapMode & SLAP_TOOL_QUICK)) {
715 rc = TXN_COMMIT( tid, 0 );
717 snprintf( text->bv_val, text->bv_len,
718 "txn_commit failed: %s (%d)",
719 db_strerror(rc), rc );
720 Debug( LDAP_DEBUG_ANY,
721 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
722 "%s\n", text->bv_val, 0, 0 );
728 if (! (slapMode & SLAP_TOOL_QUICK)) {
730 snprintf( text->bv_val, text->bv_len,
731 "txn_aborted! %s (%d)",
732 db_strerror(rc), rc );
733 Debug( LDAP_DEBUG_ANY,
734 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
735 text->bv_val, 0, 0 );
743 #ifdef BDB_TOOL_IDL_CACHING
745 bdb_tool_idl_cmp( const void *v1, const void *v2 )
747 const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
750 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
751 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
755 bdb_tool_idl_flush_one( void *v1, void *arg )
757 bdb_tool_idl_cache *ic = v1;
759 struct bdb_info *bdb = bdb_tool_info;
760 bdb_tool_idl_cache_entry *ice;
766 /* Freshly allocated, ignore it */
767 if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
771 rc = db->cursor( db, NULL, &curs, 0 );
778 bv2DBT( &ic->kstr, &key );
780 data.size = data.ulen = sizeof( ID );
781 data.flags = DB_DBT_USERMEM;
784 rc = curs->c_get( curs, &key, &data, DB_SET );
785 /* If key already exists and we're writing a range... */
786 if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
787 /* If it's not currently a range, must delete old info */
790 while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
791 curs->c_del( curs, 0 );
794 /* Store range marker */
795 curs->c_put( curs, &key, &data, DB_KEYFIRST );
799 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
802 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
805 curs->c_del( curs, 0 );
807 BDB_ID2DISK( ic->last, &nid );
808 curs->c_put( curs, &key, &data, DB_KEYLAST );
810 } else if ( rc && rc != DB_NOTFOUND ) {
812 } else if ( ic->count > BDB_IDL_DB_SIZE ) {
813 /* range, didn't exist before */
815 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
817 BDB_ID2DISK( ic->first, &nid );
818 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
820 BDB_ID2DISK( ic->last, &nid );
821 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
830 /* Just a normal write */
832 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
837 end = ic->count & (IDBLOCK-1);
841 for ( i=0; i<end; i++ ) {
842 if ( !ice->ids[i] ) continue;
843 BDB_ID2DISK( ice->ids[i], &nid );
844 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
846 if ( rc == DB_KEYEXIST ) {
860 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
861 ic->tail->next = bdb_tool_idl_free_list;
862 bdb_tool_idl_free_list = ic->head;
863 bdb->bi_idl_cache_size -= n;
864 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
867 if ( ic != db->app_private ) {
870 ic->head = ic->tail = NULL;
872 curs->c_close( curs );
877 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
879 Avlnode *root = db->app_private;
882 db->app_private = ic;
883 rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
884 avl_free( root, NULL );
885 db->app_private = NULL;
892 bdb_tool_idl_flush( BackendDB *be )
894 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
899 for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
900 db = bdb->bi_databases[i]->bdi_db;
901 if ( !db->app_private ) continue;
902 rc = bdb_tool_idl_flush_db( db, NULL );
907 bdb->bi_idl_cache_size = 0;
912 int bdb_tool_idl_add(
919 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
920 bdb_tool_idl_cache *ic, itmp;
921 bdb_tool_idl_cache_entry *ice;
924 if ( !bdb->bi_idl_cache_max_size )
925 return bdb_idl_insert_key( be, db, txn, key, id );
927 DBT2bv( key, &itmp.kstr );
929 ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
931 /* No entry yet, create one */
938 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
939 ic->kstr.bv_len = itmp.kstr.bv_len;
940 ic->kstr.bv_val = (char *)(ic+1);
941 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
942 ic->head = ic->tail = NULL;
945 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
948 /* load existing key count here */
949 rc = db->cursor( db, NULL, &curs, 0 );
952 data.ulen = sizeof( ID );
953 data.flags = DB_DBT_USERMEM;
955 rc = curs->c_get( curs, key, &data, DB_SET );
958 ic->count = BDB_IDL_DB_SIZE+1;
962 curs->c_count( curs, &count, 0 );
964 BDB_DISK2ID( &nid, &ic->first );
967 curs->c_close( curs );
969 /* are we a range already? */
970 if ( ic->count > BDB_IDL_DB_SIZE ) {
973 /* Are we at the limit, and converting to a range? */
974 } else if ( ic->count == BDB_IDL_DB_SIZE ) {
976 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
979 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
980 ic->tail->next = bdb_tool_idl_free_list;
981 bdb_tool_idl_free_list = ic->head;
982 bdb->bi_idl_cache_size -= n;
983 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
985 ic->head = ic->tail = NULL;
990 /* No free block, create that too */
991 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
993 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
994 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
995 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
996 rc = bdb_tool_idl_flush_db( db, ic );
999 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1001 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1003 bdb->bi_idl_cache_size++;
1004 if ( bdb_tool_idl_free_list ) {
1005 ice = bdb_tool_idl_free_list;
1006 bdb_tool_idl_free_list = ice->next;
1008 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1010 ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1012 memset( ice, 0, sizeof( *ice ));
1016 ic->tail->next = ice;
1023 ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1031 bdb_tool_index_task( void *ctx, void *ptr )
1033 int base = *(int *)ptr;
1037 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1038 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond,
1039 &bdb_tool_index_mutex );
1040 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1041 if ( slapd_shutdown )
1044 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1045 bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );