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 )
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 assert( tool_base == NULL );
722 assert( tool_filter == NULL );
724 Debug( LDAP_DEBUG_ARGS,
725 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
728 /* No indexes configured, nothing to do. Could return an
729 * error here to shortcut things.
735 /* Check for explicit list of attrs to index */
739 if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
741 for ( n = 0; adv[n]; n++ ) ;
744 for ( i = 0; i < n; i++ ) {
745 AttributeDescription *ad = adv[i];
746 for ( j = i-1; j>=0; j--) {
747 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
754 for ( i = 0; adv[i]; i++ ) {
755 if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
756 for ( j = i+1; j < bi->bi_nattrs; j++ ) {
757 if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
758 AttrInfo *ai = bi->bi_attrs[i];
759 bi->bi_attrs[i] = bi->bi_attrs[j];
760 bi->bi_attrs[j] = ai;
764 if ( j == bi->bi_nattrs ) {
765 Debug( LDAP_DEBUG_ANY,
766 LDAP_XSTRING(bdb_tool_entry_reindex)
767 ": no index configured for %s\n",
768 adv[i]->ad_cname.bv_val, 0, 0 );
776 /* Get the first attribute to index */
777 if (bi->bi_linear_index && !index_nattrs) {
778 index_nattrs = bi->bi_nattrs - 1;
782 e = bdb_tool_entry_get( be, id );
785 Debug( LDAP_DEBUG_ANY,
786 LDAP_XSTRING(bdb_tool_entry_reindex)
787 ": could not locate id=%ld\n",
792 if (! (slapMode & SLAP_TOOL_QUICK)) {
793 rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
795 Debug( LDAP_DEBUG_ANY,
796 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
797 "txn_begin failed: %s (%d)\n",
798 db_strerror(rc), rc, 0 );
804 * just (re)add them for now
805 * assume that some other routine (not yet implemented)
806 * will zap index databases
810 Debug( LDAP_DEBUG_TRACE,
811 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
812 (long) id, e->e_dn, 0 );
816 op.o_tmpmemctx = NULL;
817 op.o_tmpmfuncs = &ch_mfuncs;
819 rc = bdb_tool_index_add( &op, tid, e );
823 if (! (slapMode & SLAP_TOOL_QUICK)) {
824 rc = TXN_COMMIT( tid, 0 );
826 Debug( LDAP_DEBUG_ANY,
827 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
828 ": txn_commit failed: %s (%d)\n",
829 db_strerror(rc), rc, 0 );
835 if (! (slapMode & SLAP_TOOL_QUICK)) {
837 Debug( LDAP_DEBUG_ANY,
838 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
839 ": txn_aborted! %s (%d)\n",
840 db_strerror(rc), rc, 0 );
844 bdb_entry_release( &op, e, 0 );
849 ID bdb_tool_entry_modify(
852 struct berval *text )
855 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
860 assert( be != NULL );
861 assert( slapMode & SLAP_TOOL_MODE );
863 assert( text != NULL );
864 assert( text->bv_val != NULL );
865 assert( text->bv_val[0] == '\0' ); /* overconservative? */
867 assert ( e->e_id != NOID );
869 Debug( LDAP_DEBUG_TRACE,
870 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
871 (long) e->e_id, e->e_dn, 0 );
873 if (! (slapMode & SLAP_TOOL_QUICK)) {
875 cursor->c_close( cursor );
878 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid,
879 bdb->bi_db_opflags );
881 snprintf( text->bv_val, text->bv_len,
882 "txn_begin failed: %s (%d)",
883 db_strerror(rc), rc );
884 Debug( LDAP_DEBUG_ANY,
885 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
886 text->bv_val, 0, 0 );
893 op.o_tmpmemctx = NULL;
894 op.o_tmpmfuncs = &ch_mfuncs;
897 rc = bdb_id2entry_update( be, tid, e );
899 snprintf( text->bv_val, text->bv_len,
900 "id2entry_add failed: %s (%d)",
901 db_strerror(rc), rc );
902 Debug( LDAP_DEBUG_ANY,
903 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
904 text->bv_val, 0, 0 );
910 if (! (slapMode & SLAP_TOOL_QUICK)) {
911 rc = TXN_COMMIT( tid, 0 );
913 snprintf( text->bv_val, text->bv_len,
914 "txn_commit failed: %s (%d)",
915 db_strerror(rc), rc );
916 Debug( LDAP_DEBUG_ANY,
917 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
918 "%s\n", text->bv_val, 0, 0 );
924 if (! (slapMode & SLAP_TOOL_QUICK)) {
926 snprintf( text->bv_val, text->bv_len,
927 "txn_aborted! %s (%d)",
928 db_strerror(rc), rc );
929 Debug( LDAP_DEBUG_ANY,
930 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
931 text->bv_val, 0, 0 );
939 #ifdef BDB_TOOL_IDL_CACHING
941 bdb_tool_idl_cmp( const void *v1, const void *v2 )
943 const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
946 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
947 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
951 bdb_tool_idl_flush_one( void *v1, void *arg )
953 bdb_tool_idl_cache *ic = v1;
955 struct bdb_info *bdb = bdb_tool_info;
956 bdb_tool_idl_cache_entry *ice;
962 /* Freshly allocated, ignore it */
963 if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
967 rc = db->cursor( db, NULL, &curs, 0 );
974 bv2DBT( &ic->kstr, &key );
976 data.size = data.ulen = sizeof( ID );
977 data.flags = DB_DBT_USERMEM;
980 rc = curs->c_get( curs, &key, &data, DB_SET );
981 /* If key already exists and we're writing a range... */
982 if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
983 /* If it's not currently a range, must delete old info */
986 while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
987 curs->c_del( curs, 0 );
990 /* Store range marker */
991 curs->c_put( curs, &key, &data, DB_KEYFIRST );
995 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
998 rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
1001 curs->c_del( curs, 0 );
1003 BDB_ID2DISK( ic->last, &nid );
1004 curs->c_put( curs, &key, &data, DB_KEYLAST );
1006 } else if ( rc && rc != DB_NOTFOUND ) {
1008 } else if ( ic->count > BDB_IDL_DB_SIZE ) {
1009 /* range, didn't exist before */
1011 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1013 BDB_ID2DISK( ic->first, &nid );
1014 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1016 BDB_ID2DISK( ic->last, &nid );
1017 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
1026 /* Just a normal write */
1028 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
1033 end = ic->count & (IDBLOCK-1);
1037 for ( i=0; i<end; i++ ) {
1038 if ( !ice->ids[i] ) continue;
1039 BDB_ID2DISK( ice->ids[i], &nid );
1040 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
1042 if ( rc == DB_KEYEXIST ) {
1056 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1057 ic->tail->next = bdb_tool_idl_free_list;
1058 bdb_tool_idl_free_list = ic->head;
1059 bdb->bi_idl_cache_size -= n;
1060 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1063 if ( ic != db->app_private ) {
1066 ic->head = ic->tail = NULL;
1068 curs->c_close( curs );
1073 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
1075 Avlnode *root = db->app_private;
1078 db->app_private = ic;
1079 rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
1080 avl_free( root, NULL );
1081 db->app_private = NULL;
1088 bdb_tool_idl_flush( BackendDB *be )
1090 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1095 for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
1096 db = bdb->bi_databases[i]->bdi_db;
1097 if ( !db->app_private ) continue;
1098 rc = bdb_tool_idl_flush_db( db, NULL );
1103 bdb->bi_idl_cache_size = 0;
1108 int bdb_tool_idl_add(
1115 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1116 bdb_tool_idl_cache *ic, itmp;
1117 bdb_tool_idl_cache_entry *ice;
1120 if ( !bdb->bi_idl_cache_max_size )
1121 return bdb_idl_insert_key( be, db, txn, key, id );
1123 DBT2bv( key, &itmp.kstr );
1125 ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
1127 /* No entry yet, create one */
1134 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
1135 ic->kstr.bv_len = itmp.kstr.bv_len;
1136 ic->kstr.bv_val = (char *)(ic+1);
1137 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1138 ic->head = ic->tail = NULL;
1141 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1144 /* load existing key count here */
1145 rc = db->cursor( db, NULL, &curs, 0 );
1146 if ( rc ) return rc;
1148 data.ulen = sizeof( ID );
1149 data.flags = DB_DBT_USERMEM;
1151 rc = curs->c_get( curs, key, &data, DB_SET );
1154 ic->count = BDB_IDL_DB_SIZE+1;
1158 curs->c_count( curs, &count, 0 );
1160 BDB_DISK2ID( &nid, &ic->first );
1163 curs->c_close( curs );
1165 /* are we a range already? */
1166 if ( ic->count > BDB_IDL_DB_SIZE ) {
1169 /* Are we at the limit, and converting to a range? */
1170 } else if ( ic->count == BDB_IDL_DB_SIZE ) {
1172 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
1175 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1176 ic->tail->next = bdb_tool_idl_free_list;
1177 bdb_tool_idl_free_list = ic->head;
1178 bdb->bi_idl_cache_size -= n;
1179 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1181 ic->head = ic->tail = NULL;
1186 /* No free block, create that too */
1187 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
1189 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1190 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
1191 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1192 rc = bdb_tool_idl_flush_db( db, ic );
1195 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
1197 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
1199 bdb->bi_idl_cache_size++;
1200 if ( bdb_tool_idl_free_list ) {
1201 ice = bdb_tool_idl_free_list;
1202 bdb_tool_idl_free_list = ice->next;
1204 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1206 ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1208 memset( ice, 0, sizeof( *ice ));
1212 ic->tail->next = ice;
1219 ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1228 bdb_tool_trickle_task( void *ctx, void *ptr )
1233 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
1235 ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond,
1236 &bdb_tool_trickle_mutex );
1237 if ( slapd_shutdown )
1239 env->memp_trickle( env, 30, &wrote );
1241 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
1248 bdb_tool_index_task( void *ctx, void *ptr )
1250 int base = *(int *)ptr;
1254 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1255 bdb_tool_index_tcount--;
1256 if ( !bdb_tool_index_tcount )
1257 ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main );
1258 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work,
1259 &bdb_tool_index_mutex );
1260 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1261 if ( slapd_shutdown )
1264 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1265 bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );