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