|
|
dc8c34 |
From 4fd2c69b0799dc581d270262880444584ae17599 Mon Sep 17 00:00:00 2001
|
|
|
dc8c34 |
From: Noriko Hosoi <nhosoi@redhat.com>
|
|
|
dc8c34 |
Date: Fri, 9 May 2014 10:10:49 -0700
|
|
|
dc8c34 |
Subject: [PATCH 210/225] Ticket #47764 - Problem with deletion while
|
|
|
dc8c34 |
replicated
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Bug description: When checking a child entry on a node, it only
|
|
|
dc8c34 |
checked the first position, which was normally "deleted" if there
|
|
|
dc8c34 |
were no more children. But in some cases, a tombstoned child was
|
|
|
dc8c34 |
placed there. If it occurred, even though there were no live child
|
|
|
dc8c34 |
any more, _entryrdn_delete_key returned "has children" and the delete
|
|
|
dc8c34 |
operation failed.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Fix description: This patch checks all the children of the to-be-
|
|
|
dc8c34 |
deleted node and if there is no child or all of them are tombstones,
|
|
|
dc8c34 |
it goes to the next process. Also, the fixed a typo reported by
|
|
|
dc8c34 |
chatfield (Thank you!!)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
https://fedorahosted.org/389/ticket/47764
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Reviewed by chatfield and mreynolds@redhat.com (Thank you both!!)
|
|
|
dc8c34 |
(cherry picked from commit 832253ea96b83e7ebc16fe507d77090e87aed1c2)
|
|
|
dc8c34 |
(cherry picked from commit 86b34ca0a002715a263a56b1e8c870dd3035bce4)
|
|
|
dc8c34 |
(cherry picked from commit efa23ced2a6e3de3389d9b801329066f511bc38c)
|
|
|
dc8c34 |
(cherry picked from commit ca407f8a684e58067440f57049794c47255cf716)
|
|
|
dc8c34 |
---
|
|
|
dc8c34 |
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 92 +++++++++++++++++++---------
|
|
|
dc8c34 |
1 file changed, 64 insertions(+), 28 deletions(-)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
|
dc8c34 |
index 6426fb7..38b407d 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
|
dc8c34 |
@@ -2795,6 +2795,8 @@ _entryrdn_delete_key(backend *be,
|
|
|
dc8c34 |
int issuffix = 0;
|
|
|
dc8c34 |
Slapi_RDN *tmpsrdn = NULL;
|
|
|
dc8c34 |
int db_retry = 0;
|
|
|
dc8c34 |
+ int done = 0;
|
|
|
dc8c34 |
+ char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
|
|
|
dc8c34 |
|
|
|
dc8c34 |
slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
|
|
|
dc8c34 |
"--> _entryrdn_delete_key\n");
|
|
|
dc8c34 |
@@ -2828,45 +2830,79 @@ _entryrdn_delete_key(backend *be,
|
|
|
dc8c34 |
/* check if the target element has a child or not */
|
|
|
dc8c34 |
keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
|
|
|
dc8c34 |
key.data = (void *)keybuf;
|
|
|
dc8c34 |
- key.size = key.ulen = strlen(nrdn) + 1;
|
|
|
dc8c34 |
+ key.size = key.ulen = strlen(keybuf) + 1;
|
|
|
dc8c34 |
key.flags = DB_DBT_USERMEM;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+ /* Setting the bulk fetch buffer */
|
|
|
dc8c34 |
memset(&data, 0, sizeof(data));
|
|
|
dc8c34 |
- data.flags = DB_DBT_MALLOC;
|
|
|
dc8c34 |
+ data.ulen = sizeof(buffer);
|
|
|
dc8c34 |
+ data.size = sizeof(buffer);
|
|
|
dc8c34 |
+ data.data = buffer;
|
|
|
dc8c34 |
+ data.flags = DB_DBT_USERMEM;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
- for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
|
|
|
dc8c34 |
- rc = cursor->c_get(cursor, &key, &data, DB_SET);
|
|
|
dc8c34 |
- if (rc) {
|
|
|
dc8c34 |
+ done = 0;
|
|
|
dc8c34 |
+ while (!done) {
|
|
|
dc8c34 |
+ rc = cursor->c_get(cursor, &key, &data, DB_SET|DB_MULTIPLE);
|
|
|
dc8c34 |
+ if (DB_LOCK_DEADLOCK == rc) {
|
|
|
dc8c34 |
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
|
|
|
dc8c34 |
+ "_entryrdn_delete_key: cursor get deadlock\n");
|
|
|
dc8c34 |
+#ifdef FIX_TXN_DEADLOCKS
|
|
|
dc8c34 |
+#error if txn != NULL, have to retry the entire transaction
|
|
|
dc8c34 |
+#endif
|
|
|
dc8c34 |
+ /* try again */
|
|
|
dc8c34 |
+ continue;
|
|
|
dc8c34 |
+ } else if (DB_NOTFOUND == rc) {
|
|
|
dc8c34 |
+ /* no children; ok */
|
|
|
dc8c34 |
+ done = 1;
|
|
|
dc8c34 |
+ continue;
|
|
|
dc8c34 |
+ } else if (rc) {
|
|
|
dc8c34 |
+ _entryrdn_cursor_print_error("_entryrdn_delete_key",
|
|
|
dc8c34 |
+ key.data, data.size, data.ulen, rc);
|
|
|
dc8c34 |
+ goto bail;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ do {
|
|
|
dc8c34 |
+ rdn_elem *childelem = NULL;
|
|
|
dc8c34 |
+ DBT dataret;
|
|
|
dc8c34 |
+ void *ptr;
|
|
|
dc8c34 |
+ DB_MULTIPLE_INIT(ptr, &data);
|
|
|
dc8c34 |
+ do {
|
|
|
dc8c34 |
+ memset(&dataret, 0, sizeof(dataret));
|
|
|
dc8c34 |
+ DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
|
|
|
dc8c34 |
+ if (NULL == dataret.data || NULL == ptr) {
|
|
|
dc8c34 |
+ break;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ childelem = (rdn_elem *)dataret.data;
|
|
|
dc8c34 |
+ if (!slapi_is_special_rdn(childelem->rdn_elem_nrdn_rdn, RDN_IS_TOMBSTONE)) {
|
|
|
dc8c34 |
+ /* there's at least one live child */
|
|
|
dc8c34 |
+ slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
|
|
|
dc8c34 |
+ "_entryrdn_delete_key: Failed to remove %s; "
|
|
|
dc8c34 |
+ "has a child %s\n", nrdn,
|
|
|
dc8c34 |
+ (char *)childelem->rdn_elem_nrdn_rdn);
|
|
|
dc8c34 |
+ rc = -1;
|
|
|
dc8c34 |
+ goto bail;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ } while (NULL != dataret.data && NULL != ptr);
|
|
|
dc8c34 |
+retry_get:
|
|
|
dc8c34 |
+ rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP|DB_MULTIPLE);
|
|
|
dc8c34 |
if (DB_LOCK_DEADLOCK == rc) {
|
|
|
dc8c34 |
slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
|
|
|
dc8c34 |
- "_entryrdn_delete_key: cursor get deadlock\n");
|
|
|
dc8c34 |
+ "_entryrdn_delete_key: retry cursor get deadlock\n");
|
|
|
dc8c34 |
+#ifdef FIX_TXN_DEADLOCKS
|
|
|
dc8c34 |
+#error if txn != NULL, have to retry the entire transaction
|
|
|
dc8c34 |
+#endif
|
|
|
dc8c34 |
/* try again */
|
|
|
dc8c34 |
- if (db_txn) {
|
|
|
dc8c34 |
- goto bail; /* have to abort/retry the entire transaction */
|
|
|
dc8c34 |
- } else {
|
|
|
dc8c34 |
- ENTRYRDN_DELAY; /* sleep for a bit then retry immediately */
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
- } else if (DB_NOTFOUND != rc) {
|
|
|
dc8c34 |
+ goto retry_get;
|
|
|
dc8c34 |
+ } else if (DB_NOTFOUND == rc) {
|
|
|
dc8c34 |
+ rc = 0;
|
|
|
dc8c34 |
+ done = 1;
|
|
|
dc8c34 |
+ break;
|
|
|
dc8c34 |
+ } else if (rc) {
|
|
|
dc8c34 |
_entryrdn_cursor_print_error("_entryrdn_delete_key",
|
|
|
dc8c34 |
key.data, data.size, data.ulen, rc);
|
|
|
dc8c34 |
goto bail;
|
|
|
dc8c34 |
- } else {
|
|
|
dc8c34 |
- break; /* DB_NOTFOUND - ok */
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
- } else {
|
|
|
dc8c34 |
- slapi_ch_free(&data.data);
|
|
|
dc8c34 |
- slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
|
|
|
dc8c34 |
- "_entryrdn_delete_key: Failed to remove %s; "
|
|
|
dc8c34 |
- "has children\n", nrdn);
|
|
|
dc8c34 |
- rc = -1;
|
|
|
dc8c34 |
- goto bail;
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
- if (RETRY_TIMES == db_retry) {
|
|
|
dc8c34 |
- slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
|
|
|
dc8c34 |
- "_entryrdn_delete_key: failed after [%d] iterations\n", db_retry);
|
|
|
dc8c34 |
- rc = DB_LOCK_DEADLOCK;
|
|
|
dc8c34 |
- goto bail;
|
|
|
dc8c34 |
+ } while (0 == rc);
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
workid = id;
|
|
|
dc8c34 |
--
|
|
|
dc8c34 |
1.8.1.4
|
|
|
dc8c34 |
|