1 /* tools.c - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2010 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 )
445 rc = bdb_tool_entry_get_int( be, id, &e );
446 if ( rc == LDAP_SUCCESS ) {
451 static int bdb_tool_next_id(
458 struct berval dn = e->e_name;
459 struct berval ndn = e->e_nname;
460 struct berval pdn, npdn;
461 EntryInfo *ei = NULL, eidummy;
464 if (ndn.bv_len == 0) {
469 rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
470 if ( ei ) bdb_cache_entryinfo_unlock( ei );
471 if ( rc == DB_NOTFOUND ) {
472 if ( !be_issuffix( op->o_bd, &ndn ) ) {
474 dnParent( &dn, &pdn );
475 dnParent( &ndn, &npdn );
478 rc = bdb_tool_next_id( op, tid, e, text, 1 );
484 /* If parent didn't exist, it was created just now
485 * and its ID is now in e->e_id. Make sure the current
486 * entry gets added under the new parent ID.
488 if ( eid != e->e_id ) {
489 eidummy.bei_id = e->e_id;
493 rc = bdb_next_id( op->o_bd, &e->e_id );
495 snprintf( text->bv_val, text->bv_len,
496 "next_id failed: %s (%d)",
497 db_strerror(rc), rc );
498 Debug( LDAP_DEBUG_ANY,
499 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
502 rc = bdb_dn2id_add( op, tid, ei, e );
504 snprintf( text->bv_val, text->bv_len,
505 "dn2id_add failed: %s (%d)",
506 db_strerror(rc), rc );
507 Debug( LDAP_DEBUG_ANY,
508 "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
510 if ( nholes == nhmax - 1 ) {
511 if ( holes == hbuf ) {
512 holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
513 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
515 holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
519 ber_dupbv( &holes[nholes].dn, &ndn );
520 holes[nholes++].id = e->e_id;
522 } else if ( !hole ) {
525 e->e_id = ei->bei_id;
527 for ( i=0; i<nholes; i++) {
528 if ( holes[i].id == e->e_id ) {
529 free(holes[i].dn.bv_val);
530 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
534 } else if ( holes[i].id > e->e_id ) {
548 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
550 if ( !bdb->bi_nattrs )
553 if ( slapMode & SLAP_TOOL_QUICK ) {
558 ir = bdb_tool_index_rec;
559 memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
561 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
562 rc = bdb_index_recset( bdb, a, a->a_desc->ad_type,
563 &a->a_desc->ad_tags, ir );
567 bdb_tool_ix_id = e->e_id;
569 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
570 /* Wait for all threads to be ready */
571 while ( bdb_tool_index_tcount ) {
572 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
573 &bdb_tool_index_mutex );
575 for ( i=1; i<slap_tool_thread_max; i++ )
576 bdb_tool_index_threads[i] = LDAP_BUSY;
577 bdb_tool_index_tcount = slap_tool_thread_max - 1;
578 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work );
579 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
580 rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
583 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
584 for ( i=1; i<slap_tool_thread_max; i++ ) {
585 if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
586 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main,
587 &bdb_tool_index_mutex );
591 if ( bdb_tool_index_threads[i] ) {
592 rc = bdb_tool_index_threads[i];
596 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
599 return bdb_index_entry_add( op, txn, e );
603 ID bdb_tool_entry_put(
606 struct berval *text )
609 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
614 assert( be != NULL );
615 assert( slapMode & SLAP_TOOL_MODE );
617 assert( text != NULL );
618 assert( text->bv_val != NULL );
619 assert( text->bv_val[0] == '\0' ); /* overconservative? */
621 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
622 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
624 if (! (slapMode & SLAP_TOOL_QUICK)) {
625 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
626 bdb->bi_db_opflags );
628 snprintf( text->bv_val, text->bv_len,
629 "txn_begin failed: %s (%d)",
630 db_strerror(rc), rc );
631 Debug( LDAP_DEBUG_ANY,
632 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
633 text->bv_val, 0, 0 );
640 op.o_tmpmemctx = NULL;
641 op.o_tmpmfuncs = &ch_mfuncs;
643 /* add dn2id indices */
644 rc = bdb_tool_next_id( &op, tid, e, text, 0 );
650 if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) {
651 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
655 if ( !bdb->bi_linear_index )
656 rc = bdb_tool_index_add( &op, tid, e );
658 snprintf( text->bv_val, text->bv_len,
659 "index_entry_add failed: %s (%d)",
660 rc == LDAP_OTHER ? "Internal error" :
661 db_strerror(rc), rc );
662 Debug( LDAP_DEBUG_ANY,
663 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
664 text->bv_val, 0, 0 );
669 rc = bdb_id2entry_add( be, tid, e );
671 snprintf( text->bv_val, text->bv_len,
672 "id2entry_add failed: %s (%d)",
673 db_strerror(rc), rc );
674 Debug( LDAP_DEBUG_ANY,
675 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
676 text->bv_val, 0, 0 );
682 if ( !( slapMode & SLAP_TOOL_QUICK )) {
683 rc = TXN_COMMIT( tid, 0 );
685 snprintf( text->bv_val, text->bv_len,
686 "txn_commit failed: %s (%d)",
687 db_strerror(rc), rc );
688 Debug( LDAP_DEBUG_ANY,
689 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
690 text->bv_val, 0, 0 );
696 if ( !( slapMode & SLAP_TOOL_QUICK )) {
698 snprintf( text->bv_val, text->bv_len,
699 "txn_aborted! %s (%d)",
700 rc == LDAP_OTHER ? "Internal error" :
701 db_strerror(rc), rc );
702 Debug( LDAP_DEBUG_ANY,
703 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
704 text->bv_val, 0, 0 );
712 int bdb_tool_entry_reindex(
715 AttributeDescription **adv )
717 struct bdb_info *bi = (struct bdb_info *) be->be_private;
724 assert( tool_base == NULL );
725 assert( tool_filter == NULL );
727 Debug( LDAP_DEBUG_ARGS,
728 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
731 /* No indexes configured, nothing to do. Could return an
732 * error here to shortcut things.
738 /* Check for explicit list of attrs to index */
742 if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
744 for ( n = 0; adv[n]; n++ ) ;
747 for ( i = 0; i < n; i++ ) {
748 AttributeDescription *ad = adv[i];
749 for ( j = i-1; j>=0; j--) {
750 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
757 for ( i = 0; adv[i]; i++ ) {
758 if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
759 for ( j = i+1; j < bi->bi_nattrs; j++ ) {
760 if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
761 AttrInfo *ai = bi->bi_attrs[i];
762 bi->bi_attrs[i] = bi->bi_attrs[j];
763 bi->bi_attrs[j] = ai;
767 if ( j == bi->bi_nattrs ) {
768 Debug( LDAP_DEBUG_ANY,
769 LDAP_XSTRING(bdb_tool_entry_reindex)
770 ": no index configured for %s\n",
771 adv[i]->ad_cname.bv_val, 0, 0 );
779 /* Get the first attribute to index */
780 if (bi->bi_linear_index && !index_nattrs) {
781 index_nattrs = bi->bi_nattrs - 1;
785 e = bdb_tool_entry_get( be, id );
788 Debug( LDAP_DEBUG_ANY,
789 LDAP_XSTRING(bdb_tool_entry_reindex)
790 ": could not locate id=%ld\n",
795 if (! (slapMode & SLAP_TOOL_QUICK)) {
796 rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
798 Debug( LDAP_DEBUG_ANY,
799 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
800 "txn_begin failed: %s (%d)\n",
801 db_strerror(rc), rc, 0 );
807 * just (re)add them for now
808 * assume that some other routine (not yet implemented)
809 * will zap index databases
813 Debug( LDAP_DEBUG_TRACE,
814 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
815 (long) id, e->e_dn, 0 );
819 op.o_tmpmemctx = NULL;
820 op.o_tmpmfuncs = &ch_mfuncs;
822 rc = bdb_tool_index_add( &op, tid, e );
826 if (! (slapMode & SLAP_TOOL_QUICK)) {
827 rc = TXN_COMMIT( tid, 0 );
829 Debug( LDAP_DEBUG_ANY,
830 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
831 ": txn_commit failed: %s (%d)\n",
832 db_strerror(rc), rc, 0 );
838 if (! (slapMode & SLAP_TOOL_QUICK)) {
840 Debug( LDAP_DEBUG_ANY,
841 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
842 ": txn_aborted! %s (%d)\n",
843 db_strerror(rc), rc, 0 );
847 bdb_entry_release( &op, e, 0 );
852 ID bdb_tool_entry_modify(
855 struct berval *text )
858 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
863 assert( be != NULL );
864 assert( slapMode & SLAP_TOOL_MODE );
866 assert( text != NULL );
867 assert( text->bv_val != NULL );
868 assert( text->bv_val[0] == '\0' ); /* overconservative? */
870 assert ( e->e_id != NOID );
872 Debug( LDAP_DEBUG_TRACE,
873 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
874 (long) e->e_id, e->e_dn, 0 );
876 if (! (slapMode & SLAP_TOOL_QUICK)) {
878 cursor->c_close( cursor );
881 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
882 bdb->bi_db_opflags );
884 snprintf( text->bv_val, text->bv_len,
885 "txn_begin failed: %s (%d)",
886 db_strerror(rc), rc );
887 Debug( LDAP_DEBUG_ANY,
888 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
889 text->bv_val, 0, 0 );
896 op.o_tmpmemctx = NULL;
897 op.o_tmpmfuncs = &ch_mfuncs;
900 rc = bdb_id2entry_update( be, tid, e );
902 snprintf( text->bv_val, text->bv_len,
903 "id2entry_add failed: %s (%d)",
904 db_strerror(rc), rc );
905 Debug( LDAP_DEBUG_ANY,
906 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
907 text->bv_val, 0, 0 );
913 if (! (slapMode & SLAP_TOOL_QUICK)) {
914 rc = TXN_COMMIT( tid, 0 );
916 snprintf( text->bv_val, text->bv_len,
917 "txn_commit failed: %s (%d)",
918 db_strerror(rc), rc );
919 Debug( LDAP_DEBUG_ANY,
920 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
921 "%s\n", text->bv_val, 0, 0 );
927 if (! (slapMode & SLAP_TOOL_QUICK)) {
929 snprintf( text->bv_val, text->bv_len,
930 "txn_aborted! %s (%d)",
931 db_strerror(rc), rc );
932 Debug( LDAP_DEBUG_ANY,
933 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
934 text->bv_val, 0, 0 );
942 #ifdef BDB_TOOL_IDL_CACHING
944 bdb_tool_idl_cmp( const void *v1, const void *v2 )
946 const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
949 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
950 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
954 bdb_tool_idl_flush_one( void *v1, void *arg )
956 bdb_tool_idl_cache *ic = v1;
958 struct bdb_info *bdb = bdb_tool_info;
959 bdb_tool_idl_cache_entry *ice;
965 /* Freshly allocated, ignore it */
966 if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
970 rc = db->cursor( db, NULL, &curs, 0 );
977 bv2DBT( &ic->kstr, &key );
979 data.size = data.ulen = sizeof( ID );
980 data.flags = DB_DBT_USERMEM;
983 rc = curs->c_get( curs, &key, &data, DB_SET );
984 /* If key already exists and we're writing a range... */
985 if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
986 /* If it's not currently a range, must delete old info */
989 while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
990 curs->c_del( curs, 0 );
993 /* Store range marker */
994 curs->c_put( curs, &key, &data, DB_KEYFIRST );
998 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
1001 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
1004 curs->c_del( curs, 0 );
1006 BDB_ID2DISK( ic->last, &nid );
1007 curs->c_put( curs, &key, &data, DB_KEYLAST );
1009 } else if ( rc && rc != DB_NOTFOUND ) {
1011 } else if ( ic->count > BDB_IDL_DB_SIZE ) {
1012 /* range, didn't exist before */
1014 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1016 BDB_ID2DISK( ic->first, &nid );
1017 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1019 BDB_ID2DISK( ic->last, &nid );
1020 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1029 /* Just a normal write */
1031 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
1036 end = ic->count & (IDBLOCK-1);
1040 for ( i=0; i<end; i++ ) {
1041 if ( !ice->ids[i] ) continue;
1042 BDB_ID2DISK( ice->ids[i], &nid );
1043 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
1045 if ( rc == DB_KEYEXIST ) {
1059 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1060 ic->tail->next = bdb_tool_idl_free_list;
1061 bdb_tool_idl_free_list = ic->head;
1062 bdb->bi_idl_cache_size -= n;
1063 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1066 if ( ic != db->app_private ) {
1069 ic->head = ic->tail = NULL;
1071 curs->c_close( curs );
1076 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
1078 Avlnode *root = db->app_private;
1081 db->app_private = ic;
1082 rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
1083 avl_free( root, NULL );
1084 db->app_private = NULL;
1091 bdb_tool_idl_flush( BackendDB *be )
1093 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1098 for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
1099 db = bdb->bi_databases[i]->bdi_db;
1100 if ( !db->app_private ) continue;
1101 rc = bdb_tool_idl_flush_db( db, NULL );
1106 bdb->bi_idl_cache_size = 0;
1111 int bdb_tool_idl_add(
1118 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1119 bdb_tool_idl_cache *ic, itmp;
1120 bdb_tool_idl_cache_entry *ice;
1123 if ( !bdb->bi_idl_cache_max_size )
1124 return bdb_idl_insert_key( be, db, txn, key, id );
1126 DBT2bv( key, &itmp.kstr );
1128 ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
1130 /* No entry yet, create one */
1137 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
1138 ic->kstr.bv_len = itmp.kstr.bv_len;
1139 ic->kstr.bv_val = (char *)(ic+1);
1140 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1141 ic->head = ic->tail = NULL;
1144 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1147 /* load existing key count here */
1148 rc = db->cursor( db, NULL, &curs, 0 );
1149 if ( rc ) return rc;
1151 data.ulen = sizeof( ID );
1152 data.flags = DB_DBT_USERMEM;
1154 rc = curs->c_get( curs, key, &data, DB_SET );
1157 ic->count = BDB_IDL_DB_SIZE+1;
1161 curs->c_count( curs, &count, 0 );
1163 BDB_DISK2ID( &nid, &ic->first );
1166 curs->c_close( curs );
1168 /* are we a range already? */
1169 if ( ic->count > BDB_IDL_DB_SIZE ) {
1172 /* Are we at the limit, and converting to a range? */
1173 } else if ( ic->count == BDB_IDL_DB_SIZE ) {
1175 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
1178 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1179 ic->tail->next = bdb_tool_idl_free_list;
1180 bdb_tool_idl_free_list = ic->head;
1181 bdb->bi_idl_cache_size -= n;
1182 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1184 ic->head = ic->tail = NULL;
1189 /* No free block, create that too */
1190 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
1192 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1193 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
1194 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1195 rc = bdb_tool_idl_flush_db( db, ic );
1198 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1200 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1202 bdb->bi_idl_cache_size++;
1203 if ( bdb_tool_idl_free_list ) {
1204 ice = bdb_tool_idl_free_list;
1205 bdb_tool_idl_free_list = ice->next;
1207 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1209 ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1211 memset( ice, 0, sizeof( *ice ));
1215 ic->tail->next = ice;
1222 ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1231 bdb_tool_trickle_task( void *ctx, void *ptr )
1236 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
1238 ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond,
1239 &bdb_tool_trickle_mutex );
1240 if ( slapd_shutdown )
1242 env->memp_trickle( env, 30, &wrote );
1244 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
1251 bdb_tool_index_task( void *ctx, void *ptr )
1253 int base = *(int *)ptr;
1257 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1258 bdb_tool_index_tcount--;
1259 if ( !bdb_tool_index_tcount )
1260 ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
1261 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work,
1262 &bdb_tool_index_mutex );
1263 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1264 if ( slapd_shutdown )
1267 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1268 bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );