]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/tools.c
silence warnings...
[openldap] / servers / slapd / back-bdb / tools.c
1 /* tools.c - tools for slap tools */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #define AVL_INTERNAL
23 #include "back-bdb.h"
24 #include "idl.h"
25
26 static DBC *cursor = NULL;
27 static DBT key, data;
28
29 typedef struct dn_id {
30         ID id;
31         struct berval dn;
32 } dn_id;
33
34 #define HOLE_SIZE       4096
35 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
36 static unsigned nhmax = HOLE_SIZE;
37 static unsigned nholes;
38
39 static int index_nattrs;
40
41 #ifdef BDB_TOOL_IDL_CACHING
42 #define bdb_tool_idl_cmp                BDB_SYMBOL(tool_idl_cmp)
43 #define bdb_tool_idl_flush_one          BDB_SYMBOL(tool_idl_flush_one)
44 #define bdb_tool_idl_flush              BDB_SYMBOL(tool_idl_flush)
45
46 static int bdb_tool_idl_flush( BackendDB *be );
47
48 #define IDBLOCK 1024
49
50 typedef struct bdb_tool_idl_cache_entry {
51         struct bdb_tool_idl_cache_entry *next;
52         ID ids[IDBLOCK];
53 } bdb_tool_idl_cache_entry;
54  
55 typedef struct bdb_tool_idl_cache {
56         struct berval kstr;
57         bdb_tool_idl_cache_entry *head, *tail;
58         ID first, last;
59         int count;
60 } bdb_tool_idl_cache;
61
62 static bdb_tool_idl_cache_entry *bdb_tool_idl_free_list;
63 #endif  /* BDB_TOOL_IDL_CACHING */
64
65 static ID bdb_tool_ix_id;
66 static Operation *bdb_tool_ix_op;
67 static volatile int *bdb_tool_index_threads;
68 static void *bdb_tool_index_rec;
69 static struct bdb_info *bdb_tool_info;
70 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex;
71 static ldap_pvt_thread_cond_t bdb_tool_index_cond;
72
73 static void * bdb_tool_index_task( void *ctx, void *ptr );
74
75 int bdb_tool_entry_open(
76         BackendDB *be, int mode )
77 {
78         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
79
80         /* initialize key and data thangs */
81         DBTzero( &key );
82         DBTzero( &data );
83         key.flags = DB_DBT_REALLOC;
84         data.flags = DB_DBT_REALLOC;
85
86         if (cursor == NULL) {
87                 int rc = bdb->bi_id2entry->bdi_db->cursor(
88                         bdb->bi_id2entry->bdi_db, NULL, &cursor,
89                         bdb->bi_db_opflags );
90                 if( rc != 0 ) {
91                         return -1;
92                 }
93         }
94
95         /* Set up for threaded slapindex */
96         if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK) {
97                 if ( !bdb_tool_info ) {
98                         int i;
99                         ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex );
100                         ldap_pvt_thread_cond_init( &bdb_tool_index_cond );
101                         bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
102                         bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec ));
103                         for (i=1; i<slap_tool_thread_max; i++) {
104                                 int *ptr = ch_malloc( sizeof( int ));
105                                 *ptr = i;
106                                 ldap_pvt_thread_pool_submit( &connection_pool,
107                                         bdb_tool_index_task, ptr );
108                                 ldap_pvt_thread_yield();
109                         }
110                 }
111                 bdb_tool_info = bdb;
112         }
113
114         return 0;
115 }
116
117 int bdb_tool_entry_close(
118         BackendDB *be )
119 {
120         if ( bdb_tool_info ) {
121                 slapd_shutdown = 1;
122                 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
123                 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond );
124                 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
125         }
126
127         if( key.data ) {
128                 ch_free( key.data );
129                 key.data = NULL;
130         }
131         if( data.data ) {
132                 ch_free( data.data );
133                 data.data = NULL;
134         }
135
136         if( cursor ) {
137                 cursor->c_close( cursor );
138                 cursor = NULL;
139         }
140
141 #ifdef BDB_TOOL_IDL_CACHING
142         bdb_tool_idl_flush( be );
143 #endif
144
145         if( nholes ) {
146                 unsigned i;
147                 fprintf( stderr, "Error, entries missing!\n");
148                 for (i=0; i<nholes; i++) {
149                         fprintf(stderr, "  entry %ld: %s\n",
150                                 holes[i].id, holes[i].dn.bv_val);
151                 }
152                 return -1;
153         }
154                         
155         return 0;
156 }
157
158 ID bdb_tool_entry_next(
159         BackendDB *be )
160 {
161         int rc;
162         ID id;
163         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
164
165         assert( be != NULL );
166         assert( slapMode & SLAP_TOOL_MODE );
167         assert( bdb != NULL );
168         
169         rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
170
171         if( rc != 0 ) {
172                 /* If we're doing linear indexing and there are more attrs to
173                  * index, and we're at the end of the database, start over.
174                  */
175                 if ( index_nattrs && rc == DB_NOTFOUND ) {
176                         /* optional - do a checkpoint here? */
177                         bdb_attr_info_free( bdb->bi_attrs[0] );
178                         bdb->bi_attrs[0] = bdb->bi_attrs[index_nattrs];
179                         index_nattrs--;
180                         rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
181                         if ( rc ) {
182                                 return NOID;
183                         }
184                 } else {
185                         return NOID;
186                 }
187         }
188
189         if( data.data == NULL ) {
190                 return NOID;
191         }
192
193         BDB_DISK2ID( key.data, &id );
194         return id;
195 }
196
197 ID bdb_tool_dn2id_get(
198         Backend *be,
199         struct berval *dn
200 )
201 {
202         Operation op = {0};
203         Opheader ohdr = {0};
204         EntryInfo *ei = NULL;
205         int rc;
206
207         if ( BER_BVISEMPTY(dn) )
208                 return 0;
209
210         op.o_hdr = &ohdr;
211         op.o_bd = be;
212         op.o_tmpmemctx = NULL;
213         op.o_tmpmfuncs = &ch_mfuncs;
214
215         rc = bdb_cache_find_ndn( &op, NULL, dn, &ei );
216         if ( ei ) bdb_cache_entryinfo_unlock( ei );
217         if ( rc == DB_NOTFOUND )
218                 return NOID;
219         
220         return ei->bei_id;
221 }
222
223 int bdb_tool_id2entry_get(
224         Backend *be,
225         ID id,
226         Entry **e
227 )
228 {
229         int rc = bdb_id2entry( be, NULL, 0, id, e );
230
231         if ( rc == DB_NOTFOUND && id == 0 ) {
232                 Entry *dummy = ch_calloc( 1, sizeof(Entry) );
233                 struct berval gluebv = BER_BVC("glue");
234                 dummy->e_name.bv_val = ch_strdup( "" );
235                 dummy->e_nname.bv_val = ch_strdup( "" );
236                 attr_merge_one( dummy, slap_schema.si_ad_objectClass, &gluebv, NULL );
237                 attr_merge_one( dummy, slap_schema.si_ad_structuralObjectClass,
238                         &gluebv, NULL );
239                 *e = dummy;
240                 rc = LDAP_SUCCESS;
241         }
242         return rc;
243 }
244
245 Entry* bdb_tool_entry_get( BackendDB *be, ID id )
246 {
247         int rc;
248         Entry *e = NULL;
249         struct berval bv;
250
251         assert( be != NULL );
252         assert( slapMode & SLAP_TOOL_MODE );
253         assert( data.data != NULL );
254
255         DBT2bv( &data, &bv );
256
257 #ifdef SLAP_ZONE_ALLOC
258         /* FIXME: will add ctx later */
259         rc = entry_decode( &bv, &e, NULL );
260 #else
261         rc = entry_decode( &bv, &e );
262 #endif
263
264         if( rc == LDAP_SUCCESS ) {
265                 e->e_id = id;
266         }
267 #ifdef BDB_HIER
268         if ( slapMode & SLAP_TOOL_READONLY ) {
269                 EntryInfo *ei = NULL;
270                 Operation op = {0};
271                 Opheader ohdr = {0};
272
273                 op.o_hdr = &ohdr;
274                 op.o_bd = be;
275                 op.o_tmpmemctx = NULL;
276                 op.o_tmpmfuncs = &ch_mfuncs;
277
278                 rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei );
279                 if ( rc == LDAP_SUCCESS ) {
280                         bdb_cache_entryinfo_unlock( ei );
281                         e->e_private = ei;
282                         ei->bei_e = e;
283                         bdb_fix_dn( e, 0 );
284                         ei->bei_e = NULL;
285                         e->e_private = NULL;
286                 }
287         }
288 #endif
289         return e;
290 }
291
292 static int bdb_tool_next_id(
293         Operation *op,
294         DB_TXN *tid,
295         Entry *e,
296         struct berval *text,
297         int hole )
298 {
299         struct berval dn = e->e_name;
300         struct berval ndn = e->e_nname;
301         struct berval pdn, npdn;
302         EntryInfo *ei = NULL, eidummy;
303         int rc;
304
305         if (ndn.bv_len == 0) {
306                 e->e_id = 0;
307                 return 0;
308         }
309
310         rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
311         if ( ei ) bdb_cache_entryinfo_unlock( ei );
312         if ( rc == DB_NOTFOUND ) {
313                 if ( !be_issuffix( op->o_bd, &ndn ) ) {
314                         ID eid = e->e_id;
315                         dnParent( &dn, &pdn );
316                         dnParent( &ndn, &npdn );
317                         e->e_name = pdn;
318                         e->e_nname = npdn;
319                         rc = bdb_tool_next_id( op, tid, e, text, 1 );
320                         e->e_name = dn;
321                         e->e_nname = ndn;
322                         if ( rc ) {
323                                 return rc;
324                         }
325                         /* If parent didn't exist, it was created just now
326                          * and its ID is now in e->e_id. Make sure the current
327                          * entry gets added under the new parent ID.
328                          */
329                         if ( eid != e->e_id ) {
330                                 eidummy.bei_id = e->e_id;
331                                 ei = &eidummy;
332                         }
333                 }
334                 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
335                 if ( rc ) {
336                         snprintf( text->bv_val, text->bv_len,
337                                 "next_id failed: %s (%d)",
338                                 db_strerror(rc), rc );
339                 Debug( LDAP_DEBUG_ANY,
340                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
341                         return rc;
342                 }
343                 rc = bdb_dn2id_add( op, tid, ei, e );
344                 if ( rc ) {
345                         snprintf( text->bv_val, text->bv_len, 
346                                 "dn2id_add failed: %s (%d)",
347                                 db_strerror(rc), rc );
348                 Debug( LDAP_DEBUG_ANY,
349                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
350                 } else if ( hole ) {
351                         if ( nholes == nhmax - 1 ) {
352                                 if ( holes == hbuf ) {
353                                         holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
354                                         AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
355                                 } else {
356                                         holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
357                                 }
358                                 nhmax *= 2;
359                         }
360                         ber_dupbv( &holes[nholes].dn, &ndn );
361                         holes[nholes++].id = e->e_id;
362                 }
363         } else if ( !hole ) {
364                 unsigned i;
365
366                 e->e_id = ei->bei_id;
367
368                 for ( i=0; i<nholes; i++) {
369                         if ( holes[i].id == e->e_id ) {
370                                 int j;
371                                 free(holes[i].dn.bv_val);
372                                 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
373                                 holes[j].id = 0;
374                                 nholes--;
375                                 break;
376                         } else if ( holes[i].id > e->e_id ) {
377                                 break;
378                         }
379                 }
380         }
381         return rc;
382 }
383
384 static int
385 bdb_tool_index_add(
386         Operation *op,
387         DB_TXN *txn,
388         Entry *e )
389 {
390         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
391
392         if ( slapMode & SLAP_TOOL_QUICK ) {
393                 IndexRec *ir;
394                 int i, rc;
395                 Attribute *a;
396                 
397                 ir = bdb_tool_index_rec;
398                 memset(ir, 0, bdb->bi_nattrs * sizeof( IndexRec ));
399
400                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
401                         rc = bdb_index_recset( bdb, a, a->a_desc->ad_type, 
402                                 &a->a_desc->ad_tags, ir );
403                         if ( rc )
404                                 return rc;
405                 }
406                 bdb_tool_ix_id = e->e_id;
407                 bdb_tool_ix_op = op;
408                 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
409                 for ( i=1; i<slap_tool_thread_max; i++ )
410                         bdb_tool_index_threads[i] = LDAP_BUSY;
411                 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond );
412                 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
413                 rc = bdb_index_recrun( op, bdb, ir, e->e_id, 0 );
414                 if ( rc )
415                         return rc;
416                 for ( i=1; i<slap_tool_thread_max; i++ ) {
417                         if ( bdb_tool_index_threads[i] == LDAP_BUSY ) {
418                                 ldap_pvt_thread_yield();
419                                 i--;
420                                 continue;
421                         }
422                         if ( bdb_tool_index_threads[i] )
423                                 return bdb_tool_index_threads[i];
424                 }
425                 return 0;
426         } else {
427                 return bdb_index_entry_add( op, txn, e );
428         }
429 }
430
431 ID bdb_tool_entry_put(
432         BackendDB *be,
433         Entry *e,
434         struct berval *text )
435 {
436         int rc;
437         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
438         DB_TXN *tid = NULL;
439         Operation op = {0};
440         Opheader ohdr = {0};
441
442         assert( be != NULL );
443         assert( slapMode & SLAP_TOOL_MODE );
444
445         assert( text != NULL );
446         assert( text->bv_val != NULL );
447         assert( text->bv_val[0] == '\0' );      /* overconservative? */
448
449         Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
450                 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
451
452         if (! (slapMode & SLAP_TOOL_QUICK)) {
453         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
454                 bdb->bi_db_opflags );
455         if( rc != 0 ) {
456                 snprintf( text->bv_val, text->bv_len,
457                         "txn_begin failed: %s (%d)",
458                         db_strerror(rc), rc );
459                 Debug( LDAP_DEBUG_ANY,
460                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
461                          text->bv_val, 0, 0 );
462                 return NOID;
463         }
464         }
465
466         op.o_hdr = &ohdr;
467         op.o_bd = be;
468         op.o_tmpmemctx = NULL;
469         op.o_tmpmfuncs = &ch_mfuncs;
470
471         /* add dn2id indices */
472         rc = bdb_tool_next_id( &op, tid, e, text, 0 );
473         if( rc != 0 ) {
474                 goto done;
475         }
476
477         /* id2entry index */
478         rc = bdb_id2entry_add( be, tid, e );
479         if( rc != 0 ) {
480                 snprintf( text->bv_val, text->bv_len,
481                                 "id2entry_add failed: %s (%d)",
482                                 db_strerror(rc), rc );
483                 Debug( LDAP_DEBUG_ANY,
484                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
485                         text->bv_val, 0, 0 );
486                 goto done;
487         }
488
489         if ( !bdb->bi_linear_index )
490                 rc = bdb_tool_index_add( &op, tid, e );
491         if( rc != 0 ) {
492                 snprintf( text->bv_val, text->bv_len,
493                                 "index_entry_add failed: %s (%d)",
494                                 db_strerror(rc), rc );
495                 Debug( LDAP_DEBUG_ANY,
496                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
497                         text->bv_val, 0, 0 );
498                 goto done;
499         }
500
501 done:
502         if( rc == 0 ) {
503                 if ( !( slapMode & SLAP_TOOL_QUICK )) {
504                 rc = TXN_COMMIT( tid, 0 );
505                 if( rc != 0 ) {
506                         snprintf( text->bv_val, text->bv_len,
507                                         "txn_commit failed: %s (%d)",
508                                         db_strerror(rc), rc );
509                         Debug( LDAP_DEBUG_ANY,
510                                 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
511                                 text->bv_val, 0, 0 );
512                         e->e_id = NOID;
513                 }
514                 }
515
516         } else {
517                 if ( !( slapMode & SLAP_TOOL_QUICK )) {
518                 TXN_ABORT( tid );
519                 snprintf( text->bv_val, text->bv_len,
520                         "txn_aborted! %s (%d)",
521                         db_strerror(rc), rc );
522                 Debug( LDAP_DEBUG_ANY,
523                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
524                         text->bv_val, 0, 0 );
525                 }
526                 e->e_id = NOID;
527         }
528
529         return e->e_id;
530 }
531
532 int bdb_tool_entry_reindex(
533         BackendDB *be,
534         ID id )
535 {
536         struct bdb_info *bi = (struct bdb_info *) be->be_private;
537         int rc;
538         Entry *e;
539         DB_TXN *tid = NULL;
540         Operation op = {0};
541         Opheader ohdr = {0};
542
543         Debug( LDAP_DEBUG_ARGS,
544                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
545                 (long) id, 0, 0 );
546
547         /* No indexes configured, nothing to do. Could return an
548          * error here to shortcut things.
549          */
550         if (!bi->bi_attrs) {
551                 return 0;
552         }
553
554         /* Get the first attribute to index */
555         if (bi->bi_linear_index && !index_nattrs) {
556                 index_nattrs = bi->bi_nattrs - 1;
557                 bi->bi_nattrs = 1;
558         }
559
560         e = bdb_tool_entry_get( be, id );
561
562         if( e == NULL ) {
563                 Debug( LDAP_DEBUG_ANY,
564                         LDAP_XSTRING(bdb_tool_entry_reindex)
565                         ": could not locate id=%ld\n",
566                         (long) id, 0, 0 );
567                 return -1;
568         }
569
570         if (! (slapMode & SLAP_TOOL_QUICK)) {
571         rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
572         if( rc != 0 ) {
573                 Debug( LDAP_DEBUG_ANY,
574                         "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
575                         "txn_begin failed: %s (%d)\n",
576                         db_strerror(rc), rc, 0 );
577                 goto done;
578         }
579         }
580         
581         /*
582          * just (re)add them for now
583          * assume that some other routine (not yet implemented)
584          * will zap index databases
585          *
586          */
587
588         Debug( LDAP_DEBUG_TRACE,
589                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
590                 (long) id, e->e_dn, 0 );
591
592         op.o_hdr = &ohdr;
593         op.o_bd = be;
594         op.o_tmpmemctx = NULL;
595         op.o_tmpmfuncs = &ch_mfuncs;
596
597         rc = bdb_tool_index_add( &op, tid, e );
598
599 done:
600         if( rc == 0 ) {
601                 if (! (slapMode & SLAP_TOOL_QUICK)) {
602                 rc = TXN_COMMIT( tid, 0 );
603                 if( rc != 0 ) {
604                         Debug( LDAP_DEBUG_ANY,
605                                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
606                                 ": txn_commit failed: %s (%d)\n",
607                                 db_strerror(rc), rc, 0 );
608                         e->e_id = NOID;
609                 }
610                 }
611
612         } else {
613                 if (! (slapMode & SLAP_TOOL_QUICK)) {
614                 TXN_ABORT( tid );
615                 Debug( LDAP_DEBUG_ANY,
616                         "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
617                         ": txn_aborted! %s (%d)\n",
618                         db_strerror(rc), rc, 0 );
619                 }
620                 e->e_id = NOID;
621         }
622         bdb_entry_release( &op, e, 0 );
623
624         return rc;
625 }
626
627 ID bdb_tool_entry_modify(
628         BackendDB *be,
629         Entry *e,
630         struct berval *text )
631 {
632         int rc;
633         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
634         DB_TXN *tid = NULL;
635         Operation op = {0};
636         Opheader ohdr = {0};
637
638         assert( be != NULL );
639         assert( slapMode & SLAP_TOOL_MODE );
640
641         assert( text != NULL );
642         assert( text->bv_val != NULL );
643         assert( text->bv_val[0] == '\0' );      /* overconservative? */
644
645         assert ( e->e_id != NOID );
646
647         Debug( LDAP_DEBUG_TRACE,
648                 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
649                 (long) e->e_id, e->e_dn, 0 );
650
651         if (! (slapMode & SLAP_TOOL_QUICK)) {
652         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
653                 bdb->bi_db_opflags );
654         if( rc != 0 ) {
655                 snprintf( text->bv_val, text->bv_len,
656                         "txn_begin failed: %s (%d)",
657                         db_strerror(rc), rc );
658                 Debug( LDAP_DEBUG_ANY,
659                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
660                          text->bv_val, 0, 0 );
661                 return NOID;
662         }
663         }
664
665         op.o_hdr = &ohdr;
666         op.o_bd = be;
667         op.o_tmpmemctx = NULL;
668         op.o_tmpmfuncs = &ch_mfuncs;
669
670         /* id2entry index */
671         rc = bdb_id2entry_update( be, tid, e );
672         if( rc != 0 ) {
673                 snprintf( text->bv_val, text->bv_len,
674                                 "id2entry_add failed: %s (%d)",
675                                 db_strerror(rc), rc );
676                 Debug( LDAP_DEBUG_ANY,
677                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
678                         text->bv_val, 0, 0 );
679                 goto done;
680         }
681
682 #if 0
683         /* FIXME: this is bogus, we don't have the old values to delete
684          * from the index because the given entry has already been modified.
685          */
686         rc = bdb_index_entry_del( &op, tid, e );
687         if( rc != 0 ) {
688                 snprintf( text->bv_val, text->bv_len,
689                                 "index_entry_del failed: %s (%d)",
690                                 db_strerror(rc), rc );
691                 Debug( LDAP_DEBUG_ANY,
692                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
693                         text->bv_val, 0, 0 );
694                 goto done;
695         }
696 #endif
697
698         rc = bdb_index_entry_add( &op, tid, e );
699         if( rc != 0 ) {
700                 snprintf( text->bv_val, text->bv_len,
701                                 "index_entry_add failed: %s (%d)",
702                                 db_strerror(rc), rc );
703                 Debug( LDAP_DEBUG_ANY,
704                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
705                         text->bv_val, 0, 0 );
706                 goto done;
707         }
708
709 done:
710         if( rc == 0 ) {
711                 if (! (slapMode & SLAP_TOOL_QUICK)) {
712                 rc = TXN_COMMIT( tid, 0 );
713                 if( rc != 0 ) {
714                         snprintf( text->bv_val, text->bv_len,
715                                         "txn_commit failed: %s (%d)",
716                                         db_strerror(rc), rc );
717                         Debug( LDAP_DEBUG_ANY,
718                                 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
719                                 "%s\n", text->bv_val, 0, 0 );
720                         e->e_id = NOID;
721                 }
722                 }
723
724         } else {
725                 if (! (slapMode & SLAP_TOOL_QUICK)) {
726                 TXN_ABORT( tid );
727                 snprintf( text->bv_val, text->bv_len,
728                         "txn_aborted! %s (%d)",
729                         db_strerror(rc), rc );
730                 Debug( LDAP_DEBUG_ANY,
731                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
732                         text->bv_val, 0, 0 );
733                 }
734                 e->e_id = NOID;
735         }
736
737         return e->e_id;
738 }
739
740 #ifdef BDB_TOOL_IDL_CACHING
741 static int
742 bdb_tool_idl_cmp( const void *v1, const void *v2 )
743 {
744         const bdb_tool_idl_cache *c1 = v1, *c2 = v2;
745         int rc;
746
747         if (( rc = c1->kstr.bv_len - c2->kstr.bv_len )) return rc;
748         return memcmp( c1->kstr.bv_val, c2->kstr.bv_val, c1->kstr.bv_len );
749 }
750
751 static int
752 bdb_tool_idl_flush_one( void *v1, void *arg )
753 {
754         bdb_tool_idl_cache *ic = v1;
755         DB *db = arg;
756         struct bdb_info *bdb = bdb_tool_info;
757         bdb_tool_idl_cache_entry *ice;
758         DBC *curs;
759         DBT key, data;
760         int i, rc;
761         ID id, nid;
762
763         /* Freshly allocated, ignore it */
764         if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) {
765                 return 0;
766         }
767
768         rc = db->cursor( db, NULL, &curs, 0 );
769         if ( rc )
770                 return -1;
771
772         DBTzero( &key );
773         DBTzero( &data );
774
775         bv2DBT( &ic->kstr, &key );
776
777         data.size = data.ulen = sizeof( ID );
778         data.flags = DB_DBT_USERMEM;
779         data.data = &nid;
780
781         rc = curs->c_get( curs, &key, &data, DB_SET );
782         /* If key already exists and we're writing a range... */
783         if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) {
784                 /* If it's not currently a range, must delete old info */
785                 if ( nid ) {
786                         /* Skip lo */
787                         while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 )
788                                 curs->c_del( curs, 0 );
789
790                         nid = 0;
791                         /* Store range marker */
792                         curs->c_put( curs, &key, &data, DB_KEYFIRST );
793                 } else {
794                         
795                         /* Skip lo */
796                         rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
797
798                         /* Get hi */
799                         rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP );
800
801                         /* Delete hi */
802                         curs->c_del( curs, 0 );
803                 }
804                 BDB_ID2DISK( ic->last, &nid );
805                 curs->c_put( curs, &key, &data, DB_KEYLAST );
806                 rc = 0;
807         } else if ( rc && rc != DB_NOTFOUND ) {
808                 rc = -1;
809         } else if ( ic->count > BDB_IDL_DB_SIZE ) {
810                 /* range, didn't exist before */
811                 nid = 0;
812                 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
813                 if ( rc == 0 ) {
814                         BDB_ID2DISK( ic->first, &nid );
815                         rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
816                         if ( rc == 0 ) {
817                                 BDB_ID2DISK( ic->last, &nid );
818                                 rc = curs->c_put( curs, &key, &data, DB_KEYLAST );
819                         }
820                 }
821                 if ( rc ) {
822                         rc = -1;
823                 }
824         } else {
825                 int n;
826
827                 /* Just a normal write */
828                 rc = 0;
829                 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) {
830                         int end;
831                         if ( ice->next ) {
832                                 end = IDBLOCK;
833                         } else {
834                                 end = ic->count & (IDBLOCK-1);
835                                 if ( !end )
836                                         end = IDBLOCK;
837                         }
838                         for ( i=0; i<end; i++ ) {
839                                 if ( !ice->ids[i] ) continue;
840                                 BDB_ID2DISK( ice->ids[i], &nid );
841                                 rc = curs->c_put( curs, &key, &data, DB_NODUPDATA );
842                                 if ( rc ) {
843                                         if ( rc == DB_KEYEXIST ) {
844                                                 rc = 0;
845                                                 continue;
846                                         }
847                                         rc = -1;
848                                         break;
849                                 }
850                         }
851                         if ( rc ) {
852                                 rc = -1;
853                                 break;
854                         }
855                 }
856                 if ( ic->head ) {
857                         ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
858                         ic->tail->next = bdb_tool_idl_free_list;
859                         bdb_tool_idl_free_list = ic->head;
860                         bdb->bi_idl_cache_size -= n;
861                         ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
862                 }
863         }
864         if ( ic != db->app_private ) {
865                 ch_free( ic );
866         } else {
867                 ic->head = ic->tail = NULL;
868         }
869         curs->c_close( curs );
870         return rc;
871 }
872
873 static int
874 bdb_tool_idl_flush_db( DB *db, bdb_tool_idl_cache *ic )
875 {
876         Avlnode *root = db->app_private;
877         int rc;
878
879         db->app_private = ic;
880         rc = avl_apply( root, bdb_tool_idl_flush_one, db, -1, AVL_INORDER );
881         avl_free( root, NULL );
882         db->app_private = NULL;
883         if ( rc != -1 )
884                 rc = 0;
885         return rc;
886 }
887
888 static int
889 bdb_tool_idl_flush( BackendDB *be )
890 {
891         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
892         DB *db;
893         Avlnode *root;
894         int i, rc = 0;
895
896         for ( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
897                 db = bdb->bi_databases[i]->bdi_db;
898                 if ( !db->app_private ) continue;
899                 rc = bdb_tool_idl_flush_db( db, NULL );
900                 if ( rc )
901                         break;
902         }
903         if ( !rc ) {
904                 bdb->bi_idl_cache_size = 0;
905         }
906         return rc;
907 }
908
909 int bdb_tool_idl_add(
910         BackendDB *be,
911         DB *db,
912         DB_TXN *txn,
913         DBT *key,
914         ID id )
915 {
916         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
917         bdb_tool_idl_cache *ic, itmp;
918         bdb_tool_idl_cache_entry *ice;
919         int rc;
920
921         if ( !bdb->bi_idl_cache_max_size )
922                 return bdb_idl_insert_key( be, db, txn, key, id );
923
924         DBT2bv( key, &itmp.kstr );
925
926         ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp );
927
928         /* No entry yet, create one */
929         if ( !ic ) {
930                 DBC *curs;
931                 DBT data;
932                 ID nid;
933                 int rc;
934
935                 ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len );
936                 ic->kstr.bv_len = itmp.kstr.bv_len;
937                 ic->kstr.bv_val = (char *)(ic+1);
938                 AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len );
939                 ic->head = ic->tail = NULL;
940                 ic->last = 0;
941                 ic->count = 0;
942                 avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
943                         avl_dup_error );
944
945                 /* load existing key count here */
946                 rc = db->cursor( db, NULL, &curs, 0 );
947                 if ( rc ) return rc;
948
949                 data.ulen = sizeof( ID );
950                 data.flags = DB_DBT_USERMEM;
951                 data.data = &nid;
952                 rc = curs->c_get( curs, key, &data, DB_SET );
953                 if ( rc == 0 ) {
954                         if ( nid == 0 ) {
955                                 ic->count = BDB_IDL_DB_SIZE+1;
956                         } else {
957                                 db_recno_t count;
958
959                                 curs->c_count( curs, &count, 0 );
960                                 ic->count = count;
961                                 BDB_DISK2ID( &nid, &ic->first );
962                         }
963                 }
964                 curs->c_close( curs );
965         }
966         /* are we a range already? */
967         if ( ic->count > BDB_IDL_DB_SIZE ) {
968                 ic->last = id;
969                 return 0;
970         /* Are we at the limit, and converting to a range? */
971         } else if ( ic->count == BDB_IDL_DB_SIZE ) {
972                 int n;
973                 for ( ice = ic->head, n=0; ice; ice = ice->next, n++ )
974                         /* counting */ ;
975                 if ( n ) {
976                         ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
977                         ic->tail->next = bdb_tool_idl_free_list;
978                         bdb_tool_idl_free_list = ic->head;
979                         bdb->bi_idl_cache_size -= n;
980                         ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
981                 }
982                 ic->head = ic->tail = NULL;
983                 ic->last = id;
984                 ic->count++;
985                 return 0;
986         }
987         /* No free block, create that too */
988         if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) {
989                 ice = NULL;
990                 ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
991                 if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
992                         ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
993                         rc = bdb_tool_idl_flush_db( db, ic );
994                         if ( rc )
995                                 return rc;
996                         avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp,
997                                 avl_dup_error );
998                         ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
999                 }
1000                 bdb->bi_idl_cache_size++;
1001                 if ( bdb_tool_idl_free_list ) {
1002                         ice = bdb_tool_idl_free_list;
1003                         bdb_tool_idl_free_list = ice->next;
1004                 }
1005                 ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
1006                 if ( !ice ) {
1007                         ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry ));
1008                 }
1009                 memset( ice, 0, sizeof( *ice ));
1010                 if ( !ic->head ) {
1011                         ic->head = ice;
1012                 } else {
1013                         ic->tail->next = ice;
1014                 }
1015                 ic->tail = ice;
1016                 if ( !ic->count )
1017                         ic->first = id;
1018         }
1019         ice = ic->tail;
1020         ice->ids[ ic->count & (IDBLOCK-1) ] = id;
1021         ic->count++;
1022
1023         return 0;
1024 }
1025 #endif
1026
1027 static void *
1028 bdb_tool_index_task( void *ctx, void *ptr )
1029 {
1030         int base = *(int *)ptr;
1031
1032         free( ptr );
1033         while ( 1 ) {
1034                 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex );
1035                 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond,
1036                         &bdb_tool_index_mutex );
1037                 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex );
1038                 if ( slapd_shutdown )
1039                         break;
1040
1041                 bdb_tool_index_threads[base] = bdb_index_recrun( bdb_tool_ix_op,
1042                         bdb_tool_info, bdb_tool_index_rec, bdb_tool_ix_id, base );
1043         }
1044
1045         return NULL;
1046 }