1 /* tools.c - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2007 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>
27 static DBC *cursor = NULL;
29 static EntryHeader eh;
32 typedef struct dn_id {
37 #define HOLE_SIZE 4096
38 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
39 static unsigned nhmax = HOLE_SIZE;
40 static unsigned nholes;
42 static int index_nattrs;
44 #ifdef BDB_TOOL_IDL_CACHING
45 #define bdb_tool_idl_cmp BDB_SYMBOL(tool_idl_cmp)
46 #define bdb_tool_idl_flush_one BDB_SYMBOL(tool_idl_flush_one)
47 #define bdb_tool_idl_flush BDB_SYMBOL(tool_idl_flush)
49 static int bdb_tool_idl_flush( BackendDB *be );
53 typedef struct bdb_tool_idl_cache_entry {
54 struct bdb_tool_idl_cache_entry *next;
56 } bdb_tool_idl_cache_entry;
58 typedef struct bdb_tool_idl_cache {
60 bdb_tool_idl_cache_entry *head, *tail;
65 static bdb_tool_idl_cache_entry *bdb_tool_idl_free_list;
66 #endif /* BDB_TOOL_IDL_CACHING */
68 static ID bdb_tool_ix_id;
69 static Operation *bdb_tool_ix_op;
70 static int *bdb_tool_index_threads, bdb_tool_index_tcount;
71 static void *bdb_tool_index_rec;
72 static struct bdb_info *bdb_tool_info;
73 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex;
74 static ldap_pvt_thread_cond_t bdb_tool_index_cond_main;
75 static ldap_pvt_thread_cond_t bdb_tool_index_cond_work;
77 static ldap_pvt_thread_mutex_t bdb_tool_trickle_mutex;
78 static ldap_pvt_thread_cond_t bdb_tool_trickle_cond;
80 static void * bdb_tool_index_task( void *ctx, void *ptr );
81 static void * bdb_tool_trickle_task( void *ctx, void *ptr );
83 int bdb_tool_entry_open(
84 BackendDB *be, int mode )
86 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
88 /* initialize key and data thangs */
91 key.flags = DB_DBT_REALLOC;
92 data.flags = DB_DBT_USERMEM;
95 int rc = bdb->bi_id2entry->bdi_db->cursor(
96 bdb->bi_id2entry->bdi_db, NULL, &cursor,
103 /* Set up for threaded slapindex */
104 if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
105 if ( !bdb_tool_info ) {
106 ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex );
107 ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond );
108 ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_trickle_task, bdb->bi_dbenv );
110 ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex );
111 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main );
112 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work );
113 if ( bdb->bi_nattrs ) {
115 bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
116 bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec ));
117 bdb_tool_index_tcount = slap_tool_thread_max - 1;
118 for (i=1; i<slap_tool_thread_max; i++) {
119 int *ptr = ch_malloc( sizeof( int ));
121 ldap_pvt_thread_pool_submit( &connection_pool,
122 bdb_tool_index_task, ptr );
132 int bdb_tool_entry_close(
135 if ( bdb_tool_info ) {
137 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
138 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
139 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
140 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
141 bdb_tool_index_tcount = slap_tool_thread_max - 1;
142 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
143 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
151 ch_free( eh.bv.bv_val );
156 cursor->c_close( cursor );
160 #ifdef BDB_TOOL_IDL_CACHING
161 bdb_tool_idl_flush( be );
166 fprintf( stderr, "Error, entries missing!\n");
167 for (i=0; i<nholes; i++) {
168 fprintf(stderr, " entry %ld: %s\n",
169 holes[i].id, holes[i].dn.bv_val);
179 BackendDB *be, int flag )
181 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
186 data.ulen = data.dlen = sizeof( buf );
188 data.flags |= DB_DBT_PARTIAL;
189 rc = cursor->c_get( cursor, &key, &data, flag );
195 eh.bv.bv_len = data.size;
196 rc = entry_header( &eh );
197 eoff = eh.data - eh.bv.bv_val;
203 ID bdb_tool_entry_next(
208 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
211 assert( be != NULL );
212 assert( slapMode & SLAP_TOOL_MODE );
213 assert( bdb != NULL );
215 rc = bdb_tool_entry_set( be, DB_NEXT );
218 /* If we're doing linear indexing and there are more attrs to
219 * index, and we're at the end of the database, start over.
221 if ( index_nattrs && rc == DB_NOTFOUND ) {
222 /* optional - do a checkpoint here? */
223 bdb_attr_info_free( bdb->bi_attrs[0] );
224 bdb->bi_attrs[0] = bdb->bi_attrs[index_nattrs];
226 rc = bdb_tool_entry_set( be, DB_FIRST );
235 BDB_DISK2ID( key.data, &id );
239 ID bdb_tool_dn2id_get(
246 EntryInfo *ei = NULL;
249 if ( BER_BVISEMPTY(dn) )
254 op.o_tmpmemctx = NULL;
255 op.o_tmpmfuncs = &ch_mfuncs;
257 rc = bdb_cache_find_ndn( &op, NULL, dn, &ei );
258 if ( ei ) bdb_cache_entryinfo_unlock( ei );
259 if ( rc == DB_NOTFOUND )
265 int bdb_tool_id2entry_get(
274 BDB_ID2DISK( id, &nid );
275 key.ulen = key.size = sizeof(ID);
276 key.flags = DB_DBT_USERMEM;
279 rc = bdb_tool_entry_set( be, DB_SET );
281 *e = bdb_tool_entry_get( be, id );
292 Entry* bdb_tool_entry_get( BackendDB *be, ID id )
297 assert( be != NULL );
298 assert( slapMode & SLAP_TOOL_MODE );
301 data.flags ^= DB_DBT_PARTIAL;
303 rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
304 if ( rc != DB_BUFFER_SMALL ) goto done;
306 /* Allocate a block and retrieve the data */
307 eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size;
308 eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
309 eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
311 data.ulen = data.size;
313 /* Skip past already parsed nattr/nvals */
316 rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
319 #ifdef SLAP_ZONE_ALLOC
320 /* FIXME: will add ctx later */
321 rc = entry_decode( &eh, &e, NULL );
323 rc = entry_decode( &eh, &e );
326 if( rc == LDAP_SUCCESS ) {
329 if ( slapMode & SLAP_TOOL_READONLY ) {
330 EntryInfo *ei = NULL;
336 op.o_tmpmemctx = NULL;
337 op.o_tmpmfuncs = &ch_mfuncs;
339 rc = bdb_cache_find_parent( &op, NULL, CURSOR_GETLOCKER(cursor), id, &ei );
340 if ( rc == LDAP_SUCCESS ) {
341 bdb_cache_entryinfo_unlock( ei );
355 static int bdb_tool_next_id(
362 struct berval dn = e->e_name;
363 struct berval ndn = e->e_nname;
364 struct berval pdn, npdn;
365 EntryInfo *ei = NULL, eidummy;
368 if (ndn.bv_len == 0) {
373 rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
374 if ( ei ) bdb_cache_entryinfo_unlock( ei );
375 if ( rc == DB_NOTFOUND ) {
376 if ( !be_issuffix( op->o_bd, &ndn ) ) {
378 dnParent( &dn, &pdn );
379 dnParent( &ndn, &npdn );
382 rc = bdb_tool_next_id( op, tid, e, text, 1 );
388 /* If parent didn't exist, it was created just now
389 * and its ID is now in e->e_id. Make sure the current
390 * entry gets added under the new parent ID.
392 if ( eid != e->e_id ) {
393 eidummy.bei_id = e->e_id;
397 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
399 snprintf( text->bv_val, text->bv_len,
400 "next_id failed: %s (%d)",
401 db_strerror(rc), rc );
402 Debug( LDAP_DEBUG_ANY,
403 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
406 rc = bdb_dn2id_add( op, tid, ei, e );
408 snprintf( text->bv_val, text->bv_len,
409 "dn2id_add failed: %s (%d)",
410 db_strerror(rc), rc );
411 Debug( LDAP_DEBUG_ANY,
412 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
414 if ( nholes == nhmax - 1 ) {
415 if ( holes == hbuf ) {
416 holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
417 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
419 holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
423 ber_dupbv( &holes[nholes].dn, &ndn );
424 holes[nholes++].id = e->e_id;
426 } else if ( !hole ) {
429 e->e_id = ei->bei_id;
431 for ( i=0; i<nholes; i++) {
432 if ( holes[i].id == e->e_id ) {
434 free(holes[i].dn.bv_val);
435 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
439 } else if ( holes[i].id > e->e_id ) {
453 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
455 if ( !bdb->bi_nattrs )
458 if ( slapMode & SLAP_TOOL_QUICK ) {
463 ir = bdb_tool_index_rec;
464 memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
466 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
467 rc = bdb_index_recset( bdb, a, a->a_desc->ad_type,
468 &a->a_desc->ad_tags, ir );
472 bdb_tool_ix_id = e->e_id;
474 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
475 /* Wait for all threads to be ready */
476 while ( bdb_tool_index_tcount ) {
477 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
478 &bdb_tool_index_mutex );
480 for ( i=1; i<slap_tool_thread_max; i++ )
481 bdb_tool_index_threads[i] = LDAP_BUSY;
482 bdb_tool_index_tcount = slap_tool_thread_max - 1;
483 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
484 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
485 rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
488 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
489 for ( i=1; i<slap_tool_thread_max; i++ ) {
490 if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
491 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
492 &bdb_tool_index_mutex );
496 if ( bdb_tool_index_threads[i] ) {
497 rc = bdb_tool_index_threads[i];
501 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
504 return bdb_index_entry_add( op, txn, e );
508 ID bdb_tool_entry_put(
511 struct berval *text )
514 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
519 assert( be != NULL );
520 assert( slapMode & SLAP_TOOL_MODE );
522 assert( text != NULL );
523 assert( text->bv_val != NULL );
524 assert( text->bv_val[0] == '\0' ); /* overconservative? */
526 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
527 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
529 if (! (slapMode & SLAP_TOOL_QUICK)) {
530 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
531 bdb->bi_db_opflags );
533 snprintf( text->bv_val, text->bv_len,
534 "txn_begin failed: %s (%d)",
535 db_strerror(rc), rc );
536 Debug( LDAP_DEBUG_ANY,
537 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
538 text->bv_val, 0, 0 );
545 op.o_tmpmemctx = NULL;
546 op.o_tmpmfuncs = &ch_mfuncs;
548 /* add dn2id indices */
549 rc = bdb_tool_next_id( &op, tid, e, text, 0 );
554 if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) {
555 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
556 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
557 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
560 if ( !bdb->bi_linear_index )
561 rc = bdb_tool_index_add( &op, tid, e );
563 snprintf( text->bv_val, text->bv_len,
564 "index_entry_add failed: %s (%d)",
565 db_strerror(rc), rc );
566 Debug( LDAP_DEBUG_ANY,
567 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
568 text->bv_val, 0, 0 );
573 rc = bdb_id2entry_add( be, tid, e );
575 snprintf( text->bv_val, text->bv_len,
576 "id2entry_add failed: %s (%d)",
577 db_strerror(rc), rc );
578 Debug( LDAP_DEBUG_ANY,
579 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
580 text->bv_val, 0, 0 );
586 if ( !( slapMode & SLAP_TOOL_QUICK )) {
587 rc = TXN_COMMIT( tid, 0 );
589 snprintf( text->bv_val, text->bv_len,
590 "txn_commit failed: %s (%d)",
591 db_strerror(rc), rc );
592 Debug( LDAP_DEBUG_ANY,
593 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
594 text->bv_val, 0, 0 );
600 if ( !( slapMode & SLAP_TOOL_QUICK )) {
602 snprintf( text->bv_val, text->bv_len,
603 "txn_aborted! %s (%d)",
604 db_strerror(rc), rc );
605 Debug( LDAP_DEBUG_ANY,
606 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
607 text->bv_val, 0, 0 );
615 int bdb_tool_entry_reindex(
618 AttributeDescription **adv )
620 struct bdb_info *bi = (struct bdb_info *) be->be_private;
627 Debug( LDAP_DEBUG_ARGS,
628 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
631 /* No indexes configured, nothing to do. Could return an
632 * error here to shortcut things.
638 /* Check for explicit list of attrs to index */
642 if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
644 for ( n = 0; adv[n]; n++ ) ;
647 for ( i = 0; i < n; i++ ) {
648 AttributeDescription *ad = adv[i];
649 for ( j = i-1; j>=0; j--) {
650 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
657 for ( i = 0; adv[i]; i++ ) {
658 if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
659 for ( j = i+1; j < bi->bi_nattrs; j++ ) {
660 if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
661 AttrInfo *ai = bi->bi_attrs[i];
662 bi->bi_attrs[i] = bi->bi_attrs[j];
663 bi->bi_attrs[j] = ai;
667 if ( j == bi->bi_nattrs ) {
668 Debug( LDAP_DEBUG_ANY,
669 LDAP_XSTRING(bdb_tool_entry_reindex)
670 ": no index configured for %s\n",
671 adv[i]->ad_cname.bv_val, 0, 0 );
679 /* Get the first attribute to index */
680 if (bi->bi_linear_index && !index_nattrs) {
681 index_nattrs = bi->bi_nattrs - 1;
685 e = bdb_tool_entry_get( be, id );
688 Debug( LDAP_DEBUG_ANY,
689 LDAP_XSTRING(bdb_tool_entry_reindex)
690 ": could not locate id=%ld\n",
695 if (! (slapMode & SLAP_TOOL_QUICK)) {
696 rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
698 Debug( LDAP_DEBUG_ANY,
699 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
700 "txn_begin failed: %s (%d)\n",
701 db_strerror(rc), rc, 0 );
707 * just (re)add them for now
708 * assume that some other routine (not yet implemented)
709 * will zap index databases
713 Debug( LDAP_DEBUG_TRACE,
714 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
715 (long) id, e->e_dn, 0 );
719 op.o_tmpmemctx = NULL;
720 op.o_tmpmfuncs = &ch_mfuncs;
722 rc = bdb_tool_index_add( &op, tid, e );
726 if (! (slapMode & SLAP_TOOL_QUICK)) {
727 rc = TXN_COMMIT( tid, 0 );
729 Debug( LDAP_DEBUG_ANY,
730 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
731 ": txn_commit failed: %s (%d)\n",
732 db_strerror(rc), rc, 0 );
738 if (! (slapMode & SLAP_TOOL_QUICK)) {
740 Debug( LDAP_DEBUG_ANY,
741 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
742 ": txn_aborted! %s (%d)\n",
743 db_strerror(rc), rc, 0 );
747 bdb_entry_release( &op, e, 0 );
752 ID bdb_tool_entry_modify(
755 struct berval *text )
758 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
763 assert( be != NULL );
764 assert( slapMode & SLAP_TOOL_MODE );
766 assert( text != NULL );
767 assert( text->bv_val != NULL );
768 assert( text->bv_val[0] == '\0' ); /* overconservative? */
770 assert ( e->e_id != NOID );
772 Debug( LDAP_DEBUG_TRACE,
773 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
774 (long) e->e_id, e->e_dn, 0 );
776 if (! (slapMode & SLAP_TOOL_QUICK)) {
777 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
778 bdb->bi_db_opflags );
780 snprintf( text->bv_val, text->bv_len,
781 "txn_begin failed: %s (%d)",
782 db_strerror(rc), rc );
783 Debug( LDAP_DEBUG_ANY,
784 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
785 text->bv_val, 0, 0 );
792 op.o_tmpmemctx = NULL;
793 op.o_tmpmfuncs = &ch_mfuncs;
796 rc = bdb_id2entry_update( be, tid, e );
798 snprintf( text->bv_val, text->bv_len,
799 "id2entry_add failed: %s (%d)",
800 db_strerror(rc), rc );
801 Debug( LDAP_DEBUG_ANY,
802 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
803 text->bv_val, 0, 0 );
809 if (! (slapMode & SLAP_TOOL_QUICK)) {
810 rc = TXN_COMMIT( tid, 0 );
812 snprintf( text->bv_val, text->bv_len,
813 "txn_commit failed: %s (%d)",
814 db_strerror(rc), rc );
815 Debug( LDAP_DEBUG_ANY,
816 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
817 "%s\n", text->bv_val, 0, 0 );
823 if (! (slapMode & SLAP_TOOL_QUICK)) {
825 snprintf( text->bv_val, text->bv_len,
826 "txn_aborted! %s (%d)",
827 db_strerror(rc), rc );
828 Debug( LDAP_DEBUG_ANY,
829 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
830 text->bv_val, 0, 0 );
838 #ifdef BDB_TOOL_IDL_CACHING
840 bdb_tool_idl_cmp( const void *v1, const void *v2 )
842 const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
845 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
846 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
850 bdb_tool_idl_flush_one( void *v1, void *arg )
852 bdb_tool_idl_cache *ic = v1;
854 struct bdb_info *bdb = bdb_tool_info;
855 bdb_tool_idl_cache_entry *ice;
861 /* Freshly allocated, ignore it */
862 if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
866 rc = db->cursor( db, NULL, &curs, 0 );
873 bv2DBT( &ic->kstr, &key );
875 data.size = data.ulen = sizeof( ID );
876 data.flags = DB_DBT_USERMEM;
879 rc = curs->c_get( curs, &key, &data, DB_SET );
880 /* If key already exists and we're writing a range... */
881 if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
882 /* If it's not currently a range, must delete old info */
885 while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
886 curs->c_del( curs, 0 );
889 /* Store range marker */
890 curs->c_put( curs, &key, &data, DB_KEYFIRST );
894 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
897 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
900 curs->c_del( curs, 0 );
902 BDB_ID2DISK( ic->last, &nid );
903 curs->c_put( curs, &key, &data, DB_KEYLAST );
905 } else if ( rc && rc != DB_NOTFOUND ) {
907 } else if ( ic->count > BDB_IDL_DB_SIZE ) {
908 /* range, didn't exist before */
910 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
912 BDB_ID2DISK( ic->first, &nid );
913 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
915 BDB_ID2DISK( ic->last, &nid );
916 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
925 /* Just a normal write */
927 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
932 end = ic->count & (IDBLOCK-1);
936 for ( i=0; i<end; i++ ) {
937 if ( !ice->ids[i] ) continue;
938 BDB_ID2DISK( ice->ids[i], &nid );
939 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
941 if ( rc == DB_KEYEXIST ) {
955 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
956 ic->tail->next = bdb_tool_idl_free_list;
957 bdb_tool_idl_free_list = ic->head;
958 bdb->bi_idl_cache_size -= n;
959 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
962 if ( ic != db->app_private ) {
965 ic->head = ic->tail = NULL;
967 curs->c_close( curs );
972 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
974 Avlnode *root = db->app_private;
977 db->app_private = ic;
978 rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
979 avl_free( root, NULL );
980 db->app_private = NULL;
987 bdb_tool_idl_flush( BackendDB *be )
989 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
994 for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
995 db = bdb->bi_databases[i]->bdi_db;
996 if ( !db->app_private ) continue;
997 rc = bdb_tool_idl_flush_db( db, NULL );
1002 bdb->bi_idl_cache_size = 0;
1007 int bdb_tool_idl_add(
1014 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1015 bdb_tool_idl_cache *ic, itmp;
1016 bdb_tool_idl_cache_entry *ice;
1019 if ( !bdb->bi_idl_cache_max_size )
1020 return bdb_idl_insert_key( be, db, txn, key, id );
1022 DBT2bv( key, &itmp.kstr );
1024 ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
1026 /* No entry yet, create one */
1033 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
1034 ic->kstr.bv_len = itmp.kstr.bv_len;
1035 ic->kstr.bv_val = (char *)(ic+1);
1036 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1037 ic->head = ic->tail = NULL;
1040 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1043 /* load existing key count here */
1044 rc = db->cursor( db, NULL, &curs, 0 );
1045 if ( rc ) return rc;
1047 data.ulen = sizeof( ID );
1048 data.flags = DB_DBT_USERMEM;
1050 rc = curs->c_get( curs, key, &data, DB_SET );
1053 ic->count = BDB_IDL_DB_SIZE+1;
1057 curs->c_count( curs, &count, 0 );
1059 BDB_DISK2ID( &nid, &ic->first );
1062 curs->c_close( curs );
1064 /* are we a range already? */
1065 if ( ic->count > BDB_IDL_DB_SIZE ) {
1068 /* Are we at the limit, and converting to a range? */
1069 } else if ( ic->count == BDB_IDL_DB_SIZE ) {
1071 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
1074 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1075 ic->tail->next = bdb_tool_idl_free_list;
1076 bdb_tool_idl_free_list = ic->head;
1077 bdb->bi_idl_cache_size -= n;
1078 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1080 ic->head = ic->tail = NULL;
1085 /* No free block, create that too */
1086 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
1088 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1089 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
1090 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1091 rc = bdb_tool_idl_flush_db( db, ic );
1094 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1096 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1098 bdb->bi_idl_cache_size++;
1099 if ( bdb_tool_idl_free_list ) {
1100 ice = bdb_tool_idl_free_list;
1101 bdb_tool_idl_free_list = ice->next;
1103 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1105 ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1107 memset( ice, 0, sizeof( *ice ));
1111 ic->tail->next = ice;
1118 ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1126 bdb_tool_trickle_task( void *ctx, void *ptr )
1131 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
1133 ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond,
1134 &bdb_tool_trickle_mutex );
1135 if ( slapd_shutdown )
1137 env->memp_trickle( env, 30, &wrote );
1139 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
1145 bdb_tool_index_task( void *ctx, void *ptr )
1147 int base = *(int *)ptr;
1151 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1152 bdb_tool_index_tcount--;
1153 if ( !bdb_tool_index_tcount )
1154 ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
1155 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work,
1156 &bdb_tool_index_mutex );
1157 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1158 if ( slapd_shutdown )
1161 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1162 bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );