]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/tools.c
More for 2.2beta
[openldap] / servers / slapd / back-bdb / tools.c
1 /* tools.c - tools for slap tools */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 static DBC *cursor = NULL;
17 static DBT key, data;
18
19 typedef struct dn_id {
20         ID id;
21         struct berval dn;
22 } dn_id;
23
24 #define HOLE_SIZE       4096
25 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
26 static unsigned nhmax = HOLE_SIZE;
27 static unsigned nholes;
28
29 int bdb_tool_entry_open(
30         BackendDB *be, int mode )
31 {
32         /* initialize key and data thangs */
33         DBTzero( &key );
34         DBTzero( &data );
35         key.flags = DB_DBT_REALLOC;
36         data.flags = DB_DBT_REALLOC;
37
38         return 0;
39 }
40
41 int bdb_tool_entry_close(
42         BackendDB *be )
43 {
44         assert( be != NULL );
45
46         if( key.data ) {
47                 ch_free( key.data );
48                 key.data = NULL;
49         }
50         if( data.data ) {
51                 ch_free( data.data );
52                 data.data = NULL;
53         }
54
55         if( cursor ) {
56                 cursor->c_close( cursor );
57                 cursor = NULL;
58         }
59
60         if( nholes ) {
61                 unsigned i;
62                 fprintf( stderr, "Error, entries missing!\n");
63                 for (i=0; i<nholes; i++) {
64                         fprintf(stderr, "  entry %ld: %s\n",
65                                 holes[i].id, holes[i].dn.bv_val);
66                 }
67                 return -1;
68         }
69                         
70         return 0;
71 }
72
73 ID bdb_tool_entry_next(
74         BackendDB *be )
75 {
76         int rc;
77         ID id;
78         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
79
80         assert( be != NULL );
81         assert( slapMode & SLAP_TOOL_MODE );
82         assert( bdb != NULL );
83         
84         if (cursor == NULL) {
85                 rc = bdb->bi_id2entry->bdi_db->cursor(
86                         bdb->bi_id2entry->bdi_db, NULL, &cursor,
87                         bdb->bi_db_opflags );
88                 if( rc != 0 ) {
89                         return NOID;
90                 }
91         }
92
93         rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
94
95         if( rc != 0 ) {
96                 return NOID;
97         }
98
99         if( data.data == NULL ) {
100                 return NOID;
101         }
102
103         AC_MEMCPY( &id, key.data, key.size );
104         return id;
105 }
106
107 ID bdb_tool_dn2id_get(
108         Backend *be,
109         struct berval *dn
110 )
111 {
112         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
113         DB *db = bdb->bi_dn2id->bdi_db;
114         int rc;
115         DBT     key, data;
116         ID      id;
117
118         DBTzero( &key );
119         key.size = dn->bv_len + 2;
120         key.data = ch_malloc( key.size );
121         ((char*)key.data)[0] = DN_BASE_PREFIX;
122         AC_MEMCPY( &((char*)key.data)[1], dn->bv_val, key.size - 1 );
123
124         DBTzero( &data );
125         data.data = &id;
126         data.ulen = sizeof(ID);
127         data.flags = DB_DBT_USERMEM;
128
129         rc = db->get( db, NULL, &key, &data, bdb->bi_db_opflags );
130
131     if( rc != 0 ) {
132 #ifdef NEW_LOGGING
133                 LDAP_LOG ( INDEX, ERR, "bdb_tool_dn2id_get: get failed %s (%d)\n",
134                                 db_strerror(rc), rc, 0 );
135 #else
136                 Debug( LDAP_DEBUG_TRACE, "bdb_tool_dn2id_get: get failed: %s (%d)\n",
137                                 db_strerror( rc ), rc, 0 );
138 #endif
139                 id = NOID;
140         }
141
142         ch_free( key.data );
143         return id;
144 }
145
146 int bdb_tool_id2entry_get(
147         Backend *be,
148         ID id,
149         Entry **e
150 )
151 {
152         return bdb_id2entry( be, NULL, id, e );
153 }
154
155 Entry* bdb_tool_entry_get( BackendDB *be, ID id )
156 {
157         int rc;
158         Entry *e = NULL;
159         struct berval bv;
160
161         assert( be != NULL );
162         assert( slapMode & SLAP_TOOL_MODE );
163         assert( data.data != NULL );
164
165 #ifndef BDB_HIER
166         DBT2bv( &data, &bv );
167
168         rc = entry_decode( &bv, &e );
169
170         if( rc == LDAP_SUCCESS ) {
171                 e->e_id = id;
172         }
173 #else
174         {
175                 EntryInfo *ei = NULL;
176                 Operation op = {0};
177
178                 op.o_bd = be;
179                 op.o_tmpmemctx = NULL;
180                 op.o_tmpmfuncs = &ch_mfuncs;
181
182                 rc = bdb_cache_find_id( &op, NULL, id, &ei, 0, 0, NULL );
183                 if ( rc == LDAP_SUCCESS )
184                         e = ei->bei_e;
185         }
186 #endif
187         return e;
188 }
189
190 static int bdb_tool_next_id(
191         Operation *op,
192         DB_TXN *tid,
193         Entry *e,
194         struct berval *text,
195         int hole )
196 {
197         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
198         struct berval dn = e->e_nname;
199         struct berval pdn;
200         EntryInfo *ei = NULL;
201         int rc;
202
203         rc = bdb_cache_find_ndn( op, tid, &dn, &ei );
204         if ( ei ) bdb_cache_entryinfo_unlock( ei );
205         if ( rc == DB_NOTFOUND ) {
206                 if ( be_issuffix( op->o_bd, &dn ) ) {
207                         pdn = slap_empty_bv;
208                 } else {
209                         dnParent( &dn, &pdn );
210                         e->e_nname = pdn;
211                         rc = bdb_tool_next_id( op, tid, e, text, 1 );
212                         if ( rc ) {
213                                 return rc;
214                         }
215                 }
216                 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
217                 if ( rc ) {
218                         snprintf( text->bv_val, text->bv_len,
219                                 "next_id failed: %s (%d)",
220                                 db_strerror(rc), rc );
221 #ifdef NEW_LOGGING
222                 LDAP_LOG ( TOOLS, ERR, 
223                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
224 #else
225                 Debug( LDAP_DEBUG_ANY,
226                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
227 #endif
228                         return rc;
229                 }
230                 e->e_nname = dn;
231                 rc = bdb_dn2id_add( op, tid, ei, e );
232                 if ( rc ) {
233                         snprintf( text->bv_val, text->bv_len, 
234                                 "dn2id_add failed: %s (%d)",
235                                 db_strerror(rc), rc );
236 #ifdef NEW_LOGGING
237                 LDAP_LOG ( TOOLS, ERR, 
238                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
239 #else
240                 Debug( LDAP_DEBUG_ANY,
241                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
242 #endif
243                 } else if ( hole ) {
244                         if ( nholes == nhmax - 1 ) {
245                                 if ( holes == hbuf ) {
246                                         holes = ch_malloc( nhmax * sizeof(ID) * 2 );
247                                         AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
248                                 } else {
249                                         holes = ch_realloc( holes, nhmax * sizeof(ID) * 2 );
250                                 }
251                                 nhmax *= 2;
252                         }
253                         ber_dupbv( &holes[nholes].dn, &dn );
254                         holes[nholes++].id = e->e_id;
255                 }
256         } else if ( !hole ) {
257                 unsigned i;
258
259                 for ( i=0; i<nholes; i++) {
260                         if ( holes[i].id == e->e_id ) {
261                                 int j;
262                                 free(holes[i].dn.bv_val);
263                                 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
264                                 holes[j].id = 0;
265                                 nholes--;
266                                 break;
267                         } else if ( holes[i].id > e->e_id ) {
268                                 break;
269                         }
270                 }
271         }
272         return rc;
273 }
274
275 ID bdb_tool_entry_put(
276         BackendDB *be,
277         Entry *e,
278         struct berval *text )
279 {
280         int rc;
281         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
282         DB_TXN *tid = NULL;
283         Operation op = {0};
284
285         assert( be != NULL );
286         assert( slapMode & SLAP_TOOL_MODE );
287
288         assert( text );
289         assert( text->bv_val );
290         assert( text->bv_val[0] == '\0' );      /* overconservative? */
291
292 #ifdef NEW_LOGGING
293         LDAP_LOG ( TOOLS, ARGS, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
294                 (long) e->e_id, e->e_dn, 0 );
295 #else
296         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
297                 (long) e->e_id, e->e_dn, 0 );
298 #endif
299
300         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
301                 bdb->bi_db_opflags );
302         if( rc != 0 ) {
303                 snprintf( text->bv_val, text->bv_len,
304                         "txn_begin failed: %s (%d)",
305                         db_strerror(rc), rc );
306 #ifdef NEW_LOGGING
307         LDAP_LOG ( TOOLS, ERR, "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
308 #else
309                 Debug( LDAP_DEBUG_ANY,
310                         "=> bdb_tool_entry_put: %s\n",
311                          text->bv_val, 0, 0 );
312 #endif
313                 return NOID;
314         }
315
316         op.o_bd = be;
317         op.o_tmpmemctx = NULL;
318         op.o_tmpmfuncs = &ch_mfuncs;
319
320         /* add dn2id indices */
321         rc = bdb_tool_next_id( &op, tid, e, text, 0 );
322         if( rc != 0 ) {
323                 goto done;
324         }
325
326         /* id2entry index */
327         rc = bdb_id2entry_add( be, tid, e );
328         if( rc != 0 ) {
329                 snprintf( text->bv_val, text->bv_len,
330                                 "id2entry_add failed: %s (%d)",
331                                 db_strerror(rc), rc );
332 #ifdef NEW_LOGGING
333                 LDAP_LOG ( TOOLS, ERR, 
334                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
335 #else
336                 Debug( LDAP_DEBUG_ANY,
337                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
338 #endif
339                 goto done;
340         }
341
342         rc = bdb_index_entry_add( &op, tid, e );
343         if( rc != 0 ) {
344                 snprintf( text->bv_val, text->bv_len,
345                                 "index_entry_add failed: %s (%d)",
346                                 db_strerror(rc), rc );
347 #ifdef NEW_LOGGING
348                 LDAP_LOG ( TOOLS, ERR, 
349                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
350 #else
351                 Debug( LDAP_DEBUG_ANY,
352                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
353 #endif
354                 goto done;
355         }
356
357 done:
358         if( rc == 0 ) {
359                 rc = TXN_COMMIT( tid, 0 );
360                 if( rc != 0 ) {
361                         snprintf( text->bv_val, text->bv_len,
362                                         "txn_commit failed: %s (%d)",
363                                         db_strerror(rc), rc );
364 #ifdef NEW_LOGGING
365                         LDAP_LOG ( TOOLS, ERR, 
366                                 "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
367 #else
368                         Debug( LDAP_DEBUG_ANY,
369                                 "=> bdb_tool_entry_put: %s\n",
370                                 text->bv_val, 0, 0 );
371 #endif
372                         e->e_id = NOID;
373                 }
374
375         } else {
376                 TXN_ABORT( tid );
377                 snprintf( text->bv_val, text->bv_len,
378                         "txn_aborted! %s (%d)",
379                         db_strerror(rc), rc );
380 #ifdef NEW_LOGGING
381                 LDAP_LOG ( TOOLS, ERR, 
382                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
383 #else
384                 Debug( LDAP_DEBUG_ANY,
385                         "=> bdb_tool_entry_put: %s\n",
386                         text->bv_val, 0, 0 );
387 #endif
388                 e->e_id = NOID;
389         }
390
391         return e->e_id;
392 }
393
394 int bdb_tool_entry_reindex(
395         BackendDB *be,
396         ID id )
397 {
398         struct bdb_info *bi = (struct bdb_info *) be->be_private;
399         int rc;
400         Entry *e;
401         DB_TXN *tid = NULL;
402         Operation op = {0};
403
404 #ifdef NEW_LOGGING
405         LDAP_LOG ( TOOLS, ARGS, 
406                 "=> bdb_tool_entry_reindex( %ld )\n", (long) id, 0, 0 );
407 #else
408         Debug( LDAP_DEBUG_ARGS, "=> bdb_tool_entry_reindex( %ld )\n",
409                 (long) id, 0, 0 );
410 #endif
411
412         e = bdb_tool_entry_get( be, id );
413
414         if( e == NULL ) {
415 #ifdef NEW_LOGGING
416                 LDAP_LOG ( TOOLS, DETAIL1, 
417                         "bdb_tool_entry_reindex:: could not locate id=%ld\n", 
418                         (long) id, 0, 0 );
419 #else
420                 Debug( LDAP_DEBUG_ANY,
421                         "bdb_tool_entry_reindex:: could not locate id=%ld\n",
422                         (long) id, 0, 0 );
423 #endif
424                 return -1;
425         }
426
427         rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
428         if( rc != 0 ) {
429 #ifdef NEW_LOGGING
430                 LDAP_LOG ( TOOLS, ERR, 
431                         "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n", 
432                         db_strerror(rc), rc, 0 );
433 #else
434                 Debug( LDAP_DEBUG_ANY,
435                         "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n",
436                         db_strerror(rc), rc, 0 );
437 #endif
438                 goto done;
439         }
440         
441         /*
442          * just (re)add them for now
443          * assume that some other routine (not yet implemented)
444          * will zap index databases
445          *
446          */
447
448 #ifdef NEW_LOGGING
449         LDAP_LOG ( TOOLS, ERR, 
450                 "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n", (long) id, e->e_dn, 0 );
451 #else
452         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n",
453                 (long) id, e->e_dn, 0 );
454 #endif
455
456         op.o_bd = be;
457         op.o_tmpmemctx = NULL;
458         op.o_tmpmfuncs = &ch_mfuncs;
459
460 #ifndef BDB_HIER
461         /* add dn2id indices */
462         rc = bdb_dn2id_add( &op, tid, NULL, e );
463         if( rc != 0 && rc != DB_KEYEXIST ) {
464 #ifdef NEW_LOGGING
465                 LDAP_LOG ( TOOLS, ERR, 
466                         "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n", 
467                         db_strerror(rc), rc, 0 );
468 #else
469                 Debug( LDAP_DEBUG_ANY,
470                         "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n",
471                         db_strerror(rc), rc, 0 );
472 #endif
473                 goto done;
474         }
475 #endif
476
477         rc = bdb_index_entry_add( &op, tid, e );
478
479 done:
480         if( rc == 0 ) {
481                 rc = TXN_COMMIT( tid, 0 );
482                 if( rc != 0 ) {
483 #ifdef NEW_LOGGING
484                         LDAP_LOG ( TOOLS, ERR, 
485                                 "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n", 
486                                 db_strerror(rc), rc, 0 );
487 #else
488                         Debug( LDAP_DEBUG_ANY,
489                                 "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n",
490                                 db_strerror(rc), rc, 0 );
491 #endif
492                         e->e_id = NOID;
493                 }
494
495         } else {
496                 TXN_ABORT( tid );
497 #ifdef NEW_LOGGING
498                 LDAP_LOG ( TOOLS, DETAIL1, 
499                         "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n", 
500                         db_strerror(rc), rc, 0 );
501 #else
502                 Debug( LDAP_DEBUG_ANY,
503                         "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n",
504                         db_strerror(rc), rc, 0 );
505 #endif
506                 e->e_id = NOID;
507         }
508         bdb_entry_release( &op, e, 0 );
509
510         return rc;
511 }
512
513 ID bdb_tool_entry_modify(
514         BackendDB *be,
515         Entry *e,
516         struct berval *text )
517 {
518         int rc;
519         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
520         DB_TXN *tid = NULL;
521         Operation op = {0};
522
523         assert( be != NULL );
524         assert( slapMode & SLAP_TOOL_MODE );
525
526         assert( text );
527         assert( text->bv_val );
528         assert( text->bv_val[0] == '\0' );      /* overconservative? */
529
530         assert ( e->e_id != NOID );
531         assert ( e->e_id != 0 );
532
533 #ifdef NEW_LOGGING
534         LDAP_LOG ( TOOLS, ARGS, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
535                 (long) e->e_id, e->e_dn, 0 );
536 #else
537         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
538                 (long) e->e_id, e->e_dn, 0 );
539 #endif
540
541         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
542                 bdb->bi_db_opflags );
543         if( rc != 0 ) {
544                 snprintf( text->bv_val, text->bv_len,
545                         "txn_begin failed: %s (%d)",
546                         db_strerror(rc), rc );
547 #ifdef NEW_LOGGING
548         LDAP_LOG ( TOOLS, ERR, "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
549 #else
550                 Debug( LDAP_DEBUG_ANY,
551                         "=> bdb_tool_entry_put: %s\n",
552                          text->bv_val, 0, 0 );
553 #endif
554                 return NOID;
555         }
556
557         op.o_bd = be;
558         op.o_tmpmemctx = NULL;
559         op.o_tmpmfuncs = &ch_mfuncs;
560
561         /* id2entry index */
562         rc = bdb_id2entry_update( be, tid, e );
563         if( rc != 0 ) {
564                 snprintf( text->bv_val, text->bv_len,
565                                 "id2entry_add failed: %s (%d)",
566                                 db_strerror(rc), rc );
567 #ifdef NEW_LOGGING
568                 LDAP_LOG ( TOOLS, ERR, 
569                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
570 #else
571                 Debug( LDAP_DEBUG_ANY,
572                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
573 #endif
574                 goto done;
575         }
576
577         rc = bdb_index_entry_del( &op, tid, e );
578         if( rc != 0 ) {
579                 snprintf( text->bv_val, text->bv_len,
580                                 "index_entry_del failed: %s (%d)",
581                                 db_strerror(rc), rc );
582 #ifdef NEW_LOGGING
583                 LDAP_LOG ( TOOLS, ERR, 
584                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
585 #else
586                 Debug( LDAP_DEBUG_ANY,
587                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
588 #endif
589                 goto done;
590         }
591
592         rc = bdb_index_entry_add( &op, tid, e );
593         if( rc != 0 ) {
594                 snprintf( text->bv_val, text->bv_len,
595                                 "index_entry_add failed: %s (%d)",
596                                 db_strerror(rc), rc );
597 #ifdef NEW_LOGGING
598                 LDAP_LOG ( TOOLS, ERR, 
599                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
600 #else
601                 Debug( LDAP_DEBUG_ANY,
602                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
603 #endif
604                 goto done;
605         }
606
607 done:
608         if( rc == 0 ) {
609                 rc = TXN_COMMIT( tid, 0 );
610                 if( rc != 0 ) {
611                         snprintf( text->bv_val, text->bv_len,
612                                         "txn_commit failed: %s (%d)",
613                                         db_strerror(rc), rc );
614 #ifdef NEW_LOGGING
615                         LDAP_LOG ( TOOLS, ERR, 
616                                 "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
617 #else
618                         Debug( LDAP_DEBUG_ANY,
619                                 "=> bdb_tool_entry_put: %s\n",
620                                 text->bv_val, 0, 0 );
621 #endif
622                         e->e_id = NOID;
623                 }
624
625         } else {
626                 TXN_ABORT( tid );
627                 snprintf( text->bv_val, text->bv_len,
628                         "txn_aborted! %s (%d)",
629                         db_strerror(rc), rc );
630 #ifdef NEW_LOGGING
631                 LDAP_LOG ( TOOLS, ERR, 
632                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
633 #else
634                 Debug( LDAP_DEBUG_ANY,
635                         "=> bdb_tool_entry_put: %s\n",
636                         text->bv_val, 0, 0 );
637 #endif
638                 e->e_id = NOID;
639         }
640
641         return e->e_id;
642 }