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