Blame SOURCES/0003-Issue-5413-Allow-mutliple-MemberOf-fixup-tasks-with-.patch

63fe67
From 59ebf6618126547f3861fbef0b9a268f40ccb2bd Mon Sep 17 00:00:00 2001
63fe67
From: Mark Reynolds <mreynolds@redhat.com>
63fe67
Date: Tue, 13 Dec 2022 09:41:34 -0500
63fe67
Subject: [PATCH 3/3] Issue 5413 - Allow mutliple MemberOf fixup tasks with
63fe67
 different bases/filters
63fe67
63fe67
Description:
63fe67
63fe67
A change was made to only allow a single fixup task at a time, but there are
63fe67
cases where you would want to run mutliple tasks but on different branches/filters.
63fe67
63fe67
Now we maintain a linked list of bases/filters of the current running tasks to
63fe67
monitor this.
63fe67
63fe67
relates: https://github.com/389ds/389-ds-base/issues/5413
63fe67
63fe67
Reviewed by: tbordaz(Thanks!)
63fe67
---
63fe67
 .../suites/memberof_plugin/fixup_test.py      |   5 +-
63fe67
 ldap/servers/plugins/memberof/memberof.c      | 101 ++++++++++++++----
63fe67
 2 files changed, 85 insertions(+), 21 deletions(-)
63fe67
63fe67
diff --git a/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py b/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py
63fe67
index 9566e144c..d5369439f 100644
63fe67
--- a/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py
63fe67
+++ b/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py
63fe67
@@ -59,12 +59,15 @@ def test_fixup_task_limit(topo):
63fe67
     with pytest.raises(ldap.UNWILLING_TO_PERFORM):
63fe67
         memberof.fixup(DEFAULT_SUFFIX)
63fe67
 
63fe67
+    # Add second task but on different suffix which should be allowed
63fe67
+    memberof.fixup("ou=people," + DEFAULT_SUFFIX)
63fe67
+
63fe67
     # Wait for first task to complete
63fe67
     task.wait()
63fe67
 
63fe67
     # Add new task which should be allowed now
63fe67
     memberof.fixup(DEFAULT_SUFFIX)
63fe67
-     
63fe67
+
63fe67
 
63fe67
 if __name__ == '__main__':
63fe67
     # Run isolated
63fe67
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
63fe67
index f3f817f89..a5f48d2c0 100644
63fe67
--- a/ldap/servers/plugins/memberof/memberof.c
63fe67
+++ b/ldap/servers/plugins/memberof/memberof.c
63fe67
@@ -52,7 +52,6 @@ static Slapi_DN* _pluginDN = NULL;
63fe67
 MemberOfConfig *qsortConfig = 0;
63fe67
 static int usetxn = 0;
63fe67
 static int premodfn = 0;
63fe67
-static PRBool fixup_running = PR_FALSE;
63fe67
 static PRLock *fixup_lock = NULL;
63fe67
 static int32_t fixup_progress_count = 0;
63fe67
 static int64_t fixup_progress_elapsed = 0;
63fe67
@@ -65,6 +64,15 @@ typedef struct _memberofstringll
63fe67
     void *next;
63fe67
 } memberofstringll;
63fe67
 
63fe67
+typedef struct _fixup_ll
63fe67
+{
63fe67
+    Slapi_DN *sdn;
63fe67
+    char *filter_str;
63fe67
+    void *next;
63fe67
+} mo_fixup_ll;
63fe67
+
63fe67
+static mo_fixup_ll *fixup_list = NULL;
63fe67
+
63fe67
 typedef struct _memberof_get_groups_data
63fe67
 {
63fe67
     MemberOfConfig *config;
63fe67
@@ -438,6 +446,15 @@ memberof_postop_close(Slapi_PBlock *pb __attribute__((unused)))
63fe67
     PR_DestroyLock(fixup_lock);
63fe67
     fixup_lock = NULL;
63fe67
 
63fe67
+    mo_fixup_ll *fixup_task = fixup_list;
63fe67
+    while (fixup_task != NULL) {
63fe67
+        mo_fixup_ll *tmp = fixup_task;
63fe67
+        fixup_task = fixup_task->next;
63fe67
+        slapi_sdn_free(&tmp->sdn);
63fe67
+        slapi_ch_free_string(&tmp->filter_str);
63fe67
+        slapi_ch_free((void**)&tmp);
63fe67
+    }
63fe67
+
63fe67
     slapi_log_err(SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
63fe67
                   "<-- memberof_postop_close\n");
63fe67
     return 0;
63fe67
@@ -2817,7 +2834,6 @@ memberof_fixup_task_thread(void *arg)
63fe67
     }
63fe67
 
63fe67
     PR_Lock(fixup_lock);
63fe67
-    fixup_running = PR_TRUE;
63fe67
     fixup_progress_count = 0;
63fe67
     fixup_progress_elapsed = slapi_current_rel_time_t();
63fe67
     fixup_start_time = slapi_current_rel_time_t();
63fe67
@@ -2849,11 +2865,10 @@ memberof_fixup_task_thread(void *arg)
63fe67
     /* Mark this as a task operation */
63fe67
     configCopy.fixup_task = 1;
63fe67
     configCopy.task = task;
63fe67
-
63fe67
+    Slapi_DN *sdn = slapi_sdn_new_dn_byref(td->dn);
63fe67
     if (usetxn) {
63fe67
-        Slapi_DN *sdn = slapi_sdn_new_dn_byref(td->dn);
63fe67
         Slapi_Backend *be = slapi_be_select_exact(sdn);
63fe67
-        slapi_sdn_free(&sdn;;
63fe67
+
63fe67
         if (be) {
63fe67
             fixup_pb = slapi_pblock_new();
63fe67
             slapi_pblock_set(fixup_pb, SLAPI_BACKEND, be);
63fe67
@@ -2894,14 +2909,37 @@ done:
63fe67
                           fixup_progress_count, slapi_current_rel_time_t() - fixup_start_time);
63fe67
     slapi_task_inc_progress(task);
63fe67
 
63fe67
+    /* Cleanup task linked list */
63fe67
+    PR_Lock(fixup_lock);
63fe67
+    mo_fixup_ll *prev = NULL;
63fe67
+    for (mo_fixup_ll *curr = fixup_list; curr; curr = curr->next) {
63fe67
+        mo_fixup_ll *next = curr->next;
63fe67
+        if (slapi_sdn_compare(curr->sdn, sdn) == 0 &&
63fe67
+            strcasecmp(curr->filter_str, td->filter_str) == 0)
63fe67
+        {
63fe67
+            /* free current code */
63fe67
+            slapi_sdn_free(&curr->sdn);
63fe67
+            slapi_ch_free_string(&curr->filter_str);
63fe67
+            slapi_ch_free((void**)&curr);
63fe67
+
63fe67
+            /* update linked list */
63fe67
+            if (prev == NULL) {
63fe67
+                /* first node */
63fe67
+                fixup_list = next;
63fe67
+            } else {
63fe67
+                prev->next = next;
63fe67
+            }
63fe67
+            break;
63fe67
+        }
63fe67
+        prev = curr;
63fe67
+    }
63fe67
+    PR_Unlock(fixup_lock);
63fe67
+    slapi_sdn_free(&sdn;;
63fe67
+
63fe67
     /* this will queue the destruction of the task */
63fe67
     slapi_task_finish(task, rc);
63fe67
     slapi_task_dec_refcount(task);
63fe67
 
63fe67
-    PR_Lock(fixup_lock);
63fe67
-    fixup_running = PR_FALSE;
63fe67
-    PR_Unlock(fixup_lock);
63fe67
-
63fe67
     slapi_log_err(SLAPI_LOG_INFO, MEMBEROF_PLUGIN_SUBSYSTEM,
63fe67
                   "memberof_fixup_task_thread - Memberof task finished (processed %d entries in %ld seconds)\n",
63fe67
                   fixup_progress_count, slapi_current_rel_time_t() - fixup_start_time);
63fe67
@@ -2919,23 +2957,13 @@ memberof_task_add(Slapi_PBlock *pb,
63fe67
     int rv = SLAPI_DSE_CALLBACK_OK;
63fe67
     task_data *mytaskdata = NULL;
63fe67
     Slapi_Task *task = NULL;
63fe67
+    Slapi_DN *sdn = NULL;
63fe67
     char *bind_dn;
63fe67
     const char *filter;
63fe67
     const char *dn = 0;
63fe67
 
63fe67
     *returncode = LDAP_SUCCESS;
63fe67
 
63fe67
-    PR_Lock(fixup_lock);
63fe67
-    if (fixup_running) {
63fe67
-        PR_Unlock(fixup_lock);
63fe67
-        *returncode = LDAP_UNWILLING_TO_PERFORM;
63fe67
-        slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
63fe67
-                "memberof_task_add - there is already a fixup task running\n");
63fe67
-        rv = SLAPI_DSE_CALLBACK_ERROR;
63fe67
-        goto out;
63fe67
-    }
63fe67
-    PR_Unlock(fixup_lock);
63fe67
-
63fe67
     /* get arg(s) */
63fe67
     if ((dn = slapi_entry_attr_get_ref(e, "basedn")) == NULL) {
63fe67
         *returncode = LDAP_OBJECT_CLASS_VIOLATION;
63fe67
@@ -2949,6 +2977,39 @@ memberof_task_add(Slapi_PBlock *pb,
63fe67
         goto out;
63fe67
     }
63fe67
 
63fe67
+    PR_Lock(fixup_lock);
63fe67
+    sdn = slapi_sdn_new_dn_byval(dn);
63fe67
+    if (fixup_list == NULL) {
63fe67
+        fixup_list = (mo_fixup_ll *)slapi_ch_calloc(1, sizeof(mo_fixup_ll));
63fe67
+        fixup_list->sdn = sdn;
63fe67
+        fixup_list->filter_str = slapi_ch_strdup(filter);
63fe67
+    } else {
63fe67
+        for (mo_fixup_ll *fixup_task = fixup_list; fixup_task; fixup_task = fixup_task->next) {
63fe67
+            if (slapi_sdn_compare(sdn, fixup_task->sdn) == 0 &&
63fe67
+                strcasecmp(filter, fixup_task->filter_str) == 0)
63fe67
+            {
63fe67
+                /* Found an identical running task, reject it */
63fe67
+                PR_Unlock(fixup_lock);
63fe67
+                slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
63fe67
+                        "memberof_task_add - there is already an identical fixup task running: base: %s filter: %s\n",
63fe67
+                        slapi_sdn_get_dn(sdn), filter);
63fe67
+                slapi_sdn_free(&sdn;;
63fe67
+                *returncode = LDAP_UNWILLING_TO_PERFORM;
63fe67
+                rv = SLAPI_DSE_CALLBACK_ERROR;
63fe67
+                goto out;
63fe67
+            }
63fe67
+        }
63fe67
+        /* Add the new task DN to the top of the list */
63fe67
+        mo_fixup_ll *head = fixup_list;
63fe67
+        mo_fixup_ll *new_task = (mo_fixup_ll *)slapi_ch_calloc(1, sizeof(mo_fixup_ll));
63fe67
+        new_task->sdn = sdn;
63fe67
+        new_task->filter_str = slapi_ch_strdup(filter);
63fe67
+        new_task->next = head;
63fe67
+        fixup_list = new_task;
63fe67
+    }
63fe67
+    PR_Unlock(fixup_lock);
63fe67
+
63fe67
+
63fe67
     /* setup our task data */
63fe67
     slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn);
63fe67
     mytaskdata = (task_data *)slapi_ch_malloc(sizeof(task_data));
63fe67
-- 
63fe67
2.38.1
63fe67