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