]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/tools.c
Fix bogus error codes
[openldap] / servers / slapd / back-mdb / 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 2011 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 #include <ac/errno.h>
22
23 #define AVL_INTERNAL
24 #include "back-mdb.h"
25 #include "idl.h"
26
27 static MDB_txn *txn = NULL, *txi = NULL;
28 static MDB_cursor *cursor = NULL, *idcursor = NULL;
29 static MDB_val key, data;
30 static ID previd = NOID;
31
32 typedef struct dn_id {
33         ID id;
34         struct berval dn;
35 } dn_id;
36
37 #define HOLE_SIZE       4096
38 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
39 static unsigned nhmax = HOLE_SIZE;
40 static unsigned nholes;
41
42 static struct berval    *tool_base;
43 static int              tool_scope;
44 static Filter           *tool_filter;
45 static Entry            *tool_next_entry;
46
47 #if 0
48 static ID mdb_tool_ix_id;
49 static Operation *mdb_tool_ix_op;
50 static int *mdb_tool_index_threads, mdb_tool_index_tcount;
51 static void *mdb_tool_index_rec;
52 static struct mdb_info *mdb_tool_info;
53 static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
54 static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
55 static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
56 static void * mdb_tool_index_task( void *ctx, void *ptr );
57 #endif
58
59 static int      mdb_writes, mdb_writes_per_commit;
60
61 static int
62 mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
63
64 int mdb_tool_entry_open(
65         BackendDB *be, int mode )
66 {
67         /* In Quick mode, commit once per 1000 entries */
68         mdb_writes = 0;
69         if ( slapMode & SLAP_TOOL_QUICK )
70                 mdb_writes_per_commit = 1000;
71         else
72                 mdb_writes_per_commit = 1;
73
74 #if 0
75         /* Set up for threaded slapindex */
76         if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
77                 if ( !mdb_tool_info ) {
78                         ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
79                         ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
80                         ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
81                         if ( mdb->bi_nattrs ) {
82                                 int i;
83                                 mdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
84                                 mdb_tool_index_rec = ch_malloc( mdb->bi_nattrs * sizeof( IndexRec ));
85                                 mdb_tool_index_tcount = slap_tool_thread_max - 1;
86                                 for (i=1; i<slap_tool_thread_max; i++) {
87                                         int *ptr = ch_malloc( sizeof( int ));
88                                         *ptr = i;
89                                         ldap_pvt_thread_pool_submit( &connection_pool,
90                                                 mdb_tool_index_task, ptr );
91                                 }
92                         }
93                         mdb_tool_info = mdb;
94                 }
95         }
96 #endif
97
98         return 0;
99 }
100
101 int mdb_tool_entry_close(
102         BackendDB *be )
103 {
104 #if 0
105         if ( mdb_tool_info ) {
106                 slapd_shutdown = 1;
107                 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
108
109                 /* There might still be some threads starting */
110                 while ( mdb_tool_index_tcount ) {
111                         ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
112                                         &mdb_tool_index_mutex );
113                 }
114
115                 mdb_tool_index_tcount = slap_tool_thread_max - 1;
116                 ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
117
118                 /* Make sure all threads are stopped */
119                 while ( mdb_tool_index_tcount ) {
120                         ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
121                                 &mdb_tool_index_mutex );
122                 }
123                 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
124
125                 mdb_tool_info = NULL;
126                 slapd_shutdown = 0;
127                 ch_free( mdb_tool_index_threads );
128                 ch_free( mdb_tool_index_rec );
129                 mdb_tool_index_tcount = slap_tool_thread_max - 1;
130         }
131 #endif
132
133         if( idcursor ) {
134                 mdb_cursor_close( idcursor );
135                 idcursor = NULL;
136         }
137         if( cursor ) {
138                 mdb_cursor_close( cursor );
139                 cursor = NULL;
140         }
141         if( txn ) {
142                 if ( mdb_txn_commit( txn ))
143                         return -1;
144                 txn = NULL;
145         }
146
147         if( nholes ) {
148                 unsigned i;
149                 fprintf( stderr, "Error, entries missing!\n");
150                 for (i=0; i<nholes; i++) {
151                         fprintf(stderr, "  entry %ld: %s\n",
152                                 holes[i].id, holes[i].dn.bv_val);
153                 }
154                 nholes = 0;
155                 return -1;
156         }
157                         
158         return 0;
159 }
160
161 ID
162 mdb_tool_entry_first_x(
163         BackendDB *be,
164         struct berval *base,
165         int scope,
166         Filter *f )
167 {
168         tool_base = base;
169         tool_scope = scope;
170         tool_filter = f;
171         
172         return mdb_tool_entry_next( be );
173 }
174
175 ID mdb_tool_entry_next(
176         BackendDB *be )
177 {
178         int rc;
179         ID id;
180         struct mdb_info *mdb;
181
182         assert( be != NULL );
183         assert( slapMode & SLAP_TOOL_MODE );
184
185         mdb = (struct mdb_info *) be->be_private;
186         assert( mdb != NULL );
187
188         if ( !txn ) {
189                 rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &txn );
190                 if ( rc )
191                         return NOID;
192                 rc = mdb_cursor_open( txn, mdb->mi_id2entry, &cursor );
193                 if ( rc ) {
194                         mdb_txn_abort( txn );
195                         return NOID;
196                 }
197         }
198
199 next:;
200         rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
201
202         if( rc ) {
203                 return NOID;
204         }
205
206         previd = *(ID *)key.mv_data;
207         id = previd;
208
209         if ( tool_filter || tool_base ) {
210                 static Operation op = {0};
211                 static Opheader ohdr = {0};
212
213                 op.o_hdr = &ohdr;
214                 op.o_bd = be;
215                 op.o_tmpmemctx = NULL;
216                 op.o_tmpmfuncs = &ch_mfuncs;
217
218                 if ( tool_next_entry ) {
219                         mdb_entry_release( &op, tool_next_entry, 0 );
220                         tool_next_entry = NULL;
221                 }
222
223                 rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
224                 if ( rc == LDAP_NO_SUCH_OBJECT ) {
225                         goto next;
226                 }
227
228                 assert( tool_next_entry != NULL );
229
230                 if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
231                 {
232                         mdb_entry_release( &op, tool_next_entry, 0 );
233                         tool_next_entry = NULL;
234                         goto next;
235                 }
236         }
237
238         return id;
239 }
240
241 ID mdb_tool_dn2id_get(
242         Backend *be,
243         struct berval *dn
244 )
245 {
246         struct mdb_info *mdb;
247         Operation op = {0};
248         Opheader ohdr = {0};
249         ID id;
250         int rc;
251
252         if ( BER_BVISEMPTY(dn) )
253                 return 0;
254
255         mdb = (struct mdb_info *) be->be_private;
256
257         if ( !txn ) {
258                 rc = mdb_txn_begin( mdb->mi_dbenv, (slapMode & SLAP_TOOL_READONLY) != 0 ?
259                         MDB_RDONLY : 0, &txn );
260                 if ( rc )
261                         return NOID;
262         }
263
264         op.o_hdr = &ohdr;
265         op.o_bd = be;
266         op.o_tmpmemctx = NULL;
267         op.o_tmpmfuncs = &ch_mfuncs;
268
269         rc = mdb_dn2id( &op, txn, dn, &id, NULL, NULL );
270         if ( rc == MDB_NOTFOUND )
271                 return NOID;
272         
273         return id;
274 }
275
276 static int
277 mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
278 {
279         Operation op = {0};
280         Opheader ohdr = {0};
281
282         Entry *e = NULL;
283         struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
284         int rc;
285
286         assert( be != NULL );
287         assert( slapMode & SLAP_TOOL_MODE );
288
289         if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
290                 *ep = tool_next_entry;
291                 tool_next_entry = NULL;
292                 return LDAP_SUCCESS;
293         }
294
295         if ( id != previd ) {
296                 key.mv_size = sizeof(ID);
297                 key.mv_data = &id;
298                 rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
299                 if ( rc ) {
300                         rc = LDAP_OTHER;
301                         goto done;
302                 }
303         }
304
305         op.o_hdr = &ohdr;
306         op.o_bd = be;
307         op.o_tmpmemctx = NULL;
308         op.o_tmpmfuncs = &ch_mfuncs;
309         if ( slapMode & SLAP_TOOL_READONLY ) {
310                 rc = mdb_id2name( &op, txn, &idcursor, id, &dn, &ndn );
311                 if ( rc  ) {
312                         rc = LDAP_OTHER;
313                         mdb_entry_return( &op, e );
314                         e = NULL;
315                         goto done;
316                 }
317                 if ( tool_base != NULL ) {
318                         if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
319                                 ch_free( dn.bv_val );
320                                 ch_free( ndn.bv_val );
321                                 rc = LDAP_NO_SUCH_OBJECT;
322                         }
323                 }
324         }
325         rc = mdb_entry_decode( &op, &data, &e );
326         e->e_id = id;
327         if ( !BER_BVISNULL( &dn )) {
328                 e->e_name = dn;
329                 e->e_nname = ndn;
330         } else {
331                 e->e_name.bv_val = NULL;
332                 e->e_nname.bv_val = NULL;
333         }
334
335 done:
336         if ( e != NULL ) {
337                 *ep = e;
338         }
339
340         return rc;
341 }
342
343 Entry*
344 mdb_tool_entry_get( BackendDB *be, ID id )
345 {
346         Entry *e = NULL;
347
348         (void)mdb_tool_entry_get_int( be, id, &e );
349         return e;
350 }
351
352 static int mdb_tool_next_id(
353         Operation *op,
354         MDB_txn *tid,
355         Entry *e,
356         struct berval *text,
357         int hole )
358 {
359         struct berval dn = e->e_name;
360         struct berval ndn = e->e_nname;
361         struct berval pdn, npdn, nmatched;
362         ID id, pid = 0;
363         int rc;
364
365         if (ndn.bv_len == 0) {
366                 e->e_id = 0;
367                 return 0;
368         }
369
370         rc = mdb_dn2id( op, tid, &ndn, &id, NULL, &nmatched );
371         if ( rc == MDB_NOTFOUND ) {
372                 if ( !be_issuffix( op->o_bd, &ndn ) ) {
373                         ID eid = e->e_id;
374                         dnParent( &ndn, &npdn );
375                         if ( nmatched.bv_len != npdn.bv_len ) {
376                                 dnParent( &dn, &pdn );
377                                 e->e_name = pdn;
378                                 e->e_nname = npdn;
379                                 rc = mdb_tool_next_id( op, tid, e, text, 1 );
380                                 e->e_name = dn;
381                                 e->e_nname = ndn;
382                                 if ( rc ) {
383                                         return rc;
384                                 }
385                                 /* If parent didn't exist, it was created just now
386                                  * and its ID is now in e->e_id. Make sure the current
387                                  * entry gets added under the new parent ID.
388                                  */
389                                 if ( eid != e->e_id ) {
390                                         pid = e->e_id;
391                                 }
392                         } else {
393                                 pid = id;
394                         }
395                 }
396                 rc = mdb_next_id( op->o_bd, tid, &e->e_id );
397                 if ( rc ) {
398                         snprintf( text->bv_val, text->bv_len,
399                                 "next_id failed: %s (%d)",
400                                 mdb_strerror(rc), rc );
401                 Debug( LDAP_DEBUG_ANY,
402                         "=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
403                         return rc;
404                 }
405                 rc = mdb_dn2id_add( op, tid, pid, e );
406                 if ( rc ) {
407                         snprintf( text->bv_val, text->bv_len, 
408                                 "dn2id_add failed: %s (%d)",
409                                 mdb_strerror(rc), rc );
410                 Debug( LDAP_DEBUG_ANY,
411                         "=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
412                 } else if ( hole ) {
413                         if ( nholes == nhmax - 1 ) {
414                                 if ( holes == hbuf ) {
415                                         holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
416                                         AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
417                                 } else {
418                                         holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
419                                 }
420                                 nhmax *= 2;
421                         }
422                         ber_dupbv( &holes[nholes].dn, &ndn );
423                         holes[nholes++].id = e->e_id;
424                 }
425         } else if ( !hole ) {
426                 unsigned i, j;
427
428                 e->e_id = id;
429
430                 for ( i=0; i<nholes; i++) {
431                         if ( holes[i].id == e->e_id ) {
432                                 free(holes[i].dn.bv_val);
433                                 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
434                                 holes[j].id = 0;
435                                 nholes--;
436                                 break;
437                         } else if ( holes[i].id > e->e_id ) {
438                                 break;
439                         }
440                 }
441         }
442         return rc;
443 }
444
445 static int
446 mdb_tool_index_add(
447         Operation *op,
448         MDB_txn *txn,
449         Entry *e )
450 {
451         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
452
453         if ( !mdb->mi_nattrs )
454                 return 0;
455
456 #if 0
457         if ( slapMode & SLAP_TOOL_QUICK ) {
458                 IndexRec *ir;
459                 int i, rc;
460                 Attribute *a;
461                 
462                 ir = mdb_tool_index_rec;
463                 memset(ir, 0, mdb->bi_nattrs * sizeof( IndexRec ));
464
465                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
466                         rc = mdb_index_recset( mdb, a, a->a_desc->ad_type, 
467                                 &a->a_desc->ad_tags, ir );
468                         if ( rc )
469                                 return rc;
470                 }
471                 mdb_tool_ix_id = e->e_id;
472                 mdb_tool_ix_op = op;
473                 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
474                 /* Wait for all threads to be ready */
475                 while ( mdb_tool_index_tcount ) {
476                         ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main, 
477                                 &mdb_tool_index_mutex );
478                 }
479                 for ( i=1; i<slap_tool_thread_max; i++ )
480                         mdb_tool_index_threads[i] = LDAP_BUSY;
481                 mdb_tool_index_tcount = slap_tool_thread_max - 1;
482                 ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
483                 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
484                 rc = mdb_index_recrun( op, mdb, ir, e->e_id, 0 );
485                 if ( rc )
486                         return rc;
487                 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
488                 for ( i=1; i<slap_tool_thread_max; i++ ) {
489                         if ( mdb_tool_index_threads[i] == LDAP_BUSY ) {
490                                 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main, 
491                                         &mdb_tool_index_mutex );
492                                 i--;
493                                 continue;
494                         }
495                         if ( mdb_tool_index_threads[i] ) {
496                                 rc = mdb_tool_index_threads[i];
497                                 break;
498                         }
499                 }
500                 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
501                 return rc;
502         } else
503 #endif
504         {
505                 return mdb_index_entry_add( op, txn, e );
506         }
507 }
508
509 ID mdb_tool_entry_put(
510         BackendDB *be,
511         Entry *e,
512         struct berval *text )
513 {
514         int rc;
515         struct mdb_info *mdb;
516         Operation op = {0};
517         Opheader ohdr = {0};
518
519         assert( be != NULL );
520         assert( slapMode & SLAP_TOOL_MODE );
521
522         assert( text != NULL );
523         assert( text->bv_val != NULL );
524         assert( text->bv_val[0] == '\0' );      /* overconservative? */
525
526         Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
527                 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
528
529         mdb = (struct mdb_info *) be->be_private;
530
531         if ( !txn ) {
532         rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
533         if( rc != 0 ) {
534                 snprintf( text->bv_val, text->bv_len,
535                         "txn_begin failed: %s (%d)",
536                         mdb_strerror(rc), rc );
537                 Debug( LDAP_DEBUG_ANY,
538                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
539                          text->bv_val, 0, 0 );
540                 return NOID;
541         }
542         }
543
544         op.o_hdr = &ohdr;
545         op.o_bd = be;
546         op.o_tmpmemctx = NULL;
547         op.o_tmpmfuncs = &ch_mfuncs;
548
549         /* add dn2id indices */
550         rc = mdb_tool_next_id( &op, txn, e, text, 0 );
551         if( rc != 0 ) {
552                 goto done;
553         }
554
555         rc = mdb_tool_index_add( &op, txn, e );
556         if( rc != 0 ) {
557                 snprintf( text->bv_val, text->bv_len,
558                                 "index_entry_add failed: err=%d", rc );
559                 Debug( LDAP_DEBUG_ANY,
560                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
561                         text->bv_val, 0, 0 );
562                 goto done;
563         }
564
565
566         /* id2entry index */
567         rc = mdb_id2entry_add( &op, txn, e );
568         if( rc != 0 ) {
569                 snprintf( text->bv_val, text->bv_len,
570                                 "id2entry_add failed: err=%d", rc );
571                 Debug( LDAP_DEBUG_ANY,
572                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
573                         text->bv_val, 0, 0 );
574                 goto done;
575         }
576
577 done:
578         if( rc == 0 ) {
579                 mdb_writes++;
580                 if ( mdb_writes >= mdb_writes_per_commit ) {
581                         rc = mdb_txn_commit( txn );
582                         mdb_writes = 0;
583                         txn = NULL;
584                         if( rc != 0 ) {
585                                 snprintf( text->bv_val, text->bv_len,
586                                                 "txn_commit 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 );
591                                 e->e_id = NOID;
592                         }
593                 }
594
595         } else {
596                 mdb_txn_abort( txn );
597                 txn = NULL;
598                 snprintf( text->bv_val, text->bv_len,
599                         "txn_aborted! %s (%d)",
600                         rc == LDAP_OTHER ? "Internal error" :
601                         mdb_strerror(rc), rc );
602                 Debug( LDAP_DEBUG_ANY,
603                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
604                         text->bv_val, 0, 0 );
605                 e->e_id = NOID;
606         }
607
608         return e->e_id;
609 }
610
611 int mdb_tool_entry_reindex(
612         BackendDB *be,
613         ID id,
614         AttributeDescription **adv )
615 {
616         struct mdb_info *mi = (struct mdb_info *) be->be_private;
617         int rc;
618         Entry *e;
619         Operation op = {0};
620         Opheader ohdr = {0};
621
622         Debug( LDAP_DEBUG_ARGS,
623                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
624                 (long) id, 0, 0 );
625         assert( tool_base == NULL );
626         assert( tool_filter == NULL );
627
628         /* No indexes configured, nothing to do. Could return an
629          * error here to shortcut things.
630          */
631         if (!mi->mi_attrs) {
632                 return 0;
633         }
634
635         /* Check for explicit list of attrs to index */
636         if ( adv ) {
637                 int i, j, n;
638
639                 if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
640                         /* count */
641                         for ( n = 0; adv[n]; n++ ) ;
642
643                         /* insertion sort */
644                         for ( i = 0; i < n; i++ ) {
645                                 AttributeDescription *ad = adv[i];
646                                 for ( j = i-1; j>=0; j--) {
647                                         if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
648                                         adv[j+1] = adv[j];
649                                 }
650                                 adv[j+1] = ad;
651                         }
652                 }
653
654                 for ( i = 0; adv[i]; i++ ) {
655                         if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
656                                 for ( j = i+1; j < mi->mi_nattrs; j++ ) {
657                                         if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
658                                                 AttrInfo *ai = mi->mi_attrs[i];
659                                                 mi->mi_attrs[i] = mi->mi_attrs[j];
660                                                 mi->mi_attrs[j] = ai;
661                                                 break;
662                                         }
663                                 }
664                                 if ( j == mi->mi_nattrs ) {
665                                         Debug( LDAP_DEBUG_ANY,
666                                                 LDAP_XSTRING(mdb_tool_entry_reindex)
667                                                 ": no index configured for %s\n",
668                                                 adv[i]->ad_cname.bv_val, 0, 0 );
669                                         return -1;
670                                 }
671                         }
672                 }
673                 mi->mi_nattrs = i;
674         }
675
676         e = mdb_tool_entry_get( be, id );
677
678         if( e == NULL ) {
679                 Debug( LDAP_DEBUG_ANY,
680                         LDAP_XSTRING(mdb_tool_entry_reindex)
681                         ": could not locate id=%ld\n",
682                         (long) id, 0, 0 );
683                 return -1;
684         }
685
686         if ( !txi ) {
687                 rc = mdb_txn_begin( mi->mi_dbenv, 0, &txi );
688                 if( rc != 0 ) {
689                         Debug( LDAP_DEBUG_ANY,
690                                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
691                                 "txn_begin failed: %s (%d)\n",
692                                 mdb_strerror(rc), rc, 0 );
693                         goto done;
694                 }
695         }
696         
697         /*
698          * just (re)add them for now
699          * assume that some other routine (not yet implemented)
700          * will zap index databases
701          *
702          */
703
704         Debug( LDAP_DEBUG_TRACE,
705                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
706                 (long) id, e->e_dn, 0 );
707
708         op.o_hdr = &ohdr;
709         op.o_bd = be;
710         op.o_tmpmemctx = NULL;
711         op.o_tmpmfuncs = &ch_mfuncs;
712
713         rc = mdb_tool_index_add( &op, txi, e );
714
715 done:
716         if( rc == 0 ) {
717                 mdb_writes++;
718                 if ( mdb_writes >= mdb_writes_per_commit ) {
719                         rc = mdb_txn_commit( txi );
720                         if( rc != 0 ) {
721                                 Debug( LDAP_DEBUG_ANY,
722                                         "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
723                                         ": txn_commit failed: %s (%d)\n",
724                                         mdb_strerror(rc), rc, 0 );
725                                 e->e_id = NOID;
726                         }
727                         txi = NULL;
728                 }
729
730         } else {
731                 mdb_txn_abort( txi );
732                 Debug( LDAP_DEBUG_ANY,
733                         "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
734                         ": txn_aborted! err=%d\n",
735                         rc, 0, 0 );
736                 e->e_id = NOID;
737                 txi = NULL;
738         }
739         mdb_entry_release( &op, e, 0 );
740
741         return rc;
742 }
743
744 ID mdb_tool_entry_modify(
745         BackendDB *be,
746         Entry *e,
747         struct berval *text )
748 {
749         int rc;
750         struct mdb_info *mdb;
751         MDB_txn *tid;
752         Operation op = {0};
753         Opheader ohdr = {0};
754
755         assert( be != NULL );
756         assert( slapMode & SLAP_TOOL_MODE );
757
758         assert( text != NULL );
759         assert( text->bv_val != NULL );
760         assert( text->bv_val[0] == '\0' );      /* overconservative? */
761
762         assert ( e->e_id != NOID );
763
764         Debug( LDAP_DEBUG_TRACE,
765                 "=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
766                 (long) e->e_id, e->e_dn, 0 );
767
768         mdb = (struct mdb_info *) be->be_private;
769
770         if( cursor ) {
771                 mdb_cursor_close( cursor );
772                 cursor = NULL;
773         }
774         rc = mdb_txn_begin( mdb->mi_dbenv, 0, &tid );
775         if( rc != 0 ) {
776                 snprintf( text->bv_val, text->bv_len,
777                         "txn_begin failed: %s (%d)",
778                         mdb_strerror(rc), rc );
779                 Debug( LDAP_DEBUG_ANY,
780                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
781                          text->bv_val, 0, 0 );
782                 return NOID;
783         }
784
785         op.o_hdr = &ohdr;
786         op.o_bd = be;
787         op.o_tmpmemctx = NULL;
788         op.o_tmpmfuncs = &ch_mfuncs;
789
790         /* id2entry index */
791         rc = mdb_id2entry_update( &op, tid, e );
792         if( rc != 0 ) {
793                 snprintf( text->bv_val, text->bv_len,
794                                 "id2entry_update failed: err=%d", rc );
795                 Debug( LDAP_DEBUG_ANY,
796                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
797                         text->bv_val, 0, 0 );
798                 goto done;
799         }
800
801 done:
802         if( rc == 0 ) {
803                 rc = mdb_txn_commit( tid );
804                 if( rc != 0 ) {
805                         snprintf( text->bv_val, text->bv_len,
806                                         "txn_commit failed: %s (%d)",
807                                         mdb_strerror(rc), rc );
808                         Debug( LDAP_DEBUG_ANY,
809                                 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
810                                 "%s\n", text->bv_val, 0, 0 );
811                         e->e_id = NOID;
812                 }
813
814         } else {
815                 mdb_txn_abort( tid );
816                 snprintf( text->bv_val, text->bv_len,
817                         "txn_aborted! %s (%d)",
818                         mdb_strerror(rc), rc );
819                 Debug( LDAP_DEBUG_ANY,
820                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
821                         text->bv_val, 0, 0 );
822                 e->e_id = NOID;
823         }
824
825         return e->e_id;
826 }
827
828 #if 0
829 static void *
830 mdb_tool_index_task( void *ctx, void *ptr )
831 {
832         int base = *(int *)ptr;
833
834         free( ptr );
835         while ( 1 ) {
836                 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
837                 mdb_tool_index_tcount--;
838                 if ( !mdb_tool_index_tcount )
839                         ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
840                 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
841                         &mdb_tool_index_mutex );
842                 if ( slapd_shutdown ) {
843                         mdb_tool_index_tcount--;
844                         if ( !mdb_tool_index_tcount )
845                                 ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
846                         ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
847                         break;
848                 }
849                 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
850
851                 mdb_tool_index_threads[base] = mdb_index_recrun( mdb_tool_ix_op,
852                         mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
853         }
854
855         return NULL;
856 }
857 #endif