ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 263 ++++++++++++++++-----------
1 file changed, 163 insertions(+), 100 deletions(-)
New commits:
commit a722b2e3acdb6b618a104f31c0867cedca091366
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Thu Jul 10 14:05:16 2014 +0200
Ticket 47797 - DB deadlock when two threads (on separated backend) try to record
changes in retroCL
Bug Description:
The DB is opened so that if a db lock can not be granted it does not wait and returns
DB_DEADLOCK
In some part of code, the server just loops retrying where it should abort the txn
(and release the locks
it may hold) and retry with a different txn
Fix Description:
If DB_LOCK_DEADLOCK is returned, the correct course of action is to abort the
(possibly nested) transaction
and retry the database operation
file:///usr/share/doc/db4-devel-4.7.25/gsg_txn/C/lockingsubsystem.html
Resolving Deadlocks
When DB determines that a deadlock has occurred, it will select a thread of control
to
resolve the deadlock and then return DB_LOCK_DEADLOCK to that thread.
If a deadlock is detected, the thread must:
Cease all read and write operations.
Close all open cursors.
Abort the transaction.
Optionally retry the operation. If your application retries deadlocked
operations, the new attempt must be made using a new transaction.
https://fedorahosted.org/389/ticket/47797
Reviewed by: Rich and Mark (Thanks)
Platforms tested: F17/F20 (ipa unit tests)
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 91397d6..2937d1b 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -113,15 +113,15 @@ static int _entryrdn_open_index(backend *be, struct attrinfo **ai,
DB **dbp);
static char *_entryrdn_encrypt_key(backend *be, const char *key, struct attrinfo *ai);
static char *_entryrdn_decrypt_key(backend *be, const char *key, struct attrinfo *ai);
#endif
-static int _entryrdn_get_elem(DBC *cursor, DBT *key, DBT *data, const char *comp_key,
rdn_elem **elem);
-static int _entryrdn_get_tombstone_elem(DBC *cursor, Slapi_RDN *srdn, DBT *key, const
char *comp_key, rdn_elem **elem);
+static int _entryrdn_get_elem(DBC *cursor, DBT *key, DBT *data, const char *comp_key,
rdn_elem **elem, DB_TXN *db_txn);
+static int _entryrdn_get_tombstone_elem(DBC *cursor, Slapi_RDN *srdn, DBT *key, const
char *comp_key, rdn_elem **elem, DB_TXN *db_txn);
static int _entryrdn_put_data(DBC *cursor, DBT *key, DBT *data, char type, DB_TXN
*db_txn);
static int _entryrdn_del_data(DBC *cursor, DBT *key, DBT *data, DB_TXN *db_txn);
static int _entryrdn_insert_key(backend *be, DBC *cursor, Slapi_RDN *srdn, ID id, DB_TXN
*db_txn);
static int _entryrdn_insert_key_elems(backend *be, DBC *cursor, Slapi_RDN *srdn, DBT
*key, rdn_elem *elem, rdn_elem *childelem, size_t childelemlen, DB_TXN *db_txn);
static int _entryrdn_delete_key(backend *be, DBC *cursor, Slapi_RDN *srdn, ID id, DB_TXN
*db_txn);
static int _entryrdn_index_read(backend *be, DBC *cursor, Slapi_RDN *srdn, rdn_elem
**elem, rdn_elem **parentelem, rdn_elem ***childelems, int flags, DB_TXN *db_txn);
-static int _entryrdn_append_childidl(DBC *cursor, const char *nrdn, ID id, IDList
**affectedidl);
+static int _entryrdn_append_childidl(DBC *cursor, const char *nrdn, ID id, IDList
**affectedidl, DB_TXN *db_txn);
static void _entryrdn_cursor_print_error(char *fn, void *key, size_t need, size_t actual,
int rc);
static int entryrdn_warning_on_encryption = 1;
@@ -1065,6 +1065,9 @@ entryrdn_get_subordinates(backend *be,
rc = _entryrdn_index_read(be, cursor, &srdn, &elem,
NULL, &childelems, 0/*flags*/, db_txn);
+ if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
+ goto bail;
+ }
for (cep = childelems; cep && *cep; cep++) {
ID childid = id_stored_to_internal((*cep)->rdn_elem_id);
@@ -1079,7 +1082,7 @@ entryrdn_get_subordinates(backend *be,
/* set indirect subordinates to the idlist */
rc = _entryrdn_append_childidl(cursor, (*cep)->rdn_elem_nrdn_rdn,
- childid, subordinates);
+ childid, subordinates, db_txn);
if (rc) {
slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
"entryrdn_get_subordinates: Appending %d to idl "
@@ -1246,13 +1249,16 @@ retry_get0:
rc = cursor->c_get(cursor, &key, &data, DB_SET);
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- /* try again */
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "entryrdn_get_parent: cursor get deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get0;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock while under
txn -> failure\n");
+ goto bail;
+ } else {
+ /* try again */
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock\n");
+ goto retry_get0;
+ }
} else if (DB_NOTFOUND == rc) { /* could be a suffix or
note: no parent for suffix */
slapi_ch_free_string(&keybuf);
@@ -1264,13 +1270,15 @@ retry_get1:
rc = cursor->c_get(cursor, &key, &data, DB_SET);
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- /* try again */
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "entryrdn_get_parent: retry cursor get
deadlock\n");
- goto retry_get1;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock while
under txn -> failure\n");
+ } else {
+ /* try again */
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: retry cursor get
deadlock\n");
+ goto retry_get1;
+ }
} else if (DB_NOTFOUND != rc) {
_entryrdn_cursor_print_error("entryrdn_lookup_dn",
key.data, data.size, data.ulen, rc);
@@ -1456,13 +1464,15 @@ retry_get0:
rc = cursor->c_get(cursor, &key, &data, DB_SET);
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "entryrdn_get_parent: cursor get deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- /* try again */
- goto retry_get0;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock while under txn
-> failure\n");
+ } else {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock\n");
+ /* try again */
+ goto retry_get0;
+ }
} else if (DB_NOTFOUND == rc) { /* could be a suffix
note: no parent for suffix */
slapi_ch_free_string(&keybuf);
@@ -1474,13 +1484,15 @@ retry_get1:
rc = cursor->c_get(cursor, &key, &data, DB_SET);
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- /* try again */
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "entryrdn_get_parent: retry cursor get
deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get1;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: cursor get deadlock while
under txn -> failure\n");
+ } else {
+ /* try again */
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "entryrdn_get_parent: retry cursor get
deadlock\n");
+ goto retry_get1;
+ }
} else if (DB_NOTFOUND != rc) {
_entryrdn_cursor_print_error("entryrdn_get_parent",
key.data, data.size, data.ulen, rc);
@@ -1764,7 +1776,8 @@ _entryrdn_get_elem(DBC *cursor,
DBT *key,
DBT *data,
const char *comp_key,
- rdn_elem **elem)
+ rdn_elem **elem,
+ DB_TXN *db_txn)
{
int rc = 0;
void *ptr = NULL;
@@ -1786,13 +1799,15 @@ retry_get:
*elem = (rdn_elem *)data->data;
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_get_elem: cursor get deadlock\n");
- /* try again */
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_elem: cursor get deadlock while under
txn -> failure\n");
+ } else {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_elem: cursor get deadlock\n");
+ /* try again */
+ goto retry_get;
+ }
} else if (DB_BUFFER_SMALL == rc) {
/* try again */
data->flags = DB_DBT_MALLOC;
@@ -1828,7 +1843,8 @@ _entryrdn_get_tombstone_elem(DBC *cursor,
Slapi_RDN *srdn,
DBT *key,
const char *comp_key,
- rdn_elem **elem)
+ rdn_elem **elem,
+ DB_TXN *db_txn)
{
int rc = 0;
DBT data;
@@ -1859,13 +1875,17 @@ _entryrdn_get_tombstone_elem(DBC *cursor,
retry_get0:
rc = cursor->c_get(cursor, key, &data, DB_SET|DB_MULTIPLE);
if (DB_LOCK_DEADLOCK == rc) {
- /* try again */
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_get_tombstone_elem: cursor get
deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get0;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_tombstone_elem: cursor get deadlock while under
txn -> failure\n");
+ goto bail;
+ } else {
+ /* try again */
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_tombstone_elem: cursor get deadlock\n");
+ goto retry_get0;
+ }
+
} else if (DB_NOTFOUND == rc) {
rc = 0; /* Child not found is ok */
goto bail;
@@ -1914,13 +1934,16 @@ retry_get0:
retry_get1:
rc = cursor->c_get(cursor, key, &data, DB_NEXT_DUP|DB_MULTIPLE);
if (DB_LOCK_DEADLOCK == rc) {
- /* try again */
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_get_tombstone_elem: retry cursor get
deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get1;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_tombstone_elem: cursor get deadlock while
under txn -> failure\n");
+ goto bail;
+ } else {
+ /* try again */
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_tombstone_elem: retry cursor get
deadlock\n");
+ goto retry_get1;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0;
goto bail; /* done */
@@ -2552,11 +2575,18 @@ _entryrdn_insert_key(backend *be,
data.flags = DB_DBT_USERMEM;
/* getting the suffix element */
- rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, &elem);
+ rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, &elem, db_txn);
if (rc) {
const char *myrdn = slapi_rdn_get_nrdn(srdn);
const char **ep = NULL;
int isexception = 0;
+
+ if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Suffix \"%s\" cursor get
fails: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ goto bail;
+ }
/* Check the RDN is in the exception list */
for (ep = rdn_exceptions; ep && *ep; ep++) {
if (!strcmp(*ep, myrdn)) {
@@ -2659,10 +2689,15 @@ _entryrdn_insert_key(backend *be,
data.flags = DB_DBT_USERMEM;
/* getting the child element */
- rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem);
+ rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem,
db_txn);
if (rc) {
slapi_ch_free((void **)&tmpelem);
- if (DB_NOTFOUND == rc) {
+ if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Suffix \"%s\" cursor get
fails: "
+ "%s(%d)\n", childnrdn, dblayer_strerror(rc), rc);
+ goto bail;
+ } else if (DB_NOTFOUND == rc) {
/* if 0 == rdnidx, Child is a Leaf RDN to be added */
if (0 == rdnidx) {
/* keybuf (C#) is consumed in _entryrdn_insert_key_elems */
@@ -2687,7 +2722,7 @@ _entryrdn_insert_key(backend *be,
* latter case.
*/
rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn, &key,
- childnrdn, &tmpelem);
+ childnrdn, &tmpelem,
db_txn);
if (rc) {
char *dn = NULL;
slapi_rdn_get_dn(tmpsrdn, &dn);
@@ -2851,13 +2886,16 @@ _entryrdn_delete_key(backend *be,
while (!done) {
rc = cursor->c_get(cursor, &key, &data, DB_SET|DB_MULTIPLE);
if (DB_LOCK_DEADLOCK == rc) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_delete_key: cursor get deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- /* try again */
- continue;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_delete_key: cursor get deadlock while under txn
-> failure\n");
+ goto bail;
+ } else {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_delete_key: cursor get deadlock\n");
+ /* try again */
+ continue;
+ }
} else if (DB_NOTFOUND == rc) {
/* no children; ok */
done = 1;
@@ -2893,13 +2931,16 @@ _entryrdn_delete_key(backend *be,
retry_get:
rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP|DB_MULTIPLE);
if (DB_LOCK_DEADLOCK == rc) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_delete_key: retry cursor get
deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- /* try again */
- goto retry_get;
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_delete_key: cursor get deadlock while under
txn -> failure\n");
+ goto bail;
+ } else {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_delete_key: retry cursor get
deadlock\n");
+ /* try again */
+ goto retry_get;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0;
done = 1;
@@ -2985,7 +3026,7 @@ retry_get:
/* Position cursor at the matching key */
rc = _entryrdn_get_elem(cursor, &key, &data,
- slapi_rdn_get_nrdn(tmpsrdn), &elem);
+ slapi_rdn_get_nrdn(tmpsrdn), &elem, db_txn);
if (tmpsrdn != srdn) {
slapi_rdn_free(&tmpsrdn);
}
@@ -3193,13 +3234,20 @@ _entryrdn_index_read(backend *be,
data.flags = DB_DBT_USERMEM;
/* getting the suffix element */
- rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, elem);
+ rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, elem, db_txn);
if (rc || NULL == *elem) {
slapi_ch_free((void **)elem);
+ if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
+ slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
+ "_entryrdn_index_read: Suffix \"%s\" cursor get
fails: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ slapi_rdn_free(&tmpsrdn);
+ goto bail;
+ }
if (flags & TOMBSTONE_INCLUDED) {
/* Node might be a tombstone. */
rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn,
- &key, nrdn, elem);
+ &key, nrdn, elem, db_txn);
rdnidx--; /* consider nsuniqueid=..,<RDN> one RDN */
}
if (rc || NULL == *elem) {
@@ -3280,9 +3328,18 @@ _entryrdn_index_read(backend *be,
data.flags = DB_DBT_USERMEM;
/* Position cursor at the matching key */
- rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem);
+ rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem,
db_txn);
if (rc) {
slapi_ch_free((void **)&tmpelem);
+ if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
+ slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
+ "_entryrdn_index_read: Suffix \"%s\" cursor get
fails: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ if (tmpsrdn != srdn) {
+ slapi_rdn_free(&tmpsrdn);
+ }
+ goto bail;
+ }
if (flags & TOMBSTONE_INCLUDED) {
/* Node might be a tombstone */
/*
@@ -3292,7 +3349,7 @@ _entryrdn_index_read(backend *be,
* nsuniqueid=...,cn=A,nsuniqueid=...,ou=B,o=C
*/
rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn, &key,
- childnrdn, &tmpelem);
+ childnrdn, &tmpelem, db_txn);
if (rc || (NULL == tmpelem)) {
slapi_ch_free((void **)&tmpelem);
if (DB_NOTFOUND != rc) {
@@ -3374,11 +3431,12 @@ retry_get0:
if (DB_LOCK_DEADLOCK == rc) {
slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
"_entryrdn_index_read: cursor get deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- /* try again */
- goto retry_get0;
+ if (db_txn) {
+ goto bail;
+ } else {
+ /* try again */
+ goto retry_get0;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0; /* Child not found is ok */
goto bail;
@@ -3418,11 +3476,13 @@ retry_get1:
if (DB_LOCK_DEADLOCK == rc) {
slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
"_entryrdn_index_read: retry cursor get
deadlock\n");
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- /* try again */
- goto retry_get1;
+
+ if (db_txn) {
+ goto bail;
+ } else {
+ /* try again */
+ goto retry_get1;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0;
goto bail; /* done */
@@ -3448,7 +3508,8 @@ static int
_entryrdn_append_childidl(DBC *cursor,
const char *nrdn,
ID id,
- IDList **affectedidl)
+ IDList **affectedidl,
+ DB_TXN *db_txn)
{
/* E.g., C5 */
char *keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
@@ -3474,11 +3535,12 @@ retry_get0:
if (DB_LOCK_DEADLOCK == rc) {
slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
"_entryrdn_append_childidl: cursor get
deadlock\n");
- /* try again */
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get0;
+ if (db_txn) {
+ goto bail;
+ } else {
+ /* try again */
+ goto retry_get0;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0; /* okay not to have children */
} else {
@@ -3513,7 +3575,7 @@ retry_get0:
}
rc = _entryrdn_append_childidl(cursor,
(const char *)myelem->rdn_elem_nrdn_rdn,
- myid, affectedidl);
+ myid, affectedidl, db_txn);
if (rc) {
goto bail;
}
@@ -3524,11 +3586,12 @@ retry_get1:
if (DB_LOCK_DEADLOCK == rc) {
slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
"_entryrdn_append_childidl: retry cursor get
deadlock\n");
- /* try again */
-#ifdef FIX_TXN_DEADLOCKS
-#error if txn != NULL, have to retry the entire transaction
-#endif
- goto retry_get1;
+ if (db_txn) {
+ goto bail;
+ } else {
+ /* try again */
+ goto retry_get1;
+ }
} else if (DB_NOTFOUND == rc) {
rc = 0; /* okay not to have children */
} else {