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