]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Hierarchical cache management.
[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         struct berval   *pbv,
23         Entry           *e )
24 {
25         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
26         DB *db = bdb->bi_dn2id->bdi_db;
27         int             rc;
28         DBT             key, data;
29         char            *buf;
30         struct berval   ptr, pdn;
31
32 #ifdef NEW_LOGGING
33         LDAP_LOG ( INDEX, ARGS, "bdb_dn2id_add( \"%s\", 0x%08lx )\n",
34                 e->e_ndn, (long) e->e_id, 0 );
35 #else
36         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n",
37                 e->e_ndn, (long) e->e_id, 0 );
38 #endif
39         assert( e->e_id != NOID );
40
41         DBTzero( &key );
42         key.size = e->e_nname.bv_len + 2;
43         key.ulen = key.size;
44         key.flags = DB_DBT_USERMEM;
45         buf = ch_malloc( key.size );
46         key.data = buf;
47         buf[0] = DN_BASE_PREFIX;
48         ptr.bv_val = buf + 1;
49         ptr.bv_len = e->e_nname.bv_len;
50         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
51         ptr.bv_val[ptr.bv_len] = '\0';
52
53         DBTzero( &data );
54         data.data = (char *) &e->e_id;
55         data.size = sizeof( e->e_id );
56
57         /* store it -- don't override */
58         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
59         if( rc != 0 ) {
60 #ifdef NEW_LOGGING
61                 LDAP_LOG ( INDEX, ERR, "bdb_dn2id_add: put failed: %s %d\n",
62                         db_strerror(rc), rc, 0 );
63 #else
64                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
65                         db_strerror(rc), rc, 0 );
66 #endif
67                 goto done;
68         }
69
70 #ifndef BDB_MULTIPLE_SUFFIXES
71         if( !be_issuffix( be, &ptr )) {
72 #endif
73                 buf[0] = DN_SUBTREE_PREFIX;
74                 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
75                 if( rc != 0 ) {
76 #ifdef NEW_LOGGING
77                         LDAP_LOG ( INDEX, ERR, 
78                                 "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
79                                 ptr.bv_val, rc, 0 );
80 #else
81                         Debug( LDAP_DEBUG_ANY,
82                         "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
83                         ptr.bv_val, rc, 0 );
84 #endif
85                         goto done;
86                 }
87                 
88 #ifdef BDB_MULTIPLE_SUFFIXES
89         if( !be_issuffix( be, &ptr )) {
90 #endif
91                 dnParent( &ptr, &pdn );
92         
93                 key.size = pdn.bv_len + 2;
94                 key.ulen = key.size;
95                 pdn.bv_val[-1] = DN_ONE_PREFIX;
96                 key.data = pdn.bv_val-1;
97                 ptr = pdn;
98
99                 rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id );
100
101                 if( rc != 0 ) {
102 #ifdef NEW_LOGGING
103                         LDAP_LOG ( INDEX, ERR, 
104                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
105                                 ptr.bv_val, rc, 0 );
106 #else
107                         Debug( LDAP_DEBUG_ANY,
108                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
109                                         ptr.bv_val, rc, 0 );
110 #endif
111                         goto done;
112                 }
113 #ifndef BDB_MULTIPLE_SUFFIXES
114         }
115
116         while( !be_issuffix( be, &ptr )) {
117 #else
118         for (;;) {
119 #endif
120                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
121
122                 rc = bdb_idl_insert_key( be, db, txn, &key, e->e_id );
123
124                 if( rc != 0 ) {
125 #ifdef NEW_LOGGING
126                         LDAP_LOG ( INDEX, ERR, 
127                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
128                                 ptr.bv_val, rc, 0 );
129 #else
130                         Debug( LDAP_DEBUG_ANY,
131                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
132                                         ptr.bv_val, rc, 0 );
133 #endif
134                         break;
135                 }
136 #ifdef BDB_MULTIPLE_SUFFIXES
137                 if( be_issuffix( be, &ptr )) break;
138 #endif
139                 dnParent( &ptr, &pdn );
140
141                 key.size = pdn.bv_len + 2;
142                 key.ulen = key.size;
143                 key.data = pdn.bv_val - 1;
144                 ptr = pdn;
145         }
146 #ifdef BDB_MULTIPLE_SUFFIXES
147         }
148 #endif
149
150 done:
151         ch_free( buf );
152 #ifdef NEW_LOGGING
153         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
154 #else
155         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
156 #endif
157         return rc;
158 }
159
160 int
161 bdb_dn2id_delete(
162         BackendDB       *be,
163         DB_TXN *txn,
164         char    *pdnc,
165         Entry           *e )
166 {
167         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
168         DB *db = bdb->bi_dn2id->bdi_db;
169         int             rc;
170         DBT             key;
171         char            *buf;
172         struct berval   pdn, ptr;
173
174 #ifdef NEW_LOGGING
175         LDAP_LOG ( INDEX, ARGS, 
176                 "=> bdb_dn2id_delete ( \"%s\", 0x%08lx )\n", e->e_ndn, e->e_id, 0);
177 #else
178         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
179                 e->e_ndn, e->e_id, 0 );
180 #endif
181
182         DBTzero( &key );
183         key.size = e->e_nname.bv_len + 2;
184         buf = ch_malloc( key.size );
185         key.data = buf;
186         key.flags = DB_DBT_USERMEM;
187         buf[0] = DN_BASE_PREFIX;
188         ptr.bv_val = buf+1;
189         ptr.bv_len = e->e_nname.bv_len;
190         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
191         ptr.bv_val[ptr.bv_len] = '\0';
192
193         /* delete it */
194         rc = db->del( db, txn, &key, 0 );
195         if( rc != 0 ) {
196 #ifdef NEW_LOGGING
197                 LDAP_LOG ( INDEX, ERR, 
198                         "=> bdb_dn2id_delete: delete failed: %s %d\n", 
199                         db_strerror(rc), rc, 0 );
200 #else
201                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
202                         db_strerror(rc), rc, 0 );
203 #endif
204                 goto done;
205         }
206
207 #ifndef BDB_MULTIPLE_SUFFIXES
208         if( !be_issuffix( be, &ptr )) {
209 #endif
210                 buf[0] = DN_SUBTREE_PREFIX;
211                 rc = db->del( db, txn, &key, 0 );
212                 if( rc != 0 ) {
213 #ifdef NEW_LOGGING
214                         LDAP_LOG ( INDEX, ERR, 
215                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
216                                 ptr.bv_val, rc, 0 );
217 #else
218                         Debug( LDAP_DEBUG_ANY,
219                         "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
220                         ptr.bv_val, rc, 0 );
221 #endif
222                         goto done;
223                 }
224
225 #ifdef BDB_MULTIPLE_SUFFIXES
226         if( !be_issuffix( be, &ptr )) {
227 #endif
228                 dnParent( &ptr, &pdn );
229
230                 key.size = pdn.bv_len + 2;
231                 key.ulen = key.size;
232                 pdn.bv_val[-1] = DN_ONE_PREFIX;
233                 key.data = pdn.bv_val - 1;
234                 ptr = pdn;
235
236                 rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id );
237
238                 if( rc != 0 ) {
239 #ifdef NEW_LOGGING
240                         LDAP_LOG ( INDEX, ERR, 
241                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", 
242                                 ptr.bv_val, rc, 0 );
243 #else
244                         Debug( LDAP_DEBUG_ANY,
245                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
246                                 ptr.bv_val, rc, 0 );
247 #endif
248                         goto done;
249                 }
250 #ifndef BDB_MULTIPLE_SUFFIXES
251         }
252
253         while( !be_issuffix( be, &ptr )) {
254 #else
255         for (;;) {
256 #endif
257                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
258
259                 rc = bdb_idl_delete_key( be, db, txn, &key, e->e_id );
260                 if( rc != 0 ) {
261 #ifdef NEW_LOGGING
262                         LDAP_LOG ( INDEX, ERR, 
263                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
264                                 ptr.bv_val, rc, 0 );
265 #else
266                         Debug( LDAP_DEBUG_ANY,
267                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
268                                 ptr.bv_val, rc, 0 );
269 #endif
270                         goto done;
271                 }
272 #ifdef BDB_MULTIPLE_SUFFIXES
273                 if( be_issuffix( be, &ptr )) break;
274 #endif
275                 dnParent( &ptr, &pdn );
276
277                 key.size = pdn.bv_len + 2;
278                 key.ulen = key.size;
279                 key.data = pdn.bv_val - 1;
280                 ptr = pdn;
281         }
282 #ifdef BDB_MULTIPLE_SUFFIXES
283         }
284 #endif
285
286 done:
287         ch_free( buf );
288 #ifdef NEW_LOGGING
289         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
290 #else
291         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
292 #endif
293         return rc;
294 }
295
296 int
297 bdb_dn2id(
298         BackendDB       *be,
299         DB_TXN *txn,
300         struct berval   *dn,
301         ID *id,
302         void *ctx )
303 {
304         int             rc;
305         DBT             key, data;
306         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
307         DB *db = bdb->bi_dn2id->bdi_db;
308
309 #ifdef NEW_LOGGING
310         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
311 #else
312         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
313 #endif
314
315         assert (id);
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 = 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", *id, 0, 0 );
344 #else
345                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
346                         *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         BackendDB       *be,
357         DB_TXN *txn,
358         struct berval *dn, 
359         int flags )
360 {
361         int             rc;
362         DBT             key, data;
363         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
364         DB *db = bdb->bi_dn2id->bdi_db;
365         ID              id;
366
367 #ifdef NEW_LOGGING
368         LDAP_LOG ( INDEX, ARGS, 
369                 "=> bdb_dn2id_children( %s )\n", dn->bv_val, 0, 0 );
370 #else
371         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n",
372                 dn->bv_val, 0, 0 );
373 #endif
374
375         DBTzero( &key );
376         key.size = dn->bv_len + 2;
377         key.data = ch_malloc( key.size );
378         ((char *)key.data)[0] = DN_ONE_PREFIX;
379         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
380
381         /* we actually could do a empty get... */
382         DBTzero( &data );
383         data.data = &id;
384         data.ulen = sizeof(id);
385         data.flags = DB_DBT_USERMEM;
386         data.doff = 0;
387         data.dlen = sizeof(id);
388
389         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags | flags );
390         free( key.data );
391
392 #ifdef NEW_LOGGING
393         LDAP_LOG ( INDEX, DETAIL1, 
394                 "<= bdb_dn2id_children( %s ): %s (%d)\n", 
395                 dn->bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
396                 db_strerror(rc)), rc );
397 #else
398         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %s (%d)\n",
399                 dn->bv_val,
400                 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
401                         db_strerror(rc) ), rc );
402 #endif
403
404         return rc;
405 }
406
407 int
408 bdb_dn2idl(
409         BackendDB       *be,
410         struct berval   *dn,
411         int prefix,
412         ID *ids )
413 {
414         int             rc;
415         DBT             key;
416         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
417         DB *db = bdb->bi_dn2id->bdi_db;
418
419 #ifdef NEW_LOGGING
420         LDAP_LOG ( INDEX, ARGS, 
421                 "=> bdb_dn2ididl( \"%s\" )\n", dn->bv_val, 0, 0 );
422 #else
423         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n", dn->bv_val, 0, 0 );
424 #endif
425
426 #ifndef BDB_MULTIPLE_SUFFIXES
427         if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn))
428         {
429                 BDB_IDL_ALL(bdb, ids);
430                 return 0;
431         }
432 #endif
433
434         DBTzero( &key );
435         key.size = dn->bv_len + 2;
436         key.ulen = key.size;
437         key.flags = DB_DBT_USERMEM;
438         key.data = ch_malloc( key.size );
439         ((char *)key.data)[0] = prefix;
440         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
441
442         rc = bdb_idl_fetch_key( be, db, NULL, &key, ids );
443
444         if( rc != 0 ) {
445 #ifdef NEW_LOGGING
446                 LDAP_LOG ( INDEX, ERR, 
447                         "<= bdb_dn2ididl: get failed: %s (%d)\n", db_strerror(rc), rc, 0 );
448 #else
449                 Debug( LDAP_DEBUG_TRACE,
450                         "<= bdb_dn2idl: get failed: %s (%d)\n",
451                         db_strerror( rc ), rc, 0 );
452 #endif
453
454         } else {
455 #ifdef NEW_LOGGING
456                 LDAP_LOG ( INDEX, RESULTS, 
457                         "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", 
458                         (long) ids[0], (long) BDB_IDL_FIRST( ids ), 
459                         (long) BDB_IDL_LAST( ids ) );
460 #else
461                 Debug( LDAP_DEBUG_TRACE,
462                         "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
463                         (long) ids[0],
464                         (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
465 #endif
466         }
467
468         ch_free( key.data );
469         return rc;
470 }
471 #else   /* BDB_HIER */
472
473 /* Experimental management routines for a hierarchically structured backend.
474  *
475  * Unsupported! Use at your own risk!
476  *
477  * Instead of a dn2id database, we use an id2parent database. Each entry in
478  * this database is a struct diskNode, containing the ID of the node's parent
479  * and the RDN of the node.
480  */
481 typedef struct diskNode {
482         ID parent;
483         struct berval rdn;
484         struct berval nrdn;
485 } diskNode;
486
487 /* In bdb_db_open() we call bdb_build_tree() which reads the entire id2parent
488  * database into memory (into an AVL tree). Next we iterate through each node
489  * of this tree, connecting each child to its parent. The nodes in this AVL
490  * tree are a struct idNode. The immediate (Onelevel) children of a node are
491  * referenced in the i_kids AVL tree. With this arrangement, there is no need
492  * to maintain the DN_ONE_PREFIX or DN_SUBTREE_PREFIX database keys. Note that
493  * the DN of an entry is constructed by walking up the list of i_parent
494  * pointers, so no full DN is stored on disk anywhere. This makes modrdn
495  * extremely efficient, even when operating on a populated subtree.
496  *
497  * The idNode tree is searched directly from the root when performing id to
498  * entry lookups. The tree is traversed using the i_kids subtrees when
499  * performing dn to id lookups.
500  */
501 typedef struct idNode {
502         ID i_id;
503         struct idNode *i_parent;
504         diskNode *i_rdn;
505         Avlnode *i_kids;
506         ldap_pvt_thread_rdwr_t i_kids_rdwr;
507 } idNode;
508
509
510 /* The main AVL tree is sorted in ID order. The i_kids AVL trees are
511  * sorted in lexical order. These are the various helper routines used
512  * for the searches and sorts.
513  */
514 static int
515 node_find_cmp(
516         const void *id,
517         const void *node
518 )
519 {
520         return *(const ID *)id - ((const idNode *)node)->i_id;
521 }
522
523 static int
524 node_frdn_cmp(
525         const void *v_nrdn,
526         const void *v_n
527 )
528 {
529         const struct berval *nrdn = v_nrdn;
530         const idNode *n = v_n;
531         return ber_bvcmp(nrdn, &n->i_rdn->nrdn);
532 }
533
534 static int
535 node_add_cmp(
536         const void *v_a,
537         const void *v_b
538 )
539 {
540         const idNode *a = v_a, *b = v_b;
541         return a->i_id - b->i_id;
542 }
543
544 static int
545 node_rdn_cmp(
546         const void *v_a,
547         const void *v_b
548 )
549 {
550         const idNode *a = v_a, *b = v_b;
551         /* should be slightly better without ordering drawbacks */
552         return ber_bvcmp(&a->i_rdn->nrdn, &b->i_rdn->nrdn);
553 }
554
555 idNode * bdb_find_id_node(
556         ID id,
557         Avlnode *tree
558 )
559 {
560         return avl_find(tree, &id, node_find_cmp);
561 }
562
563 idNode * bdb_find_rdn_node(
564         struct berval *nrdn,
565         Avlnode *tree
566 )
567 {
568         return avl_find(tree, nrdn, node_frdn_cmp);
569 }
570
571 /* This function links a node into its parent's i_kids tree. */
572 static int bdb_insert_kid(
573         void *v_a,
574         void *v_tree
575 )
576 {
577         idNode *a = v_a;
578         Avlnode *tree = v_tree;
579         int rc;
580
581         if (a->i_rdn->parent == 0)
582                 return 0;
583         a->i_parent = bdb_find_id_node(a->i_rdn->parent, tree);
584         if (!a->i_parent)
585                 return -1;
586         ldap_pvt_thread_rdwr_wlock(&a->i_parent->i_kids_rdwr);
587         rc = avl_insert( &a->i_parent->i_kids, (caddr_t) a,
588                          node_rdn_cmp, avl_dup_error );
589         ldap_pvt_thread_rdwr_wunlock(&a->i_parent->i_kids_rdwr);
590         return rc;
591 }
592
593 /* This function adds a node into the main AVL tree */
594 idNode *bdb_add_node(
595         ID id,
596         char *d,
597         struct bdb_info *bdb
598 )
599 {
600         idNode *node;
601
602         node = (idNode *)ch_malloc(sizeof(idNode));
603         node->i_id = id;
604         node->i_parent = NULL;
605         node->i_kids = NULL;
606         node->i_rdn = (diskNode *)d;
607         node->i_rdn->rdn.bv_val += (long)d;
608         node->i_rdn->nrdn.bv_val += (long)d;
609         ldap_pvt_thread_rdwr_init(&node->i_kids_rdwr);
610         avl_insert( &bdb->bi_tree, (caddr_t) node, node_add_cmp, avl_dup_error );
611         if (id == 1)
612                 bdb->bi_troot = node;
613         return node;
614 }
615
616 /* This function initializes the trees at startup time. */
617 int bdb_build_tree(
618         Backend *be
619 )
620 {
621         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
622         int rc;
623         DBC *cursor;
624         DBT key, data;
625         ID id;
626         idNode *node;
627
628         bdb->bi_tree = NULL;
629
630         rc = bdb->bi_id2parent->bdi_db->cursor(
631                 bdb->bi_id2parent->bdi_db, NULL, &cursor,
632                 bdb->bi_db_opflags );
633         if( rc != 0 ) {
634                 return NOID;
635         }
636
637         DBTzero( &key );
638         DBTzero( &data );
639         key.data = (char *)&id;
640         key.ulen = sizeof( id );
641         key.flags = DB_DBT_USERMEM;
642         data.flags = DB_DBT_MALLOC;
643
644         while (cursor->c_get( cursor, &key, &data, DB_NEXT ) == 0) {
645                 bdb_add_node( id, data.data, bdb );
646         }
647         cursor->c_close( cursor );
648
649         rc = avl_apply(bdb->bi_tree, bdb_insert_kid, bdb->bi_tree,
650                 -1, AVL_INORDER );
651
652         return rc;
653 }
654
655 /* This function constructs a full DN for a given id. We really should
656  * be passing idNodes directly, to save some effort...
657  */
658 int bdb_fix_dn(
659         BackendDB *be,
660         ID id,
661         Entry *e
662 )
663 {
664         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
665         idNode *n, *o;
666         int rlen, nrlen;
667         char *ptr, *nptr;
668         
669         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
670         o = bdb_find_id_node(id, bdb->bi_tree);
671         rlen = be->be_suffix[0].bv_len + 1;
672         nrlen = be->be_nsuffix[0].bv_len + 1;
673         for (n = o; n && n->i_parent; n=n->i_parent) {
674                 rlen += n->i_rdn->rdn.bv_len + 1;
675                 nrlen += n->i_rdn->nrdn.bv_len + 1;
676         }
677         e->e_name.bv_len = rlen - 1;
678         e->e_nname.bv_len = nrlen - 1;
679         e->e_name.bv_val = ch_malloc(rlen + nrlen);
680         e->e_nname.bv_val = e->e_name.bv_val + rlen;
681         ptr = e->e_name.bv_val;
682         nptr = e->e_nname.bv_val;
683         for (n = o; n && n->i_parent; n=n->i_parent) {
684                 ptr = lutil_strcopy(ptr, n->i_rdn->rdn.bv_val);
685                 *ptr++ = ',';
686                 nptr = lutil_strcopy(nptr, n->i_rdn->nrdn.bv_val);
687                 *nptr++ = ',';
688         }
689         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
690
691         strcpy(ptr, be->be_suffix[0].bv_val);
692         strcpy(nptr, be->be_nsuffix[0].bv_val);
693
694         return 0;
695 }
696
697 int
698 bdb_dn2id_add(
699         BackendDB       *be,
700         DB_TXN *txn,
701         struct berval   *pdn,
702         Entry           *e )
703 {
704         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
705         int             rc, rlen, nrlen;
706         DBT             key, data;
707         DB *db = bdb->bi_id2parent->bdi_db;
708         diskNode *d;
709         idNode *n;
710
711         nrlen = dn_rdnlen( be, &e->e_nname );
712         if (nrlen) {
713                 rlen = dn_rdnlen( be, &e->e_name );
714         } else {
715                 rlen = 0;
716         }
717
718         d = ch_malloc(sizeof(diskNode) + rlen + nrlen + 2);
719         d->rdn.bv_len = rlen;
720         d->nrdn.bv_len = nrlen;
721         d->rdn.bv_val = (char *)(d+1);
722         d->nrdn.bv_val = d->rdn.bv_val + rlen + 1;
723         strncpy(d->rdn.bv_val, e->e_dn, rlen);
724         d->rdn.bv_val[rlen] = '\0';
725         strncpy(d->nrdn.bv_val, e->e_ndn, nrlen);
726         d->nrdn.bv_val[nrlen] = '\0';
727         d->rdn.bv_val -= (long)d;
728         d->nrdn.bv_val -= (long)d;
729
730         if (pdn->bv_len) {
731                 bdb_dn2id(be, txn, pdn, &d->parent, 0);
732         } else {
733                 d->parent = 0;
734         }
735
736         DBTzero(&key);
737         DBTzero(&data);
738         key.data = &e->e_id;
739         key.size = sizeof(ID);
740         key.flags = DB_DBT_USERMEM;
741
742         data.data = d;
743         data.size = sizeof(diskNode) + rlen + nrlen + 2;
744         data.flags = DB_DBT_USERMEM;
745
746         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
747
748         if (rc == 0) {
749                 ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr);
750                 n = bdb_add_node( e->e_id, data.data, bdb);
751                 ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr);
752
753                 if (d->parent) {
754                         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
755                         bdb_insert_kid(n, bdb->bi_tree);
756                         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
757                 }
758         } else {
759                 free(d);
760         }
761         return rc;
762 }
763
764 int
765 bdb_dn2id_delete(
766         BackendDB       *be,
767         DB_TXN *txn,
768         char    *pdn,
769         Entry   *e )
770 {
771         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
772         int rc;
773         DBT             key;
774         DB *db = bdb->bi_id2parent->bdi_db;
775         idNode *n;
776
777         DBTzero(&key);
778         key.size = sizeof(e->e_id);
779         key.data = &e->e_id;
780
781         rc = db->del( db, txn, &key, 0);
782
783         ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr);
784         n = avl_delete(&bdb->bi_tree, &e->e_id, node_find_cmp);
785         if (n) {
786                 if (n->i_parent) {
787                         ldap_pvt_thread_rdwr_wlock(&n->i_parent->i_kids_rdwr);
788                         avl_delete(&n->i_parent->i_kids, &n->i_rdn->nrdn, node_frdn_cmp);
789                         ldap_pvt_thread_rdwr_wunlock(&n->i_parent->i_kids_rdwr);
790                 }
791                 free(n->i_rdn);
792                 ldap_pvt_thread_rdwr_destroy(&n->i_kids_rdwr);
793                 free(n);
794         }
795         if (e->e_id == 1)
796                 bdb->bi_troot = NULL;
797         ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr);
798
799         return rc;
800 }
801
802 int
803 bdb_dn2id_matched(
804         BackendDB       *be,
805         DB_TXN *txn,
806         struct berval   *in,
807         ID *id,
808         ID *id2,
809         int flags )
810 {
811         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
812         struct berval   rdn;
813         char            *p1, *p2;
814         idNode *n, *p;
815         int             rc = 0;
816
817         if (!bdb->bi_troot)
818                 return DB_NOTFOUND;
819
820         p = bdb->bi_troot;
821         if (be_issuffix(be, in)) {
822                 *id = p->i_id;
823                 return 0;
824         }
825
826         p1 = in->bv_val + in->bv_len - be->be_nsuffix[0].bv_len - 1;
827
828         n = p;
829         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
830         for (;;) {
831                 for (p2 = p1-1; (p2 >= in->bv_val) && !DN_SEPARATOR(*p2); p2--);
832                 rdn.bv_val = p2+1;
833                 rdn.bv_len = p1-rdn.bv_val;
834                 p1 = p2;
835
836                 ldap_pvt_thread_rdwr_rlock(&p->i_kids_rdwr);
837                 n = bdb_find_rdn_node(&rdn, p->i_kids);
838                 ldap_pvt_thread_rdwr_runlock(&p->i_kids_rdwr);
839                 if (!n || p2 < in->bv_val) break;
840                 p = n;
841         }
842         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
843
844         if (n) {
845                 *id = n->i_id;
846         } else if (id2) {
847                 *id2 = p->i_id;
848         } else {
849                 rc = DB_NOTFOUND;
850         }
851
852         return rc;
853 }
854
855 int
856 bdb_dn2id(
857         BackendDB       *be,
858         DB_TXN *txn,
859         struct berval   *dn,
860         ID *id,
861         int flags )
862 {
863         return bdb_dn2id_matched(be, txn, dn, id, NULL, flags);
864 }
865
866 int
867 bdb_dn2id_children(
868         BackendDB       *be,
869         DB_TXN *txn,
870         struct berval   *dn,
871         int flags )
872 {
873         int             rc;
874         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
875         ID              id;
876         idNode *n;
877
878         rc = bdb_dn2id(be, txn, dn, &id, flags);
879         if (rc != 0)
880                 return rc;
881
882         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
883         n = bdb_find_id_node(id, bdb->bi_tree);
884         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
885
886         if (!n->i_kids)
887                 return DB_NOTFOUND;
888         else
889                 return 0;
890 }
891
892 /* Since we don't store IDLs for onelevel or subtree, we have to construct
893  * them on the fly... Perhaps the i_kids tree ought to just be an IDL?
894  */
895 static int
896 insert_one(
897         void *v_n,
898         void *v_ids
899 )
900 {
901         idNode *n = v_n;
902         ID *ids = v_ids;
903         return bdb_idl_insert(ids, n->i_id);
904 }
905
906 static int
907 insert_sub(
908         void *v_n,
909         void *v_ids
910 )
911 {
912         idNode *n = v_n;
913         ID *ids = v_ids;
914         int rc;
915
916         rc = bdb_idl_insert(ids, n->i_id);
917         if (rc == 0) {
918                 ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
919                 rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER);
920                 ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
921         }
922         return rc;
923 }
924
925 int
926 bdb_dn2idl(
927         BackendDB       *be,
928         struct berval   *dn,
929         int prefix,
930         ID *ids )
931 {
932         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
933         int             rc;
934         ID              id;
935         idNode          *n;
936
937         if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) {
938                 BDB_IDL_ALL(bdb, ids);
939                 return 0;
940         }
941
942         rc = bdb_dn2id(be, NULL, dn, &id, 0);
943         if (rc) return rc;
944
945         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
946         n = bdb_find_id_node(id, bdb->bi_tree);
947         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
948
949         ids[0] = 0;
950         ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
951         if (prefix == DN_ONE_PREFIX) {
952                 rc = avl_apply(n->i_kids, insert_one, ids, -1, AVL_INORDER);
953         } else {
954                 ids[0] = 1;
955                 ids[1] = id;
956                 if (n->i_kids)
957                         rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER);
958         }
959         ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
960         return rc;
961 }
962 #endif  /* BDB_HIER */