diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 36b821c8aebeca4585afa90a4f4f0726130bd672..14ca178f6859b8f492c6f52d76f4c26ed58e065e 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -70,13 +70,15 @@ typedef struct __db_locker * BDB_LOCKER; extern int __lock_getlocker(DB_LOCKTAB *lt, u_int32_t locker, int create, DB_LOCKER **ret); #define CURSOR_SETLOCKER(cursor, id) cursor->locker = id -#define CURSOR_GETLOCKER(cursor) cursor->locker +#define CURSOR_GETLOCKER(cursor) cursor->locker +#define BDB_LOCKID(locker) locker->id #else typedef u_int32_t BDB_LOCKER; #define CURSOR_SETLOCKER(cursor, id) cursor->locker = id #define CURSOR_GETLOCKER(cursor) cursor->locker +#define BDB_LOCKID(locker) locker #endif @@ -106,7 +108,7 @@ typedef struct bdb_entry_info { * to avoid conflicting with BDB's internal locks. So add a byte here * that is always zero. */ - char bei_lockpad; + short bei_lockpad; short bei_state; #define CACHE_ENTRY_DELETED 1 @@ -312,6 +314,25 @@ struct bdb_op_info { #define TXN_ID(txn) (txn)->locker #endif +/* #undef BDB_LOG_DEBUG */ + +#ifdef BDB_LOG_DEBUG + +/* env->log_printf appeared in 4.4 */ +#if DB_VERSION_FULL >= 0x04040000 +#define BDB_LOG_PRINTF(env,txn,fmt,...) (env)->log_printf((env),(txn),(fmt),__VA_ARGS__) +#else +extern int __db_logmsg(const DB_ENV *env, DB_TXN *txn, const char *op, u_int32_t flags, + const char *fmt,...); +#define BDB_LOG_PRINTF(env,txn,fmt,...) __db_logmsg((env),(txn),"DIAGNOSTIC",0,(fmt),__VA_ARGS__) +#endif + +#else /* !BDB_LOG_DEBUG */ + +#define BDB_LOG_PRINTF(a,b,c,...) + +#endif /* BDB_LOG_DEBUG */ + #endif #ifndef DB_BUFFER_SMALL diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index 7cd7194ab7c407b04b7a27c5d338eb72e729de51..d666364e1dfe39efd82ba779d03db5ae8d150df0 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -155,12 +155,6 @@ bdb_cache_lru_link( struct bdb_info *bdb, EntryInfo *ei ) * alternatives though. */ -#if DB_VERSION_FULL >= 0x04060012 -#define BDB_LOCKID(locker) locker->id -#else -#define BDB_LOCKID(locker) locker -#endif - /* Atomically release and reacquire a lock */ int bdb_cache_entry_db_relock( @@ -351,6 +345,8 @@ bdb_entryinfo_add_internal( ei->bei_rdn.bv_val = NULL; #endif } else { + int rc; + bdb->bi_cache.c_eiused++; ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn ); @@ -360,8 +356,13 @@ bdb_entryinfo_add_internal( */ if ( ei->bei_parent->bei_kids || !ei->bei_parent->bei_id ) bdb->bi_cache.c_leaves++; - avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp, + rc = avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp, avl_dup_error ); + if ( rc ) { + /* This should never happen; entry cache is corrupt */ + bdb->bi_dbenv->log_flush( bdb->bi_dbenv, NULL ); + assert( !rc ); + } #ifdef BDB_HIER ei->bei_parent->bei_ckids++; #endif @@ -380,7 +381,7 @@ bdb_entryinfo_add_internal( int bdb_cache_find_ndn( Operation *op, - DB_TXN *txn, + BDB_LOCKER locker, struct berval *ndn, EntryInfo **res ) { @@ -418,6 +419,7 @@ bdb_cache_find_ndn( ei.bei_parent = eip; ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp ); if ( !ei2 ) { + DB_LOCK lock; int len = ei.bei_nrdn.bv_len; if ( BER_BVISEMPTY( ndn )) { @@ -429,18 +431,27 @@ bdb_cache_find_ndn( (ei.bei_nrdn.bv_val - ndn->bv_val); bdb_cache_entryinfo_unlock( eip ); - rc = bdb_dn2id( op, txn, &ei.bei_nrdn, &ei ); + BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Reading %s", + ei.bei_nrdn.bv_val ); + + lock.mode = DB_LOCK_NG; + rc = bdb_dn2id( op, &ei.bei_nrdn, &ei, locker, &lock ); if (rc) { bdb_cache_entryinfo_lock( eip ); + bdb_cache_entry_db_unlock( bdb, &lock ); *res = eip; return rc; } + BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Read got %s(%d)", + ei.bei_nrdn.bv_val, ei.bei_id ); + /* DN exists but needs to be added to cache */ ei.bei_nrdn.bv_len = len; 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 ); + bdb_cache_entry_db_unlock( bdb, &lock ); if ( rc ) { *res = eip; return rc; @@ -484,7 +495,6 @@ bdb_cache_find_ndn( int hdb_cache_find_parent( Operation *op, - DB_TXN *txn, BDB_LOCKER locker, ID id, EntryInfo **res ) @@ -498,7 +508,7 @@ hdb_cache_find_parent( ei.bei_ckids = 0; for (;;) { - rc = hdb_dn2id_parent( op, txn, locker, &ei, &eip.bei_id ); + rc = hdb_dn2id_parent( op, locker, &ei, &eip.bei_id ); if ( rc ) break; /* Save the previous node, if any */ @@ -821,7 +831,7 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); #ifndef BDB_HIER rc = bdb_id2entry( op->o_bd, tid, locker, id, &ep ); if ( rc == 0 ) { - rc = bdb_cache_find_ndn( op, tid, + rc = bdb_cache_find_ndn( op, locker, &ep->e_nname, eip ); if ( *eip ) flag |= ID_LOCKED; if ( rc ) { @@ -835,7 +845,7 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); } } #else - rc = hdb_cache_find_parent(op, tid, locker, id, eip ); + rc = hdb_cache_find_parent(op, locker, id, eip ); if ( rc == 0 ) flag |= ID_LOCKED; #endif } diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index c9fdba93d6ab159c01569aa6686ea4415e306b07..2e711cc846e02aeffb4818073eab5ce15e745067 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -372,6 +372,9 @@ retry: /* transaction retry */ goto return_results; } + BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Starting delete %s(%d)", + e->e_nname.bv_val, e->e_id ); + /* Can't do it if we have kids */ rs->sr_err = bdb_cache_children( op, lt2, e ); if( rs->sr_err != DB_NOTFOUND ) { @@ -492,6 +495,9 @@ retry: /* transaction retry */ p = NULL; } + BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Commit1 delete %s(%d)", + e->e_nname.bv_val, e->e_id ); + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; @@ -517,6 +523,10 @@ retry: /* transaction retry */ goto return_results; } } else { + + BDB_LOG_PRINTF( bdb->bi_dbenv, ltid, "slapd Cache delete %s(%d)", + e->e_nname.bv_val, e->e_id ); + rc = bdb_cache_delete( bdb, e, locker, &lock ); switch( rc ) { case DB_LOCK_DEADLOCK: @@ -529,6 +539,9 @@ retry: /* transaction retry */ ltid = NULL; op->o_private = NULL; + BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Committed delete %s(%d)", + e->e_nname.bv_val, e->e_id ); + if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_delete) ": txn_%s failed: %s (%d)\n", diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c index e897cbef262d540a3195bf8c2ccbda35d472e2e0..e79562f5faa672b7640c0b77bd4b669bbfc7396e 100644 --- a/servers/slapd/back-bdb/dn2entry.c +++ b/servers/slapd/back-bdb/dn2entry.c @@ -45,7 +45,7 @@ bdb_dn2entry( *e = NULL; - rc = bdb_cache_find_ndn( op, tid, dn, &ei ); + rc = bdb_cache_find_ndn( op, locker, dn, &ei ); if ( rc ) { if ( matched && rc == DB_NOTFOUND ) { /* Set the return value, whether we have its entry diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 3f83cf4fc6944799f0db63f575c2898f4976e852..33234ceaa005c21d17a6e094eb0ffc509ece8517 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -23,6 +23,29 @@ #include "idl.h" #include "lutil.h" +#define bdb_dn2id_lock BDB_SYMBOL(dn2id_lock) + +static int +bdb_dn2id_lock( struct bdb_info *bdb, struct berval *dn, + int rw, BDB_LOCKER locker, DB_LOCK *lock ) +{ + int rc; + DBT lockobj; + int db_rw; + + if (rw) + db_rw = DB_LOCK_WRITE; + else + db_rw = DB_LOCK_READ; + + lockobj.data = dn->bv_val; + lockobj.size = dn->bv_len; + + rc = LOCK_GET(bdb->bi_dbenv, BDB_LOCKID(locker), DB_LOCK_NOWAIT, + &lockobj, db_rw, lock); + return rc; +} + #ifndef BDB_HIER int bdb_dn2id_add( @@ -146,10 +169,11 @@ bdb_dn2id_delete( { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; - int rc; - DBT key; char *buf; + DBT key; + DB_LOCK lock; struct berval pdn, ptr; + int rc; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n", e->e_ndn, e->e_id, 0 ); @@ -165,6 +189,10 @@ bdb_dn2id_delete( AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); ptr.bv_val[ptr.bv_len] = '\0'; + /* We hold this lock until the TXN completes */ + rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, TXN_ID( txn ), &lock ); + if ( rc ) return rc; + /* delete it */ rc = db->del( db, txn, &key, 0 ); if( rc != 0 ) { @@ -244,12 +272,14 @@ done: int bdb_dn2id( Operation *op, - DB_TXN *txn, struct berval *dn, - EntryInfo *ei ) + EntryInfo *ei, + BDB_LOCKER locker, + DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; + DBC *cursor; int rc; DBT key, data; ID nid; @@ -267,8 +297,17 @@ bdb_dn2id( data.ulen = sizeof(ID); data.flags = DB_DBT_USERMEM; + rc = bdb_dn2id_lock( bdb, dn, 0, locker, lock ); + if ( rc ) return rc; + + rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags ); + if ( rc ) return rc; + if ( locker ) { + CURSOR_SETLOCKER(cursor, locker); + } + /* fetch it */ - rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags ); + rc = cursor->c_get( cursor, &key, &data, DB_SET ); if( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n", @@ -279,6 +318,7 @@ bdb_dn2id( ei->bei_id, 0, 0 ); } + cursor->c_close( cursor ); op->o_tmpfree( key.data, op->o_tmpmemctx ); return rc; } @@ -568,6 +608,7 @@ hdb_dn2id_delete( int rc; ID nid; unsigned char dlen[2]; + DB_LOCK lock; DBTzero(&key); key.size = sizeof(ID); @@ -581,6 +622,10 @@ hdb_dn2id_delete( data.dlen = data.size; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; + /* We hold this lock until the TXN completes */ + rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, TXN_ID( txn ), &lock ); + if ( rc ) return rc; + key.data = &nid; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; @@ -638,9 +683,10 @@ hdb_dn2id_delete( int hdb_dn2id( Operation *op, - DB_TXN *txn, struct berval *in, - EntryInfo *ei ) + EntryInfo *ei, + BDB_LOCKER locker, + DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; @@ -669,9 +715,15 @@ hdb_dn2id( data.dlen = data.ulen; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; - rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); + rc = bdb_dn2id_lock( bdb, in, 0, locker, lock ); if ( rc ) return rc; + rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags ); + if ( rc ) return rc; + if ( locker ) { + CURSOR_SETLOCKER( cursor, locker ); + } + d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx ); d->nrdnlen[1] = nrlen & 0xff; d->nrdnlen[0] = (nrlen >> 8) | 0x80; @@ -711,7 +763,6 @@ hdb_dn2id( int hdb_dn2id_parent( Operation *op, - DB_TXN *txn, BDB_LOCKER locker, EntryInfo *ei, ID *idp ) @@ -735,9 +786,9 @@ hdb_dn2id_parent( DBTzero(&data); data.flags = DB_DBT_USERMEM; - rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); + rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; - if ( !txn && locker ) { + if ( locker ) { CURSOR_SETLOCKER(cursor, locker); } diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c index 0e4983f0fc83387f1c5249aa7581ae025ea146fd..d5a3108d8f59fea2622560960f26aea141c732b4 100644 --- a/servers/slapd/back-bdb/filterindex.c +++ b/servers/slapd/back-bdb/filterindex.c @@ -504,7 +504,7 @@ ext_candidates( BDB_IDL_ZERO( ids ); if ( mra->ma_rule == slap_schema.si_mr_distinguishedNameMatch ) { ei = NULL; - rc = bdb_cache_find_ndn( op, NULL, &mra->ma_value, &ei ); + rc = bdb_cache_find_ndn( op, locker, &mra->ma_value, &ei ); if ( rc == LDAP_SUCCESS ) bdb_idl_insert( ids, ei->bei_id ); if ( ei ) @@ -518,7 +518,7 @@ ext_candidates( struct berval pdn; ei = NULL; dnParent( &mra->ma_value, &pdn ); - bdb_cache_find_ndn( op, NULL, &pdn, &ei ); + bdb_cache_find_ndn( op, locker, &pdn, &ei ); if ( ei ) { bdb_cache_entryinfo_unlock( ei ); while ( ei && ei->bei_id ) { @@ -538,7 +538,7 @@ ext_candidates( scope = LDAP_SCOPE_BASE; if ( scope > LDAP_SCOPE_BASE ) { ei = NULL; - rc = bdb_cache_find_ndn( op, NULL, &mra->ma_value, &ei ); + rc = bdb_cache_find_ndn( op, locker, &mra->ma_value, &ei ); if ( ei ) bdb_cache_entryinfo_unlock( ei ); if ( rc == LDAP_SUCCESS ) { diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index ffb2a3a8911e0572b312092fcfa5d7f2e63523e0..9fa9f33d62949dadb0a037866ebef33efef51ec2 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -551,7 +551,7 @@ retry: /* transaction retry */ /* Shortcut the search */ nei = neip ? neip : eip; - rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei ); + rs->sr_err = bdb_cache_find_ndn ( op, locker, &new_ndn, &nei ); if ( nei ) bdb_cache_entryinfo_unlock( nei ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 779f100a93b3968849b9506aecb0edf70f6738b7..d1691b0808d0269de28b2289337d06f017b9031f 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -97,9 +97,10 @@ int bdb_dn2entry LDAP_P(( Operation *op, DB_TXN *tid, int bdb_dn2id( Operation *op, - DB_TXN *tid, struct berval *dn, - EntryInfo *ei ); + EntryInfo *ei, + BDB_LOCKER locker, + DB_LOCK *lock ); int bdb_dn2id_add( Operation *op, @@ -132,7 +133,6 @@ int bdb_dn2idl( int bdb_dn2id_parent( Operation *op, - DB_TXN *txn, BDB_LOCKER locker, EntryInfo *ei, ID *idp ); @@ -529,7 +529,7 @@ int bdb_cache_modify( ); int bdb_cache_find_ndn( Operation *op, - DB_TXN *txn, + BDB_LOCKER locker, struct berval *ndn, EntryInfo **res ); @@ -552,7 +552,6 @@ int bdb_cache_find_id( int bdb_cache_find_parent( Operation *op, - DB_TXN *txn, BDB_LOCKER locker, ID id, EntryInfo **res diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c index e971d9080ac757261b844d891ccf444b1649eb26..05e6fc3fbaeb231b4b7b3fd426376b52957aa14b 100644 --- a/servers/slapd/back-bdb/tools.c +++ b/servers/slapd/back-bdb/tools.c @@ -231,7 +231,7 @@ ID bdb_tool_dn2id_get( op.o_tmpmemctx = NULL; op.o_tmpmfuncs = &ch_mfuncs; - rc = bdb_cache_find_ndn( &op, NULL, dn, &ei ); + rc = bdb_cache_find_ndn( &op, 0, dn, &ei ); if ( ei ) bdb_cache_entryinfo_unlock( ei ); if ( rc == DB_NOTFOUND ) return NOID; @@ -306,7 +306,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) op.o_tmpmemctx = NULL; op.o_tmpmfuncs = &ch_mfuncs; - rc = bdb_cache_find_parent( &op, NULL, CURSOR_GETLOCKER(cursor), id, &ei ); + rc = bdb_cache_find_parent( &op, CURSOR_GETLOCKER(cursor), id, &ei ); if ( rc == LDAP_SUCCESS ) { bdb_cache_entryinfo_unlock( ei ); e->e_private = ei; @@ -340,7 +340,7 @@ static int bdb_tool_next_id( return 0; } - rc = bdb_cache_find_ndn( op, tid, &ndn, &ei ); + rc = bdb_cache_find_ndn( op, TXN_ID( tid ), &ndn, &ei ); if ( ei ) bdb_cache_entryinfo_unlock( ei ); if ( rc == DB_NOTFOUND ) { if ( !be_issuffix( op->o_bd, &ndn ) ) {