]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/tools.c
Changes from HEAD for beta
[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         u_int32_t locker )
197 {
198         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
199         struct berval dn = e->e_nname;
200         struct berval pdn;
201         EntryInfo *ei = NULL;
202         int rc;
203
204         rc = bdb_cache_find_ndn( op, tid, &dn, &ei, locker );
205         if ( ei ) bdb_cache_entryinfo_unlock( ei );
206         if ( rc == DB_NOTFOUND ) {
207                 if ( be_issuffix( op->o_bd, &dn ) ) {
208                         pdn = slap_empty_bv;
209                 } else {
210                         dnParent( &dn, &pdn );
211                         e->e_nname = pdn;
212                         rc = bdb_tool_next_id( op, tid, e, text, 1, locker );
213                         if ( rc ) {
214                                 return rc;
215                         }
216                 }
217                 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
218                 if ( rc ) {
219                         snprintf( text->bv_val, text->bv_len,
220                                 "next_id failed: %s (%d)",
221                                 db_strerror(rc), rc );
222 #ifdef NEW_LOGGING
223                 LDAP_LOG ( TOOLS, ERR, 
224                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
225 #else
226                 Debug( LDAP_DEBUG_ANY,
227                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
228 #endif
229                         return rc;
230                 }
231                 e->e_nname = dn;
232                 rc = bdb_dn2id_add( op, tid, ei, e );
233                 if ( rc ) {
234                         snprintf( text->bv_val, text->bv_len, 
235                                 "dn2id_add failed: %s (%d)",
236                                 db_strerror(rc), rc );
237 #ifdef NEW_LOGGING
238                 LDAP_LOG ( TOOLS, ERR, 
239                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
240 #else
241                 Debug( LDAP_DEBUG_ANY,
242                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
243 #endif
244                 } else if ( hole ) {
245                         if ( nholes == nhmax - 1 ) {
246                                 if ( holes == hbuf ) {
247                                         holes = ch_malloc( nhmax * sizeof(ID) * 2 );
248                                         AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
249                                 } else {
250                                         holes = ch_realloc( holes, nhmax * sizeof(ID) * 2 );
251                                 }
252                                 nhmax *= 2;
253                         }
254                         ber_dupbv( &holes[nholes].dn, &dn );
255                         holes[nholes++].id = e->e_id;
256                 }
257         } else if ( !hole ) {
258                 unsigned i;
259
260                 for ( i=0; i<nholes; i++) {
261                         if ( holes[i].id == e->e_id ) {
262                                 int j;
263                                 free(holes[i].dn.bv_val);
264                                 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
265                                 holes[j].id = 0;
266                                 nholes--;
267                                 break;
268                         } else if ( holes[i].id > e->e_id ) {
269                                 break;
270                         }
271                 }
272         }
273         return rc;
274 }
275
276 ID bdb_tool_entry_put(
277         BackendDB *be,
278         Entry *e,
279         struct berval *text )
280 {
281         int rc;
282         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
283         DB_TXN *tid = NULL;
284         Operation op = {0};
285         u_int32_t locker;
286
287         assert( be != NULL );
288         assert( slapMode & SLAP_TOOL_MODE );
289
290         assert( text );
291         assert( text->bv_val );
292         assert( text->bv_val[0] == '\0' );      /* overconservative? */
293
294 #ifdef NEW_LOGGING
295         LDAP_LOG ( TOOLS, ARGS, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
296                 (long) e->e_id, e->e_dn, 0 );
297 #else
298         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
299                 (long) e->e_id, e->e_dn, 0 );
300 #endif
301
302         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
303                 bdb->bi_db_opflags );
304         if( rc != 0 ) {
305                 snprintf( text->bv_val, text->bv_len,
306                         "txn_begin failed: %s (%d)",
307                         db_strerror(rc), rc );
308 #ifdef NEW_LOGGING
309         LDAP_LOG ( TOOLS, ERR, "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
310 #else
311                 Debug( LDAP_DEBUG_ANY,
312                         "=> bdb_tool_entry_put: %s\n",
313                          text->bv_val, 0, 0 );
314 #endif
315                 return NOID;
316         }
317
318         op.o_bd = be;
319         op.o_tmpmemctx = NULL;
320         op.o_tmpmfuncs = &ch_mfuncs;
321
322         locker = TXN_ID( tid );
323         /* add dn2id indices */
324         rc = bdb_tool_next_id( &op, tid, e, text, 0, locker );
325         if( rc != 0 ) {
326                 goto done;
327         }
328
329         /* id2entry index */
330         rc = bdb_id2entry_add( be, tid, e );
331         if( rc != 0 ) {
332                 snprintf( text->bv_val, text->bv_len,
333                                 "id2entry_add failed: %s (%d)",
334                                 db_strerror(rc), rc );
335 #ifdef NEW_LOGGING
336                 LDAP_LOG ( TOOLS, ERR, 
337                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
338 #else
339                 Debug( LDAP_DEBUG_ANY,
340                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
341 #endif
342                 goto done;
343         }
344
345         rc = bdb_index_entry_add( &op, tid, e );
346         if( rc != 0 ) {
347                 snprintf( text->bv_val, text->bv_len,
348                                 "index_entry_add failed: %s (%d)",
349                                 db_strerror(rc), rc );
350 #ifdef NEW_LOGGING
351                 LDAP_LOG ( TOOLS, ERR, 
352                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
353 #else
354                 Debug( LDAP_DEBUG_ANY,
355                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
356 #endif
357                 goto done;
358         }
359
360 done:
361         if( rc == 0 ) {
362                 rc = TXN_COMMIT( tid, 0 );
363                 if( rc != 0 ) {
364                         snprintf( text->bv_val, text->bv_len,
365                                         "txn_commit failed: %s (%d)",
366                                         db_strerror(rc), rc );
367 #ifdef NEW_LOGGING
368                         LDAP_LOG ( TOOLS, ERR, 
369                                 "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
370 #else
371                         Debug( LDAP_DEBUG_ANY,
372                                 "=> bdb_tool_entry_put: %s\n",
373                                 text->bv_val, 0, 0 );
374 #endif
375                         e->e_id = NOID;
376                 }
377
378         } else {
379                 TXN_ABORT( tid );
380                 snprintf( text->bv_val, text->bv_len,
381                         "txn_aborted! %s (%d)",
382                         db_strerror(rc), rc );
383 #ifdef NEW_LOGGING
384                 LDAP_LOG ( TOOLS, ERR, 
385                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
386 #else
387                 Debug( LDAP_DEBUG_ANY,
388                         "=> bdb_tool_entry_put: %s\n",
389                         text->bv_val, 0, 0 );
390 #endif
391                 e->e_id = NOID;
392         }
393
394         return e->e_id;
395 }
396
397 int bdb_tool_entry_reindex(
398         BackendDB *be,
399         ID id )
400 {
401         struct bdb_info *bi = (struct bdb_info *) be->be_private;
402         int rc;
403         Entry *e;
404         DB_TXN *tid = NULL;
405         Operation op = {0};
406
407 #ifdef NEW_LOGGING
408         LDAP_LOG ( TOOLS, ARGS, 
409                 "=> bdb_tool_entry_reindex( %ld )\n", (long) id, 0, 0 );
410 #else
411         Debug( LDAP_DEBUG_ARGS, "=> bdb_tool_entry_reindex( %ld )\n",
412                 (long) id, 0, 0 );
413 #endif
414
415         e = bdb_tool_entry_get( be, id );
416
417         if( e == NULL ) {
418 #ifdef NEW_LOGGING
419                 LDAP_LOG ( TOOLS, DETAIL1, 
420                         "bdb_tool_entry_reindex:: could not locate id=%ld\n", 
421                         (long) id, 0, 0 );
422 #else
423                 Debug( LDAP_DEBUG_ANY,
424                         "bdb_tool_entry_reindex:: could not locate id=%ld\n",
425                         (long) id, 0, 0 );
426 #endif
427                 return -1;
428         }
429
430         rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
431         if( rc != 0 ) {
432 #ifdef NEW_LOGGING
433                 LDAP_LOG ( TOOLS, ERR, 
434                         "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n", 
435                         db_strerror(rc), rc, 0 );
436 #else
437                 Debug( LDAP_DEBUG_ANY,
438                         "=> bdb_tool_entry_reindex: txn_begin failed: %s (%d)\n",
439                         db_strerror(rc), rc, 0 );
440 #endif
441                 goto done;
442         }
443         
444         /*
445          * just (re)add them for now
446          * assume that some other routine (not yet implemented)
447          * will zap index databases
448          *
449          */
450
451 #ifdef NEW_LOGGING
452         LDAP_LOG ( TOOLS, ERR, 
453                 "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n", (long) id, e->e_dn, 0 );
454 #else
455         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_reindex( %ld, \"%s\" )\n",
456                 (long) id, e->e_dn, 0 );
457 #endif
458
459         op.o_bd = be;
460         op.o_tmpmemctx = NULL;
461         op.o_tmpmfuncs = &ch_mfuncs;
462
463 #ifndef BDB_HIER
464         /* add dn2id indices */
465         rc = bdb_dn2id_add( &op, tid, NULL, e );
466         if( rc != 0 && rc != DB_KEYEXIST ) {
467 #ifdef NEW_LOGGING
468                 LDAP_LOG ( TOOLS, ERR, 
469                         "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n", 
470                         db_strerror(rc), rc, 0 );
471 #else
472                 Debug( LDAP_DEBUG_ANY,
473                         "=> bdb_tool_entry_reindex: dn2id_add failed: %s (%d)\n",
474                         db_strerror(rc), rc, 0 );
475 #endif
476                 goto done;
477         }
478 #endif
479
480         rc = bdb_index_entry_add( &op, tid, e );
481
482 done:
483         if( rc == 0 ) {
484                 rc = TXN_COMMIT( tid, 0 );
485                 if( rc != 0 ) {
486 #ifdef NEW_LOGGING
487                         LDAP_LOG ( TOOLS, ERR, 
488                                 "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n", 
489                                 db_strerror(rc), rc, 0 );
490 #else
491                         Debug( LDAP_DEBUG_ANY,
492                                 "=> bdb_tool_entry_reindex: txn_commit failed: %s (%d)\n",
493                                 db_strerror(rc), rc, 0 );
494 #endif
495                         e->e_id = NOID;
496                 }
497
498         } else {
499                 TXN_ABORT( tid );
500 #ifdef NEW_LOGGING
501                 LDAP_LOG ( TOOLS, DETAIL1, 
502                         "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n", 
503                         db_strerror(rc), rc, 0 );
504 #else
505                 Debug( LDAP_DEBUG_ANY,
506                         "=> bdb_tool_entry_reindex: txn_aborted! %s (%d)\n",
507                         db_strerror(rc), rc, 0 );
508 #endif
509                 e->e_id = NOID;
510         }
511         bdb_entry_release( &op, e, 0 );
512
513         return rc;
514 }
515
516 ID bdb_tool_entry_modify(
517         BackendDB *be,
518         Entry *e,
519         struct berval *text )
520 {
521         int rc;
522         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
523         DB_TXN *tid = NULL;
524         Operation op = {0};
525
526         assert( be != NULL );
527         assert( slapMode & SLAP_TOOL_MODE );
528
529         assert( text );
530         assert( text->bv_val );
531         assert( text->bv_val[0] == '\0' );      /* overconservative? */
532
533         assert ( e->e_id != NOID );
534         assert ( e->e_id != 0 );
535
536 #ifdef NEW_LOGGING
537         LDAP_LOG ( TOOLS, ARGS, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
538                 (long) e->e_id, e->e_dn, 0 );
539 #else
540         Debug( LDAP_DEBUG_TRACE, "=> bdb_tool_entry_put( %ld, \"%s\" )\n",
541                 (long) e->e_id, e->e_dn, 0 );
542 #endif
543
544         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
545                 bdb->bi_db_opflags );
546         if( rc != 0 ) {
547                 snprintf( text->bv_val, text->bv_len,
548                         "txn_begin failed: %s (%d)",
549                         db_strerror(rc), rc );
550 #ifdef NEW_LOGGING
551         LDAP_LOG ( TOOLS, ERR, "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
552 #else
553                 Debug( LDAP_DEBUG_ANY,
554                         "=> bdb_tool_entry_put: %s\n",
555                          text->bv_val, 0, 0 );
556 #endif
557                 return NOID;
558         }
559
560         op.o_bd = be;
561         op.o_tmpmemctx = NULL;
562         op.o_tmpmfuncs = &ch_mfuncs;
563
564         /* id2entry index */
565         rc = bdb_id2entry_update( be, tid, e );
566         if( rc != 0 ) {
567                 snprintf( text->bv_val, text->bv_len,
568                                 "id2entry_add failed: %s (%d)",
569                                 db_strerror(rc), rc );
570 #ifdef NEW_LOGGING
571                 LDAP_LOG ( TOOLS, ERR, 
572                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
573 #else
574                 Debug( LDAP_DEBUG_ANY,
575                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
576 #endif
577                 goto done;
578         }
579
580         rc = bdb_index_entry_del( &op, tid, e );
581         if( rc != 0 ) {
582                 snprintf( text->bv_val, text->bv_len,
583                                 "index_entry_del failed: %s (%d)",
584                                 db_strerror(rc), rc );
585 #ifdef NEW_LOGGING
586                 LDAP_LOG ( TOOLS, ERR, 
587                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
588 #else
589                 Debug( LDAP_DEBUG_ANY,
590                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
591 #endif
592                 goto done;
593         }
594
595         rc = bdb_index_entry_add( &op, tid, e );
596         if( rc != 0 ) {
597                 snprintf( text->bv_val, text->bv_len,
598                                 "index_entry_add failed: %s (%d)",
599                                 db_strerror(rc), rc );
600 #ifdef NEW_LOGGING
601                 LDAP_LOG ( TOOLS, ERR, 
602                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
603 #else
604                 Debug( LDAP_DEBUG_ANY,
605                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
606 #endif
607                 goto done;
608         }
609
610 done:
611         if( rc == 0 ) {
612                 rc = TXN_COMMIT( tid, 0 );
613                 if( rc != 0 ) {
614                         snprintf( text->bv_val, text->bv_len,
615                                         "txn_commit failed: %s (%d)",
616                                         db_strerror(rc), rc );
617 #ifdef NEW_LOGGING
618                         LDAP_LOG ( TOOLS, ERR, 
619                                 "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
620 #else
621                         Debug( LDAP_DEBUG_ANY,
622                                 "=> bdb_tool_entry_put: %s\n",
623                                 text->bv_val, 0, 0 );
624 #endif
625                         e->e_id = NOID;
626                 }
627
628         } else {
629                 TXN_ABORT( tid );
630                 snprintf( text->bv_val, text->bv_len,
631                         "txn_aborted! %s (%d)",
632                         db_strerror(rc), rc );
633 #ifdef NEW_LOGGING
634                 LDAP_LOG ( TOOLS, ERR, 
635                         "=> bdb_tool_entry_put: %s\n", text->bv_val, 0, 0 );
636 #else
637                 Debug( LDAP_DEBUG_ANY,
638                         "=> bdb_tool_entry_put: %s\n",
639                         text->bv_val, 0, 0 );
640 #endif
641                 e->e_id = NOID;
642         }
643
644         return e->e_id;
645 }