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