DBT lockobj;
DB_LOCKREQ list[2];
+ if ( !lock ) return 0;
+
lockobj.data = ei;
lockobj.size = sizeof(ei->bei_parent) + sizeof(ei->bei_id);
DBT lockobj;
int db_rw;
+ if ( !lock ) return 0;
+
if (rw)
db_rw = DB_LOCK_WRITE;
else
int
bdb_entryinfo_add_internal(
struct bdb_info *bdb,
- EntryInfo *eip,
- ID id,
- struct berval *nrdn,
+ EntryInfo *ei,
EntryInfo **res,
u_int32_t locker
)
*res = NULL;
ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock );
- bdb_cache_entryinfo_lock( eip );
+ bdb_cache_entryinfo_lock( ei->bei_parent );
/* if parent was previously considered a leaf node,
* it was on the LRU list. Now it's going to have
* kids, take it off the LRU list.
*/
ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
- if ( eip->bei_id && !eip->bei_kids ) {
- LRU_DELETE( cache, eip );
+ if ( ei->bei_parent->bei_id && !ei->bei_parent->bei_kids ) {
+ LRU_DELETE( cache, ei->bei_parent );
incr = 0;
}
if (!ei2) {
ei2 = bdb_cache_entryinfo_new();
}
- ei2->bei_id = id;
- ei2->bei_parent = eip;
+ ei2->bei_id = ei->bei_id;
+ ei2->bei_parent = ei->bei_parent;
+ ei2->bei_rdn = ei->bei_rdn;
/* Add to cache ID tree */
if (avl_insert( &cache->c_idtree, ei2, bdb_id_cmp, avl_dup_error )) {
- EntryInfo *ei;
- ei = avl_find( cache->c_idtree, ei2, bdb_id_cmp );
+ EntryInfo *eix;
+ eix = avl_find( cache->c_idtree, ei2, bdb_id_cmp );
bdb_cache_entryinfo_destroy( ei2 );
- ei2 = ei;
+ ei2 = eix;
addkid = 0;
cache->c_cursize -= incr;
+ if ( ei->bei_rdn.bv_val )
+ ber_memfree_x( ei->bei_rdn.bv_val, NULL );
} else {
LRU_ADD( cache, ei2 );
- ber_dupbv( &ei2->bei_nrdn, nrdn );
+ ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn );
}
if ( addkid ) {
- avl_insert( &eip->bei_kids, ei2, bdb_rdn_cmp, avl_dup_error );
+ avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp,
+ avl_dup_error );
}
ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
-#if 0 /* caller must do these frees */
- ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
- bdb_cache_entryinfo_unlock( eip );
-#endif
-
*res = ei2;
return 0;
}
}
for ( bdb_cache_entryinfo_lock( eip ); eip; ) {
+ ei.bei_parent = eip;
ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp );
if ( !ei2 ) {
int len = ei.bei_nrdn.bv_len;
/* DN exists but needs to be added to cache */
ei.bei_nrdn.bv_len = len;
- rc = bdb_entryinfo_add_internal( bdb,
- eip, ei.bei_id, &ei.bei_nrdn, &ei2, locker );
+ rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2,
+ locker );
/* add_internal left eip and c_rwlock locked */
ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
if ( rc ) {
return rc;
}
+#ifdef BDB_HIER
+/* Walk up the tree from a child node, looking for an ID that's already
+ * been linked into the cache.
+ */
+int
+bdb_cache_find_parent(
+ Backend *be,
+ DB_TXN *txn,
+ ID id,
+ EntryInfo **res,
+ void *ctx
+)
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ EntryInfo ei, eip, *ei2 = NULL, *ein = NULL, *eir = NULL;
+ ID parent;
+ int rc;
+
+ ei.bei_id = id;
+ ei.bei_kids = NULL;
+
+ for (;;) {
+ rc = bdb_dn2id_parent( be, txn, &ei, &eip.bei_id, ctx );
+ if ( rc ) break;
+
+ /* Save the previous node, if any */
+ ei2 = ein;
+
+ /* Create a new node for the current ID */
+ ein = bdb_cache_entryinfo_new();
+ ein->bei_id = ei.bei_id;
+ ein->bei_nrdn = ei.bei_nrdn;
+ ein->bei_rdn = ei.bei_rdn;
+ ein->bei_kids = ei.bei_kids;
+
+ /* This node is not fully connected yet */
+ ein->bei_state = CACHE_ENTRY_NOT_LINKED;
+
+ /* If this is the first time, save this node
+ * to be returned later.
+ */
+ if ( eir == NULL ) eir = ein;
+
+ /* Insert this node into the ID tree */
+ ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock );
+ if ( avl_insert( &bdb->bi_cache.c_idtree, (caddr_t)ein,
+ bdb_id_cmp, avl_dup_error ) ) {
+
+ /* Hm, can this really happen? */
+ bdb_cache_entryinfo_destroy( ein );
+ ein = (EntryInfo *)avl_find( bdb->bi_cache.c_idtree,
+ (caddr_t) &ei, bdb_id_cmp );
+ bdb_cache_entryinfo_lock( ein );
+ avl_insert( &ein->bei_kids, (caddr_t)ei2, bdb_rdn_cmp,
+ avl_dup_error );
+ bdb_cache_entryinfo_unlock( ein );
+ }
+
+ /* If there was a previous node, link it to this one */
+ if ( ei2 ) ei2->bei_parent = ein;
+
+ if ( eip.bei_id ) {
+ ei2 = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree,
+ (caddr_t) &eip, bdb_id_cmp );
+ } else {
+ ei2 = &bdb->bi_cache.c_dntree;
+ }
+
+ if ( ei2 ) {
+ ein->bei_parent = ei2;
+ bdb_cache_entryinfo_lock( ei2 );
+ avl_insert( &ei2->bei_kids, (caddr_t)ein, bdb_rdn_cmp,
+ avl_dup_error);
+ bdb_cache_entryinfo_unlock( ei2 );
+ *res = eir;
+ bdb_cache_entryinfo_lock( eir );
+ }
+ ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
+ if ( ei2 ) {
+ /* Found a link. Reset all the state info */
+ for (ein = eir; ein != ei2; ein=ein->bei_parent)
+ ein->bei_state &= ~CACHE_ENTRY_NOT_LINKED;
+ break;
+ }
+ ei.bei_kids = NULL;
+ ei.bei_id = eip.bei_id;
+ avl_insert( &ei.bei_kids, (caddr_t)ein, bdb_rdn_cmp,
+ avl_dup_error );
+ }
+ return rc;
+}
+#endif
+
/*
* cache_find_entry_id - find an entry in the cache, given id.
* The entry is locked for Read upon return. Call with islocked TRUE if
/* See if the ID exists in the database; add it to the cache if so */
if ( !*eip ) {
+#ifndef BDB_HIER
rc = bdb_id2entry( be, tid, id, &ep );
if ( rc == 0 ) {
rc = bdb_cache_find_entry_ndn2id( be, tid,
ep = NULL;
}
}
+#else
+ rc = bdb_cache_find_parent(be, tid, id, eip, ctx );
+ if ( rc == 0 && *eip )
+ islocked = 1;
+#endif
}
/* Ok, we found the info, do we have the entry? */
if ( rc == 0 ) {
bdb_cache_entry_db_lock( bdb->bi_dbenv, locker,
*eip, 1, 0, lock );
- (*eip)->bei_e = ep;
ep->e_private = *eip;
+#ifdef BDB_HIER
+ hdb_fix_dn( ep );
+#endif
+ (*eip)->bei_e = ep;
bdb_cache_entry_db_relock( bdb->bi_dbenv, locker,
*eip, 0, 0, lock );
}
int
bdb_cache_add(
struct bdb_info *bdb,
- EntryInfo *ei,
+ EntryInfo *eip,
Entry *e,
struct berval *nrdn,
u_int32_t locker
)
{
- EntryInfo *new;
+ EntryInfo *new, ei;
+ struct berval rdn = e->e_name;
int rc;
- rc = bdb_entryinfo_add_internal( bdb, ei, e->e_id, nrdn, &new, locker );
+ ei.bei_id = e->e_id;
+ ei.bei_parent = eip;
+ ei.bei_nrdn = *nrdn;
+ if ( nrdn->bv_len != e->e_nname.bv_len ) {
+ char *ptr = strchr( rdn.bv_val, ',' );
+ rdn.bv_len = ptr - rdn.bv_val;
+ }
+ ber_dupbv( &ei.bei_rdn, &rdn );
+ rc = bdb_entryinfo_add_internal( bdb, &ei, &new, locker );
new->bei_e = e;
e->e_private = new;
new->bei_state = CACHE_ENTRY_NO_KIDS;
- ei->bei_state &= ~CACHE_ENTRY_NO_KIDS;
- bdb_cache_entryinfo_unlock( ei );
+ eip->bei_state &= ~CACHE_ENTRY_NO_KIDS;
+ bdb_cache_entryinfo_unlock( eip );
ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
return rc;
}
)
{
EntryInfo *ei = BEI(e), *pei;
+ struct berval rdn;
int rc = 0;
/* Get write lock on data */
bdb_cache_entryinfo_lock( pei );
avl_delete( &pei->bei_kids, (caddr_t) ei, bdb_rdn_cmp );
free( ei->bei_nrdn.bv_val );
+ free( ei->bei_rdn.bv_val );
ber_dupbv( &ei->bei_nrdn, nrdn );
+ rdn = e->e_name;
+ if ( nrdn->bv_len != e->e_nname.bv_len ) {
+ char *ptr = strchr(rdn.bv_val, ',');
+ rdn.bv_len = ptr - rdn.bv_val;
+ }
+ ber_dupbv( &ei->bei_rdn, &rdn );
+
if (!ein) {
ein = ei->bei_parent;
} else {
bdb_entryinfo_release( void *data )
{
EntryInfo *ei = (EntryInfo *)data;
- avl_free( ei->bei_kids, NULL );
+ if ( ei->bei_kids ) {
+ avl_free( ei->bei_kids, NULL );
+ }
if ( ei->bei_e ) {
ei->bei_e->e_private = NULL;
bdb_entry_return( ei->bei_e );
* entry in this database is a struct diskNode, keyed by entryID and with
* the data containing the RDN and entryID of the node's children. We use
* a B-Tree with sorted duplicates to store all the children of a node under
- * the same key. Also, the first item under the key contains an empty rdn
- * and the ID of the node's parent, to allow bottom-up tree traversal as
- * well as top-down.
+ * the same key. Also, the first item under the key contains the entry's own
+ * rdn and the ID of the node's parent, to allow bottom-up tree traversal as
+ * well as top-down. To keep this info first in the list, the nrdnlen is set
+ * to the negative of its value.
*
* The diskNode is a variable length structure. This definition is not
* directly usable for in-memory manipulation.
* Sorts based on normalized RDN, in lexical order.
*/
int
-bdb_hdb_compare(
+hdb_dup_compare(
DB *db,
const DBT *usrkey,
const DBT *curkey
{
diskNode *usr = usrkey->data;
diskNode *cur = curkey->data;
- short curlen;
- char *ptr = (char *)&cur->nrdnlen;
+ short curlen, usrlen;
+ char *ptr;
+ unsigned char *pt2;
int rc;
- curlen = ptr[0] << 8 | ptr[1];
+ /* Make sure to detect negative values in the nrdnlen */
+ ptr = (char *)&usr->nrdnlen;
+ pt2 = (unsigned char *)(ptr+1);
+
+ usrlen = ptr[0] << 8 | *pt2;
+
+ ptr = (char *)&cur->nrdnlen;
+ pt2 = (unsigned char *)(ptr+1);
+
+ curlen = ptr[0] << 8 | *pt2;
+
+ if ( usrlen < 0 ) {
+ if ( curlen < 0 ) return 0;
+ return -1;
+ }
+
+ if ( curlen < 0 ) return 1;
- rc = strncmp( usr->nrdn, cur->nrdn, usr->nrdnlen );
+ rc = strncmp( usr->nrdn, cur->nrdn, usrlen );
if ( rc == 0 ) rc = usrlen - curlen;
return rc;
}
/* This function constructs a full DN for a given entry.
*/
-int bdb_fix_dn(
- BackendDB *be,
+int hdb_fix_dn(
Entry *e
)
{
- struct bdb_info *bdb = (struct bdb_info *) be->be_private;
EntryInfo *ei;
int rlen = 0, nrlen = 0;
char *ptr, *nptr;
- for ( ei = BEI(e); ei; ei=ei->bei_parent ) {
+ for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
rlen += ei->bei_rdn.bv_len + 1;
nrlen += ei->bei_nrdn.bv_len + 1;
}
e->e_nname.bv_val = e->e_name.bv_val + rlen;
ptr = e->e_name.bv_val;
nptr = e->e_nname.bv_val;
- for ( ei = BEI(e); ei; ei=ei->bei_parent ) {
+ for ( ei = BEI(e); ei && ei->bei_id; ei=ei->bei_parent ) {
ptr = lutil_strcopy(ptr, ei->bei_rdn.bv_val);
nptr = lutil_strcopy(nptr, ei->bei_nrdn.bv_val);
if ( ei->bei_parent ) {
*nptr++ = ',';
}
}
- *ptr = '\0';
- *nptr = '\0';
+ ptr[-1] = '\0';
+ nptr[-1] = '\0';
return 0;
}
}
#endif
data.data = d;
- data.size = sizeof(diskNode) + rlen + nrlen + 2;
+ data.size = sizeof(diskNode) + rlen + nrlen;
data.flags = DB_DBT_USERMEM;
- rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
+ rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
if (rc == 0) {
key.data = &e->e_id;
d->entryID = eip->bei_id;
- d->nrdnlen = 0;
- d->nrdn[0] = '\0';
- d->rdn[0] = '\0';
- data.size = sizeof(diskNode);
+ d->nrdnlen = 0 - nrlen;
- rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
+ rc = db->put( db, txn, &key, &data, DB_NODUPDATA );
}
sl_free( d, ctx );
key.flags = DB_DBT_USERMEM;
DBTzero(&data);
- data.size = sizeof(diskNode) + BEI(e)->nrdn.bv_len;
- d = sl_malloc( data.size, ctx );
- d->entryID = e->e_id;
- d->nrdnlen = BEI(e)->nrdn.bv_len;
- strcpy( d->nrdn, BEI(e)->nrdn.bv_val );
- data.data = d;
+ data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len;
data.ulen = data.size;
data.dlen = data.size;
data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
+ d = sl_malloc( data.size, ctx );
+ d->entryID = e->e_id;
+ d->nrdnlen = BEI(e)->bei_nrdn.bv_len;
+ strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
+ data.data = d;
+
+ /* Delete our ID from the parent's list */
rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH | DB_RMW );
if ( rc == 0 )
rc = cursor->c_del( cursor, 0 );
- cursor->c_close( cursor );
- key.data = &e->e_id;
- rc = db->del( db, txn, &key, 0);
+ /* Delete our ID from the tree. With sorted duplicates, this
+ * will leave any child nodes still hanging around. This is OK
+ * for modrdn, which will add our info back in later.
+ */
+ if ( rc == 0 ) {
+ key.data = &e->e_id;
+ rc = cursor->c_get( cursor, &key, &data, DB_SET );
+ if ( rc == 0 )
+ rc = cursor->c_del( cursor, 0 );
+ }
+ cursor->c_close( cursor );
sl_free( d, ctx );
return rc;
DBT key, data;
DBC *cursor;
int rc = 0, nrlen;
+ diskNode *d;
char *ptr;
+ ID idp = ei->bei_parent->bei_id;
- nrlen = dn_rdnlen( be, &in );
+ nrlen = dn_rdnlen( be, in );
if (!nrlen) nrlen = in->bv_len;
DBTzero(&key);
key.size = sizeof(ID);
- key.data = &eip->bei_id;
+ key.data = &idp;
+ key.ulen = sizeof(ID);
key.flags = DB_DBT_USERMEM;
DBTzero(&data);
data.size = sizeof(diskNode) + nrlen;
- d = sl_malloc( data.size * 3, ctx );
- d->nrdnlen = nrlen;
- ptr = lutil_strncopy( d->nrdn, BEI(e)->nrdn.bv_val, nrlen );
- *ptr = '\0';
- data.data = d;
data.ulen = data.size * 3;
data.flags = DB_DBT_USERMEM;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
+ d = sl_malloc( data.size * 3, ctx );
+ d->nrdnlen = nrlen;
+ ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen );
+ *ptr = '\0';
+ data.data = d;
+
rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH );
cursor->c_close( cursor );
+
+ if ( rc == 0 ) {
+ AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
+ ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
+ ptr = d->nrdn + nrlen + 1;
+ ei->bei_rdn.bv_val = ch_malloc( ei->bei_rdn.bv_len + 1 );
+ strcpy( ei->bei_rdn.bv_val, ptr );
+ }
+ sl_free( d, ctx );
+
+ return rc;
+}
+
+int
+bdb_dn2id_parent(
+ Backend *be,
+ DB_TXN *txn,
+ EntryInfo *ei,
+ ID *idp,
+ void *ctx )
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ DB *db = bdb->bi_dn2id->bdi_db;
+ DBT key, data;
+ DBC *cursor;
+ int rc = 0;
+ diskNode *d;
+ char *ptr;
+ unsigned char *pt2;
+
+ DBTzero(&key);
+ key.size = sizeof(ID);
+ key.data = &ei->bei_id;
+ key.ulen = sizeof(ID);
+ key.flags = DB_DBT_USERMEM;
+
+ DBTzero(&data);
+ data.flags = DB_DBT_USERMEM;
+
+ rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
- AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
- ei->rdn.bv_len = data.size - sizeof(diskNode) - nrlen;
- ptr = d->nrdn + nrlen + 1;
- strcpy( ei->rdn.bv_val, ptr );
+ data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2);
+ d = sl_malloc( data.ulen, ctx );
+ data.data = d;
+ rc = cursor->c_get( cursor, &key, &data, DB_SET );
+ cursor->c_close( cursor );
+ if ( rc == 0 ) {
+ if (d->nrdnlen >= 0) {
+ return LDAP_OTHER;
+ }
+ AC_MEMCPY( idp, &d->entryID, sizeof(ID) );
+ ei->bei_nrdn.bv_len = 0 - d->nrdnlen;
+ ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn );
+ ei->bei_rdn.bv_len = data.size - sizeof(diskNode) -
+ ei->bei_nrdn.bv_len;
+ ptr = d->nrdn + ei->bei_nrdn.bv_len + 1;
+ ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
+ }
+ sl_free( d, ctx );
return rc;
}
if ( bdb->bi_idl_cache_size ) {
rc = bdb_idl_cache_get( bdb, db, &key, NULL );
if ( rc != LDAP_NO_SUCH_OBJECT ) {
- sl_free( key.data, o->o_tmpmemctx );
return rc;
}
}
#endif
DBTzero(&data);
+ data.data = &d;
data.ulen = sizeof(d);
data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
data.dlen = sizeof(d);
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
- rc = cursor->c_get( cursor, &key, &data, DB_FIRST );
+ rc = cursor->c_get( cursor, &key, &data, DB_SET );
if ( rc == 0 ) {
rc = cursor->c_get( cursor, &key, &data, DB_NEXT_DUP );
}
return rc;
}
+/* bdb_dn2idl:
+ * We can't just use bdb_idl_fetch_key because
+ * 1 - our data items are longer than just an entry ID
+ * 2 - our data items are sorted alphabetically by nrdn, not by ID.
+ *
+ * We descend the tree recursively, so we define this cookie
+ * to hold our necessary state information. The bdb_dn2idl_internal
+ * function uses this cookie when calling itself.
+ */
+
struct dn2id_cookie {
struct bdb_info *bdb;
DB *db;
ID dbuf;
ID *ids;
ID tmp[BDB_IDL_DB_SIZE];
- ID buf[BDB_IDL_UM_SIZE];
DBT key;
DBT data;
- DBC dbc;
- void *ptr;
+ DBC *dbc;
void *ctx;
};
-/* We can't just use bdb_idl_fetch_key because
- * 1 - our data items are longer than just an entry ID
- * 2 - our data items are sorted alphabetically by nrdn, not by ID.
- */
int
bdb_dn2idl_internal(
struct dn2id_cookie *cx
)
{
- ID *save, *i;
-
#ifdef SLAP_IDL_CACHE
if ( cx->bdb->bi_idl_cache_size ) {
cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
return cx->rc;
}
if ( cx->rc == LDAP_SUCCESS ) {
- readit = 0;
+ goto saveit;
}
}
#endif
-
- cx->data.data = &cx->dbuf;
- cx->data.ulen = sizeof(ID);
- cx->data.dlen = sizeof(ID);
- cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
- cx->rc = db->cursor( cx->db, NULL, &cx->dbc, cx->bdb->bi_db_opflags );
+ cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
+ cx->bdb->bi_db_opflags );
if ( cx->rc ) return cx->rc;
BDB_IDL_ZERO( cx->tmp );
- cx->rc = dbc->c_get( dbc, &cx->key, &cx->data, DB_FIRST );
- cx->data.data = &cx->buf;
- cx->data.ulen = sizeof(cx->buf);
- while ( cx->rc == 0 ) {
- u_int8_t *j;
- size_t len;
- cx->rc = dbc->c_get( dbc, &cx->key, &cx->data, DB_MULTIPLE |
- DB_NEXT_DUP );
- DB_MULTIPLE_INIT( cx->ptr, &cx->data );
- while (cx->ptr) {
- DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
- if (j) {
- AC_MEMCPY( &cx->dbuf, j, sizeof(ID) );
- bdb_idl_insert( cx->tmp, cx->dbuf );
+ /* The first item holds the parent ID. Ignore it. */
+ cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
+ if ( cx->rc == DB_NOTFOUND ) goto saveit;
+ if ( cx->rc ) return cx->rc;
+
+ /* Fetch the rest of the IDs in a loop... */
+ while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
+ DB_NEXT_DUP )) == 0 ) {
+ bdb_idl_insert( cx->tmp, cx->dbuf );
+ }
+ cx->dbc->c_close( cx->dbc );
+
+ /* If we got some records, treat as success */
+ if (!BDB_IDL_IS_ZERO(cx->tmp)) {
+ cx->rc = 0;
+ }
+
+saveit:
+#ifdef SLAP_IDL_CACHE
+ if ( cx->bdb->bi_idl_cache_max_size ) {
+ bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
+ }
+#endif
+ if ( cx->rc == 0 ) {
+ if ( cx->prefix == DN_SUBTREE_PREFIX ) {
+ ID *save, idcurs;
+
+ save = sl_malloc( BDB_IDL_SIZEOF( cx->tmp ), cx->ctx );
+ BDB_IDL_CPY( save, cx->tmp );
+ bdb_idl_union( cx->ids, cx->tmp );
+
+ idcurs = 0;
+ for ( cx->id = bdb_idl_first( save, &idcurs );
+ cx->id != NOID;
+ cx->id = bdb_idl_next( save, &idcurs )) {
+ bdb_dn2idl_internal( cx );
}
+ sl_free( save, cx->ctx );
+ cx->rc = 0;
+ } else {
+ BDB_IDL_CPY( cx->ids, cx->tmp );
}
}
- dbc->c_close( dbc );
-
+ return cx->rc;
}
int
cx.ids = ids;
cx.ctx = ctx;
+ BDB_IDL_ZERO( ids );
+ if ( prefix == DN_SUBTREE_PREFIX ) {
+ bdb_idl_insert( ids, cx.id );
+ }
+
DBTzero(&cx.key);
cx.key.data = &cx.id;
+ cx.key.ulen = sizeof(ID);
cx.key.size = sizeof(ID);
cx.key.flags = DB_DBT_USERMEM;
+
DBTzero(&cx.data);
+ cx.data.data = &cx.dbuf;
+ cx.data.ulen = sizeof(ID);
+ cx.data.dlen = sizeof(ID);
+ cx.data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
return bdb_dn2idl_internal(&cx);
}