andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
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