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