1 /* dn2id.c - routines to deal with the dn2id index */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2004 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/string.h>
34 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
35 DB *db = bdb->bi_dn2id->bdi_db;
39 struct berval ptr, pdn;
41 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n",
42 e->e_ndn, (long) e->e_id, 0 );
43 assert( e->e_id != NOID );
46 key.size = e->e_nname.bv_len + 2;
48 key.flags = DB_DBT_USERMEM;
49 buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
51 buf[0] = DN_BASE_PREFIX;
53 ptr.bv_len = e->e_nname.bv_len;
54 AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
55 ptr.bv_val[ptr.bv_len] = '\0';
58 data.data = (char *) &e->e_id;
59 data.size = sizeof( e->e_id );
61 /* store it -- don't override */
62 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
64 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
65 db_strerror(rc), rc, 0 );
69 #ifndef BDB_MULTIPLE_SUFFIXES
70 if( !be_issuffix( op->o_bd, &ptr ))
73 buf[0] = DN_SUBTREE_PREFIX;
74 rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
76 Debug( LDAP_DEBUG_ANY,
77 "=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
82 #ifdef BDB_MULTIPLE_SUFFIXES
83 if( !be_issuffix( op->o_bd, &ptr ))
86 dnParent( &ptr, &pdn );
88 key.size = pdn.bv_len + 2;
90 pdn.bv_val[-1] = DN_ONE_PREFIX;
91 key.data = pdn.bv_val-1;
94 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
97 Debug( LDAP_DEBUG_ANY,
98 "=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
104 #ifndef BDB_MULTIPLE_SUFFIXES
105 while( !be_issuffix( op->o_bd, &ptr ))
110 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
112 rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id );
115 Debug( LDAP_DEBUG_ANY,
116 "=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
120 #ifdef BDB_MULTIPLE_SUFFIXES
121 if( be_issuffix( op->o_bd, &ptr )) break;
123 dnParent( &ptr, &pdn );
125 key.size = pdn.bv_len + 2;
127 key.data = pdn.bv_val - 1;
133 op->o_tmpfree( buf, op->o_tmpmemctx );
134 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
145 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
146 DB *db = bdb->bi_dn2id->bdi_db;
150 struct berval pdn, ptr;
152 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
153 e->e_ndn, e->e_id, 0 );
156 key.size = e->e_nname.bv_len + 2;
157 buf = op->o_tmpalloc( key.size, op->o_tmpmemctx );
159 key.flags = DB_DBT_USERMEM;
160 buf[0] = DN_BASE_PREFIX;
162 ptr.bv_len = e->e_nname.bv_len;
163 AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
164 ptr.bv_val[ptr.bv_len] = '\0';
167 rc = db->del( db, txn, &key, 0 );
169 Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
170 db_strerror(rc), rc, 0 );
174 #ifndef BDB_MULTIPLE_SUFFIXES
175 if( !be_issuffix( op->o_bd, &ptr ))
178 buf[0] = DN_SUBTREE_PREFIX;
179 rc = db->del( db, txn, &key, 0 );
181 Debug( LDAP_DEBUG_ANY,
182 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
187 #ifdef BDB_MULTIPLE_SUFFIXES
188 if( !be_issuffix( op->o_bd, &ptr ))
191 dnParent( &ptr, &pdn );
193 key.size = pdn.bv_len + 2;
195 pdn.bv_val[-1] = DN_ONE_PREFIX;
196 key.data = pdn.bv_val - 1;
199 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
202 Debug( LDAP_DEBUG_ANY,
203 "=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
209 #ifndef BDB_MULTIPLE_SUFFIXES
210 while( !be_issuffix( op->o_bd, &ptr ))
215 ptr.bv_val[-1] = DN_SUBTREE_PREFIX;
217 rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
219 Debug( LDAP_DEBUG_ANY,
220 "=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
224 #ifdef BDB_MULTIPLE_SUFFIXES
225 if( be_issuffix( op->o_bd, &ptr )) break;
227 dnParent( &ptr, &pdn );
229 key.size = pdn.bv_len + 2;
231 key.data = pdn.bv_val - 1;
237 op->o_tmpfree( buf, op->o_tmpmemctx );
238 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
251 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
252 DB *db = bdb->bi_dn2id->bdi_db;
254 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id(\"%s\")\n", dn->bv_val, 0, 0 );
256 key.size = dn->bv_len + 2;
257 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
258 ((char *)key.data)[0] = DN_BASE_PREFIX;
259 AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 );
263 data.data = &ei->bei_id;
264 data.ulen = sizeof(ID);
265 data.flags = DB_DBT_USERMEM;
268 rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
271 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
272 db_strerror( rc ), rc, 0 );
274 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
278 op->o_tmpfree( key.data, op->o_tmpmemctx );
289 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
290 DB *db = bdb->bi_dn2id->bdi_db;
294 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children(\"%s\")\n",
295 e->e_nname.bv_val, 0, 0 );
297 key.size = e->e_nname.bv_len + 2;
298 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
299 ((char *)key.data)[0] = DN_ONE_PREFIX;
300 AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
302 if ( bdb->bi_idl_cache_size ) {
303 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
304 if ( rc != LDAP_NO_SUCH_OBJECT ) {
305 op->o_tmpfree( key.data, op->o_tmpmemctx );
309 /* we actually could do a empty get... */
312 data.ulen = sizeof(id);
313 data.flags = DB_DBT_USERMEM;
315 data.dlen = sizeof(id);
317 rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
318 op->o_tmpfree( key.data, op->o_tmpmemctx );
320 Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children(\"%s\"): %s (%d)\n",
322 rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " :
323 db_strerror(rc) ), rc );
337 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
338 DB *db = bdb->bi_dn2id->bdi_db;
339 int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
340 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
342 Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl(\"%s\")\n",
343 e->e_nname.bv_val, 0, 0 );
345 #ifndef BDB_MULTIPLE_SUFFIXES
346 if ( prefix == DN_SUBTREE_PREFIX && BEI(e)->bei_parent->bei_id == 0 ) {
347 BDB_IDL_ALL(bdb, ids);
353 key.size = e->e_nname.bv_len + 2;
355 key.flags = DB_DBT_USERMEM;
356 key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
357 ((char *)key.data)[0] = prefix;
358 AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
360 rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids, NULL, 0 );
363 Debug( LDAP_DEBUG_TRACE,
364 "<= bdb_dn2idl: get failed: %s (%d)\n",
365 db_strerror( rc ), rc, 0 );
368 Debug( LDAP_DEBUG_TRACE,
369 "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n",
371 (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) );
374 op->o_tmpfree( key.data, op->o_tmpmemctx );
379 /* Experimental management routines for a hierarchically structured database.
381 * Unsupported! Use at your own risk!
382 * -- Howard Chu, Symas Corp. 2003.
384 * Instead of a ldbm-style dn2id database, we use a hierarchical one. Each
385 * entry in this database is a struct diskNode, keyed by entryID and with
386 * the data containing the RDN and entryID of the node's children. We use
387 * a B-Tree with sorted duplicates to store all the children of a node under
388 * the same key. Also, the first item under the key contains the entry's own
389 * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
390 * well as top-down. To keep this info first in the list, the nrdnlen is set
391 * to the negative of its value.
393 * The diskNode is a variable length structure. This definition is not
394 * directly usable for in-memory manipulation.
396 typedef struct diskNode {
403 /* Sort function for the sorted duplicate data items of a dn2id key.
404 * Sorts based on normalized RDN, in length order.
412 signed char *u = (signed char *)&(((diskNode *)(usrkey->data))->nrdnlen);
413 signed char *c = (signed char *)&(((diskNode *)(curkey->data))->nrdnlen);
416 /* data is not aligned, cannot compare directly */
417 #ifdef WORDS_BIGENDIAN
418 for( i = 0; i < (int)sizeof(short); i++)
420 for( i = sizeof(short)-1; i >= 0; i--)
426 return strcmp( u+sizeof(short), c+sizeof(short) );
429 /* This function constructs a full DN for a given entry.
436 int rlen = 0, nrlen = 0;
440 /* count length of all DN components */
441 for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
442 rlen += ei->bei_rdn.bv_len + 1;
443 nrlen += ei->bei_nrdn.bv_len + 1;
444 if (ei->bei_modrdns > max) max = ei->bei_modrdns;
447 /* See if the entry DN was invalidated by a subtree rename */
449 if ( BEI(e)->bei_modrdns >= max ) {
452 /* We found a mismatch, tell the caller to lock it */
453 if ( checkit == 1 ) {
456 /* checkit == 2. do the fix. */
457 free( e->e_name.bv_val );
458 free( e->e_nname.bv_val );
461 e->e_name.bv_len = rlen - 1;
462 e->e_nname.bv_len = nrlen - 1;
463 e->e_name.bv_val = ch_malloc(rlen);
464 e->e_nname.bv_val = ch_malloc(nrlen);
465 ptr = e->e_name.bv_val;
466 nptr = e->e_nname.bv_val;
467 for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
468 ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
469 nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
470 if ( ei->bei_parent ) {
475 BEI(e)->bei_modrdns = max;
482 /* We add two elements to the DN2ID database - a data item under the parent's
483 * entryID containing the child's RDN and entryID, and an item under the
484 * child's entryID containing the parent's entryID.
493 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
494 DB *db = bdb->bi_dn2id->bdi_db;
500 nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
502 rlen = dn_rdnlen( op->o_bd, &e->e_name );
504 nrlen = e->e_nname.bv_len;
505 rlen = e->e_name.bv_len;
508 d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx);
509 d->entryID = e->e_id;
511 ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen );
513 ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen );
518 key.data = &eip->bei_id;
519 key.size = sizeof(ID);
520 key.flags = DB_DBT_USERMEM;
522 /* Need to make dummy root node once. Subsequent attempts
523 * will fail harmlessly.
525 if ( eip->bei_id == 0 ) {
526 diskNode dummy = {0};
528 data.size = sizeof(diskNode);
529 data.flags = DB_DBT_USERMEM;
531 db->put( db, txn, &key, &data, DB_NODUPDATA );
534 if ( bdb->bi_idl_cache_size ) {
535 bdb_idl_cache_del( bdb, db, &key );
538 data.size = sizeof(diskNode) + rlen + nrlen;
539 data.flags = DB_DBT_USERMEM;
541 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
545 d->entryID = eip->bei_id;
546 d->nrdnlen = 0 - nrlen;
548 rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
551 op->o_tmpfree( d, op->o_tmpmemctx );
563 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
564 DB *db = bdb->bi_dn2id->bdi_db;
571 key.size = sizeof(ID);
573 key.data = &eip->bei_id;
574 key.flags = DB_DBT_USERMEM;
577 data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
578 data.ulen = data.size;
579 data.dlen = data.size;
580 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
582 if ( bdb->bi_idl_cache_size ) {
583 bdb_idl_cache_del( bdb, db, &key );
585 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
588 d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
589 d->entryID = e->e_id;
590 d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
591 strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
594 /* Delete our ID from the parent's list */
595 rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
597 rc = cursor->c_del( cursor, 0 );
599 /* Delete our ID from the tree. With sorted duplicates, this
600 * will leave any child nodes still hanging around. This is OK
601 * for modrdn, which will add our info back in later.
605 rc = cursor->c_get( cursor, &key, &data, DB_SET | DB_RMW );
607 rc = cursor->c_del( cursor, 0 );
609 cursor->c_close( cursor );
610 op->o_tmpfree( d, op->o_tmpmemctx );
623 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
624 DB *db = bdb->bi_dn2id->bdi_db;
630 ID idp = ei->bei_parent->bei_id;
632 nrlen = dn_rdnlen( op->o_bd, in );
633 if (!nrlen) nrlen = in->bv_len;
636 key.size = sizeof(ID);
638 key.ulen = sizeof(ID);
639 key.flags = DB_DBT_USERMEM;
642 data.size = sizeof(diskNode) + nrlen;
643 data.ulen = data.size * 3;
644 data.flags = DB_DBT_USERMEM;
646 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
649 d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
651 ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
655 rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
657 ei->bei_id = d->entryID;
658 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
659 ptr = d->nrdn + nrlen + 1;
660 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
661 if ( !ei->bei_parent->bei_dkids ) {
663 /* How many children does the parent have? */
664 /* FIXME: do we need to lock the parent
665 * entryinfo? Seems safe...
667 cursor->c_count( cursor, &dkids, 0 );
668 ei->bei_parent->bei_dkids = dkids;
671 cursor->c_close( cursor );
672 op->o_tmpfree( d, op->o_tmpmemctx );
684 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
685 DB *db = bdb->bi_dn2id->bdi_db;
694 key.size = sizeof(ID);
695 key.data = &ei->bei_id;
696 key.ulen = sizeof(ID);
697 key.flags = DB_DBT_USERMEM;
700 data.flags = DB_DBT_USERMEM;
702 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
705 data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
706 d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx );
709 rc = cursor->c_get( cursor, &key, &data, DB_SET );
711 if (d->nrdnlen >= 0) {
716 ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
717 ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
718 ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
720 ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
721 ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
722 /* How many children does this node have? */
723 cursor->c_count( cursor, &dkids, 0 );
724 ei->bei_dkids = dkids;
727 cursor->c_close( cursor );
728 op->o_tmpfree( d, op->o_tmpmemctx );
738 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
739 DB *db = bdb->bi_dn2id->bdi_db;
747 key.size = sizeof(ID);
749 key.flags = DB_DBT_USERMEM;
751 if ( bdb->bi_idl_cache_size ) {
752 rc = bdb_idl_cache_get( bdb, db, &key, NULL );
753 if ( rc != LDAP_NO_SUCH_OBJECT ) {
759 data.ulen = sizeof(d);
760 data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
761 data.dlen = sizeof(d);
763 rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
766 rc = cursor->c_get( cursor, &key, &data, DB_SET );
769 rc = cursor->c_count( cursor, &dkids, 0 );
771 BEI(e)->bei_dkids = dkids;
772 if ( dkids < 2 ) rc = DB_NOTFOUND;
775 cursor->c_close( cursor );
780 * We can't just use bdb_idl_fetch_key because
781 * 1 - our data items are longer than just an entry ID
782 * 2 - our data items are sorted alphabetically by nrdn, not by ID.
784 * We descend the tree recursively, so we define this cookie
785 * to hold our necessary state information. The bdb_dn2idl_internal
786 * function uses this cookie when calling itself.
789 struct dn2id_cookie {
790 struct bdb_info *bdb;
799 ID tmp[BDB_IDL_DB_SIZE];
812 EntryInfo *ei = data;
815 bdb_idl_insert( idl, ei->bei_id );
821 struct dn2id_cookie *cx
824 if ( cx->bdb->bi_idl_cache_size ) {
825 cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
826 if ( cx->rc == DB_NOTFOUND ) {
829 if ( cx->rc == LDAP_SUCCESS ) {
833 BDB_IDL_ZERO( cx->tmp );
836 cx->ei = bdb_cache_find_info( cx->bdb, cx->id );
838 cx->rc = DB_NOTFOUND;
843 bdb_cache_entryinfo_lock( cx->ei );
845 /* If number of kids in the cache differs from on-disk, load
846 * up all the kids from the database
848 if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
850 db_recno_t dkids = cx->ei->bei_dkids;
851 ei.bei_parent = cx->ei;
853 bdb_cache_entryinfo_unlock( cx->ei );
855 cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
856 cx->bdb->bi_db_opflags );
857 if ( cx->rc ) return cx->rc;
859 cx->data.data = &cx->dbuf;
860 cx->data.ulen = sizeof(ID);
861 cx->data.dlen = sizeof(ID);
862 cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
864 /* The first item holds the parent ID. Ignore it. */
865 cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
867 cx->dbc->c_close( cx->dbc );
868 if ( cx->rc == DB_NOTFOUND ) goto saveit;
872 /* If the on-disk count is zero we've never checked it.
876 cx->dbc->c_count( cx->dbc, &dkids, 0 );
877 cx->ei->bei_dkids = dkids;
880 cx->data.data = cx->buf;
881 cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
882 cx->data.flags = DB_DBT_USERMEM;
884 /* Fetch the rest of the IDs in a loop... */
885 while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
886 DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
889 DB_MULTIPLE_INIT( cx->ptr, &cx->data );
891 DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
894 diskNode *d = (diskNode *)j;
897 AC_MEMCPY( &ei.bei_id, &d->entryID, sizeof(ID) );
898 AC_MEMCPY( &nrlen, &d->nrdnlen, sizeof(d->nrdnlen) );
899 ei.bei_nrdn.bv_len = nrlen;
900 /* nrdn/rdn are set in-place.
901 * hdb_cache_load will copy them as needed
903 ei.bei_nrdn.bv_val = d->nrdn;
904 ei.bei_rdn.bv_len = len - sizeof(diskNode)
905 - ei.bei_nrdn.bv_len;
906 ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
907 bdb_idl_insert( cx->tmp, ei.bei_id );
908 hdb_cache_load( cx->bdb, &ei, &ei2 );
912 cx->rc = cx->dbc->c_close( cx->dbc );
914 /* The in-memory cache is in sync with the on-disk data.
915 * do we have any kids?
918 if ( cx->ei->bei_ckids > 0 ) {
919 /* Walk the kids tree; order is irrelevant since bdb_idl_insert
920 * will insert in sorted order.
922 avl_apply( cx->ei->bei_kids, apply_func,
923 cx->tmp, -1, AVL_POSTORDER );
925 bdb_cache_entryinfo_unlock( cx->ei );
929 if ( cx->bdb->bi_idl_cache_max_size ) {
930 bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
934 if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
935 if ( cx->prefix == DN_SUBTREE_PREFIX ) {
936 if (cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS) {
937 bdb_idl_union( cx->ids, cx->tmp );
940 EntryInfo *ei = cx->ei;
942 save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
943 cx->op->o_tmpmemctx );
944 BDB_IDL_CPY( save, cx->tmp );
945 bdb_idl_union( cx->ids, cx->tmp );
948 for ( cx->id = bdb_idl_first( save, &idcurs );
950 cx->id = bdb_idl_next( save, &idcurs )) {
952 hdb_dn2idl_internal( cx );
953 if ( !BDB_IDL_IS_ZERO( cx->tmp ))
956 cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
957 if ( nokids ) ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS;
959 /* Make sure caller knows it had kids! */
964 BDB_IDL_CPY( cx->ids, cx->tmp );
977 struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private;
978 struct dn2id_cookie cx;
980 Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl(\"%s\")\n",
981 e->e_nname.bv_val, 0, 0 );
983 #ifndef BDB_MULTIPLE_SUFFIXES
984 if ( op->ors_scope != LDAP_SCOPE_ONELEVEL &&
985 BEI(e)->bei_parent->bei_id == 0 )
987 BDB_IDL_ALL( bdb, ids );
993 cx.ei = e->e_id ? BEI(e) : &bdb->bi_cache.c_dntree;
995 cx.db = cx.bdb->bi_dn2id->bdi_db;
996 cx.prefix = op->ors_scope == LDAP_SCOPE_ONELEVEL
997 ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX;
1002 BDB_IDL_ZERO( ids );
1003 if ( cx.prefix == DN_SUBTREE_PREFIX ) {
1004 bdb_idl_insert( ids, cx.id );
1008 cx.key.data = &cx.id;
1009 cx.key.ulen = sizeof(ID);
1010 cx.key.size = sizeof(ID);
1011 cx.key.flags = DB_DBT_USERMEM;
1015 return hdb_dn2idl_internal(&cx);
1017 #endif /* BDB_HIER */