1 /* tools.c - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2011 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;
30 static ID nid, previd = NOID;
31 static char ehbuf[16];
33 typedef struct dn_id {
38 #define HOLE_SIZE 4096
39 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
40 static unsigned nhmax = HOLE_SIZE;
41 static unsigned nholes;
43 static int index_nattrs;
45 static struct berval *tool_base;
46 static int tool_scope;
47 static Filter *tool_filter;
48 static Entry *tool_next_entry;
50 #ifdef BDB_TOOL_IDL_CACHING
51 #define bdb_tool_idl_cmp BDB_SYMBOL(tool_idl_cmp)
52 #define bdb_tool_idl_flush_one BDB_SYMBOL(tool_idl_flush_one)
53 #define bdb_tool_idl_flush BDB_SYMBOL(tool_idl_flush)
55 static int bdb_tool_idl_flush( BackendDB *be );
59 typedef struct bdb_tool_idl_cache_entry {
60 struct bdb_tool_idl_cache_entry *next;
62 } bdb_tool_idl_cache_entry;
64 typedef struct bdb_tool_idl_cache {
66 bdb_tool_idl_cache_entry *head, *tail;
71 static bdb_tool_idl_cache_entry *bdb_tool_idl_free_list;
72 #endif /* BDB_TOOL_IDL_CACHING */
74 static ID bdb_tool_ix_id;
75 static Operation *bdb_tool_ix_op;
76 static int *bdb_tool_index_threads, bdb_tool_index_tcount;
77 static void *bdb_tool_index_rec;
78 static struct bdb_info *bdb_tool_info;
79 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex;
80 static ldap_pvt_thread_cond_t bdb_tool_index_cond_main;
81 static ldap_pvt_thread_cond_t bdb_tool_index_cond_work;
83 #if DB_VERSION_FULL >= 0x04060000
86 /* Seems to slow things down too much in BDB 4.5 */
91 static ldap_pvt_thread_mutex_t bdb_tool_trickle_mutex;
92 static ldap_pvt_thread_cond_t bdb_tool_trickle_cond;
94 static void * bdb_tool_trickle_task( void *ctx, void *ptr );
97 static void * bdb_tool_index_task( void *ctx, void *ptr );
100 bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
102 int bdb_tool_entry_open(
103 BackendDB *be, int mode )
105 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
107 /* initialize key and data thangs */
110 key.flags = DB_DBT_USERMEM;
112 key.size = key.ulen = sizeof( nid );
113 data.flags = DB_DBT_USERMEM;
115 if (cursor == NULL) {
116 int rc = bdb->bi_id2entry->bdi_db->cursor(
117 bdb->bi_id2entry->bdi_db, bdb->bi_cache.c_txn, &cursor,
118 bdb->bi_db_opflags );
124 /* Set up for threaded slapindex */
125 if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
126 if ( !bdb_tool_info ) {
128 ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex );
129 ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond );
130 ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_trickle_task, bdb->bi_dbenv );
133 ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex );
134 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main );
135 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work );
136 if ( bdb->bi_nattrs ) {
138 bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
139 bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec ));
140 bdb_tool_index_tcount = slap_tool_thread_max - 1;
141 for (i=1; i<slap_tool_thread_max; i++) {
142 int *ptr = ch_malloc( sizeof( int ));
144 ldap_pvt_thread_pool_submit( &connection_pool,
145 bdb_tool_index_task, ptr );
155 int bdb_tool_entry_close(
158 if ( bdb_tool_info ) {
161 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
162 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
163 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
165 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
166 bdb_tool_index_tcount = slap_tool_thread_max - 1;
167 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
168 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
172 ch_free( eh.bv.bv_val );
177 cursor->c_close( cursor );
181 #ifdef BDB_TOOL_IDL_CACHING
182 bdb_tool_idl_flush( be );
187 fprintf( stderr, "Error, entries missing!\n");
188 for (i=0; i<nholes; i++) {
189 fprintf(stderr, " entry %ld: %s\n",
190 holes[i].id, holes[i].dn.bv_val);
199 bdb_tool_entry_first_x(
209 return bdb_tool_entry_next( be );
212 ID bdb_tool_entry_next(
217 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
219 assert( be != NULL );
220 assert( slapMode & SLAP_TOOL_MODE );
221 assert( bdb != NULL );
225 data.ulen = data.dlen = sizeof( ehbuf );
227 data.flags |= DB_DBT_PARTIAL;
228 rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
231 /* If we're doing linear indexing and there are more attrs to
232 * index, and we're at the end of the database, start over.
234 if ( index_nattrs && rc == DB_NOTFOUND ) {
235 /* optional - do a checkpoint here? */
236 bdb_attr_info_free( bdb->bi_attrs[0] );
237 bdb->bi_attrs[0] = bdb->bi_attrs[index_nattrs];
239 rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
248 BDB_DISK2ID( key.data, &id );
251 if ( tool_filter || tool_base ) {
252 static Operation op = {0};
253 static Opheader ohdr = {0};
257 op.o_tmpmemctx = NULL;
258 op.o_tmpmfuncs = &ch_mfuncs;
260 if ( tool_next_entry ) {
261 bdb_entry_release( &op, tool_next_entry, 0 );
262 tool_next_entry = NULL;
265 rc = bdb_tool_entry_get_int( be, id, &tool_next_entry );
266 if ( rc == LDAP_NO_SUCH_OBJECT ) {
270 assert( tool_next_entry != NULL );
273 /* TODO: needed until BDB_HIER is handled accordingly
274 * in bdb_tool_entry_get_int() */
275 if ( tool_base && !dnIsSuffixScope( &tool_next_entry->e_nname, tool_base, tool_scope ) )
277 bdb_entry_release( &op, tool_next_entry, 0 );
278 tool_next_entry = NULL;
283 if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
285 bdb_entry_release( &op, tool_next_entry, 0 );
286 tool_next_entry = NULL;
294 ID bdb_tool_dn2id_get(
301 EntryInfo *ei = NULL;
304 if ( BER_BVISEMPTY(dn) )
309 op.o_tmpmemctx = NULL;
310 op.o_tmpmfuncs = &ch_mfuncs;
312 rc = bdb_cache_find_ndn( &op, 0, dn, &ei );
313 if ( ei ) bdb_cache_entryinfo_unlock( ei );
314 if ( rc == DB_NOTFOUND )
321 bdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
327 assert( be != NULL );
328 assert( slapMode & SLAP_TOOL_MODE );
330 if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
331 *ep = tool_next_entry;
332 tool_next_entry = NULL;
336 if ( id != previd ) {
337 data.ulen = data.dlen = sizeof( ehbuf );
339 data.flags |= DB_DBT_PARTIAL;
341 BDB_ID2DISK( id, &nid );
342 rc = cursor->c_get( cursor, &key, &data, DB_SET );
351 eh.bv.bv_val = ehbuf;
352 eh.bv.bv_len = data.size;
353 rc = entry_header( &eh );
354 eoff = eh.data - eh.bv.bv_val;
362 data.flags &= ~DB_DBT_PARTIAL;
364 rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
365 if ( rc != DB_BUFFER_SMALL ) {
370 /* Allocate a block and retrieve the data */
371 eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size;
372 eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
373 eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
375 data.ulen = data.size;
377 /* Skip past already parsed nattr/nvals */
380 rc = cursor->c_get( cursor, &key, &data, DB_CURRENT );
387 /* TODO: handle BDB_HIER accordingly */
388 if ( tool_base != NULL ) {
390 entry_decode_dn( &eh, NULL, &ndn );
392 if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
393 return LDAP_NO_SUCH_OBJECT;
398 #ifdef SLAP_ZONE_ALLOC
399 /* FIXME: will add ctx later */
400 rc = entry_decode( &eh, &e, NULL );
402 rc = entry_decode( &eh, &e );
405 if( rc == LDAP_SUCCESS ) {
408 if ( slapMode & SLAP_TOOL_READONLY ) {
409 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
410 EntryInfo *ei = NULL;
416 op.o_tmpmemctx = NULL;
417 op.o_tmpmfuncs = &ch_mfuncs;
419 rc = bdb_cache_find_parent( &op, bdb->bi_cache.c_txn, id, &ei );
420 if ( rc == LDAP_SUCCESS ) {
421 bdb_cache_entryinfo_unlock( ei );
440 bdb_tool_entry_get( BackendDB *be, ID id )
444 (void)bdb_tool_entry_get_int( be, id, &e );
448 static int bdb_tool_next_id(
455 struct berval dn = e->e_name;
456 struct berval ndn = e->e_nname;
457 struct berval pdn, npdn;
458 EntryInfo *ei = NULL, eidummy;
461 if (ndn.bv_len == 0) {
466 rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
467 if ( ei ) bdb_cache_entryinfo_unlock( ei );
468 if ( rc == DB_NOTFOUND ) {
469 if ( !be_issuffix( op->o_bd, &ndn ) ) {
471 dnParent( &dn, &pdn );
472 dnParent( &ndn, &npdn );
475 rc = bdb_tool_next_id( op, tid, e, text, 1 );
481 /* If parent didn't exist, it was created just now
482 * and its ID is now in e->e_id. Make sure the current
483 * entry gets added under the new parent ID.
485 if ( eid != e->e_id ) {
486 eidummy.bei_id = e->e_id;
490 rc = bdb_next_id( op->o_bd, &e->e_id );
492 snprintf( text->bv_val, text->bv_len,
493 "next_id failed: %s (%d)",
494 db_strerror(rc), rc );
495 Debug( LDAP_DEBUG_ANY,
496 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
499 rc = bdb_dn2id_add( op, tid, ei, e );
501 snprintf( text->bv_val, text->bv_len,
502 "dn2id_add failed: %s (%d)",
503 db_strerror(rc), rc );
504 Debug( LDAP_DEBUG_ANY,
505 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
507 if ( nholes == nhmax - 1 ) {
508 if ( holes == hbuf ) {
509 holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
510 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
512 holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
516 ber_dupbv( &holes[nholes].dn, &ndn );
517 holes[nholes++].id = e->e_id;
519 } else if ( !hole ) {
522 e->e_id = ei->bei_id;
524 for ( i=0; i<nholes; i++) {
525 if ( holes[i].id == e->e_id ) {
526 free(holes[i].dn.bv_val);
527 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
531 } else if ( holes[i].id > e->e_id ) {
545 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
547 if ( !bdb->bi_nattrs )
550 if ( slapMode & SLAP_TOOL_QUICK ) {
555 ir = bdb_tool_index_rec;
556 memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
558 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
559 rc = bdb_index_recset( bdb, a, a->a_desc->ad_type,
560 &a->a_desc->ad_tags, ir );
564 bdb_tool_ix_id = e->e_id;
566 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
567 /* Wait for all threads to be ready */
568 while ( bdb_tool_index_tcount ) {
569 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
570 &bdb_tool_index_mutex );
572 for ( i=1; i<slap_tool_thread_max; i++ )
573 bdb_tool_index_threads[i] = LDAP_BUSY;
574 bdb_tool_index_tcount = slap_tool_thread_max - 1;
575 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
576 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
577 rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
580 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
581 for ( i=1; i<slap_tool_thread_max; i++ ) {
582 if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
583 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
584 &bdb_tool_index_mutex );
588 if ( bdb_tool_index_threads[i] ) {
589 rc = bdb_tool_index_threads[i];
593 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
596 return bdb_index_entry_add( op, txn, e );
600 ID bdb_tool_entry_put(
603 struct berval *text )
606 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
611 assert( be != NULL );
612 assert( slapMode & SLAP_TOOL_MODE );
614 assert( text != NULL );
615 assert( text->bv_val != NULL );
616 assert( text->bv_val[0] == '\0' ); /* overconservative? */
618 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
619 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
621 if (! (slapMode & SLAP_TOOL_QUICK)) {
622 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
623 bdb->bi_db_opflags );
625 snprintf( text->bv_val, text->bv_len,
626 "txn_begin failed: %s (%d)",
627 db_strerror(rc), rc );
628 Debug( LDAP_DEBUG_ANY,
629 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
630 text->bv_val, 0, 0 );
637 op.o_tmpmemctx = NULL;
638 op.o_tmpmfuncs = &ch_mfuncs;
640 /* add dn2id indices */
641 rc = bdb_tool_next_id( &op, tid, e, text, 0 );
647 if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) {
648 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
652 if ( !bdb->bi_linear_index )
653 rc = bdb_tool_index_add( &op, tid, e );
655 snprintf( text->bv_val, text->bv_len,
656 "index_entry_add failed: %s (%d)",
657 rc == LDAP_OTHER ? "Internal error" :
658 db_strerror(rc), rc );
659 Debug( LDAP_DEBUG_ANY,
660 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
661 text->bv_val, 0, 0 );
666 rc = bdb_id2entry_add( be, tid, e );
668 snprintf( text->bv_val, text->bv_len,
669 "id2entry_add failed: %s (%d)",
670 db_strerror(rc), rc );
671 Debug( LDAP_DEBUG_ANY,
672 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
673 text->bv_val, 0, 0 );
679 if ( !( slapMode & SLAP_TOOL_QUICK )) {
680 rc = TXN_COMMIT( tid, 0 );
682 snprintf( text->bv_val, text->bv_len,
683 "txn_commit failed: %s (%d)",
684 db_strerror(rc), rc );
685 Debug( LDAP_DEBUG_ANY,
686 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
687 text->bv_val, 0, 0 );
693 if ( !( slapMode & SLAP_TOOL_QUICK )) {
695 snprintf( text->bv_val, text->bv_len,
696 "txn_aborted! %s (%d)",
697 rc == LDAP_OTHER ? "Internal error" :
698 db_strerror(rc), rc );
699 Debug( LDAP_DEBUG_ANY,
700 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
701 text->bv_val, 0, 0 );
709 int bdb_tool_entry_reindex(
712 AttributeDescription **adv )
714 struct bdb_info *bi = (struct bdb_info *) be->be_private;
721 Debug( LDAP_DEBUG_ARGS,
722 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
724 assert( tool_base == NULL );
725 assert( tool_filter == NULL );
727 /* No indexes configured, nothing to do. Could return an
728 * error here to shortcut things.
734 /* Check for explicit list of attrs to index */
738 if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
740 for ( n = 0; adv[n]; n++ ) ;
743 for ( i = 0; i < n; i++ ) {
744 AttributeDescription *ad = adv[i];
745 for ( j = i-1; j>=0; j--) {
746 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
753 for ( i = 0; adv[i]; i++ ) {
754 if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
755 for ( j = i+1; j < bi->bi_nattrs; j++ ) {
756 if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
757 AttrInfo *ai = bi->bi_attrs[i];
758 bi->bi_attrs[i] = bi->bi_attrs[j];
759 bi->bi_attrs[j] = ai;
763 if ( j == bi->bi_nattrs ) {
764 Debug( LDAP_DEBUG_ANY,
765 LDAP_XSTRING(bdb_tool_entry_reindex)
766 ": no index configured for %s\n",
767 adv[i]->ad_cname.bv_val, 0, 0 );
775 /* Get the first attribute to index */
776 if (bi->bi_linear_index && !index_nattrs) {
777 index_nattrs = bi->bi_nattrs - 1;
781 e = bdb_tool_entry_get( be, id );
784 Debug( LDAP_DEBUG_ANY,
785 LDAP_XSTRING(bdb_tool_entry_reindex)
786 ": could not locate id=%ld\n",
791 if (! (slapMode & SLAP_TOOL_QUICK)) {
792 rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
794 Debug( LDAP_DEBUG_ANY,
795 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
796 "txn_begin failed: %s (%d)\n",
797 db_strerror(rc), rc, 0 );
803 * just (re)add them for now
804 * assume that some other routine (not yet implemented)
805 * will zap index databases
809 Debug( LDAP_DEBUG_TRACE,
810 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
811 (long) id, e->e_dn, 0 );
815 op.o_tmpmemctx = NULL;
816 op.o_tmpmfuncs = &ch_mfuncs;
818 rc = bdb_tool_index_add( &op, tid, e );
822 if (! (slapMode & SLAP_TOOL_QUICK)) {
823 rc = TXN_COMMIT( tid, 0 );
825 Debug( LDAP_DEBUG_ANY,
826 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
827 ": txn_commit failed: %s (%d)\n",
828 db_strerror(rc), rc, 0 );
834 if (! (slapMode & SLAP_TOOL_QUICK)) {
836 Debug( LDAP_DEBUG_ANY,
837 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
838 ": txn_aborted! %s (%d)\n",
839 db_strerror(rc), rc, 0 );
843 bdb_entry_release( &op, e, 0 );
848 ID bdb_tool_entry_modify(
851 struct berval *text )
854 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
859 assert( be != NULL );
860 assert( slapMode & SLAP_TOOL_MODE );
862 assert( text != NULL );
863 assert( text->bv_val != NULL );
864 assert( text->bv_val[0] == '\0' ); /* overconservative? */
866 assert ( e->e_id != NOID );
868 Debug( LDAP_DEBUG_TRACE,
869 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
870 (long) e->e_id, e->e_dn, 0 );
872 if (! (slapMode & SLAP_TOOL_QUICK)) {
874 cursor->c_close( cursor );
877 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
878 bdb->bi_db_opflags );
880 snprintf( text->bv_val, text->bv_len,
881 "txn_begin failed: %s (%d)",
882 db_strerror(rc), rc );
883 Debug( LDAP_DEBUG_ANY,
884 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
885 text->bv_val, 0, 0 );
892 op.o_tmpmemctx = NULL;
893 op.o_tmpmfuncs = &ch_mfuncs;
896 rc = bdb_id2entry_update( be, tid, e );
898 snprintf( text->bv_val, text->bv_len,
899 "id2entry_add failed: %s (%d)",
900 db_strerror(rc), rc );
901 Debug( LDAP_DEBUG_ANY,
902 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
903 text->bv_val, 0, 0 );
909 if (! (slapMode & SLAP_TOOL_QUICK)) {
910 rc = TXN_COMMIT( tid, 0 );
912 snprintf( text->bv_val, text->bv_len,
913 "txn_commit failed: %s (%d)",
914 db_strerror(rc), rc );
915 Debug( LDAP_DEBUG_ANY,
916 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
917 "%s\n", text->bv_val, 0, 0 );
923 if (! (slapMode & SLAP_TOOL_QUICK)) {
925 snprintf( text->bv_val, text->bv_len,
926 "txn_aborted! %s (%d)",
927 db_strerror(rc), rc );
928 Debug( LDAP_DEBUG_ANY,
929 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
930 text->bv_val, 0, 0 );
938 #ifdef BDB_TOOL_IDL_CACHING
940 bdb_tool_idl_cmp( const void *v1, const void *v2 )
942 const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
945 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
946 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
950 bdb_tool_idl_flush_one( void *v1, void *arg )
952 bdb_tool_idl_cache *ic = v1;
954 struct bdb_info *bdb = bdb_tool_info;
955 bdb_tool_idl_cache_entry *ice;
961 /* Freshly allocated, ignore it */
962 if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
966 rc = db->cursor( db, NULL, &curs, 0 );
973 bv2DBT( &ic->kstr, &key );
975 data.size = data.ulen = sizeof( ID );
976 data.flags = DB_DBT_USERMEM;
979 rc = curs->c_get( curs, &key, &data, DB_SET );
980 /* If key already exists and we're writing a range... */
981 if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
982 /* If it's not currently a range, must delete old info */
985 while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
986 curs->c_del( curs, 0 );
989 /* Store range marker */
990 curs->c_put( curs, &key, &data, DB_KEYFIRST );
994 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
997 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
1000 curs->c_del( curs, 0 );
1002 BDB_ID2DISK( ic->last, &nid );
1003 curs->c_put( curs, &key, &data, DB_KEYLAST );
1005 } else if ( rc && rc != DB_NOTFOUND ) {
1007 } else if ( ic->count > BDB_IDL_DB_SIZE ) {
1008 /* range, didn't exist before */
1010 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1012 BDB_ID2DISK( ic->first, &nid );
1013 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1015 BDB_ID2DISK( ic->last, &nid );
1016 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1025 /* Just a normal write */
1027 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
1032 end = ic->count & (IDBLOCK-1);
1036 for ( i=0; i<end; i++ ) {
1037 if ( !ice->ids[i] ) continue;
1038 BDB_ID2DISK( ice->ids[i], &nid );
1039 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
1041 if ( rc == DB_KEYEXIST ) {
1055 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1056 ic->tail->next = bdb_tool_idl_free_list;
1057 bdb_tool_idl_free_list = ic->head;
1058 bdb->bi_idl_cache_size -= n;
1059 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1062 if ( ic != db->app_private ) {
1065 ic->head = ic->tail = NULL;
1067 curs->c_close( curs );
1072 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
1074 Avlnode *root = db->app_private;
1077 db->app_private = ic;
1078 rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
1079 avl_free( root, NULL );
1080 db->app_private = NULL;
1087 bdb_tool_idl_flush( BackendDB *be )
1089 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1094 for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
1095 db = bdb->bi_databases[i]->bdi_db;
1096 if ( !db->app_private ) continue;
1097 rc = bdb_tool_idl_flush_db( db, NULL );
1102 bdb->bi_idl_cache_size = 0;
1107 int bdb_tool_idl_add(
1114 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1115 bdb_tool_idl_cache *ic, itmp;
1116 bdb_tool_idl_cache_entry *ice;
1119 if ( !bdb->bi_idl_cache_max_size )
1120 return bdb_idl_insert_key( be, db, txn, key, id );
1122 DBT2bv( key, &itmp.kstr );
1124 ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
1126 /* No entry yet, create one */
1133 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
1134 ic->kstr.bv_len = itmp.kstr.bv_len;
1135 ic->kstr.bv_val = (char *)(ic+1);
1136 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1137 ic->head = ic->tail = NULL;
1140 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1143 /* load existing key count here */
1144 rc = db->cursor( db, NULL, &curs, 0 );
1145 if ( rc ) return rc;
1147 data.ulen = sizeof( ID );
1148 data.flags = DB_DBT_USERMEM;
1150 rc = curs->c_get( curs, key, &data, DB_SET );
1153 ic->count = BDB_IDL_DB_SIZE+1;
1157 curs->c_count( curs, &count, 0 );
1159 BDB_DISK2ID( &nid, &ic->first );
1162 curs->c_close( curs );
1164 /* are we a range already? */
1165 if ( ic->count > BDB_IDL_DB_SIZE ) {
1168 /* Are we at the limit, and converting to a range? */
1169 } else if ( ic->count == BDB_IDL_DB_SIZE ) {
1171 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
1174 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1175 ic->tail->next = bdb_tool_idl_free_list;
1176 bdb_tool_idl_free_list = ic->head;
1177 bdb->bi_idl_cache_size -= n;
1178 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1180 ic->head = ic->tail = NULL;
1185 /* No free block, create that too */
1186 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
1188 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1189 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
1190 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1191 rc = bdb_tool_idl_flush_db( db, ic );
1194 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1196 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1198 bdb->bi_idl_cache_size++;
1199 if ( bdb_tool_idl_free_list ) {
1200 ice = bdb_tool_idl_free_list;
1201 bdb_tool_idl_free_list = ice->next;
1203 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1205 ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1207 memset( ice, 0, sizeof( *ice ));
1211 ic->tail->next = ice;
1218 ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1227 bdb_tool_trickle_task( void *ctx, void *ptr )
1232 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
1234 ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond,
1235 &bdb_tool_trickle_mutex );
1236 if ( slapd_shutdown )
1238 env->memp_trickle( env, 30, &wrote );
1240 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
1247 bdb_tool_index_task( void *ctx, void *ptr )
1249 int base = *(int *)ptr;
1253 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1254 bdb_tool_index_tcount--;
1255 if ( !bdb_tool_index_tcount )
1256 ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
1257 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work,
1258 &bdb_tool_index_mutex );
1259 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1260 if ( slapd_shutdown )
1263 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1264 bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );