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