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
#ifdef MDB_TOOL_IDL_CACHING
28
static int mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn );
32
typedef struct mdb_tool_idl_cache_entry {
33
struct mdb_tool_idl_cache_entry *next;
35
} mdb_tool_idl_cache_entry;
37
typedef struct mdb_tool_idl_cache {
39
mdb_tool_idl_cache_entry *head, *tail;
45
#define WAS_FOUND 0x01
46
#define WAS_RANGE 0x02
48
#define MDB_TOOL_IDL_FLUSH(be, txn) mdb_tool_idl_flush(be, txn)
50
#define MDB_TOOL_IDL_FLUSH(be, txn)
51
#endif /* MDB_TOOL_IDL_CACHING */
53
static MDB_txn *txn = NULL, *txi = NULL;
54
static MDB_cursor *cursor = NULL, *idcursor = NULL;
55
static MDB_cursor *mcp = NULL, *mcd = NULL;
56
static MDB_val key, data;
57
static ID previd = NOID;
59
typedef struct dn_id {
64
#define HOLE_SIZE 4096
65
static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
66
static unsigned nhmax = HOLE_SIZE;
67
static unsigned nholes;
69
static struct berval *tool_base;
70
static int tool_scope;
71
static Filter *tool_filter;
72
static Entry *tool_next_entry;
74
static ID mdb_tool_ix_id;
75
static Operation *mdb_tool_ix_op;
76
static MDB_txn *mdb_tool_ix_txn;
77
static int mdb_tool_index_tcount, mdb_tool_threads;
78
static IndexRec *mdb_tool_index_rec;
79
static struct mdb_info *mdb_tool_info;
80
static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
81
static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
82
static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
83
static void * mdb_tool_index_task( void *ctx, void *ptr );
85
static int mdb_writes, mdb_writes_per_commit;
88
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
90
int mdb_tool_entry_open(
91
BackendDB *be, int mode )
93
/* In Quick mode, commit once per 1000 entries */
95
if ( slapMode & SLAP_TOOL_QUICK )
96
mdb_writes_per_commit = 1000;
98
mdb_writes_per_commit = 1;
100
/* Set up for threaded slapindex */
101
if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
102
if ( !mdb_tool_info ) {
103
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
104
ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
105
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
106
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
107
if ( mdb->mi_nattrs ) {
109
mdb_tool_threads = slap_tool_thread_max - 1;
110
if ( mdb_tool_threads > 1 ) {
111
mdb_tool_index_rec = ch_calloc( mdb->mi_nattrs, sizeof( IndexRec ));
112
mdb_tool_index_tcount = mdb_tool_threads - 1;
113
for (i=1; i<mdb_tool_threads; i++) {
114
int *ptr = ch_malloc( sizeof( int ));
116
ldap_pvt_thread_pool_submit( &connection_pool,
117
mdb_tool_index_task, ptr );
128
int mdb_tool_entry_close(
131
if ( mdb_tool_info ) {
133
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
135
/* There might still be some threads starting */
136
while ( mdb_tool_index_tcount > 0 ) {
137
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
138
&mdb_tool_index_mutex );
141
mdb_tool_index_tcount = mdb_tool_threads - 1;
142
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
144
/* Make sure all threads are stopped */
145
while ( mdb_tool_index_tcount > 0 ) {
146
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
147
&mdb_tool_index_mutex );
149
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
151
mdb_tool_info = NULL;
153
ch_free( mdb_tool_index_rec );
154
mdb_tool_index_tcount = mdb_tool_threads - 1;
158
mdb_cursor_close( idcursor );
162
mdb_cursor_close( cursor );
166
MDB_TOOL_IDL_FLUSH( be, txn );
167
if ( mdb_txn_commit( txn ))
174
fprintf( stderr, "Error, entries missing!\n");
175
for (i=0; i<nholes; i++) {
176
fprintf(stderr, " entry %ld: %s\n",
177
holes[i].id, holes[i].dn.bv_val);
187
mdb_tool_entry_first_x(
197
return mdb_tool_entry_next( be );
200
ID mdb_tool_entry_next(
205
struct mdb_info *mdb;
207
assert( be != NULL );
208
assert( slapMode & SLAP_TOOL_MODE );
210
mdb = (struct mdb_info *) be->be_private;
211
assert( mdb != NULL );
214
rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &txn );
217
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &cursor );
219
mdb_txn_abort( txn );
225
rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
231
previd = *(ID *)key.mv_data;
234
if ( tool_filter || tool_base ) {
235
static Operation op = {0};
236
static Opheader ohdr = {0};
240
op.o_tmpmemctx = NULL;
241
op.o_tmpmfuncs = &ch_mfuncs;
243
if ( tool_next_entry ) {
244
mdb_entry_release( &op, tool_next_entry, 0 );
245
tool_next_entry = NULL;
248
rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
249
if ( rc == LDAP_NO_SUCH_OBJECT ) {
253
assert( tool_next_entry != NULL );
255
if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
257
mdb_entry_release( &op, tool_next_entry, 0 );
258
tool_next_entry = NULL;
266
ID mdb_tool_dn2id_get(
271
struct mdb_info *mdb;
277
if ( BER_BVISEMPTY(dn) )
280
mdb = (struct mdb_info *) be->be_private;
283
rc = mdb_txn_begin( mdb->mi_dbenv, NULL, (slapMode & SLAP_TOOL_READONLY) != 0 ?
284
MDB_RDONLY : 0, &txn );
291
op.o_tmpmemctx = NULL;
292
op.o_tmpmfuncs = &ch_mfuncs;
294
rc = mdb_dn2id( &op, txn, NULL, dn, &id, NULL, NULL );
295
if ( rc == MDB_NOTFOUND )
302
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
308
struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
311
assert( be != NULL );
312
assert( slapMode & SLAP_TOOL_MODE );
314
if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
315
*ep = tool_next_entry;
316
tool_next_entry = NULL;
320
if ( id != previd ) {
321
key.mv_size = sizeof(ID);
323
rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
332
op.o_tmpmemctx = NULL;
333
op.o_tmpmfuncs = &ch_mfuncs;
334
if ( slapMode & SLAP_TOOL_READONLY ) {
335
rc = mdb_id2name( &op, txn, &idcursor, id, &dn, &ndn );
338
mdb_entry_return( &op, e );
342
if ( tool_base != NULL ) {
343
if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
344
ch_free( dn.bv_val );
345
ch_free( ndn.bv_val );
346
rc = LDAP_NO_SUCH_OBJECT;
350
rc = mdb_entry_decode( &op, &data, &e );
352
if ( !BER_BVISNULL( &dn )) {
356
e->e_name.bv_val = NULL;
357
e->e_nname.bv_val = NULL;
369
mdb_tool_entry_get( BackendDB *be, ID id )
373
(void)mdb_tool_entry_get_int( be, id, &e );
377
static int mdb_tool_next_id(
384
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
385
struct berval dn = e->e_name;
386
struct berval ndn = e->e_nname;
387
struct berval pdn, npdn, nmatched;
391
if (ndn.bv_len == 0) {
396
rc = mdb_dn2id( op, tid, mcp, &ndn, &id, NULL, &nmatched );
397
if ( rc == MDB_NOTFOUND ) {
398
if ( !be_issuffix( op->o_bd, &ndn ) ) {
400
dnParent( &ndn, &npdn );
401
if ( nmatched.bv_len != npdn.bv_len ) {
402
dnParent( &dn, &pdn );
405
rc = mdb_tool_next_id( op, tid, e, text, 1 );
411
/* If parent didn't exist, it was created just now
412
* and its ID is now in e->e_id. Make sure the current
413
* entry gets added under the new parent ID.
415
if ( eid != e->e_id ) {
422
rc = mdb_next_id( op->o_bd, idcursor, &e->e_id );
424
snprintf( text->bv_val, text->bv_len,
425
"next_id failed: %s (%d)",
426
mdb_strerror(rc), rc );
427
Debug( LDAP_DEBUG_ANY,
428
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
431
rc = mdb_dn2id_add( op, mcp, mcd, pid, e );
433
snprintf( text->bv_val, text->bv_len,
434
"dn2id_add failed: %s (%d)",
435
mdb_strerror(rc), rc );
436
Debug( LDAP_DEBUG_ANY,
437
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
440
if ( nholes == nhmax - 1 ) {
441
if ( holes == hbuf ) {
442
holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
443
AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
445
holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
449
ber_dupbv( &holes[nholes].dn, &ndn );
450
holes[nholes++].id = e->e_id;
451
key.mv_size = sizeof(ID);
452
key.mv_data = &e->e_id;
455
rc = mdb_cursor_put( idcursor, &key, &data, MDB_NOOVERWRITE );
456
if ( rc == MDB_KEYEXIST )
459
snprintf( text->bv_val, text->bv_len,
460
"dummy id2entry add failed: %s (%d)",
461
mdb_strerror(rc), rc );
462
Debug( LDAP_DEBUG_ANY,
463
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
466
} else if ( !hole ) {
471
for ( i=0; i<nholes; i++) {
472
if ( holes[i].id == e->e_id ) {
473
free(holes[i].dn.bv_val);
474
for (j=i;j<nholes;j++) holes[j] = holes[j+1];
478
} else if ( holes[i].id > e->e_id ) {
492
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
494
if ( !mdb->mi_nattrs )
497
if ( mdb_tool_threads > 1 ) {
502
ir = mdb_tool_index_rec;
503
for (i=0; i<mdb->mi_nattrs; i++)
504
ir[i].ir_attrs = NULL;
506
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
507
rc = mdb_index_recset( mdb, a, a->a_desc->ad_type,
508
&a->a_desc->ad_tags, ir );
512
for (i=0; i<mdb->mi_nattrs; i++) {
515
rc = mdb_cursor_open( txn, ir[i].ir_ai->ai_dbi,
516
&ir[i].ir_ai->ai_cursor );
520
mdb_tool_ix_id = e->e_id;
522
mdb_tool_ix_txn = txn;
523
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
524
/* Wait for all threads to be ready */
525
while ( mdb_tool_index_tcount ) {
526
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
527
&mdb_tool_index_mutex );
530
for ( i=1; i<mdb_tool_threads; i++ )
531
mdb_tool_index_rec[i].ir_i = LDAP_BUSY;
532
mdb_tool_index_tcount = mdb_tool_threads - 1;
533
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
534
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
536
rc = mdb_index_recrun( op, txn, mdb, ir, e->e_id, 0 );
539
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
540
for ( i=1; i<mdb_tool_threads; i++ ) {
541
if ( mdb_tool_index_rec[i].ir_i == LDAP_BUSY ) {
542
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
543
&mdb_tool_index_mutex );
547
if ( mdb_tool_index_rec[i].ir_i ) {
548
rc = mdb_tool_index_rec[i].ir_i;
552
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
556
return mdb_index_entry_add( op, txn, e );
560
ID mdb_tool_entry_put(
563
struct berval *text )
566
struct mdb_info *mdb;
570
assert( be != NULL );
571
assert( slapMode & SLAP_TOOL_MODE );
573
assert( text != NULL );
574
assert( text->bv_val != NULL );
575
assert( text->bv_val[0] == '\0' ); /* overconservative? */
577
Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
578
"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
580
mdb = (struct mdb_info *) be->be_private;
583
rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
585
snprintf( text->bv_val, text->bv_len,
586
"txn_begin failed: %s (%d)",
587
mdb_strerror(rc), rc );
588
Debug( LDAP_DEBUG_ANY,
589
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
590
text->bv_val, 0, 0 );
593
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &idcursor );
595
snprintf( text->bv_val, text->bv_len,
596
"cursor_open failed: %s (%d)",
597
mdb_strerror(rc), rc );
598
Debug( LDAP_DEBUG_ANY,
599
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
600
text->bv_val, 0, 0 );
603
rc = mdb_cursor_open( txn, mdb->mi_dn2id, &mcp );
605
snprintf( text->bv_val, text->bv_len,
606
"cursor_open failed: %s (%d)",
607
mdb_strerror(rc), rc );
608
Debug( LDAP_DEBUG_ANY,
609
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
610
text->bv_val, 0, 0 );
613
rc = mdb_cursor_open( txn, mdb->mi_dn2id, &mcd );
615
snprintf( text->bv_val, text->bv_len,
616
"cursor_open failed: %s (%d)",
617
mdb_strerror(rc), rc );
618
Debug( LDAP_DEBUG_ANY,
619
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
620
text->bv_val, 0, 0 );
627
op.o_tmpmemctx = NULL;
628
op.o_tmpmfuncs = &ch_mfuncs;
630
/* add dn2id indices */
631
rc = mdb_tool_next_id( &op, txn, e, text, 0 );
636
rc = mdb_tool_index_add( &op, txn, e );
638
snprintf( text->bv_val, text->bv_len,
639
"index_entry_add failed: err=%d", rc );
640
Debug( LDAP_DEBUG_ANY,
641
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
642
text->bv_val, 0, 0 );
648
rc = mdb_id2entry_add( &op, txn, idcursor, e );
650
snprintf( text->bv_val, text->bv_len,
651
"id2entry_add failed: err=%d", rc );
652
Debug( LDAP_DEBUG_ANY,
653
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
654
text->bv_val, 0, 0 );
661
if ( mdb_writes >= mdb_writes_per_commit ) {
663
MDB_TOOL_IDL_FLUSH( be, txn );
664
rc = mdb_txn_commit( txn );
665
for ( i=0; i<mdb->mi_nattrs; i++ )
666
mdb->mi_attrs[i]->ai_cursor = NULL;
671
snprintf( text->bv_val, text->bv_len,
672
"txn_commit failed: %s (%d)",
673
mdb_strerror(rc), rc );
674
Debug( LDAP_DEBUG_ANY,
675
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
676
text->bv_val, 0, 0 );
682
mdb_txn_abort( txn );
685
snprintf( text->bv_val, text->bv_len,
686
"txn_aborted! %s (%d)",
687
rc == LDAP_OTHER ? "Internal error" :
688
mdb_strerror(rc), rc );
689
Debug( LDAP_DEBUG_ANY,
690
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
691
text->bv_val, 0, 0 );
698
int mdb_tool_entry_reindex(
701
AttributeDescription **adv )
703
struct mdb_info *mi = (struct mdb_info *) be->be_private;
709
Debug( LDAP_DEBUG_ARGS,
710
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
712
assert( tool_base == NULL );
713
assert( tool_filter == NULL );
715
/* No indexes configured, nothing to do. Could return an
716
* error here to shortcut things.
722
/* Check for explicit list of attrs to index */
726
if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
728
for ( n = 0; adv[n]; n++ ) ;
731
for ( i = 0; i < n; i++ ) {
732
AttributeDescription *ad = adv[i];
733
for ( j = i-1; j>=0; j--) {
734
if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
741
for ( i = 0; adv[i]; i++ ) {
742
if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
743
for ( j = i+1; j < mi->mi_nattrs; j++ ) {
744
if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
745
AttrInfo *ai = mi->mi_attrs[i];
746
mi->mi_attrs[i] = mi->mi_attrs[j];
747
mi->mi_attrs[j] = ai;
751
if ( j == mi->mi_nattrs ) {
752
Debug( LDAP_DEBUG_ANY,
753
LDAP_XSTRING(mdb_tool_entry_reindex)
754
": no index configured for %s\n",
755
adv[i]->ad_cname.bv_val, 0, 0 );
763
if ( slapMode & SLAP_TRUNCATE_MODE ) {
765
for ( i=0; i < mi->mi_nattrs; i++ ) {
766
rc = mdb_drop( txn, mi->mi_attrs[i]->ai_dbi, 0 );
768
Debug( LDAP_DEBUG_ANY,
769
LDAP_XSTRING(mdb_tool_entry_reindex)
770
": (Truncate) mdb_drop(%s) failed: %s (%d)\n",
771
mi->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
772
mdb_strerror(rc), rc );
776
slapMode ^= SLAP_TRUNCATE_MODE;
779
e = mdb_tool_entry_get( be, id );
782
Debug( LDAP_DEBUG_ANY,
783
LDAP_XSTRING(mdb_tool_entry_reindex)
784
": could not locate id=%ld\n",
790
rc = mdb_txn_begin( mi->mi_dbenv, NULL, 0, &txi );
792
Debug( LDAP_DEBUG_ANY,
793
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
794
"txn_begin failed: %s (%d)\n",
795
mdb_strerror(rc), rc, 0 );
801
* just (re)add them for now
802
* assume that some other routine (not yet implemented)
803
* will zap index databases
807
Debug( LDAP_DEBUG_TRACE,
808
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
813
op.o_tmpmemctx = NULL;
814
op.o_tmpmfuncs = &ch_mfuncs;
816
rc = mdb_tool_index_add( &op, txi, e );
821
if ( mdb_writes >= mdb_writes_per_commit ) {
823
MDB_TOOL_IDL_FLUSH( be, txi );
824
rc = mdb_txn_commit( txi );
825
for ( i=0; i<mi->mi_nattrs; i++ )
826
mi->mi_attrs[i]->ai_cursor = NULL;
828
Debug( LDAP_DEBUG_ANY,
829
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
830
": txn_commit failed: %s (%d)\n",
831
mdb_strerror(rc), rc, 0 );
838
mdb_txn_abort( txi );
839
Debug( LDAP_DEBUG_ANY,
840
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
841
": txn_aborted! err=%d\n",
846
mdb_entry_release( &op, e, 0 );
851
ID mdb_tool_entry_modify(
854
struct berval *text )
857
struct mdb_info *mdb;
862
assert( be != NULL );
863
assert( slapMode & SLAP_TOOL_MODE );
865
assert( text != NULL );
866
assert( text->bv_val != NULL );
867
assert( text->bv_val[0] == '\0' ); /* overconservative? */
869
assert ( e->e_id != NOID );
871
Debug( LDAP_DEBUG_TRACE,
872
"=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
873
(long) e->e_id, e->e_dn, 0 );
875
mdb = (struct mdb_info *) be->be_private;
878
mdb_cursor_close( cursor );
881
rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &tid );
883
snprintf( text->bv_val, text->bv_len,
884
"txn_begin failed: %s (%d)",
885
mdb_strerror(rc), rc );
886
Debug( LDAP_DEBUG_ANY,
887
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
888
text->bv_val, 0, 0 );
894
op.o_tmpmemctx = NULL;
895
op.o_tmpmfuncs = &ch_mfuncs;
898
rc = mdb_id2entry_update( &op, tid, NULL, e );
900
snprintf( text->bv_val, text->bv_len,
901
"id2entry_update failed: err=%d", rc );
902
Debug( LDAP_DEBUG_ANY,
903
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
904
text->bv_val, 0, 0 );
910
rc = mdb_txn_commit( tid );
912
snprintf( text->bv_val, text->bv_len,
913
"txn_commit failed: %s (%d)",
914
mdb_strerror(rc), rc );
915
Debug( LDAP_DEBUG_ANY,
916
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
917
"%s\n", text->bv_val, 0, 0 );
922
mdb_txn_abort( tid );
923
snprintf( text->bv_val, text->bv_len,
924
"txn_aborted! %s (%d)",
925
mdb_strerror(rc), rc );
926
Debug( LDAP_DEBUG_ANY,
927
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
928
text->bv_val, 0, 0 );
936
mdb_tool_index_task( void *ctx, void *ptr )
938
int base = *(int *)ptr;
942
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
943
mdb_tool_index_tcount--;
944
if ( !mdb_tool_index_tcount )
945
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
946
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
947
&mdb_tool_index_mutex );
948
if ( slapd_shutdown ) {
949
mdb_tool_index_tcount--;
950
if ( !mdb_tool_index_tcount )
951
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
952
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
955
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
956
mdb_tool_index_rec[base].ir_i = mdb_index_recrun( mdb_tool_ix_op,
958
mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
964
#ifdef MDB_TOOL_IDL_CACHING
966
mdb_tool_idl_cmp( const void *v1, const void *v2 )
968
const mdb_tool_idl_cache *c1 = v1, *c2 = v2;
971
if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
972
return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
976
mdb_tool_idl_flush_one( MDB_cursor *mc, AttrInfo *ai, mdb_tool_idl_cache *ic )
978
mdb_tool_idl_cache_entry *ice;
979
MDB_val key, data[2];
983
/* Freshly allocated, ignore it */
984
if ( !ic->head && ic->count <= MDB_IDL_DB_SIZE ) {
988
key.mv_data = ic->kstr.bv_val;
989
key.mv_size = ic->kstr.bv_len;
991
if ( ic->count > MDB_IDL_DB_SIZE ) {
992
while ( ic->flags & WAS_FOUND ) {
993
rc = mdb_cursor_get( mc, &key, data, MDB_SET );
995
/* FIXME: find out why this happens */
999
if ( ic->flags & WAS_RANGE ) {
1001
rc = mdb_cursor_get( mc, &key, data, MDB_NEXT_DUP );
1004
rc = mdb_cursor_get( mc, &key, data, MDB_NEXT_DUP );
1006
/* Store range hi */
1007
data[0].mv_data = &ic->last;
1008
rc = mdb_cursor_put( mc, &key, data, MDB_CURRENT );
1010
/* Delete old data, replace with range */
1011
ic->first = *(ID *)data[0].mv_data;
1012
mdb_cursor_del( mc, MDB_NODUPDATA );
1016
if ( !(ic->flags & WAS_RANGE)) {
1017
/* range, didn't exist before */
1019
data[0].mv_size = sizeof(ID);
1020
data[0].mv_data = &nid;
1021
rc = mdb_cursor_put( mc, &key, data, 0 );
1023
data[0].mv_data = &ic->first;
1024
rc = mdb_cursor_put( mc, &key, data, 0 );
1026
data[0].mv_data = &ic->last;
1027
rc = mdb_cursor_put( mc, &key, data, 0 );
1038
data[0].mv_size = sizeof(ID);
1041
for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
1046
end = ic->count & (IDBLOCK-1);
1050
data[1].mv_size = end - i;
1051
data[0].mv_data = &ice->ids[i];
1053
rc = mdb_cursor_put( mc, &key, data, MDB_NODUPDATA|MDB_APPEND|MDB_MULTIPLE );
1055
if ( rc == MDB_KEYEXIST ) {
1064
ic->tail->next = ai->ai_flist;
1065
ai->ai_flist = ic->head;
1068
ic->head = ai->ai_clist;
1074
mdb_tool_idl_flush_db( MDB_txn *txn, AttrInfo *ai )
1080
mdb_cursor_open( txn, ai->ai_dbi, &mc );
1081
root = tavl_end( ai->ai_root, TAVL_DIR_LEFT );
1083
rc = mdb_tool_idl_flush_one( mc, ai, root->avl_data );
1086
} while ((root = tavl_next(root, TAVL_DIR_RIGHT)));
1087
mdb_cursor_close( mc );
1093
mdb_tool_idl_flush( BackendDB *be, MDB_txn *txn )
1095
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
1097
unsigned int i, dbi;
1099
for ( i=0; i < mdb->mi_nattrs; i++ ) {
1100
if ( !mdb->mi_attrs[i]->ai_root ) continue;
1101
rc = mdb_tool_idl_flush_db( txn, mdb->mi_attrs[i] );
1102
tavl_free(mdb->mi_attrs[i]->ai_root, NULL);
1103
mdb->mi_attrs[i]->ai_root = NULL;
1110
int mdb_tool_idl_add(
1112
struct berval *keys,
1116
mdb_tool_idl_cache *ic, itmp;
1117
mdb_tool_idl_cache_entry *ice;
1119
AttrInfo *ai = (AttrInfo *)mc;
1123
for (i=0; keys[i].bv_val; i++) {
1124
itmp.kstr = keys[i];
1125
ic = tavl_find( (Avlnode *)ai->ai_root, &itmp, mdb_tool_idl_cmp );
1127
/* No entry yet, create one */
1133
if ( ai->ai_clist ) {
1135
ai->ai_clist = ic->head;
1137
ic = ch_malloc( sizeof( mdb_tool_idl_cache ) + itmp.kstr.bv_len + 4 );
1139
ic->kstr.bv_len = itmp.kstr.bv_len;
1140
ic->kstr.bv_val = (char *)(ic+1);
1141
memcpy( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
1142
ic->head = ic->tail = NULL;
1147
tavl_insert( (Avlnode **)&ai->ai_root, ic, mdb_tool_idl_cmp,
1150
/* load existing key count here */
1151
key.mv_size = keys[i].bv_len;
1152
key.mv_data = keys[i].bv_val;
1153
rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
1155
ic->flags |= WAS_FOUND;
1156
nid = *(ID *)data.mv_data;
1158
ic->count = MDB_IDL_DB_SIZE+1;
1159
ic->flags |= WAS_RANGE;
1163
mdb_cursor_count( mc, &count );
1166
ic->offset = count & (IDBLOCK-1);
1170
/* are we a range already? */
1171
if ( ic->count > MDB_IDL_DB_SIZE ) {
1174
/* Are we at the limit, and converting to a range? */
1175
} else if ( ic->count == MDB_IDL_DB_SIZE ) {
1177
ic->tail->next = ai->ai_flist;
1178
ai->ai_flist = ic->head;
1180
ic->head = ic->tail = NULL;
1185
/* No free block, create that too */
1186
lcount = ic->count & (IDBLOCK-1);
1187
if ( !ic->tail || lcount == 0) {
1188
if ( ai->ai_flist ) {
1190
ai->ai_flist = ice->next;
1192
ice = ch_malloc( sizeof( mdb_tool_idl_cache_entry ));
1198
ic->tail->next = ice;
1202
ice->ids[lcount-1] = 0;
1207
if (!lcount || ice->ids[lcount-1] != id)
1208
ice->ids[lcount] = id;
1214
#endif /* MDB_TOOL_IDL_CACHING */