]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/tools.c
Merge remote branch 'origin/mdb.master'
[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( 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: %s (%d)",
559                                 rc == LDAP_OTHER ? "Internal error" :
560                                 mdb_strerror(rc), rc );
561                 Debug( LDAP_DEBUG_ANY,
562                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
563                         text->bv_val, 0, 0 );
564                 goto done;
565         }
566
567
568         /* id2entry index */
569         rc = mdb_id2entry_add( &op, txn, e );
570         if( rc != 0 ) {
571                 snprintf( text->bv_val, text->bv_len,
572                                 "id2entry_add failed: %s (%d)",
573                                 mdb_strerror(rc), rc );
574                 Debug( LDAP_DEBUG_ANY,
575                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
576                         text->bv_val, 0, 0 );
577                 goto done;
578         }
579
580 done:
581         if( rc == 0 ) {
582                 mdb_writes++;
583                 if ( mdb_writes >= mdb_writes_per_commit ) {
584                         rc = mdb_txn_commit( txn );
585                         mdb_writes = 0;
586                         txn = NULL;
587                         if( rc != 0 ) {
588                                 snprintf( text->bv_val, text->bv_len,
589                                                 "txn_commit failed: %s (%d)",
590                                                 mdb_strerror(rc), rc );
591                                 Debug( LDAP_DEBUG_ANY,
592                                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
593                                         text->bv_val, 0, 0 );
594                                 e->e_id = NOID;
595                         }
596                 }
597
598         } else {
599                 mdb_txn_abort( txn );
600                 txn = NULL;
601                 snprintf( text->bv_val, text->bv_len,
602                         "txn_aborted! %s (%d)",
603                         rc == LDAP_OTHER ? "Internal error" :
604                         mdb_strerror(rc), rc );
605                 Debug( LDAP_DEBUG_ANY,
606                         "=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
607                         text->bv_val, 0, 0 );
608                 e->e_id = NOID;
609         }
610
611         return e->e_id;
612 }
613
614 int mdb_tool_entry_reindex(
615         BackendDB *be,
616         ID id,
617         AttributeDescription **adv )
618 {
619         struct mdb_info *mi = (struct mdb_info *) be->be_private;
620         int rc;
621         Entry *e;
622         Operation op = {0};
623         Opheader ohdr = {0};
624
625         Debug( LDAP_DEBUG_ARGS,
626                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
627                 (long) id, 0, 0 );
628         assert( tool_base == NULL );
629         assert( tool_filter == NULL );
630
631         /* No indexes configured, nothing to do. Could return an
632          * error here to shortcut things.
633          */
634         if (!mi->mi_attrs) {
635                 return 0;
636         }
637
638         /* Check for explicit list of attrs to index */
639         if ( adv ) {
640                 int i, j, n;
641
642                 if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
643                         /* count */
644                         for ( n = 0; adv[n]; n++ ) ;
645
646                         /* insertion sort */
647                         for ( i = 0; i < n; i++ ) {
648                                 AttributeDescription *ad = adv[i];
649                                 for ( j = i-1; j>=0; j--) {
650                                         if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
651                                         adv[j+1] = adv[j];
652                                 }
653                                 adv[j+1] = ad;
654                         }
655                 }
656
657                 for ( i = 0; adv[i]; i++ ) {
658                         if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
659                                 for ( j = i+1; j < mi->mi_nattrs; j++ ) {
660                                         if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
661                                                 AttrInfo *ai = mi->mi_attrs[i];
662                                                 mi->mi_attrs[i] = mi->mi_attrs[j];
663                                                 mi->mi_attrs[j] = ai;
664                                                 break;
665                                         }
666                                 }
667                                 if ( j == mi->mi_nattrs ) {
668                                         Debug( LDAP_DEBUG_ANY,
669                                                 LDAP_XSTRING(mdb_tool_entry_reindex)
670                                                 ": no index configured for %s\n",
671                                                 adv[i]->ad_cname.bv_val, 0, 0 );
672                                         return -1;
673                                 }
674                         }
675                 }
676                 mi->mi_nattrs = i;
677         }
678
679         e = mdb_tool_entry_get( be, id );
680
681         if( e == NULL ) {
682                 Debug( LDAP_DEBUG_ANY,
683                         LDAP_XSTRING(mdb_tool_entry_reindex)
684                         ": could not locate id=%ld\n",
685                         (long) id, 0, 0 );
686                 return -1;
687         }
688
689         if ( !txi ) {
690                 rc = mdb_txn_begin( mi->mi_dbenv, 0, &txi );
691                 if( rc != 0 ) {
692                         Debug( LDAP_DEBUG_ANY,
693                                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
694                                 "txn_begin failed: %s (%d)\n",
695                                 mdb_strerror(rc), rc, 0 );
696                         goto done;
697                 }
698         }
699         
700         /*
701          * just (re)add them for now
702          * assume that some other routine (not yet implemented)
703          * will zap index databases
704          *
705          */
706
707         Debug( LDAP_DEBUG_TRACE,
708                 "=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
709                 (long) id, e->e_dn, 0 );
710
711         op.o_hdr = &ohdr;
712         op.o_bd = be;
713         op.o_tmpmemctx = NULL;
714         op.o_tmpmfuncs = &ch_mfuncs;
715
716         rc = mdb_tool_index_add( &op, txi, e );
717
718 done:
719         if( rc == 0 ) {
720                 mdb_writes++;
721                 if ( mdb_writes >= mdb_writes_per_commit ) {
722                         rc = mdb_txn_commit( txi );
723                         if( rc != 0 ) {
724                                 Debug( LDAP_DEBUG_ANY,
725                                         "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
726                                         ": txn_commit failed: %s (%d)\n",
727                                         mdb_strerror(rc), rc, 0 );
728                                 e->e_id = NOID;
729                         }
730                         txi = NULL;
731                 }
732
733         } else {
734                 mdb_txn_abort( txi );
735                 Debug( LDAP_DEBUG_ANY,
736                         "=> " LDAP_XSTRING(mdb_tool_entry_reindex)
737                         ": txn_aborted! %s (%d)\n",
738                         mdb_strerror(rc), rc, 0 );
739                 e->e_id = NOID;
740                 txi = NULL;
741         }
742         mdb_entry_release( &op, e, 0 );
743
744         return rc;
745 }
746
747 ID mdb_tool_entry_modify(
748         BackendDB *be,
749         Entry *e,
750         struct berval *text )
751 {
752         int rc;
753         struct mdb_info *mdb;
754         MDB_txn *tid;
755         Operation op = {0};
756         Opheader ohdr = {0};
757
758         assert( be != NULL );
759         assert( slapMode & SLAP_TOOL_MODE );
760
761         assert( text != NULL );
762         assert( text->bv_val != NULL );
763         assert( text->bv_val[0] == '\0' );      /* overconservative? */
764
765         assert ( e->e_id != NOID );
766
767         Debug( LDAP_DEBUG_TRACE,
768                 "=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
769                 (long) e->e_id, e->e_dn, 0 );
770
771         mdb = (struct mdb_info *) be->be_private;
772
773         if( cursor ) {
774                 mdb_cursor_close( cursor );
775                 cursor = NULL;
776         }
777         rc = mdb_txn_begin( mdb->mi_dbenv, 0, &tid );
778         if( rc != 0 ) {
779                 snprintf( text->bv_val, text->bv_len,
780                         "txn_begin failed: %s (%d)",
781                         mdb_strerror(rc), rc );
782                 Debug( LDAP_DEBUG_ANY,
783                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
784                          text->bv_val, 0, 0 );
785                 return NOID;
786         }
787
788         op.o_hdr = &ohdr;
789         op.o_bd = be;
790         op.o_tmpmemctx = NULL;
791         op.o_tmpmfuncs = &ch_mfuncs;
792
793         /* id2entry index */
794         rc = mdb_id2entry_update( &op, tid, e );
795         if( rc != 0 ) {
796                 snprintf( text->bv_val, text->bv_len,
797                                 "id2entry_add failed: %s (%d)",
798                                 mdb_strerror(rc), rc );
799                 Debug( LDAP_DEBUG_ANY,
800                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
801                         text->bv_val, 0, 0 );
802                 goto done;
803         }
804
805 done:
806         if( rc == 0 ) {
807                 rc = mdb_txn_commit( tid );
808                 if( rc != 0 ) {
809                         snprintf( text->bv_val, text->bv_len,
810                                         "txn_commit failed: %s (%d)",
811                                         mdb_strerror(rc), rc );
812                         Debug( LDAP_DEBUG_ANY,
813                                 "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
814                                 "%s\n", text->bv_val, 0, 0 );
815                         e->e_id = NOID;
816                 }
817
818         } else {
819                 mdb_txn_abort( tid );
820                 snprintf( text->bv_val, text->bv_len,
821                         "txn_aborted! %s (%d)",
822                         mdb_strerror(rc), rc );
823                 Debug( LDAP_DEBUG_ANY,
824                         "=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
825                         text->bv_val, 0, 0 );
826                 e->e_id = NOID;
827         }
828
829         return e->e_id;
830 }
831
832 #if 0
833 static void *
834 mdb_tool_index_task( void *ctx, void *ptr )
835 {
836         int base = *(int *)ptr;
837
838         free( ptr );
839         while ( 1 ) {
840                 ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
841                 mdb_tool_index_tcount--;
842                 if ( !mdb_tool_index_tcount )
843                         ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
844                 ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
845                         &mdb_tool_index_mutex );
846                 if ( slapd_shutdown ) {
847                         mdb_tool_index_tcount--;
848                         if ( !mdb_tool_index_tcount )
849                                 ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
850                         ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
851                         break;
852                 }
853                 ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
854
855                 mdb_tool_index_threads[base] = mdb_index_recrun( mdb_tool_ix_op,
856                         mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
857         }
858
859         return NULL;
860 }
861 #endif