]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/dn2id.c
back-hdb caching updates, use EntryInfo cache for hdb_dn2idl.
[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         Operation *op,
21         DB_TXN *txn,
22         EntryInfo *eip,
23         Entry           *e )
24 {
25         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->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 = op->o_tmpalloc( key.size, op->o_tmpmemctx );
46         key.data = buf;
47         buf[0] = DN_BASE_PREFIX;
48         ptr.bv_val = buf + 1;
49         ptr.bv_len = e->e_nname.bv_len;
50         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
51         ptr.bv_val[ptr.bv_len] = '\0';
52
53         DBTzero( &data );
54         data.data = (char *) &e->e_id;
55         data.size = sizeof( e->e_id );
56
57         /* store it -- don't override */
58         rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
59         if( rc != 0 ) {
60 #ifdef NEW_LOGGING
61                 LDAP_LOG ( INDEX, ERR, "bdb_dn2id_add: put failed: %s %d\n",
62                         db_strerror(rc), rc, 0 );
63 #else
64                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
65                         db_strerror(rc), rc, 0 );
66 #endif
67                 goto done;
68         }
69
70 #ifndef BDB_MULTIPLE_SUFFIXES
71         if( !be_issuffix( op->o_bd, &ptr )) {
72 #endif
73                 buf[0] = DN_SUBTREE_PREFIX;
74                 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
75                 if( rc != 0 ) {
76 #ifdef NEW_LOGGING
77                         LDAP_LOG ( INDEX, ERR, 
78                                 "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
79                                 ptr.bv_val, rc, 0 );
80 #else
81                         Debug( LDAP_DEBUG_ANY,
82                         "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
83                         ptr.bv_val, rc, 0 );
84 #endif
85                         goto done;
86                 }
87                 
88 #ifdef BDB_MULTIPLE_SUFFIXES
89         if( !be_issuffix( op->o_bd, &ptr )) {
90 #endif
91                 dnParent( &ptr, &pdn );
92         
93                 key.size = pdn.bv_len + 2;
94                 key.ulen = key.size;
95                 pdn.bv_val[-1] = DN_ONE_PREFIX;
96                 key.data = pdn.bv_val-1;
97                 ptr = pdn;
98
99                 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
100
101                 if( rc != 0 ) {
102 #ifdef NEW_LOGGING
103                         LDAP_LOG ( INDEX, ERR, 
104                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
105                                 ptr.bv_val, rc, 0 );
106 #else
107                         Debug( LDAP_DEBUG_ANY,
108                                 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
109                                         ptr.bv_val, rc, 0 );
110 #endif
111                         goto done;
112                 }
113 #ifndef BDB_MULTIPLE_SUFFIXES
114         }
115
116         while( !be_issuffix( op->o_bd, &ptr )) {
117 #else
118         for (;;) {
119 #endif
120                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
121
122                 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
123
124                 if( rc != 0 ) {
125 #ifdef NEW_LOGGING
126                         LDAP_LOG ( INDEX, ERR, 
127                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
128                                 ptr.bv_val, rc, 0 );
129 #else
130                         Debug( LDAP_DEBUG_ANY,
131                                 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
132                                         ptr.bv_val, rc, 0 );
133 #endif
134                         break;
135                 }
136 #ifdef BDB_MULTIPLE_SUFFIXES
137                 if( be_issuffix( op->o_bd, &ptr )) break;
138 #endif
139                 dnParent( &ptr, &pdn );
140
141                 key.size = pdn.bv_len + 2;
142                 key.ulen = key.size;
143                 key.data = pdn.bv_val - 1;
144                 ptr = pdn;
145         }
146 #ifdef BDB_MULTIPLE_SUFFIXES
147         }
148 #endif
149
150 done:
151         op->o_tmpfree( buf, op->o_tmpmemctx );
152 #ifdef NEW_LOGGING
153         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
154 #else
155         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
156 #endif
157         return rc;
158 }
159
160 int
161 bdb_dn2id_delete(
162         Operation *op,
163         DB_TXN *txn,
164         EntryInfo       *eip,
165         Entry           *e )
166 {
167         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
168         DB *db = bdb->bi_dn2id->bdi_db;
169         int             rc;
170         DBT             key;
171         char            *buf;
172         struct berval   pdn, ptr;
173
174 #ifdef NEW_LOGGING
175         LDAP_LOG ( INDEX, ARGS, 
176                 "=> bdb_dn2id_delete ( \"%s\", 0x%08lx )\n", e->e_ndn, e->e_id, 0);
177 #else
178         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
179                 e->e_ndn, e->e_id, 0 );
180 #endif
181
182         DBTzero( &key );
183         key.size = e->e_nname.bv_len + 2;
184         buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
185         key.data = buf;
186         key.flags = DB_DBT_USERMEM;
187         buf[0] = DN_BASE_PREFIX;
188         ptr.bv_val = buf+1;
189         ptr.bv_len = e->e_nname.bv_len;
190         AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
191         ptr.bv_val[ptr.bv_len] = '\0';
192
193         /* delete it */
194         rc = db->del( db, txn, &key, 0 );
195         if( rc != 0 ) {
196 #ifdef NEW_LOGGING
197                 LDAP_LOG ( INDEX, ERR, 
198                         "=> bdb_dn2id_delete: delete failed: %s %d\n", 
199                         db_strerror(rc), rc, 0 );
200 #else
201                 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
202                         db_strerror(rc), rc, 0 );
203 #endif
204                 goto done;
205         }
206
207 #ifndef BDB_MULTIPLE_SUFFIXES
208         if( !be_issuffix( op->o_bd, &ptr )) {
209 #endif
210                 buf[0] = DN_SUBTREE_PREFIX;
211                 rc = db->del( db, txn, &key, 0 );
212                 if( rc != 0 ) {
213 #ifdef NEW_LOGGING
214                         LDAP_LOG ( INDEX, ERR, 
215                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
216                                 ptr.bv_val, rc, 0 );
217 #else
218                         Debug( LDAP_DEBUG_ANY,
219                         "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
220                         ptr.bv_val, rc, 0 );
221 #endif
222                         goto done;
223                 }
224
225 #ifdef BDB_MULTIPLE_SUFFIXES
226         if( !be_issuffix( op->o_bd, &ptr )) {
227 #endif
228                 dnParent( &ptr, &pdn );
229
230                 key.size = pdn.bv_len + 2;
231                 key.ulen = key.size;
232                 pdn.bv_val[-1] = DN_ONE_PREFIX;
233                 key.data = pdn.bv_val - 1;
234                 ptr = pdn;
235
236                 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
237
238                 if( rc != 0 ) {
239 #ifdef NEW_LOGGING
240                         LDAP_LOG ( INDEX, ERR, 
241                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n", 
242                                 ptr.bv_val, rc, 0 );
243 #else
244                         Debug( LDAP_DEBUG_ANY,
245                                 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
246                                 ptr.bv_val, rc, 0 );
247 #endif
248                         goto done;
249                 }
250 #ifndef BDB_MULTIPLE_SUFFIXES
251         }
252
253         while( !be_issuffix( op->o_bd, &ptr )) {
254 #else
255         for (;;) {
256 #endif
257                 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
258
259                 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
260                 if( rc != 0 ) {
261 #ifdef NEW_LOGGING
262                         LDAP_LOG ( INDEX, ERR, 
263                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n", 
264                                 ptr.bv_val, rc, 0 );
265 #else
266                         Debug( LDAP_DEBUG_ANY,
267                                 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
268                                 ptr.bv_val, rc, 0 );
269 #endif
270                         goto done;
271                 }
272 #ifdef BDB_MULTIPLE_SUFFIXES
273                 if( be_issuffix( op->o_bd, &ptr )) break;
274 #endif
275                 dnParent( &ptr, &pdn );
276
277                 key.size = pdn.bv_len + 2;
278                 key.ulen = key.size;
279                 key.data = pdn.bv_val - 1;
280                 ptr = pdn;
281         }
282 #ifdef BDB_MULTIPLE_SUFFIXES
283         }
284 #endif
285
286 done:
287         op->o_tmpfree( buf, op->o_tmpmemctx );
288 #ifdef NEW_LOGGING
289         LDAP_LOG ( INDEX, RESULTS, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
290 #else
291         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
292 #endif
293         return rc;
294 }
295
296 int
297 bdb_dn2id(
298         Operation *op,
299         DB_TXN *txn,
300         struct berval   *dn,
301         EntryInfo *ei )
302 {
303         int             rc;
304         DBT             key, data;
305         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
306         DB *db = bdb->bi_dn2id->bdi_db;
307
308 #ifdef NEW_LOGGING
309         LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
310 #else
311         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
312 #endif
313         DBTzero( &key );
314         key.size = dn->bv_len + 2;
315         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
316         ((char *)key.data)[0] = DN_BASE_PREFIX;
317         AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
318
319         /* store the ID */
320         DBTzero( &data );
321         data.data = &ei->bei_id;
322         data.ulen = sizeof(ID);
323         data.flags = DB_DBT_USERMEM;
324
325         /* fetch it */
326         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
327
328         if( rc != 0 ) {
329 #ifdef NEW_LOGGING
330                 LDAP_LOG ( INDEX, ERR, "<= bdb_dn2id: get failed %s (%d)\n", 
331                         db_strerror(rc), rc, 0 );
332 #else
333                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
334                         db_strerror( rc ), rc, 0 );
335 #endif
336         } else {
337 #ifdef NEW_LOGGING
338                 LDAP_LOG ( INDEX, RESULTS, 
339                         "<= bdb_dn2id: got id=0x%08lx\n", ei->bei_id, 0, 0 );
340 #else
341                 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
342                         ei->bei_id, 0, 0 );
343 #endif
344         }
345
346         op->o_tmpfree( key.data, op->o_tmpmemctx );
347         return rc;
348 }
349
350 int
351 bdb_dn2id_children(
352         Operation *op,
353         DB_TXN *txn,
354         Entry *e )
355 {
356         DBT             key, data;
357         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
358         DB *db = bdb->bi_dn2id->bdi_db;
359         ID              id;
360         int             rc;
361
362 #ifdef NEW_LOGGING
363         LDAP_LOG ( INDEX, ARGS, 
364                 "=> bdb_dn2id_children( %s )\n", e->e_nname.bv_val, 0, 0 );
365 #else
366         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n",
367                 e->e_nname.bv_val, 0, 0 );
368 #endif
369         DBTzero( &key );
370         key.size = e->e_nname.bv_len + 2;
371         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
372         ((char *)key.data)[0] = DN_ONE_PREFIX;
373         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
374
375 #ifdef SLAP_IDL_CACHE
376         if ( bdb->bi_idl_cache_size ) {
377                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
378                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
379                         op->o_tmpfree( key.data, op->o_tmpmemctx );
380                         return rc;
381                 }
382         }
383 #endif
384         /* we actually could do a empty get... */
385         DBTzero( &data );
386         data.data = &id;
387         data.ulen = sizeof(id);
388         data.flags = DB_DBT_USERMEM;
389         data.doff = 0;
390         data.dlen = sizeof(id);
391
392         rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
393         op->o_tmpfree( key.data, op->o_tmpmemctx );
394
395 #ifdef NEW_LOGGING
396         LDAP_LOG ( INDEX, DETAIL1, 
397                 "<= bdb_dn2id_children( %s ): %s (%d)\n", 
398                 e->e_nname.bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
399                 db_strerror(rc)), rc );
400 #else
401         Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %s (%d)\n",
402                 e->e_nname.bv_val,
403                 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
404                         db_strerror(rc) ), rc );
405 #endif
406
407         return rc;
408 }
409
410 int
411 bdb_dn2idl(
412         Operation *op,
413         Entry *e,
414         ID *ids,
415         ID *stack )
416 {
417         int             rc;
418         DBT             key;
419         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
420         DB *db = bdb->bi_dn2id->bdi_db;
421         int prefix = op->ors_scope == LDAP_SCOPE_SUBTREE ? DN_SUBTREE_PREFIX :
422                         DN_ONE_PREFIX;
423
424 #ifdef NEW_LOGGING
425         LDAP_LOG ( INDEX, ARGS, 
426                 "=> bdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
427 #else
428         Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
429 #endif
430
431 #ifndef BDB_MULTIPLE_SUFFIXES
432         if (prefix == DN_SUBTREE_PREFIX && BEI(e)->bei_parent->bei_id == 0 )
433         {
434                 BDB_IDL_ALL(bdb, ids);
435                 return 0;
436         }
437 #endif
438
439         DBTzero( &key );
440         key.size = e->e_nname.bv_len + 2;
441         key.ulen = key.size;
442         key.flags = DB_DBT_USERMEM;
443         key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
444         ((char *)key.data)[0] = prefix;
445         AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
446
447         rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids );
448
449         if( rc != 0 ) {
450 #ifdef NEW_LOGGING
451                 LDAP_LOG ( INDEX, ERR, 
452                         "<= bdb_dn2ididl: get failed: %s (%d)\n", db_strerror(rc), rc, 0 );
453 #else
454                 Debug( LDAP_DEBUG_TRACE,
455                         "<= bdb_dn2idl: get failed: %s (%d)\n",
456                         db_strerror( rc ), rc, 0 );
457 #endif
458
459         } else {
460 #ifdef NEW_LOGGING
461                 LDAP_LOG ( INDEX, RESULTS, 
462                         "<= bdb_dn2ididl: id=%ld first=%ld last=%ld\n", 
463                         (long) ids[0], (long) BDB_IDL_FIRST( ids ), 
464                         (long) BDB_IDL_LAST( ids ) );
465 #else
466                 Debug( LDAP_DEBUG_TRACE,
467                         "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
468                         (long) ids[0],
469                         (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
470 #endif
471         }
472
473         op->o_tmpfree( key.data, op->o_tmpmemctx );
474         return rc;
475 }
476 #else   /* BDB_HIER */
477
478 /* Experimental management routines for a hierarchically structured database.
479  *
480  * Unsupported! Use at your own risk!
481  * -- Howard Chu, Symas Corp. 2003.
482  *
483  * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
484  * entry in this database is a struct diskNode, keyed by entryID and with
485  * the data containing the RDN and entryID of the node's children. We use
486  * a B-Tree with sorted duplicates to store all the children of a node under
487  * the same key. Also, the first item under the key contains the entry's own
488  * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
489  * well as top-down. To keep this info first in the list, the nrdnlen is set
490  * to the negative of its value.
491  *
492  * The diskNode is a variable length structure. This definition is not
493  * directly usable for in-memory manipulation.
494  */
495 typedef struct diskNode {
496         ID entryID;
497         short nrdnlen;
498         char nrdn[1];
499         char rdn[1];
500 } diskNode;
501
502 /* Sort function for the sorted duplicate data items of a dn2id key.
503  * Sorts based on normalized RDN, in length order.
504  */
505 int
506 hdb_dup_compare(
507         DB *db, 
508         const DBT *usrkey,
509         const DBT *curkey
510 )
511 {
512         char *u = (char *)&(((diskNode *)(usrkey->data))->nrdnlen);
513         char *c = (char *)&(((diskNode *)(curkey->data))->nrdnlen);
514         int rc, i;
515
516         /* data is not aligned, cannot compare directly */
517 #ifdef WORDS_BIGENDIAN
518         for( i = 0; i < (int)sizeof(short); i++)
519 #else
520         for( i = sizeof(short)-1; i >= 0; i--)
521 #endif
522         {
523                 rc = u[i] - c[i];
524                 if( rc ) return rc;
525         }
526         return strcmp( u+sizeof(short), c+sizeof(short) );
527 }
528
529 /* This function constructs a full DN for a given entry.
530  */
531 int hdb_fix_dn(
532         Entry *e,
533         int checkit
534 )
535 {
536         EntryInfo *ei;
537         int rlen = 0, nrlen = 0;
538         char *ptr, *nptr;
539         int max = 0;
540
541         /* count length of all DN components */
542         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
543                 rlen += ei->bei_rdn.bv_len + 1;
544                 nrlen += ei->bei_nrdn.bv_len + 1;
545                 if (ei->bei_modrdns > max) max = ei->bei_modrdns;
546         }
547
548         /* See if the entry DN was invalidated by a subtree rename */
549         if ( checkit ) {
550                 if ( BEI(e)->bei_modrdns >= max ) {
551                         return 0;
552                 }
553                 /* We found a mismatch, tell the caller to lock it */
554                 if ( checkit == 1 ) {
555                         return 1;
556                 }
557                 /* checkit == 2. do the fix. */
558                 free( e->e_name.bv_val );
559                 free( e->e_nname.bv_val );
560         }
561
562         e->e_name.bv_len = rlen - 1;
563         e->e_nname.bv_len = nrlen - 1;
564         e->e_name.bv_val = ch_malloc(rlen);
565         e->e_nname.bv_val = ch_malloc(nrlen);
566         ptr = e->e_name.bv_val;
567         nptr = e->e_nname.bv_val;
568         for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
569                 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
570                 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
571                 if ( ei->bei_parent ) {
572                         *ptr++ = ',';
573                         *nptr++ = ',';
574                 }
575         }
576         BEI(e)->bei_modrdns = max;
577         ptr[-1] = '\0';
578         nptr[-1] = '\0';
579
580         return 0;
581 }
582
583 /* We add two elements to the DN2ID database - a data item under the parent's
584  * entryID containing the child's RDN and entryID, and an item under the
585  * child's entryID containing the parent's entryID.
586  */
587 int
588 hdb_dn2id_add(
589         Operation       *op,
590         DB_TXN *txn,
591         EntryInfo       *eip,
592         Entry           *e )
593 {
594         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
595         DB *db = bdb->bi_dn2id->bdi_db;
596         DBT             key, data;
597         int             rc, rlen, nrlen;
598         diskNode *d;
599         char *ptr;
600
601         nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
602         if (nrlen) {
603                 rlen = dn_rdnlen( op->o_bd, &e->e_name );
604         } else {
605                 nrlen = e->e_nname.bv_len;
606                 rlen = e->e_name.bv_len;
607         }
608
609         d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
610         d->entryID = e->e_id;
611         d->nrdnlen = nrlen;
612         ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
613         *ptr++ = '\0';
614         ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
615         *ptr = '\0';
616
617         DBTzero(&key);
618         DBTzero(&data);
619         key.data = &eip->bei_id;
620         key.size = sizeof(ID);
621         key.flags = DB_DBT_USERMEM;
622
623 #ifdef SLAP_IDL_CACHE
624         if ( bdb->bi_idl_cache_size ) {
625                 bdb_idl_cache_del( bdb, db, &key );
626         }
627 #endif
628         data.data = d;
629         data.size = sizeof(diskNode) + rlen + nrlen;
630         data.flags = DB_DBT_USERMEM;
631
632         rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
633
634         if (rc == 0) {
635                 key.data = &e->e_id;
636                 d->entryID = eip->bei_id;
637                 d->nrdnlen = 0 - nrlen;
638
639                 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
640         }
641
642         op->o_tmpfree( d, op->o_tmpmemctx );
643
644         return rc;
645 }
646
647 int
648 hdb_dn2id_delete(
649         Operation       *op,
650         DB_TXN *txn,
651         EntryInfo       *eip,
652         Entry   *e )
653 {
654         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
655         DB *db = bdb->bi_dn2id->bdi_db;
656         DBT             key, data;
657         DBC     *cursor;
658         diskNode *d;
659         int rc, nrlen;
660
661         DBTzero(&key);
662         key.size = sizeof(ID);
663         key.ulen = key.size;
664         key.data = &eip->bei_id;
665         key.flags = DB_DBT_USERMEM;
666
667         DBTzero(&data);
668         data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
669         data.ulen = data.size;
670         data.dlen = data.size;
671         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
672
673 #ifdef SLAP_IDL_CACHE
674         if ( bdb->bi_idl_cache_size ) {
675                 bdb_idl_cache_del( bdb, db, &key );
676         }
677 #endif
678         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
679         if ( rc ) return rc;
680
681         d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
682         d->entryID = e->e_id;
683         d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
684         strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
685         data.data = d;
686
687         /* Delete our ID from the parent's list */
688         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
689         if ( rc == 0 )
690                 rc = cursor->c_del( cursor, 0 );
691
692         /* Delete our ID from the tree. With sorted duplicates, this
693          * will leave any child nodes still hanging around. This is OK
694          * for modrdn, which will add our info back in later.
695          */
696         if ( rc == 0 ) {
697                 key.data = &e->e_id;
698                 rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
699                 if ( rc == 0 )
700                         rc = cursor->c_del( cursor, 0 );
701         }
702         cursor->c_close( cursor );
703         op->o_tmpfree( d, op->o_tmpmemctx );
704
705         return rc;
706 }
707
708
709 int
710 hdb_dn2id(
711         Operation       *op,
712         DB_TXN *txn,
713         struct berval   *in,
714         EntryInfo       *ei )
715 {
716         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
717         DB *db = bdb->bi_dn2id->bdi_db;
718         DBT             key, data;
719         DBC     *cursor;
720         int             rc = 0, nrlen;
721         diskNode *d;
722         char    *ptr;
723         ID idp = ei->bei_parent->bei_id;
724
725         nrlen = dn_rdnlen( op->o_bd, in );
726         if (!nrlen) nrlen = in->bv_len;
727
728         DBTzero(&key);
729         key.size = sizeof(ID);
730         key.data = &idp;
731         key.ulen = sizeof(ID);
732         key.flags = DB_DBT_USERMEM;
733
734         DBTzero(&data);
735         data.size = sizeof(diskNode) + nrlen;
736         data.ulen = data.size * 3;
737         data.flags = DB_DBT_USERMEM;
738
739         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
740         if ( rc ) return rc;
741
742         d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
743         d->nrdnlen = nrlen;
744         ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
745         *ptr = '\0';
746         data.data = d;
747
748         rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
749         if ( rc == 0 ) {
750                 ei->bei_id = d->entryID;
751                 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
752                 ptr = d->nrdn + nrlen + 1;
753                 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
754                 if ( !ei->bei_parent->bei_dkids ) {
755                         db_recno_t dkids;
756                         /* How many children does the parent have? */
757                         /* FIXME: do we need to lock the parent
758                          * entryinfo? Seems safe...
759                          */
760                         cursor->c_count( cursor, &dkids, 0 );
761                         ei->bei_parent->bei_dkids = dkids;
762                 }
763         }
764         cursor->c_close( cursor );
765         op->o_tmpfree( d, op->o_tmpmemctx );
766
767         return rc;
768 }
769
770 static void
771 hdb_dn2ei(
772         char    *buf,
773         int     len,
774         EntryInfo       *ei )
775 {
776         diskNode *d = (diskNode *)buf;
777         char *ptr;
778
779         AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
780         AC_MEMCPY( &ei->bei_nrdn.bv_len, &d->nrdnlen, sizeof(d->nrdnlen) );
781         ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 0, &ei->bei_nrdn );
782         ei->bei_rdn.bv_len = len - sizeof(diskNode) - ei->bei_nrdn.bv_len;
783         ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
784         ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
785 }
786
787 int
788 hdb_dn2id_parent(
789         Operation *op,
790         DB_TXN *txn,
791         EntryInfo *ei,
792         ID *idp )
793 {
794         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
795         DB *db = bdb->bi_dn2id->bdi_db;
796         DBT             key, data;
797         DBC     *cursor;
798         int             rc = 0;
799         diskNode *d;
800         char    *ptr;
801         unsigned char *pt2;
802
803         DBTzero(&key);
804         key.size = sizeof(ID);
805         key.data = &ei->bei_id;
806         key.ulen = sizeof(ID);
807         key.flags = DB_DBT_USERMEM;
808
809         DBTzero(&data);
810         data.flags = DB_DBT_USERMEM;
811
812         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
813         if ( rc ) return rc;
814
815         data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
816         d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
817         data.data = d;
818
819         rc = cursor->c_get( cursor, &key, &data, DB_SET );
820         if ( rc == 0 ) {
821                 if (d->nrdnlen >= 0) {
822                         rc = LDAP_OTHER;
823                 } else {
824                         db_recno_t dkids;
825                         *idp = d->entryID;
826                         ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
827                         ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
828                         ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
829                                 ei->bei_nrdn.bv_len;
830                         ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
831                         ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
832                         /* How many children does this node have? */
833                         cursor->c_count( cursor, &dkids, 0 );
834                         ei->bei_dkids = dkids;
835                 }
836         }
837         cursor->c_close( cursor );
838         op->o_tmpfree( d, op->o_tmpmemctx );
839         return rc;
840 }
841
842 int
843 hdb_dn2id_children(
844         Operation *op,
845         DB_TXN *txn,
846         Entry *e )
847 {
848         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
849         DB *db = bdb->bi_dn2id->bdi_db;
850         DBT             key, data;
851         DBC             *cursor;
852         int             rc;
853         ID              id;
854         diskNode d;
855
856         DBTzero(&key);
857         key.size = sizeof(ID);
858         key.data = &e->e_id;
859         key.flags = DB_DBT_USERMEM;
860
861 #ifdef SLAP_IDL_CACHE
862         if ( bdb->bi_idl_cache_size ) {
863                 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
864                 if ( rc != LDAP_NO_SUCH_OBJECT ) {
865                         return rc;
866                 }
867         }
868 #endif
869         DBTzero(&data);
870         data.data = &d;
871         data.ulen = sizeof(d);
872         data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
873         data.dlen = sizeof(d);
874
875         rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
876         if ( rc ) return rc;
877
878         rc = cursor->c_get( cursor, &key, &data, DB_SET );
879         if ( rc == 0 ) {
880                 db_recno_t dkids;
881                 rc = cursor->c_count( cursor, &dkids, 0 );
882                 if ( rc == 0 ) {
883                         BEI(e)->bei_dkids = dkids;
884                         if ( dkids < 2 ) rc = DB_NOTFOUND;
885                 }
886         }
887         cursor->c_close( cursor );
888         return rc;
889 }
890
891 /* bdb_dn2idl:
892  * We can't just use bdb_idl_fetch_key because
893  * 1 - our data items are longer than just an entry ID
894  * 2 - our data items are sorted alphabetically by nrdn, not by ID.
895  *
896  * We descend the tree recursively, so we define this cookie
897  * to hold our necessary state information. The bdb_dn2idl_internal
898  * function uses this cookie when calling itself.
899  */
900
901 struct dn2id_cookie {
902         struct bdb_info *bdb;
903         DB *db;
904         int prefix;
905         int rc;
906         EntryInfo *ei;
907         ID id;
908         ID dbuf;
909         ID *ids;
910         void *ptr;
911         ID tmp[BDB_IDL_DB_SIZE];
912         ID *buf;
913         DBT key;
914         DBT data;
915         DBC *dbc;
916         Operation *op;
917 };
918
919 struct apply_arg {
920         ID *idl;
921         EntryInfo **ei;
922 };
923
924 static int
925 apply_func(
926         void *data,
927         void *arg )
928 {
929         EntryInfo *ei = data;
930         struct apply_arg *ap = arg;
931
932         bdb_idl_insert( ap->idl, ei->bei_id );
933         if ( ap->ei ) {
934                 *(ap->ei)++ = ei;
935         }
936         return 0;
937 }
938
939 static int
940 hdb_dn2idl_internal(
941         struct dn2id_cookie *cx
942 )
943 {
944         EntryInfo **eilist = NULL, **ptr;
945 #ifdef SLAP_IDL_CACHE
946         if ( cx->bdb->bi_idl_cache_size ) {
947                 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
948                 if ( cx->rc == DB_NOTFOUND ) {
949                         return cx->rc;
950                 }
951                 if ( cx->rc == LDAP_SUCCESS ) {
952                         goto gotit;
953                 }
954         }
955 #endif
956         BDB_IDL_ZERO( cx->tmp );
957
958         if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
959                 EntryInfo ei;
960                 ei.bei_parent = cx->ei;
961
962                 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
963                         cx->bdb->bi_db_opflags );
964                 if ( cx->rc ) return cx->rc;
965
966                 cx->data.data = &cx->dbuf;
967                 cx->data.ulen = sizeof(ID);
968                 cx->data.dlen = sizeof(ID);
969                 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
970
971                 /* The first item holds the parent ID. Ignore it. */
972                 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
973                 if ( cx->rc == DB_NOTFOUND ) goto saveit;
974                 if ( cx->rc ) return cx->rc;
975
976                 if ( !cx->ei->bei_dkids ) {
977                         db_recno_t dkids;
978                         cx->dbc->c_count( cx->dbc, &dkids, 0 );
979                         cx->ei->bei_dkids = dkids;
980                 }
981
982                 if ( cx->prefix == DN_SUBTREE_PREFIX && cx->ei->bei_dkids > 1 ) {
983                         eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
984                         eilist[cx->ei->bei_dkids-1] = NULL;
985                         ptr = eilist;
986                 }
987
988                 cx->data.data = cx->buf;
989                 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
990                 cx->data.flags = DB_DBT_USERMEM;
991
992                 /* Fetch the rest of the IDs in a loop... */
993                 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
994                         DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
995                         u_int8_t *j;
996                         size_t len;
997                         DB_MULTIPLE_INIT( cx->ptr, &cx->data );
998                         while (cx->ptr) {
999                                 DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
1000                                 if (j) {
1001                                         EntryInfo *ei2;
1002                                         hdb_dn2ei( j, len, &ei );
1003                                         bdb_idl_insert( cx->tmp, ei.bei_id );
1004                                         hdb_entryinfo_load( cx->bdb, &ei, &ei2 );
1005                                         if ( eilist )
1006                                                 *ptr++ = ei2;
1007                                 }
1008                         }
1009                 }
1010                 cx->dbc->c_close( cx->dbc );
1011         } else {
1012                 if ( cx->ei->bei_ckids > 0 ) {
1013                         struct apply_arg ap;
1014                         if ( cx->prefix == DN_SUBTREE_PREFIX ) {
1015                                 eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
1016                                 eilist[cx->ei->bei_dkids-1] = NULL;
1017                         }
1018                         ap.idl = cx->tmp;
1019                         ap.ei = eilist;
1020                         bdb_cache_entryinfo_lock( cx->ei );
1021                         avl_apply( cx->ei->bei_kids, apply_func, &ap, -1, AVL_POSTORDER );
1022                         bdb_cache_entryinfo_unlock( cx->ei );
1023                 }
1024         }
1025
1026         /* If we got some records, treat as success */
1027         if (!BDB_IDL_IS_ZERO(cx->tmp)) {
1028                 cx->rc = 0;
1029         }
1030
1031 saveit:
1032 #ifdef SLAP_IDL_CACHE
1033         if ( cx->bdb->bi_idl_cache_max_size ) {
1034                 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
1035         }
1036 #endif
1037         ;
1038 gotit:
1039         if ( cx->rc == 0 ) {
1040                 /* If eilist is NULL, cx->tmp is empty... */
1041                 if ( cx->prefix == DN_SUBTREE_PREFIX && eilist ) {
1042                         bdb_idl_union( cx->ids, cx->tmp );
1043                         for (ptr = eilist; *ptr; ptr++) {
1044                                 cx->ei = *ptr;
1045                                 cx->id = cx->ei->bei_id;
1046                                 hdb_dn2idl_internal( cx );
1047                         cx->op->o_tmpfree( eilist, cx->op->o_tmpmemctx );
1048                         cx->rc = 0;
1049                 } else {
1050                         BDB_IDL_CPY( cx->ids, cx->tmp );
1051                 }
1052         }
1053         return cx->rc;
1054 }
1055
1056 int
1057 hdb_dn2idl(
1058         Operation       *op,
1059         Entry           *e,
1060         ID *ids,
1061         ID *stack )
1062 {
1063         struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
1064         struct dn2id_cookie cx;
1065
1066 #ifdef NEW_LOGGING
1067         LDAP_LOG ( INDEX, ARGS, 
1068                 "=> hdb_dn2ididl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1069 #else
1070         Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl( \"%s\" )\n", e->e_nname.bv_val, 0, 0 );
1071 #endif
1072
1073 #ifndef BDB_MULTIPLE_SUFFIXES
1074         if ( op->ors_scope == LDAP_SCOPE_SUBTREE && 
1075                 BEI(e)->bei_parent->bei_id == 0 ) {
1076                 BDB_IDL_ALL( bdb, ids );
1077                 return 0;
1078         }
1079 #endif
1080
1081         cx.id = e->e_id;
1082         cx.ei = BEI(e);
1083         cx.bdb = bdb;
1084         cx.db = cx.bdb->bi_dn2id->bdi_db;
1085         cx.prefix = op->ors_scope == LDAP_SCOPE_SUBTREE ? DN_SUBTREE_PREFIX :
1086                         DN_ONE_PREFIX;
1087         cx.ids = ids;
1088         cx.buf = stack;
1089         cx.op = op;
1090
1091         BDB_IDL_ZERO( ids );
1092         if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1093                 bdb_idl_insert( ids, cx.id );
1094         }
1095
1096         DBTzero(&cx.key);
1097         cx.key.data = &cx.id;
1098         cx.key.ulen = sizeof(ID);
1099         cx.key.size = sizeof(ID);
1100         cx.key.flags = DB_DBT_USERMEM;
1101
1102         DBTzero(&cx.data);
1103
1104         return hdb_dn2idl_internal(&cx);
1105 }
1106 #endif  /* BDB_HIER */