1 /* tools.c - tools for slap tools */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 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 int mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn );
31 typedef struct mdb_tool_idl_cache_entry {
32 struct mdb_tool_idl_cache_entry *next;
34 } mdb_tool_idl_cache_entry;
36 typedef struct mdb_tool_idl_cache {
38 mdb_tool_idl_cache_entry *head, *tail;
43 static mdb_tool_idl_cache_entry *mdb_tool_idl_free_list;
44 static Avlnode *mdb_tool_roots[MDB_INDICES];
46 static MDB_txn *txn = NULL, *txi = NULL;
47 static MDB_cursor *cursor = NULL, *idcursor = NULL;
48 static MDB_val key, data;
49 static ID previd = NOID;
51 typedef struct dn_id {
56 #define HOLE_SIZE 4096
57 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
58 static unsigned nhmax = HOLE_SIZE;
59 static unsigned nholes;
61 static struct berval *tool_base;
62 static int tool_scope;
63 static Filter *tool_filter;
64 static Entry *tool_next_entry;
67 static ID mdb_tool_ix_id;
68 static Operation *mdb_tool_ix_op;
69 static int *mdb_tool_index_threads, mdb_tool_index_tcount;
70 static void *mdb_tool_index_rec;
71 static struct mdb_info *mdb_tool_info;
72 static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
73 static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
74 static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
75 static void * mdb_tool_index_task( void *ctx, void *ptr );
78 static int mdb_writes, mdb_writes_per_commit;
81 mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
83 int mdb_tool_entry_open(
84 BackendDB *be, int mode )
86 /* In Quick mode, commit once per 1000 entries */
88 if ( slapMode & SLAP_TOOL_QUICK )
89 mdb_writes_per_commit = 1000;
91 mdb_writes_per_commit = 1;
94 /* Set up for threaded slapindex */
95 if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
96 if ( !mdb_tool_info ) {
97 ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
98 ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
99 ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
100 if ( mdb->bi_nattrs ) {
102 mdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
103 mdb_tool_index_rec = ch_malloc( mdb->bi_nattrs * sizeof( IndexRec ));
104 mdb_tool_index_tcount = slap_tool_thread_max - 1;
105 for (i=1; i<slap_tool_thread_max; i++) {
106 int *ptr = ch_malloc( sizeof( int ));
108 ldap_pvt_thread_pool_submit( &connection_pool,
109 mdb_tool_index_task, ptr );
120 int mdb_tool_entry_close(
124 if ( mdb_tool_info ) {
126 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
128 /* There might still be some threads starting */
129 while ( mdb_tool_index_tcount ) {
130 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
131 &mdb_tool_index_mutex );
134 mdb_tool_index_tcount = slap_tool_thread_max - 1;
135 ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
137 /* Make sure all threads are stopped */
138 while ( mdb_tool_index_tcount ) {
139 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
140 &mdb_tool_index_mutex );
142 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
144 mdb_tool_info = NULL;
146 ch_free( mdb_tool_index_threads );
147 ch_free( mdb_tool_index_rec );
148 mdb_tool_index_tcount = slap_tool_thread_max - 1;
153 mdb_cursor_close( idcursor );
157 mdb_cursor_close( cursor );
160 mdb_tool_idl_flush( be, txn );
162 if ( mdb_txn_commit( txn ))
169 fprintf( stderr, "Error, entries missing!\n");
170 for (i=0; i<nholes; i++) {
171 fprintf(stderr, " entry %ld: %s\n",
172 holes[i].id, holes[i].dn.bv_val);
182 mdb_tool_entry_first_x(
192 return mdb_tool_entry_next( be );
195 ID mdb_tool_entry_next(
200 struct mdb_info *mdb;
202 assert( be != NULL );
203 assert( slapMode & SLAP_TOOL_MODE );
205 mdb = (struct mdb_info *) be->be_private;
206 assert( mdb != NULL );
209 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &txn );
212 rc = mdb_cursor_open( txn, mdb->mi_id2entry, &cursor );
214 mdb_txn_abort( txn );
220 rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
226 previd = *(ID *)key.mv_data;
229 if ( tool_filter || tool_base ) {
230 static Operation op = {0};
231 static Opheader ohdr = {0};
235 op.o_tmpmemctx = NULL;
236 op.o_tmpmfuncs = &ch_mfuncs;
238 if ( tool_next_entry ) {
239 mdb_entry_release( &op, tool_next_entry, 0 );
240 tool_next_entry = NULL;
243 rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
244 if ( rc == LDAP_NO_SUCH_OBJECT ) {
248 assert( tool_next_entry != NULL );
250 if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
252 mdb_entry_release( &op, tool_next_entry, 0 );
253 tool_next_entry = NULL;
261 ID mdb_tool_dn2id_get(
266 struct mdb_info *mdb;
272 if ( BER_BVISEMPTY(dn) )
275 mdb = (struct mdb_info *) be->be_private;
278 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, (slapMode & SLAP_TOOL_READONLY) != 0 ?
279 MDB_RDONLY : 0, &txn );
286 op.o_tmpmemctx = NULL;
287 op.o_tmpmfuncs = &ch_mfuncs;
289 rc = mdb_dn2id( &op, txn, dn, &id, NULL, NULL );
290 if ( rc == MDB_NOTFOUND )
297 mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
303 struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
306 assert( be != NULL );
307 assert( slapMode & SLAP_TOOL_MODE );
309 if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
310 *ep = tool_next_entry;
311 tool_next_entry = NULL;
315 if ( id != previd ) {
316 key.mv_size = sizeof(ID);
318 rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
327 op.o_tmpmemctx = NULL;
328 op.o_tmpmfuncs = &ch_mfuncs;
329 if ( slapMode & SLAP_TOOL_READONLY ) {
330 rc = mdb_id2name( &op, txn, &idcursor, id, &dn, &ndn );
333 mdb_entry_return( &op, e );
337 if ( tool_base != NULL ) {
338 if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
339 ch_free( dn.bv_val );
340 ch_free( ndn.bv_val );
341 rc = LDAP_NO_SUCH_OBJECT;
345 rc = mdb_entry_decode( &op, &data, &e );
347 if ( !BER_BVISNULL( &dn )) {
351 e->e_name.bv_val = NULL;
352 e->e_nname.bv_val = NULL;
364 mdb_tool_entry_get( BackendDB *be, ID id )
368 (void)mdb_tool_entry_get_int( be, id, &e );
372 static int mdb_tool_next_id(
379 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
380 struct berval dn = e->e_name;
381 struct berval ndn = e->e_nname;
382 struct berval pdn, npdn, nmatched;
386 if (ndn.bv_len == 0) {
391 rc = mdb_dn2id( op, tid, &ndn, &id, NULL, &nmatched );
392 if ( rc == MDB_NOTFOUND ) {
393 if ( !be_issuffix( op->o_bd, &ndn ) ) {
395 dnParent( &ndn, &npdn );
396 if ( nmatched.bv_len != npdn.bv_len ) {
397 dnParent( &dn, &pdn );
400 rc = mdb_tool_next_id( op, tid, e, text, 1 );
406 /* If parent didn't exist, it was created just now
407 * and its ID is now in e->e_id. Make sure the current
408 * entry gets added under the new parent ID.
410 if ( eid != e->e_id ) {
417 rc = mdb_next_id( op->o_bd, tid, &e->e_id );
419 snprintf( text->bv_val, text->bv_len,
420 "next_id failed: %s (%d)",
421 mdb_strerror(rc), rc );
422 Debug( LDAP_DEBUG_ANY,
423 "=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
426 rc = mdb_dn2id_add( op, tid, pid, e );
428 snprintf( text->bv_val, text->bv_len,
429 "dn2id_add failed: %s (%d)",
430 mdb_strerror(rc), rc );
431 Debug( LDAP_DEBUG_ANY,
432 "=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
435 if ( nholes == nhmax - 1 ) {
436 if ( holes == hbuf ) {
437 holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
438 AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
440 holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
444 ber_dupbv( &holes[nholes].dn, &ndn );
445 holes[nholes++].id = e->e_id;
446 key.mv_size = sizeof(ID);
447 key.mv_data = &e->e_id;
450 rc = mdb_put( tid, mdb->mi_id2entry, &key, &data, MDB_NOOVERWRITE );
451 if ( rc == MDB_KEYEXIST )
454 snprintf( text->bv_val, text->bv_len,
455 "dummy id2entry add failed: %s (%d)",
456 mdb_strerror(rc), rc );
457 Debug( LDAP_DEBUG_ANY,
458 "=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
461 } else if ( !hole ) {
466 for ( i=0; i<nholes; i++) {
467 if ( holes[i].id == e->e_id ) {
468 free(holes[i].dn.bv_val);
469 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
473 } else if ( holes[i].id > e->e_id ) {
487 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
489 if ( !mdb->mi_nattrs )
493 if ( slapMode & SLAP_TOOL_QUICK ) {
498 ir = mdb_tool_index_rec;
499 memset(ir, 0, mdb->bi_nattrs * sizeof( IndexRec ));
501 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
502 rc = mdb_index_recset( mdb, a, a->a_desc->ad_type,
503 &a->a_desc->ad_tags, ir );
507 mdb_tool_ix_id = e->e_id;
509 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
510 /* Wait for all threads to be ready */
511 while ( mdb_tool_index_tcount ) {
512 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
513 &mdb_tool_index_mutex );
515 for ( i=1; i<slap_tool_thread_max; i++ )
516 mdb_tool_index_threads[i] = LDAP_BUSY;
517 mdb_tool_index_tcount = slap_tool_thread_max - 1;
518 ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
519 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
520 rc = mdb_index_recrun( op, mdb, ir, e->e_id, 0 );
523 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
524 for ( i=1; i<slap_tool_thread_max; i++ ) {
525 if ( mdb_tool_index_threads[i] == LDAP_BUSY ) {
526 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
527 &mdb_tool_index_mutex );
531 if ( mdb_tool_index_threads[i] ) {
532 rc = mdb_tool_index_threads[i];
536 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
541 return mdb_index_entry_add( op, txn, e );
545 ID mdb_tool_entry_put(
548 struct berval *text )
551 struct mdb_info *mdb;
555 assert( be != NULL );
556 assert( slapMode & SLAP_TOOL_MODE );
558 assert( text != NULL );
559 assert( text->bv_val != NULL );
560 assert( text->bv_val[0] == '\0' ); /* overconservative? */
562 Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
563 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
565 mdb = (struct mdb_info *) be->be_private;
568 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
570 snprintf( text->bv_val, text->bv_len,
571 "txn_begin failed: %s (%d)",
572 mdb_strerror(rc), rc );
573 Debug( LDAP_DEBUG_ANY,
574 "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
575 text->bv_val, 0, 0 );
582 op.o_tmpmemctx = NULL;
583 op.o_tmpmfuncs = &ch_mfuncs;
585 /* add dn2id indices */
586 rc = mdb_tool_next_id( &op, txn, e, text, 0 );
591 rc = mdb_tool_index_add( &op, txn, e );
593 snprintf( text->bv_val, text->bv_len,
594 "index_entry_add failed: err=%d", rc );
595 Debug( LDAP_DEBUG_ANY,
596 "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
597 text->bv_val, 0, 0 );
603 rc = mdb_id2entry_add( &op, txn, e );
605 snprintf( text->bv_val, text->bv_len,
606 "id2entry_add failed: err=%d", rc );
607 Debug( LDAP_DEBUG_ANY,
608 "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
609 text->bv_val, 0, 0 );
616 if ( mdb_writes >= mdb_writes_per_commit ) {
617 mdb_tool_idl_flush( be, txn );
618 rc = mdb_txn_commit( txn );
622 snprintf( text->bv_val, text->bv_len,
623 "txn_commit failed: %s (%d)",
624 mdb_strerror(rc), rc );
625 Debug( LDAP_DEBUG_ANY,
626 "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
627 text->bv_val, 0, 0 );
633 mdb_txn_abort( txn );
635 snprintf( text->bv_val, text->bv_len,
636 "txn_aborted! %s (%d)",
637 rc == LDAP_OTHER ? "Internal error" :
638 mdb_strerror(rc), rc );
639 Debug( LDAP_DEBUG_ANY,
640 "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
641 text->bv_val, 0, 0 );
648 int mdb_tool_entry_reindex(
651 AttributeDescription **adv )
653 struct mdb_info *mi = (struct mdb_info *) be->be_private;
659 Debug( LDAP_DEBUG_ARGS,
660 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
662 assert( tool_base == NULL );
663 assert( tool_filter == NULL );
665 /* No indexes configured, nothing to do. Could return an
666 * error here to shortcut things.
672 /* Check for explicit list of attrs to index */
676 if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
678 for ( n = 0; adv[n]; n++ ) ;
681 for ( i = 0; i < n; i++ ) {
682 AttributeDescription *ad = adv[i];
683 for ( j = i-1; j>=0; j--) {
684 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
691 for ( i = 0; adv[i]; i++ ) {
692 if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
693 for ( j = i+1; j < mi->mi_nattrs; j++ ) {
694 if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
695 AttrInfo *ai = mi->mi_attrs[i];
696 mi->mi_attrs[i] = mi->mi_attrs[j];
697 mi->mi_attrs[j] = ai;
701 if ( j == mi->mi_nattrs ) {
702 Debug( LDAP_DEBUG_ANY,
703 LDAP_XSTRING(mdb_tool_entry_reindex)
704 ": no index configured for %s\n",
705 adv[i]->ad_cname.bv_val, 0, 0 );
713 if ( slapMode & SLAP_TRUNCATE_MODE ) {
715 for ( i=0; i < mi->mi_nattrs; i++ ) {
716 rc = mdb_drop( txn, mi->mi_attrs[i]->ai_dbi, 0 );
718 Debug( LDAP_DEBUG_ANY,
719 LDAP_XSTRING(mdb_tool_entry_reindex)
720 ": (Truncate) mdb_drop(%s) failed: %s (%d)\n",
721 mi->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
722 mdb_strerror(rc), rc );
726 slapMode ^= SLAP_TRUNCATE_MODE;
729 e = mdb_tool_entry_get( be, id );
732 Debug( LDAP_DEBUG_ANY,
733 LDAP_XSTRING(mdb_tool_entry_reindex)
734 ": could not locate id=%ld\n",
740 rc = mdb_txn_begin( mi->mi_dbenv, NULL, 0, &txi );
742 Debug( LDAP_DEBUG_ANY,
743 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
744 "txn_begin failed: %s (%d)\n",
745 mdb_strerror(rc), rc, 0 );
751 * just (re)add them for now
752 * assume that some other routine (not yet implemented)
753 * will zap index databases
757 Debug( LDAP_DEBUG_TRACE,
758 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
759 (long) id, e->e_dn, 0 );
763 op.o_tmpmemctx = NULL;
764 op.o_tmpmfuncs = &ch_mfuncs;
766 rc = mdb_tool_index_add( &op, txi, e );
771 if ( mdb_writes >= mdb_writes_per_commit ) {
772 mdb_tool_idl_flush( be, txi );
773 rc = mdb_txn_commit( txi );
775 Debug( LDAP_DEBUG_ANY,
776 "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
777 ": txn_commit failed: %s (%d)\n",
778 mdb_strerror(rc), rc, 0 );
785 mdb_txn_abort( txi );
786 Debug( LDAP_DEBUG_ANY,
787 "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
788 ": txn_aborted! err=%d\n",
793 mdb_entry_release( &op, e, 0 );
798 ID mdb_tool_entry_modify(
801 struct berval *text )
804 struct mdb_info *mdb;
809 assert( be != NULL );
810 assert( slapMode & SLAP_TOOL_MODE );
812 assert( text != NULL );
813 assert( text->bv_val != NULL );
814 assert( text->bv_val[0] == '\0' ); /* overconservative? */
816 assert ( e->e_id != NOID );
818 Debug( LDAP_DEBUG_TRACE,
819 "=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
820 (long) e->e_id, e->e_dn, 0 );
822 mdb = (struct mdb_info *) be->be_private;
825 mdb_cursor_close( cursor );
828 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &tid );
830 snprintf( text->bv_val, text->bv_len,
831 "txn_begin failed: %s (%d)",
832 mdb_strerror(rc), rc );
833 Debug( LDAP_DEBUG_ANY,
834 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
835 text->bv_val, 0, 0 );
841 op.o_tmpmemctx = NULL;
842 op.o_tmpmfuncs = &ch_mfuncs;
845 rc = mdb_id2entry_update( &op, tid, e );
847 snprintf( text->bv_val, text->bv_len,
848 "id2entry_update failed: err=%d", rc );
849 Debug( LDAP_DEBUG_ANY,
850 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
851 text->bv_val, 0, 0 );
857 rc = mdb_txn_commit( tid );
859 snprintf( text->bv_val, text->bv_len,
860 "txn_commit failed: %s (%d)",
861 mdb_strerror(rc), rc );
862 Debug( LDAP_DEBUG_ANY,
863 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
864 "%s\n", text->bv_val, 0, 0 );
869 mdb_txn_abort( tid );
870 snprintf( text->bv_val, text->bv_len,
871 "txn_aborted! %s (%d)",
872 mdb_strerror(rc), rc );
873 Debug( LDAP_DEBUG_ANY,
874 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
875 text->bv_val, 0, 0 );
884 mdb_tool_index_task( void *ctx, void *ptr )
886 int base = *(int *)ptr;
890 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
891 mdb_tool_index_tcount--;
892 if ( !mdb_tool_index_tcount )
893 ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
894 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
895 &mdb_tool_index_mutex );
896 if ( slapd_shutdown ) {
897 mdb_tool_index_tcount--;
898 if ( !mdb_tool_index_tcount )
899 ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
900 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
903 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
905 mdb_tool_index_threads[base] = mdb_index_recrun( mdb_tool_ix_op,
906 mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
914 mdb_tool_idl_cmp( const void *v1, const void *v2 )
916 const mdb_tool_idl_cache *c1 = v1, *c2 = v2;
919 if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
920 return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
924 mdb_tool_idl_flush_one( MDB_cursor *mc, mdb_tool_idl_cache *ic )
926 mdb_tool_idl_cache_entry *ice;
931 /* Freshly allocated, ignore it */
932 if ( !ic->head && ic->count <= MDB_IDL_DB_SIZE ) {
936 key.mv_data = ic->kstr.bv_val;
937 key.mv_size = ic->kstr.bv_len;
939 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
940 /* If key already exists and we're writing a range... */
941 if ( rc == 0 && ic->count > MDB_IDL_DB_SIZE ) {
942 nid = *(ID *)data.mv_data;
943 /* If it's not currently a range, must delete old info */
946 mdb_cursor_del( mc, MDB_NODUPDATA );
951 rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT_DUP );
954 rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT_DUP );
957 data.mv_data = &ic->last;
958 rc = mdb_cursor_put( mc, &key, &data, MDB_CURRENT );
961 } else if ( rc && rc != MDB_NOTFOUND ) {
963 } else if ( ic->count > MDB_IDL_DB_SIZE ) {
964 /* range, didn't exist before */
967 data.mv_size = sizeof(ID);
969 rc = mdb_cursor_put( mc, &key, &data, 0 );
971 data.mv_data = &ic->first;
972 rc = mdb_cursor_put( mc, &key, &data, 0 );
974 data.mv_data = &ic->last;
975 rc = mdb_cursor_put( mc, &key, &data, 0 );
984 data.mv_size = sizeof(ID);
985 /* Just a normal write */
987 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
992 end = ic->count & (IDBLOCK-1);
996 for ( i=0; i<end; i++ ) {
997 if ( !ice->ids[i] ) continue;
998 data.mv_data = &ice->ids[i];
999 rc = mdb_cursor_put( mc, &key, &data, MDB_NODUPDATA|MDB_APPEND );
1001 if ( rc == MDB_KEYEXIST ) {
1015 ic->tail->next = mdb_tool_idl_free_list;
1016 mdb_tool_idl_free_list = ic->head;
1024 mdb_tool_idl_flush_db( MDB_txn *txn, MDB_dbi dbi, Avlnode *root )
1029 mdb_cursor_open( txn, dbi, &mc );
1030 root = tavl_end( root, TAVL_DIR_LEFT );
1032 rc = mdb_tool_idl_flush_one( mc, root->avl_data );
1035 } while ((root = tavl_next(root, TAVL_DIR_RIGHT)));
1036 mdb_cursor_close( mc );
1042 mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn )
1044 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
1048 for ( i=MDB_NDB; i < mdb->mi_nattrs+MDB_NDB; i++ ) {
1049 if ( !mdb_tool_roots[i] ) continue;
1050 rc = mdb_tool_idl_flush_db( txn, i, mdb_tool_roots[i] );
1051 tavl_free(mdb_tool_roots[i], NULL);
1052 mdb_tool_roots[i] = NULL;
1059 int mdb_tool_idl_add(
1061 struct berval *keys,
1065 mdb_tool_idl_cache *ic, itmp;
1066 mdb_tool_idl_cache_entry *ice;
1069 dbi = mdb_cursor_dbi(mc);
1070 for (i=0; keys[i].bv_val; i++) {
1071 itmp.kstr = keys[i];
1072 ic = tavl_find( (Avlnode *)mdb_tool_roots[dbi], &itmp, mdb_tool_idl_cmp );
1074 /* No entry yet, create one */
1080 ic = ch_malloc( sizeof( mdb_tool_idl_cache ) + itmp.kstr.bv_len );
1081 ic->kstr.bv_len = itmp.kstr.bv_len;
1082 ic->kstr.bv_val = (char *)(ic+1);
1083 memcpy( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1084 ic->head = ic->tail = NULL;
1087 tavl_insert( (Avlnode **)&mdb_tool_roots[dbi], ic, mdb_tool_idl_cmp,
1090 /* load existing key count here */
1091 key.mv_size = keys[i].bv_len;
1092 key.mv_data = keys[i].bv_val;
1093 data.mv_size = sizeof( ID );
1094 data.mv_data = &nid;
1095 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
1098 ic->count = MDB_IDL_DB_SIZE+1;
1102 mdb_cursor_count( mc, &count );
1108 /* are we a range already? */
1109 if ( ic->count > MDB_IDL_DB_SIZE ) {
1112 /* Are we at the limit, and converting to a range? */
1113 } else if ( ic->count == MDB_IDL_DB_SIZE ) {
1115 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
1118 ic->tail->next = mdb_tool_idl_free_list;
1119 mdb_tool_idl_free_list = ic->head;
1121 ic->head = ic->tail = NULL;
1126 /* No free block, create that too */
1127 if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
1129 if ( mdb_tool_idl_free_list ) {
1130 ice = mdb_tool_idl_free_list;
1131 mdb_tool_idl_free_list = ice->next;
1134 ice = ch_malloc( sizeof( mdb_tool_idl_cache_entry ));
1136 memset( ice, 0, sizeof( *ice ));
1140 ic->tail->next = ice;
1147 ice->ids[ ic->count & (IDBLOCK-1) ] = id;