]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
Happy new year
[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         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         const void *id,
617         const void *node
618 )
619 {
620         return *(const ID *)id - ((const idNode *)node)->i_id;
621 }
622
623 static int
624 node_frdn_cmp(
625         const void *v_nrdn,
626         const void *v_n
627 )
628 {
629         const struct berval *nrdn = v_nrdn;
630         const idNode *n = v_n;
631         return ber_bvcmp(nrdn, &n->i_rdn->nrdn);
632 }
633
634 static int
635 node_add_cmp(
636         const void *v_a,
637         const void *v_b
638 )
639 {
640         const idNode *a = v_a, *b = v_b;
641         return a->i_id - b->i_id;
642 }
643
644 static int
645 node_rdn_cmp(
646         const void *v_a,
647         const void *v_b
648 )
649 {
650         const idNode *a = v_a, *b = v_b;
651         /* should be slightly better without ordering drawbacks */
652         return ber_bvcmp(&a->i_rdn->nrdn, &b->i_rdn->nrdn);
653 }
654
655 idNode * bdb_find_id_node(
656         ID id,
657         Avlnode *tree
658 )
659 {
660         return avl_find(tree, &id, node_find_cmp);
661 }
662
663 idNode * bdb_find_rdn_node(
664         struct berval *nrdn,
665         Avlnode *tree
666 )
667 {
668         return avl_find(tree, nrdn, node_frdn_cmp);
669 }
670
671 /* This function links a node into its parent's i_kids tree. */
672 static int bdb_insert_kid(
673         void *v_a,
674         void *v_tree
675 )
676 {
677         idNode *a = v_a;
678         Avlnode *tree = v_tree;
679         int rc;
680
681         if (a->i_rdn->parent == 0)
682                 return 0;
683         a->i_parent = bdb_find_id_node(a->i_rdn->parent, tree);
684         if (!a->i_parent)
685                 return -1;
686         ldap_pvt_thread_rdwr_wlock(&a->i_parent->i_kids_rdwr);
687         rc = avl_insert( &a->i_parent->i_kids, (caddr_t) a,
688                          node_rdn_cmp, avl_dup_error );
689         ldap_pvt_thread_rdwr_wunlock(&a->i_parent->i_kids_rdwr);
690         return rc;
691 }
692
693 /* This function adds a node into the main AVL tree */
694 idNode *bdb_add_node(
695         ID id,
696         char *d,
697         struct bdb_info *bdb
698 )
699 {
700         idNode *node;
701
702         node = (idNode *)ch_malloc(sizeof(idNode));
703         node->i_id = id;
704         node->i_parent = NULL;
705         node->i_kids = NULL;
706         node->i_rdn = (diskNode *)d;
707         node->i_rdn->rdn.bv_val += (long)d;
708         node->i_rdn->nrdn.bv_val += (long)d;
709         ldap_pvt_thread_rdwr_init(&node->i_kids_rdwr);
710         avl_insert( &bdb->bi_tree, (caddr_t) node, node_add_cmp, avl_dup_error );
711         if (id == 1)
712                 bdb->bi_troot = node;
713         return node;
714 }
715
716 /* This function initializes the trees at startup time. */
717 int bdb_build_tree(
718         Backend *be
719 )
720 {
721         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
722         int rc;
723         DBC *cursor;
724         DBT key, data;
725         ID id;
726         idNode *node;
727
728         bdb->bi_tree = NULL;
729
730         rc = bdb->bi_id2parent->bdi_db->cursor(
731                 bdb->bi_id2parent->bdi_db, NULL, &cursor,
732                 bdb->bi_db_opflags );
733         if( rc != 0 ) {
734                 return NOID;
735         }
736
737         DBTzero( &key );
738         DBTzero( &data );
739         key.data = (char *)&id;
740         key.ulen = sizeof( id );
741         key.flags = DB_DBT_USERMEM;
742         data.flags = DB_DBT_MALLOC;
743
744         while (cursor->c_get( cursor, &key, &data, DB_NEXT ) == 0) {
745                 bdb_add_node( id, data.data, bdb );
746         }
747         cursor->c_close( cursor );
748
749         rc = avl_apply(bdb->bi_tree, bdb_insert_kid, bdb->bi_tree,
750                 -1, AVL_INORDER );
751
752         return rc;
753 }
754
755 /* This function constructs a full DN for a given id. We really should
756  * be passing idNodes directly, to save some effort...
757  */
758 int bdb_fix_dn(
759         BackendDB *be,
760         ID id,
761         Entry *e
762 )
763 {
764         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
765         idNode *n, *o;
766         int rlen, nrlen;
767         char *ptr, *nptr;
768         
769         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
770         o = bdb_find_id_node(id, bdb->bi_tree);
771         rlen = be->be_suffix[0].bv_len + 1;
772         nrlen = be->be_nsuffix[0].bv_len + 1;
773         for (n = o; n && n->i_parent; n=n->i_parent) {
774                 rlen += n->i_rdn->rdn.bv_len + 1;
775                 nrlen += n->i_rdn->nrdn.bv_len + 1;
776         }
777         e->e_name.bv_len = rlen - 1;
778         e->e_nname.bv_len = nrlen - 1;
779         e->e_name.bv_val = ch_malloc(rlen + nrlen);
780         e->e_nname.bv_val = e->e_name.bv_val + rlen;
781         ptr = e->e_name.bv_val;
782         nptr = e->e_nname.bv_val;
783         for (n = o; n && n->i_parent; n=n->i_parent) {
784                 ptr = lutil_strcopy(ptr, n->i_rdn->rdn.bv_val);
785                 *ptr++ = ',';
786                 nptr = lutil_strcopy(nptr, n->i_rdn->nrdn.bv_val);
787                 *nptr++ = ',';
788         }
789         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
790
791         strcpy(ptr, be->be_suffix[0].bv_val);
792         strcpy(nptr, be->be_nsuffix[0].bv_val);
793
794         return 0;
795 }
796
797 int
798 bdb_dn2id_add(
799         BackendDB       *be,
800         DB_TXN *txn,
801         struct berval   *pdn,
802         Entry           *e )
803 {
804         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
805         int             rc, rlen, nrlen;
806         DBT             key, data;
807         DB *db = bdb->bi_id2parent->bdi_db;
808         diskNode *d;
809         idNode *n;
810
811         nrlen = dn_rdnlen( be, &e->e_nname );
812         if (nrlen) {
813                 rlen = dn_rdnlen( be, &e->e_name );
814         } else {
815                 rlen = 0;
816         }
817
818         d = ch_malloc(sizeof(diskNode) + rlen + nrlen + 2);
819         d->rdn.bv_len = rlen;
820         d->nrdn.bv_len = nrlen;
821         d->rdn.bv_val = (char *)(d+1);
822         d->nrdn.bv_val = d->rdn.bv_val + rlen + 1;
823         strncpy(d->rdn.bv_val, e->e_dn, rlen);
824         d->rdn.bv_val[rlen] = '\0';
825         strncpy(d->nrdn.bv_val, e->e_ndn, nrlen);
826         d->nrdn.bv_val[nrlen] = '\0';
827         d->rdn.bv_val -= (long)d;
828         d->nrdn.bv_val -= (long)d;
829
830         if (pdn->bv_len) {
831                 bdb_dn2id(be, txn, pdn, &d->parent, 0);
832         } else {
833                 d->parent = 0;
834         }
835
836         DBTzero(&key);
837         DBTzero(&data);
838         key.data = &e->e_id;
839         key.size = sizeof(ID);
840         key.flags = DB_DBT_USERMEM;
841
842         data.data = d;
843         data.size = sizeof(diskNode) + rlen + nrlen + 2;
844         data.flags = DB_DBT_USERMEM;
845
846         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
847
848         if (rc == 0) {
849                 ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr);
850                 n = bdb_add_node( e->e_id, data.data, bdb);
851                 ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr);
852
853                 if (d->parent) {
854                         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
855                         bdb_insert_kid(n, bdb->bi_tree);
856                         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
857                 }
858         } else {
859                 free(d);
860         }
861         return rc;
862 }
863
864 int
865 bdb_dn2id_delete(
866         BackendDB       *be,
867         DB_TXN *txn,
868         char    *pdn,
869         Entry   *e )
870 {
871         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
872         int rc;
873         DBT             key;
874         DB *db = bdb->bi_id2parent->bdi_db;
875         idNode *n;
876
877         DBTzero(&key);
878         key.size = sizeof(e->e_id);
879         key.data = &e->e_id;
880
881         rc = db->del( db, txn, &key, 0);
882
883         ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr);
884         n = avl_delete(&bdb->bi_tree, &e->e_id, node_find_cmp);
885         if (n) {
886                 if (n->i_parent) {
887                         ldap_pvt_thread_rdwr_wlock(&n->i_parent->i_kids_rdwr);
888                         avl_delete(&n->i_parent->i_kids, &n->i_rdn->nrdn, node_frdn_cmp);
889                         ldap_pvt_thread_rdwr_wunlock(&n->i_parent->i_kids_rdwr);
890                 }
891                 free(n->i_rdn);
892                 ldap_pvt_thread_rdwr_destroy(&n->i_kids_rdwr);
893                 free(n);
894         }
895         if (e->e_id == 1)
896                 bdb->bi_troot = NULL;
897         ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr);
898
899         return rc;
900 }
901
902 int
903 bdb_dn2id_matched(
904         BackendDB       *be,
905         DB_TXN *txn,
906         struct berval   *in,
907         ID *id,
908         ID *id2,
909         int flags )
910 {
911         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
912         struct berval   rdn;
913         char            *p1, *p2;
914         idNode *n, *p;
915
916         if (!bdb->bi_troot)
917                 return DB_NOTFOUND;
918
919         p = bdb->bi_troot;
920         if (be_issuffix(be, in)) {
921                 *id = p->i_id;
922                 return 0;
923         }
924
925         p1 = in->bv_val + in->bv_len - be->be_nsuffix[0].bv_len - 1;
926
927         n = p;
928         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
929         for (;;) {
930                 for (p2 = p1-1; (p2 >= in->bv_val) && !DN_SEPARATOR(*p2); p2--);
931                 rdn.bv_val = p2+1;
932                 rdn.bv_len = p1-rdn.bv_val;
933                 p1 = p2;
934
935                 ldap_pvt_thread_rdwr_rlock(&p->i_kids_rdwr);
936                 n = bdb_find_rdn_node(&rdn, p->i_kids);
937                 ldap_pvt_thread_rdwr_runlock(&p->i_kids_rdwr);
938                 if (!n || p2 < in->bv_val) break;
939                 p = n;
940         }
941         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
942
943         if (n) {
944                 *id = n->i_id;
945         } else if (id2) {
946                 *id2 = p->i_id;
947         }
948         return n ? 0 : DB_NOTFOUND;
949 }
950
951 int
952 bdb_dn2id(
953         BackendDB       *be,
954         DB_TXN *txn,
955         struct berval   *dn,
956         ID *id,
957         int flags )
958 {
959         return bdb_dn2id_matched(be, txn, dn, id, NULL, flags);
960 }
961
962 int
963 bdb_dn2id_children(
964         BackendDB       *be,
965         DB_TXN *txn,
966         struct berval   *dn,
967         int flags )
968 {
969         int             rc;
970         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
971         ID              id;
972         idNode *n;
973
974         rc = bdb_dn2id(be, txn, dn, &id, flags);
975         if (rc != 0)
976                 return rc;
977
978         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
979         n = bdb_find_id_node(id, bdb->bi_tree);
980         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
981
982         if (!n->i_kids)
983                 return DB_NOTFOUND;
984         else
985                 return 0;
986 }
987
988 /* Since we don't store IDLs for onelevel or subtree, we have to construct
989  * them on the fly... Perhaps the i_kids tree ought to just be an IDL?
990  */
991 static int
992 insert_one(
993         void *v_n,
994         void *v_ids
995 )
996 {
997         idNode *n = v_n;
998         ID *ids = v_ids;
999         return bdb_idl_insert(ids, n->i_id);
1000 }
1001
1002 static int
1003 insert_sub(
1004         void *v_n,
1005         void *v_ids
1006 )
1007 {
1008         idNode *n = v_n;
1009         ID *ids = v_ids;
1010         int rc;
1011
1012         rc = bdb_idl_insert(ids, n->i_id);
1013         if (rc == 0) {
1014                 ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
1015                 rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER);
1016                 ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
1017         }
1018         return rc;
1019 }
1020
1021 int
1022 bdb_dn2idl(
1023         BackendDB       *be,
1024         struct berval   *dn,
1025         int prefix,
1026         ID *ids )
1027 {
1028         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1029         int             rc;
1030         ID              id;
1031         idNode          *n;
1032
1033         if (prefix == DN_SUBTREE_PREFIX && be_issuffix(be, dn)) {
1034                 BDB_IDL_ALL(bdb, ids);
1035                 return 0;
1036         }
1037
1038         rc = bdb_dn2id(be, NULL, dn, &id, 0);
1039         if (rc) return rc;
1040
1041         ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr);
1042         n = bdb_find_id_node(id, bdb->bi_tree);
1043         ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr);
1044
1045         ids[0] = 0;
1046         ldap_pvt_thread_rdwr_rlock(&n->i_kids_rdwr);
1047         if (prefix == DN_ONE_PREFIX) {
1048                 rc = avl_apply(n->i_kids, insert_one, ids, -1, AVL_INORDER);
1049         } else {
1050                 rc = avl_apply(n->i_kids, insert_sub, ids, -1, AVL_INORDER);
1051         }
1052         ldap_pvt_thread_rdwr_runlock(&n->i_kids_rdwr);
1053         return rc;
1054 }
1055 #endif  /* BDB_HIER */