Commit 377bccbc authored by Howard Chu's avatar Howard Chu
Browse files

Hierarchical cache management.

parent d9d59123
......@@ -18,13 +18,13 @@ bdb_add(Operation *op, SlapReply *rs )
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
struct berval pdn;
Entry *p = NULL;
const char *text;
Entry *p;
EntryInfo *ei;
char textbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof textbuf;
AttributeDescription *children = slap_schema.si_ad_children;
AttributeDescription *entry = slap_schema.si_ad_entry;
DB_TXN *ltid = NULL;
DB_TXN *ltid = NULL, *lt2;
struct bdb_op_info opinfo;
#ifdef BDB_SUBENTRIES
int subentry;
......@@ -137,42 +137,37 @@ retry: /* transaction retry */
dnParent( &op->oq_add.rs_e->e_nname, &pdn );
}
if( pdn.bv_len != 0 ) {
Entry *matched = NULL;
/* get parent */
rs->sr_err = bdb_dn2entry_r( op->o_bd, ltid, &pdn, &p, &matched, 0, locker, &lock );
switch( rs->sr_err ) {
case 0:
case DB_NOTFOUND:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( p == NULL ) {
if ( matched != NULL ) {
rs->sr_matched = ch_strdup( matched->e_dn );
rs->sr_ref = is_entry_referral( matched )
? get_entry_referrals( op, matched )
: NULL;
bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched );
matched = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral,
NULL, &op->oq_add.rs_e->e_name, LDAP_SCOPE_DEFAULT );
}
/* get entry or parent */
rs->sr_err = bdb_dn2entry( op->o_bd, ltid, &op->ora_e->e_nname, &ei,
1, locker, &lock, op->o_tmpmemctx );
switch( rs->sr_err ) {
case 0:
rs->sr_err = LDAP_ALREADY_EXISTS;
goto return_results;
case DB_NOTFOUND:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
p = ei->bei_e;
if ( p ) {
if ( !bvmatch( &pdn, &p->e_nname ) ) {
rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
op->o_tmpmemctx );
rs->sr_ref = is_entry_referral( p )
? get_entry_referrals( op, p )
: NULL;
bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
p = NULL;
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, DETAIL1,
"bdb_add: parent does not exist\n", 0, 0, 0 );
......@@ -185,7 +180,7 @@ retry: /* transaction retry */
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
ch_free( (char *)rs->sr_matched );
op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
rs->sr_ref = NULL;
rs->sr_matched = NULL;
......@@ -370,8 +365,26 @@ retry: /* transaction retry */
goto return_results;;
}
/* nested transaction */
rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2,
bdb->bi_db_opflags );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
"bdb_add: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_add: txn_begin(2) failed: %s (%d)\n",
db_strerror(rs->sr_err), rs->sr_err, 0 );
#endif
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* dn2id index */
rs->sr_err = bdb_dn2id_add( op->o_bd, ltid, &pdn, op->oq_add.rs_e );
rs->sr_err = bdb_dn2id_add( op->o_bd, lt2, &pdn, op->oq_add.rs_e );
if ( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
......@@ -395,7 +408,7 @@ retry: /* transaction retry */
}
/* id2entry index */
rs->sr_err = bdb_id2entry_add( op->o_bd, ltid, op->oq_add.rs_e );
rs->sr_err = bdb_id2entry_add( op->o_bd, lt2, op->oq_add.rs_e );
if ( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR, "bdb_add: id2entry_add failed\n", 0, 0, 0 );
......@@ -415,7 +428,7 @@ retry: /* transaction retry */
}
/* attribute indexes */
rs->sr_err = bdb_index_entry_add( op, ltid, op->oq_add.rs_e );
rs->sr_err = bdb_index_entry_add( op, lt2, op->oq_add.rs_e );
if ( rs->sr_err != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
......@@ -434,7 +447,11 @@ retry: /* transaction retry */
rs->sr_text = "index generation failed";
goto return_results;
}
if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "txn_commit(2) failed";
goto return_results;
}
if( op->o_noop ) {
if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
......@@ -454,32 +471,21 @@ retry: /* transaction retry */
rs->sr_text = "txn_prepare failed";
} else {
int ret = bdb_cache_add_entry_rw(bdb->bi_dbenv,
&bdb->bi_cache, op->oq_add.rs_e, CACHE_WRITE_LOCK,
locker, &lock);
switch ( ret ) {
case 0:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
default:
ret = LDAP_OTHER;
struct berval nrdn;
if (pdn.bv_len) {
nrdn.bv_val = op->ora_e->e_nname.bv_val;
nrdn.bv_len = pdn.bv_val - nrdn.bv_val - 1;
} else {
nrdn = op->ora_e->e_nname;
}
if ( ret ) {
if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
rs->sr_text = "cache add & txn_abort failed";
} else {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "cache add failed";
}
bdb_cache_add(bdb, ei, op->oq_add.rs_e, &nrdn, locker );
if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
rs->sr_text = "txn_commit failed";
} else {
if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
rs->sr_text = "txn_commit failed";
} else {
rs->sr_err = LDAP_SUCCESS;
}
rs->sr_err = LDAP_SUCCESS;
}
}
}
......@@ -497,9 +503,6 @@ retry: /* transaction retry */
op->o_noop ? " (no-op)" : "", op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn );
#endif
rs->sr_text = NULL;
if ( !noop ) {
bdb_cache_entry_commit( op->oq_add.rs_e );
}
}
else {
#ifdef NEW_LOGGING
......
......@@ -82,16 +82,39 @@ typedef struct bdb_idl_cache_entry_s {
} bdb_idl_cache_entry_t;
#endif
/* BDB backend specific entry info */
typedef struct bdb_entry_info {
struct bdb_entry_info *bei_parent;
ID bei_id;
int bei_state;
#define CACHE_ENTRY_DELETED 1
/*
* remaining fields require backend cache lock to access
*/
struct berval bei_nrdn;
struct berval bei_rdn;
Entry *bei_e;
Avlnode *bei_kids;
ldap_pvt_thread_mutex_t bei_kids_mutex;
struct bdb_entry_info *bei_lrunext; /* for cache lru list */
struct bdb_entry_info *bei_lruprev;
} EntryInfo;
#undef BEI
#define BEI(e) ((EntryInfo *) ((e)->e_private))
/* for the in-core cache of entries */
typedef struct bdb_cache {
int c_maxsize;
int c_cursize;
Avlnode *c_dntree;
Avlnode *c_idtree;
Entry *c_lruhead; /* lru - add accessed entries here */
Entry *c_lrutail; /* lru - rem lru entries from here */
ldap_pvt_thread_rdwr_t c_rwlock;
ldap_pvt_thread_mutex_t lru_mutex;
int c_maxsize;
int c_cursize;
EntryInfo c_dntree;
Avlnode *c_idtree;
EntryInfo *c_lruhead; /* lru - add accessed entries here */
EntryInfo *c_lrutail; /* lru - rem lru entries from here */
ldap_pvt_thread_rdwr_t c_rwlock;
ldap_pvt_thread_mutex_t lru_mutex;
} Cache;
#define CACHE_READ_LOCK 0
......
......@@ -21,7 +21,7 @@ bdb_bind( Operation *op, SlapReply *rs )
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
Entry *e;
Attribute *a;
Entry *matched;
EntryInfo *ei;
#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
char krbname[MAX_K_NAME_SZ + 1];
AttributeDescription *krbattr = slap_schema.si_ad_krbName;
......@@ -59,7 +59,8 @@ bdb_bind( Operation *op, SlapReply *rs )
dn2entry_retry:
/* get entry with reader lock */
rs->sr_err = bdb_dn2entry_r( op->o_bd, NULL, &op->o_req_ndn, &e, &matched, 0, locker, &lock );
rs->sr_err = bdb_dn2entry( op->o_bd, NULL, &op->o_req_ndn, &ei, 1,
locker, &lock, op->o_tmpmemctx );
switch(rs->sr_err) {
case DB_NOTFOUND:
......@@ -78,17 +79,17 @@ dn2entry_retry:
return rs->sr_err;
}
if ( e == NULL ) {
if( matched != NULL ) {
rs->sr_ref = is_entry_referral( matched )
? get_entry_referrals( op, matched )
e = ei->bei_e;
if ( rs->sr_err == DB_NOTFOUND ) {
if( e != NULL ) {
rs->sr_ref = is_entry_referral( e )
? get_entry_referrals( op, e )
: NULL;
if (rs->sr_ref)
rs->sr_matched = ch_strdup( matched->e_name.bv_val );
bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock );
matched = NULL;
rs->sr_matched = ch_strdup( e->e_name.bv_val );
bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
e = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral,
NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
......
This diff is collapsed.
......@@ -17,8 +17,8 @@ int
bdb_compare( Operation *op, SlapReply *rs )
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
Entry *matched;
Entry *e;
EntryInfo *ei;
Attribute *a;
int manageDSAit = get_manageDSAit( op );
......@@ -36,7 +36,7 @@ bdb_compare( Operation *op, SlapReply *rs )
dn2entry_retry:
/* get entry */
rs->sr_err = bdb_dn2entry_r( op->o_bd, NULL, &op->o_req_ndn, &e, &matched, 0, locker, &lock );
rs->sr_err = bdb_dn2entry( op->o_bd, NULL, &op->o_req_ndn, &ei, 1, locker, &lock, op->o_tmpmemctx );
switch( rs->sr_err ) {
case DB_NOTFOUND:
......@@ -54,14 +54,15 @@ dn2entry_retry:
goto return_results;
}
if ( e == NULL ) {
if ( matched != NULL ) {
rs->sr_matched = ch_strdup( matched->e_dn );
rs->sr_ref = is_entry_referral( matched )
? get_entry_referrals( op, matched )
e = ei->bei_e;
if ( rs->sr_err == DB_NOTFOUND ) {
if ( e != NULL ) {
rs->sr_matched = ch_strdup( e->e_dn );
rs->sr_ref = is_entry_referral( e )
? get_entry_referrals( op, e )
: NULL;
bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock );
matched = NULL;
bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
e = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral,
......
......@@ -21,14 +21,15 @@ bdb_delete( Operation *op, SlapReply *rs )
struct berval pdn = {0, NULL};
Entry *e = NULL;
Entry *p = NULL;
EntryInfo *ei = NULL, *eip = NULL;
int manageDSAit = get_manageDSAit( op );
AttributeDescription *children = slap_schema.si_ad_children;
AttributeDescription *entry = slap_schema.si_ad_entry;
DB_TXN *ltid = NULL;
DB_TXN *ltid = NULL, *lt2;
struct bdb_op_info opinfo;
u_int32_t locker = 0;
DB_LOCK lock;
DB_LOCK lock, plock;
int noop = 0;
......@@ -47,6 +48,7 @@ bdb_delete( Operation *op, SlapReply *rs )
retry: /* transaction retry */
if( e != NULL ) {
bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
e = NULL;
}
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, DETAIL1,
......@@ -99,27 +101,38 @@ retry: /* transaction retry */
dnParent( &op->o_req_ndn, &pdn );
}
if( pdn.bv_len != 0 ) {
/* get parent */
rs->sr_err = bdb_dn2entry_r( op->o_bd, ltid, &pdn, &p, NULL, 0, locker, &lock );
/* get entry */
rs->sr_err = bdb_dn2entry( op->o_bd, ltid, &op->o_req_ndn, &ei, 1,
locker, &lock, op->o_tmpmemctx );
switch( rs->sr_err ) {
case 0:
case DB_NOTFOUND:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
switch( rs->sr_err ) {
case 0:
case DB_NOTFOUND:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( rs->sr_err == 0 ) {
e = ei->bei_e;
eip = ei->bei_parent;
bdb_cache_find_entry_id( op->o_bd, ltid, eip->bei_id, &eip,
0, locker, &plock, op->o_tmpmemctx );
}
if ( eip ) {
p = eip->bei_e;
}
if( p == NULL) {
if ( pdn.bv_len != 0 ) {
if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, DETAIL1,
"<=- bdb_delete: parent does not exist\n", 0, 0, 0 );
......@@ -208,25 +221,6 @@ retry: /* transaction retry */
}
}
/* get entry for read/modify/write */
rs->sr_err = bdb_dn2entry_w( op->o_bd, ltid, &op->o_req_ndn, &e, &matched, DB_RMW, locker, &lock );
switch( rs->sr_err ) {
case 0:
case DB_NOTFOUND:
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( e == NULL ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ARGS,
......@@ -310,7 +304,27 @@ retry: /* transaction retry */
goto done;
}
rs->sr_err = bdb_dn2id_children( op->o_bd, ltid, &e->e_nname, 0 );
/* nested transaction */
rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2,
bdb->bi_db_opflags );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
"bdb_delete: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_delete: txn_begin(2) failed: %s (%d)\n",
db_strerror(rs->sr_err), rs->sr_err, 0 );
#endif
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* Can't do it if we have kids */
rs->sr_err = ei->bei_kids ? 0 : bdb_dn2id_children( op->o_bd, lt2,
&e->e_nname, 0 );
if( rs->sr_err != DB_NOTFOUND ) {
switch( rs->sr_err ) {
case DB_LOCK_DEADLOCK:
......@@ -345,7 +359,7 @@ retry: /* transaction retry */
}
/* delete from dn2id */
rs->sr_err = bdb_dn2id_delete( op->o_bd, ltid, pdn.bv_val, e );
rs->sr_err = bdb_dn2id_delete( op->o_bd, lt2, pdn.bv_val, e );
if ( rs->sr_err != 0 ) {
switch( rs->sr_err ) {
case DB_LOCK_DEADLOCK:
......@@ -366,7 +380,7 @@ retry: /* transaction retry */
}
/* delete from id2entry */
rs->sr_err = bdb_id2entry_delete( op->o_bd, ltid, e );
rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
if ( rs->sr_err != 0 ) {
switch( rs->sr_err ) {
case DB_LOCK_DEADLOCK:
......@@ -388,7 +402,7 @@ retry: /* transaction retry */
}
/* delete indices for old attributes */
rs->sr_err = bdb_index_entry_del( op, ltid, e );
rs->sr_err = bdb_index_entry_del( op, lt2, e );
if ( rs->sr_err != LDAP_SUCCESS ) {
switch( rs->sr_err ) {
case DB_LOCK_DEADLOCK:
......@@ -406,6 +420,11 @@ retry: /* transaction retry */
rs->sr_err = LDAP_OTHER;
goto return_results;
}
if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "txn_commit(2) failed";
goto return_results;
}
#if 0 /* Do we want to reclaim deleted IDs? */
ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
......@@ -423,6 +442,8 @@ retry: /* transaction retry */
rs->sr_err = LDAP_SUCCESS;
}
} else {
bdb_cache_delete_entry( &bdb->bi_cache, e, bdb->bi_dbenv,
locker, &lock );
rs->sr_err = TXN_COMMIT( ltid, 0 );
}
ltid = NULL;
......@@ -477,7 +498,11 @@ return_results:
done:
/* free entry */
if( e != NULL ) {
bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
if ( rs->sr_err == LDAP_SUCCESS ) {
bdb_entry_return( e );
} else {
bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
}
}
if( ltid != NULL ) {
......
......@@ -15,48 +15,60 @@
/*
* dn2entry - look up dn in the cache/indexes and return the corresponding
* entry.
* entry. If the requested DN is not found and matched is TRUE, return info
* for the closest ancestor of the DN. Otherwise e is NULL.
*/
int
bdb_dn2entry_rw(
bdb_dn2entry(
BackendDB *be,
DB_TXN *tid,
struct berval *dn,
Entry **e,
Entry **matched,
int flags,
int rw,
EntryInfo **e,
int matched,
u_int32_t locker,
DB_LOCK *lock )
DB_LOCK *lock,
void *ctx )
{
EntryInfo *ei = NULL;
int rc;
ID id, id2 = 0;
#ifdef NEW_LOGGING
LDAP_LOG ( CACHE, ARGS, "bdb_dn2entry_rw(\"%s\")\n", dn->bv_val, 0, 0 );
LDAP_LOG ( CACHE, ARGS, "bdb_dn2entry(\"%s\")\n", dn->bv_val, 0, 0 );
#else
Debug(LDAP_DEBUG_TRACE, "bdb_dn2entry_rw(\"%s\")\n",
Debug(LDAP_DEBUG_TRACE, "bdb_dn2entry(\"%s\")\n",
dn->bv_val, 0, 0 );
#endif
*e = NULL;
if( matched != NULL ) {
*matched = NULL;
rc = bdb_dn2id_matched( be, tid, dn, &id, &id2, flags );
rc = bdb_cache_find_entry_ndn2id( be, tid, dn, &ei, locker, ctx );
if ( rc ) {
if ( matched && rc == DB_NOTFOUND ) {
/* Set the return value, whether we have its entry
* or not.
*/
*e = ei;
if ( ei && ei->bei_id )
bdb_cache_find_entry_id( be, tid, ei->bei_id,
&ei, 1, locker, lock, ctx );
else if ( ei )
bdb_cache_entryinfo_unlock( ei );
} else if ( ei ) {
bdb_cache_entryinfo_unlock( ei );
}
} else {
rc = bdb_dn2id( be, tid, dn, &id, flags );
}