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 ) ) {