]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Moved IDL cache code to standalone functions.
[openldap] / servers / slapd / back-bdb / dn2id.c
1 /* dn2id.c - routines to deal with the dn2id index */
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 "idl.h"
15 #include "lutil.h"
16
17 #ifndef BDB_HIER
18 int
19 bdb_dn2id_add(
20         BackendDB       *be,
21         DB_TXN *txn,
22         EntryInfo *eip,
23         Entry           *e,
24         void *ctx )
25 {
26         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
27         DB *db = bdb->bi_dn2id->bdi_db;
28         int             rc;
29         DBT             key, data;
30         char            *buf;
31         struct berval   ptr, pdn;
32
33 #ifdef NEW_LOGGING
34         LDAP_LOG ( INDEX, ARGS, "bdb_dn2id_add( \"%s\", 0x%08lx )\n",
35                 e->e_ndn, (long) e->e_id, 0 );
36 #else
37         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n",
38                 e->e_ndn, (long) e->e_id, 0 );
39 #endif
40         assert( e->e_id != NOID );
41
42         DBTzero( &key );
43         key.size = e->e_nname.bv_len + 2;
44         key.ulen = key.size;
45         key.flags = DB_DBT_USERMEM;
46         buf = sl_malloc( key.size, ctx );
47         key.data = buf;
48         buf[0] = DN_BASE_PREFIX;
49         ptr.bv_val = buf + 1;
50         ptr.bv_len = e->e_nname.bv_len;
51         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
52         ptr.bv_val[ptr.bv_len] = '\0';
53
54         DBTzero( &data );
55         data.data = (char *) &e->e_id;
56         data.size = sizeof( e->e_id );
57
58         /* store it -- don't override */
59         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
60         if( rc != 0 ) {
61 #ifdef NEW_LOGGING
62                 LDAP_LOG ( INDEX, ERR, "bdb_dn2id_add: put failed: %s %d\n",
63                         db_strerror(rc), rc, 0 );
64 #else
65                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
66                         db_strerror(rc), rc, 0 );
67 #endif
68                 goto done;
69         }
70
71 #ifndef BDB_MULTIPLE_SUFFIXES
72         if( !be_issuffix( be, &ptr )) {
73 #endif
74                 buf[0] = DN_SUBTREE_PREFIX;
75                 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
76                 if( rc != 0 ) {
77 #ifdef NEW_LOGGING
78                         LDAP_LOG ( INDEX, ERR, 
79                                 "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
80                                 ptr.bv_val, rc, 0 );
81 #else
82                         Debug( LDAP_DEBUG_ANY,
83                         "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
84                         ptr.bv_val, rc, 0 );
85 #endif
86                         goto done;
87                 }
88                 
89 #ifdef BDB_MULTIPLE_SUFFIXES
90         if( !be_issuffix( be, &ptr )) {
91 #endif
92                 dnParent( &ptr, &pdn );
93         
94                 key.size = pdn.bv_len + 2;
95                 key.ulen = key.size;
96                 pdn.bv_val[-1] = DN_ONE_PREFIX;
97                 key.data = pdn.bv_val-1;
98                 ptr = pdn;
99
100                 rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id );
101
102                 if( rc != 0 ) {
103 #ifdef NEW_LOGGING
104                         LDAP_LOG ( INDEX, ERR, 
105                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
106                                 ptr.bv_val, rc, 0 );
107 #else
108                         Debug( LDAP_DEBUG_ANY,
109                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
110                                         ptr.bv_val, rc, 0 );
111 #endif
112                         goto done;
113                 }
114 #ifndef BDB_MULTIPLE_SUFFIXES
115         }
116
117         while( !be_issuffix( be, &ptr )) {
118 #else
119         for (;;) {
120 #endif
121                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
122
123                 rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id );
124
125                 if( rc != 0 ) {
126 #ifdef NEW_LOGGING
127                         LDAP_LOG ( INDEX, ERR, 
128                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
129                                 ptr.bv_val, rc, 0 );
130 #else
131                         Debug( LDAP_DEBUG_ANY,
132                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
133                                         ptr.bv_val, rc, 0 );
134 #endif
135                         break;
136                 }
137 #ifdef BDB_MULTIPLE_SUFFIXES
138                 if( be_issuffix( be, &ptr )) break;
139 #endif
140                 dnParent( &ptr, &pdn );
141
142                 key.size = pdn.bv_len + 2;
143                 key.ulen = key.size;
144                 key.data = pdn.bv_val - 1;
145                 ptr = pdn;
146         }
147 #ifdef BDB_MULTIPLE_SUFFIXES
148         }
149 #endif
150
151 done:
152         sl_free( buf, ctx );
153 #ifdef NEW_LOGGING
154         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
155 #else
156         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
157 #endif
158         return rc;
159 }
160
161 int
162 bdb_dn2id_delete(
163         BackendDB       *be,
164         DB_TXN *txn,
165         EntryInfo       *eip,
166         Entry           *e,
167         void *ctx )
168 {
169         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
170         DB *db = bdb->bi_dn2id->bdi_db;
171         int             rc;
172         DBT             key;
173         char            *buf;
174         struct berval   pdn, ptr;
175
176 #ifdef NEW_LOGGING
177         LDAP_LOG ( INDEX, ARGS, 
178                 "=> bdb_dn2id_delete ( \"%s\", 0x%08lx )\n", e->e_ndn, e->e_id, 0);
179 #else
180         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
181                 e->e_ndn, e->e_id, 0 );
182 #endif
183
184         DBTzero( &key );
185         key.size = e->e_nname.bv_len + 2;
186         buf = sl_malloc( key.size, ctx );
187         key.data = buf;
188         key.flags = DB_DBT_USERMEM;
189         buf[0] = DN_BASE_PREFIX;
190         ptr.bv_val = buf+1;
191         ptr.bv_len = e->e_nname.bv_len;
192         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
193         ptr.bv_val[ptr.bv_len] = '\0';
194
195         /* delete it */
196         rc = db->del( db, txn, &key, 0 );
197         if( rc != 0 ) {
198 #ifdef NEW_LOGGING
199                 LDAP_LOG ( INDEX, ERR, 
200                         "=> bdb_dn2id_delete: delete failed: %s %d\n", 
201                         db_strerror(rc), rc, 0 );
202 #else
203                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
204                         db_strerror(rc), rc, 0 );
205 #endif
206                 goto done;
207         }
208
209 #ifndef BDB_MULTIPLE_SUFFIXES
210         if( !be_issuffix( be, &ptr )) {
211 #endif
212                 buf[0] = DN_SUBTREE_PREFIX;
213                 rc = db->del( db, txn, &key, 0 );
214                 if( rc != 0 ) {
215 #ifdef NEW_LOGGING
216                         LDAP_LOG ( INDEX, ERR, 
217                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
218                                 ptr.bv_val, rc, 0 );
219 #else
220                         Debug( LDAP_DEBUG_ANY,
221                         "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
222                         ptr.bv_val, rc, 0 );
223 #endif
224                         goto done;
225                 }
226
227 #ifdef BDB_MULTIPLE_SUFFIXES
228         if( !be_issuffix( be, &ptr )) {
229 #endif
230                 dnParent( &ptr, &pdn );
231
232                 key.size = pdn.bv_len + 2;
233                 key.ulen = key.size;
234                 pdn.bv_val[-1] = DN_ONE_PREFIX;
235                 key.data = pdn.bv_val - 1;
236                 ptr = pdn;
237
238                 rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id );
239
240                 if( rc != 0 ) {
241 #ifdef NEW_LOGGING
242                         LDAP_LOG ( INDEX, ERR, 
243                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", 
244                                 ptr.bv_val, rc, 0 );
245 #else
246                         Debug( LDAP_DEBUG_ANY,
247                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
248                                 ptr.bv_val, rc, 0 );
249 #endif
250                         goto done;
251                 }
252 #ifndef BDB_MULTIPLE_SUFFIXES
253         }
254
255         while( !be_issuffix( be, &ptr )) {
256 #else
257         for (;;) {
258 #endif
259                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
260
261                 rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id );
262                 if( rc != 0 ) {
263 #ifdef NEW_LOGGING
264                         LDAP_LOG ( INDEX, ERR, 
265                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
266                                 ptr.bv_val, rc, 0 );
267 #else
268                         Debug( LDAP_DEBUG_ANY,
269                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
270                                 ptr.bv_val, rc, 0 );
271 #endif
272                         goto done;
273                 }
274 #ifdef BDB_MULTIPLE_SUFFIXES
275                 if( be_issuffix( be, &ptr )) break;
276 #endif
277                 dnParent( &ptr, &pdn );
278
279                 key.size = pdn.bv_len + 2;
280                 key.ulen = key.size;
281                 key.data = pdn.bv_val - 1;
282                 ptr = pdn;
283         }
284 #ifdef BDB_MULTIPLE_SUFFIXES
285         }
286 #endif
287
288 done:
289         sl_free( buf, ctx );
290 #ifdef NEW_LOGGING
291         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
292 #else
293         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
294 #endif
295         return rc;
296 }
297
298 int
299 bdb_dn2id(
300         BackendDB       *be,
301         DB_TXN *txn,
302         struct berval   *dn,
303         EntryInfo *ei,
304         void *ctx )
305 {
306         int             rc;
307         DBT             key, data;
308         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
309         DB *db = bdb->bi_dn2id->bdi_db;
310
311 #ifdef NEW_LOGGING
312         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
313 #else
314         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
315 #endif
316
317         DBTzero( &key );
318         key.size = dn->bv_len + 2;
319         key.data = sl_malloc( key.size, ctx );
320         ((char *)key.data)[0] = DN_BASE_PREFIX;
321         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
322
323         /* store the ID */
324         DBTzero( &data );
325         data.data = &ei->bei_id;
326         data.ulen = sizeof(ID);
327         data.flags = DB_DBT_USERMEM;
328
329         /* fetch it */
330         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
331
332         if( rc != 0 ) {
333 #ifdef NEW_LOGGING
334                 LDAP_LOG ( INDEX, ERR, "<= bdb_dn2id: get failed %s (%d)\n", 
335                         db_strerror(rc), rc, 0 );
336 #else
337                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
338                         db_strerror( rc ), rc, 0 );
339 #endif
340         } else {
341 #ifdef NEW_LOGGING
342                 LDAP_LOG ( INDEX, RESULTS, 
343                         "<= bdb_dn2id: got id=0x%08lx\n", ei->bei_id, 0, 0 );
344 #else
345                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
346                         ei->bei_id, 0, 0 );
347 #endif
348         }
349
350         sl_free( key.data, ctx );
351         return rc;
352 }
353
354 int
355 bdb_dn2id_children(
356         Operation *op,
357         DB_TXN *txn,
358         Entry *e )
359 {
360         DBT             key, data;
361         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
362         DB *db = bdb->bi_dn2id->bdi_db;
363         ID              id;
364         int             rc;
365
366 #ifdef NEW_LOGGING
367         LDAP_LOG ( INDEX, ARGS, 
368                 "=> bdb_dn2id_children( %s )\n", e->e_nname.bv_val, 0, 0 );
369 #else
370         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n",
371                 e->e_nname.bv_val, 0, 0 );
372 #endif
373         DBTzero( &key );
374         key.size = e->e_nname.bv_len + 2;
375         key.data = sl_malloc( key.size, op->o_tmpmemctx );
376         ((char *)key.data)[0] = DN_ONE_PREFIX;
377         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
378
379 #ifdef SLAP_IDL_CACHE
380         if ( bdb->bi_idl_cache_size ) {
381                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
382                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
383                         sl_free( key.data, o->o_tmpmemctx );
384                         return rc;
385                 }
386         }
387 #endif
388         /* we actually could do a empty get... */
389         DBTzero( &data );
390         data.data = &id;
391         data.ulen = sizeof(id);
392         data.flags = DB_DBT_USERMEM;
393         data.doff = 0;
394         data.dlen = sizeof(id);
395
396         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
397         sl_free( key.data, op->o_tmpmemctx );
398
399 #ifdef NEW_LOGGING
400         LDAP_LOG ( INDEX, DETAIL1, 
401                 "<= bdb_dn2id_children( %s ): %s (%d)\n", 
402                 e->e_nname.bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
403                 db_strerror(rc)), rc );
404 #else
405         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %s (%d)\n",
406                 e->e_nname.bv_val,
407                 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
408                         db_strerror(rc) ), rc );
409 #endif
410
411         return rc;
412 }
413
414 int
415 bdb_dn2idl(
416         BackendDB       *be,
417         struct berval   *dn,
418         int prefix,
419         ID *ids )
420 {
421         int             rc;
422         DBT             key;
423         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
424         DB *db = bdb->bi_dn2id->bdi_db;
425
426 #ifdef NEW_LOGGING
427         LDAP_LOG ( INDEX, ARGS, 
428                 "=> bdb_dn2ididl( \"%s\" )\n", dn->bv_val, 0, 0 );
429 #else
430         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n", dn->bv_val, 0, 0 );
431 #endif
432
433 #ifndef BDB_MULTIPLE_SUFFIXES
434         if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn))
435         {
436                 BDB_IDL_ALL(bdb, ids);
437                 return 0;
438         }
439 #endif
440
441         DBTzero( &key );
442         key.size = dn->bv_len + 2;
443         key.ulen = key.size;
444         key.flags = DB_DBT_USERMEM;
445         key.data = ch_malloc( key.size );
446         ((char *)key.data)[0] = prefix;
447         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
448
449         rc = bdb_idl_fetch_key( be, db, NULL, &key, ids );
450
451         if( rc != 0 ) {
452 #ifdef NEW_LOGGING
453                 LDAP_LOG ( INDEX, ERR, 
454                         "<= bdb_dn2ididl: get failed: %s (%d)\n", db_strerror(rc), rc, 0 );
455 #else
456                 Debug( LDAP_DEBUG_TRACE,
457                         "<= bdb_dn2idl: get failed: %s (%d)\n",
458                         db_strerror( rc ), rc, 0 );
459 #endif
460
461         } else {
462 #ifdef NEW_LOGGING
463                 LDAP_LOG ( INDEX, RESULTS, 
464                         "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", 
465                         (long) ids[0], (long) BDB_IDL_FIRST( ids ), 
466                         (long) BDB_IDL_LAST( ids ) );
467 #else
468                 Debug( LDAP_DEBUG_TRACE,
469                         "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
470                         (long) ids[0],
471                         (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
472 #endif
473         }
474
475         ch_free( key.data );
476         return rc;
477 }
478 #else   /* BDB_HIER */
479
480 /* Experimental management routines for a hierarchically structured database.
481  *
482  * Unsupported! Use at your own risk!
483  *
484  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
485  * entry in this database is a struct diskNode, keyed by entryID and with
486  * the data containing the RDN and entryID of the node's children. We use
487  * a B-Tree with sorted duplicates to store all the children of a node under
488  * the same key. Also, the first item under the key contains an empty rdn
489  * and the ID of the node's parent, to allow bottom-up tree traversal as
490  * well as top-down.
491  *
492  * The diskNode is a variable length structure. This definition is not
493  * directly usable for in-memory manipulation.
494  */
495 typedef struct diskNode {
496         ID entryID;
497         short nrdnlen;
498         char nrdn[1];
499         char rdn[1];
500 } diskNode;
501
502 /* Sort function for the sorted duplicate data items of a dn2id key.
503  * Sorts based on normalized RDN, in lexical order.
504  */
505 int
506 bdb_hdb_compare(
507         DB *db, 
508         const DBT *usrkey,
509         const DBT *curkey
510 )
511 {
512         diskNode *usr = usrkey->data;
513         diskNode *cur = curkey->data;
514         short curlen;
515         char *ptr = (char *)&cur->nrdnlen;
516         int rc;
517
518         curlen = ptr[0] << 8 | ptr[1];
519
520         rc = strncmp( usr->nrdn, cur->nrdn, usr->nrdnlen );
521         if ( rc == 0 ) rc = usrlen - curlen;
522         return rc;
523 }
524
525 /* This function constructs a full DN for a given entry.
526  */
527 int bdb_fix_dn(
528         BackendDB *be,
529         Entry *e
530 )
531 {
532         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
533         EntryInfo *ei;
534         int rlen = 0, nrlen = 0;
535         char *ptr, *nptr;
536         
537         for ( ei = BEI(e); ei; ei=ei->bei_parent ) {
538                 rlen += ei->bei_rdn.bv_len + 1;
539                 nrlen += ei->bei_nrdn.bv_len + 1;
540         }
541         e->e_name.bv_len = rlen - 1;
542         e->e_nname.bv_len = nrlen - 1;
543         e->e_name.bv_val = ch_malloc(rlen + nrlen);
544         e->e_nname.bv_val = e->e_name.bv_val + rlen;
545         ptr = e->e_name.bv_val;
546         nptr = e->e_nname.bv_val;
547         for ( ei = BEI(e); ei; ei=ei->bei_parent ) {
548                 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
549                 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
550                 if ( ei->bei_parent ) {
551                         *ptr++ = ',';
552                         *nptr++ = ',';
553                 }
554         }
555         *ptr = '\0';
556         *nptr = '\0';
557
558         return 0;
559 }
560
561 /* We add two elements to the DN2ID database - a data item under the parent's
562  * entryID containing the child's RDN and entryID, and an item under the
563  * child's entryID containing the parent's entryID.
564  */
565 int
566 bdb_dn2id_add(
567         BackendDB       *be,
568         DB_TXN *txn,
569         EntryInfo       *eip,
570         Entry           *e,
571         void *ctx )
572 {
573         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
574         DB *db = bdb->bi_dn2id->bdi_db;
575         DBT             key, data;
576         int             rc, rlen, nrlen;
577         diskNode *d;
578         char *ptr;
579
580         nrlen = dn_rdnlen( be, &e->e_nname );
581         if (nrlen) {
582                 rlen = dn_rdnlen( be, &e->e_name );
583         } else {
584                 rlen = 0;
585         }
586
587         d = sl_malloc(sizeof(diskNode) + rlen + nrlen, ctx);
588         d->entryID = e->e_id;
589         d->nrdnlen = nrlen;
590         ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
591         *ptr++ = '\0';
592         ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
593         *ptr = '\0';
594
595         DBTzero(&key);
596         DBTzero(&data);
597         key.data = &eip->bei_id;
598         key.size = sizeof(ID);
599         key.flags = DB_DBT_USERMEM;
600
601 #ifdef SLAP_IDL_CACHE
602         if ( bdb->bi_idl_cache_size ) {
603                 bdb_idl_cache_del( bdb, db, &key );
604         }
605 #endif
606         data.data = d;
607         data.size = sizeof(diskNode) + rlen + nrlen + 2;
608         data.flags = DB_DBT_USERMEM;
609
610         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
611
612         if (rc == 0) {
613                 key.data = &e->e_id;
614                 d->entryID = eip->bei_id;
615                 d->nrdnlen = 0;
616                 d->nrdn[0] = '\0';
617                 d->rdn[0] = '\0';
618                 data.size = sizeof(diskNode);
619
620                 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
621         }
622
623         sl_free( d, ctx );
624
625         return rc;
626 }
627
628 int
629 bdb_dn2id_delete(
630         BackendDB       *be,
631         DB_TXN *txn,
632         EntryInfo       *eip,
633         Entry   *e,
634         void    *ctx )
635 {
636         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
637         DB *db = bdb->bi_dn2id->bdi_db;
638         DBT             key, data;
639         DBC     *cursor;
640         diskNode *d;
641         int rc, nrlen;
642
643         DBTzero(&key);
644         key.size = sizeof(ID);
645         key.ulen = key.size;
646         key.data = &eip->bei_id;
647         key.flags = DB_DBT_USERMEM;
648
649         DBTzero(&data);
650         data.size = sizeof(diskNode) + BEI(e)->nrdn.bv_len;
651         d = sl_malloc( data.size, ctx );
652         d->entryID = e->e_id;
653         d->nrdnlen = BEI(e)->nrdn.bv_len;
654         strcpy( d->nrdn, BEI(e)->nrdn.bv_val );
655         data.data = d;
656         data.ulen = data.size;
657         data.dlen = data.size;
658         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
659
660 #ifdef SLAP_IDL_CACHE
661         if ( bdb->bi_idl_cache_size ) {
662                 bdb_idl_cache_del( bdb, db, &key );
663         }
664 #endif
665         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
666         if ( rc ) return rc;
667
668         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
669         if ( rc == 0 )
670                 rc = cursor->c_del( cursor, 0 );
671         cursor->c_close( cursor );
672
673         key.data = &e->e_id;
674         rc = db->del( db, txn, &key, 0);
675         sl_free( d, ctx );
676
677         return rc;
678 }
679
680 int
681 bdb_dn2id(
682         BackendDB       *be,
683         DB_TXN *txn,
684         struct berval   *in,
685         EntryInfo       *ei,
686         void *ctx )
687 {
688         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
689         DB *db = bdb->bi_dn2id->bdi_db;
690         DBT             key, data;
691         DBC     *cursor;
692         int             rc = 0, nrlen;
693         char    *ptr;
694
695         nrlen = dn_rdnlen( be, &in );
696
697         DBTzero(&key);
698         key.size = sizeof(ID);
699         key.data = &eip->bei_id;
700         key.flags = DB_DBT_USERMEM;
701
702         DBTzero(&data);
703         data.size = sizeof(diskNode) + nrlen;
704         d = sl_malloc( data.size * 3, ctx );
705         d->nrdnlen = nrlen;
706         ptr = lutil_strncopy( d->nrdn, BEI(e)->nrdn.bv_val, nrlen );
707         *ptr = '\0';
708         data.data = d;
709         data.ulen = data.size * 3;
710         data.flags = DB_DBT_USERMEM;
711
712         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
713         if ( rc ) return rc;
714
715         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
716         cursor->c_close( cursor );
717         if ( rc ) return rc;
718
719         AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
720         ei->rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
721         ptr = d->nrdn + nrlen + 1;
722         strcpy( ei->rdn.bv_val, ptr );
723
724         return rc;
725 }
726
727 int
728 bdb_dn2id_children(
729         Operation *op,
730         DB_TXN *txn,
731         Entry *e )
732 {
733         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
734         DB *db = bdb->bi_dn2id->bdi_db;
735         DBT             key, data;
736         DBC             *cursor;
737         int             rc;
738         ID              id;
739         diskNode d;
740
741         DBTzero(&key);
742         key.size = sizeof(ID);
743         key.data = &e->e_id;
744         key.flags = DB_DBT_USERMEM;
745
746 #ifdef SLAP_IDL_CACHE
747         if ( bdb->bi_idl_cache_size ) {
748                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
749                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
750                         sl_free( key.data, o->o_tmpmemctx );
751                         return rc;
752                 }
753         }
754 #endif
755         DBTzero(&data);
756         data.ulen = sizeof(d);
757         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
758         data.dlen = sizeof(d);
759
760         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
761         if ( rc ) return rc;
762
763         rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
764         if ( rc == 0 ) {
765                 rc = cursor->c_get( cursor, &key, &data, DB_NEXT_DUP );
766         }
767         cursor->c_close( cursor );
768         return rc;
769 }
770
771 int
772 bdb_dn2idl(
773         BackendDB       *be,
774         struct berval   *dn,
775         int prefix,
776         ID *ids )
777 {
778         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
779         int             rc;
780         ID              id;
781         idNode          *n;
782
783         if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) {
784                 BDB_IDL_ALL(bdb, ids);
785                 return 0;
786         }
787
788         rc = bdb_dn2id(be, NULL, dn, &id, 0);
789         if (rc) return rc;
790
791         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
792         n = bdb_find_id_node(id, bdb->bi_tree);
793         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
794
795         ids[0] = 0;
796         ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
797         if (prefix == DN_ONE_PREFIX) {
798                 rc = avl_apply(n->i_kids, insert_one, ids, -1, AVL_INORDER);
799         } else {
800                 ids[0] = 1;
801                 ids[1] = id;
802                 if (n->i_kids)
803                         rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER);
804         }
805         ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
806         return rc;
807 }
808 #endif  /* BDB_HIER */