bdb_entryinfo_add_internal(
struct bdb_info *bdb,
EntryInfo *ei,
- EntryInfo **res,
- u_int32_t locker
+ EntryInfo **res
)
{
EntryInfo *ei2 = NULL;
ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn );
avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp,
avl_dup_error );
+#ifdef BDB_HIER
+ ei->bei_parent->bei_ckids++;
+#endif
}
*res = ei2;
Operation *op,
DB_TXN *txn,
struct berval *ndn,
- EntryInfo **res,
- u_int32_t locker
+ EntryInfo **res
)
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
/* DN exists but needs to be added to cache */
ei.bei_nrdn.bv_len = len;
- rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2,
- locker );
+ rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2 );
/* add_internal left eip and c_rwlock locked */
ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
if ( rc ) {
}
return rc;
}
+
+int hdb_entryinfo_load(
+ struct bdb_info *bdb,
+ EntryInfo *ei,
+ EntryInfo **res )
+{
+ EntryInfo *ei2;
+ int rc;
+
+ bdb_cache_entryinfo_lock( ei->bei_parent );
+ ei2 = (EntryInfo *)avl_find( ei->bei_parent->bei_kids, ei, bdb_rdn_cmp );
+ bdb_cache_entryinfo_unlock( ei->bei_parent );
+ if ( !ei2 ) {
+ rc = bdb_entryinfo_add_internal( bdb, ei, res );
+ bdb_cache_entryinfo_unlock( ei->bei_parent );
+ ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
+ } else {
+ *res = ei2;
+ free( ei->bei_rdn.bv_val );
+ return 0;
+ }
+ return rc;
+}
#endif
/* caller must have lru_mutex locked. mutex
rc = bdb_id2entry( op->o_bd, tid, id, &ep );
if ( rc == 0 ) {
rc = bdb_cache_find_ndn( op, tid,
- &ep->e_nname, eip, locker );
+ &ep->e_nname, eip );
if ( *eip )
islocked = 1;
if ( rc ) {
rdn.bv_len = ptr - rdn.bv_val;
}
ber_dupbv( &ei.bei_rdn, &rdn );
+ if ( eip->bei_dkids ) eip->bei_dkids++;
#endif
- rc = bdb_entryinfo_add_internal( bdb, &ei, &new, locker );
+ rc = bdb_entryinfo_add_internal( bdb, &ei, &new );
new->bei_e = e;
e->e_private = new;
new->bei_state = CACHE_ENTRY_NO_KIDS;
{
int rc = 0; /* return code */
+#ifdef BDB_HIER
+ e->bei_parent->bei_ckids--;
+ if ( e->bei_parent->bei_dkids ) e->bei_parent->bei_dkids--;
+#endif
/* dn tree */
if ( avl_delete( &e->bei_parent->bei_kids, (caddr_t) e, bdb_rdn_cmp ) == NULL )
{
return rc;
}
+
int
hdb_dn2id(
Operation *op,
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_id = d->entryID;
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 );
+ ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn );
+ if ( !ei->bei_parent->bei_dkids ) {
+ db_recno_t dkids;
+ /* How many children does the parent have? */
+ /* FIXME: do we need to lock the parent
+ * entryinfo? Seems safe...
+ */
+ cursor->c_count( cursor, &dkids, 0 );
+ ei->bei_parent->bei_dkids = dkids;
+ }
}
+ cursor->c_close( cursor );
op->o_tmpfree( d, op->o_tmpmemctx );
return rc;
}
+static void
+hdb_dn2ei(
+ char *buf,
+ int len,
+ EntryInfo *ei )
+{
+ diskNode *d = (diskNode *)buf;
+ char *ptr;
+
+ AC_MEMCPY( &ei->bei_id, &d->entryID, sizeof(ID) );
+ AC_MEMCPY( &ei->bei_nrdn.bv_len, &d->nrdnlen, sizeof(d->nrdnlen) );
+ ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 0, &ei->bei_nrdn );
+ ei->bei_rdn.bv_len = len - 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 );
+}
+
int
hdb_dn2id_parent(
Operation *op,
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;
+ rc = LDAP_OTHER;
+ } else {
+ db_recno_t dkids;
+ *idp = d->entryID;
+ 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 );
+ /* How many children does this node have? */
+ cursor->c_count( cursor, &dkids, 0 );
+ ei->bei_dkids = dkids;
}
- 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 );
}
+ cursor->c_close( cursor );
op->o_tmpfree( d, op->o_tmpmemctx );
return rc;
}
rc = cursor->c_get( cursor, &key, &data, DB_SET );
if ( rc == 0 ) {
- rc = cursor->c_get( cursor, &key, &data, DB_NEXT_DUP );
+ db_recno_t dkids;
+ rc = cursor->c_count( cursor, &dkids, 0 );
+ if ( rc == 0 ) {
+ BEI(e)->bei_dkids = dkids;
+ if ( dkids < 2 ) rc = DB_NOTFOUND;
+ }
}
cursor->c_close( cursor );
return rc;
DB *db;
int prefix;
int rc;
+ EntryInfo *ei;
ID id;
ID dbuf;
ID *ids;
Operation *op;
};
+struct apply_arg {
+ ID *idl;
+ EntryInfo **ei;
+};
+
+static int
+apply_func(
+ void *data,
+ void *arg )
+{
+ EntryInfo *ei = data;
+ struct apply_arg *ap = arg;
+
+ bdb_idl_insert( ap->idl, ei->bei_id );
+ if ( ap->ei ) {
+ *(ap->ei)++ = ei;
+ }
+ return 0;
+}
+
static int
hdb_dn2idl_internal(
struct dn2id_cookie *cx
)
{
+ EntryInfo **eilist = NULL, **ptr;
#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);
}
}
#endif
-
- 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->data.data = &cx->dbuf;
- cx->data.ulen = sizeof(ID);
- cx->data.dlen = sizeof(ID);
- cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
-
- /* 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;
-
- cx->data.data = cx->buf;
- cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
- cx->data.flags = DB_DBT_USERMEM;
-
- /* Fetch the rest of the IDs in a loop... */
- while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
- DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
- u_int8_t *j;
- size_t len;
- 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 );
+ if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
+ EntryInfo ei;
+ ei.bei_parent = cx->ei;
+
+ cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
+ cx->bdb->bi_db_opflags );
+ if ( cx->rc ) return cx->rc;
+
+ cx->data.data = &cx->dbuf;
+ cx->data.ulen = sizeof(ID);
+ cx->data.dlen = sizeof(ID);
+ cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
+
+ /* 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;
+
+ if ( !cx->ei->bei_dkids ) {
+ db_recno_t dkids;
+ cx->dbc->c_count( cx->dbc, &dkids, 0 );
+ cx->ei->bei_dkids = dkids;
+ }
+
+ if ( cx->prefix == DN_SUBTREE_PREFIX && cx->ei->bei_dkids > 1 ) {
+ eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
+ eilist[cx->ei->bei_dkids-1] = NULL;
+ ptr = eilist;
+ }
+
+ cx->data.data = cx->buf;
+ cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
+ cx->data.flags = DB_DBT_USERMEM;
+
+ /* Fetch the rest of the IDs in a loop... */
+ while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
+ DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
+ u_int8_t *j;
+ size_t len;
+ DB_MULTIPLE_INIT( cx->ptr, &cx->data );
+ while (cx->ptr) {
+ DB_MULTIPLE_NEXT( cx->ptr, &cx->data, j, len );
+ if (j) {
+ EntryInfo *ei2;
+ hdb_dn2ei( j, len, &ei );
+ bdb_idl_insert( cx->tmp, ei.bei_id );
+ hdb_entryinfo_load( cx->bdb, &ei, &ei2 );
+ if ( eilist )
+ *ptr++ = ei2;
+ }
+ }
+ }
+ cx->dbc->c_close( cx->dbc );
+ } else {
+ if ( cx->ei->bei_ckids > 0 ) {
+ struct apply_arg ap;
+ if ( cx->prefix == DN_SUBTREE_PREFIX ) {
+ eilist = cx->op->o_tmpalloc( sizeof(EntryInfo *) * cx->ei->bei_dkids, cx->op->o_tmpmemctx );
+ eilist[cx->ei->bei_dkids-1] = NULL;
}
+ ap.idl = cx->tmp;
+ ap.ei = eilist;
+ bdb_cache_entryinfo_lock( cx->ei );
+ avl_apply( cx->ei->bei_kids, apply_func, &ap, -1, AVL_POSTORDER );
+ bdb_cache_entryinfo_unlock( cx->ei );
}
}
- cx->dbc->c_close( cx->dbc );
/* If we got some records, treat as success */
if (!BDB_IDL_IS_ZERO(cx->tmp)) {
;
gotit:
if ( cx->rc == 0 ) {
- if ( cx->prefix == DN_SUBTREE_PREFIX ) {
- ID *save, idcurs;
-
- save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
- cx->op->o_tmpmemctx );
- BDB_IDL_CPY( save, cx->tmp );
+ /* If eilist is NULL, cx->tmp is empty... */
+ if ( cx->prefix == DN_SUBTREE_PREFIX && eilist ) {
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 )) {
+ for (ptr = eilist; *ptr; ptr++) {
+ cx->ei = *ptr;
+ cx->id = cx->ei->bei_id;
hdb_dn2idl_internal( cx );
- }
- cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
+ cx->op->o_tmpfree( eilist, cx->op->o_tmpmemctx );
cx->rc = 0;
} else {
BDB_IDL_CPY( cx->ids, cx->tmp );
#endif
cx.id = e->e_id;
+ cx.ei = BEI(e);
cx.bdb = bdb;
cx.db = cx.bdb->bi_dn2id->bdi_db;
cx.prefix = op->ors_scope == LDAP_SCOPE_SUBTREE ? DN_SUBTREE_PREFIX :