Blame SOURCES/0007-Ticket-48235-Remove-memberOf-global-lock.patch

058656
From cbe71d7e4901232eaa423b9dc55dba9401c05bec Mon Sep 17 00:00:00 2001
058656
From: Mark Reynolds <mreynolds@redhat.com>
058656
Date: Fri, 13 Oct 2017 07:09:08 -0400
058656
Subject: [PATCH] Ticket 48235 - Remove memberOf global lock
058656
058656
Bug Description:  The memberOf global lock no longer servers a purpose since
058656
                  the plugin is BETXN.  This was causing potential deadlocks
058656
                  when multiple backends are used.
058656
058656
Fix Description:  Remove the lock, and rework the fixup/ancestors caches/hashtables.
058656
                  Instead of reusing a single cache, we create a fresh cache
058656
                  when we copy the plugin config (which only happens at the start
058656
                  of an operation).  Then we destroy the caches when we free
058656
                  the config.
058656
058656
https://pagure.io/389-ds-base/issue/48235
058656
058656
Reviewed by: firstyear & tbordaz(Thanks!!)
058656
058656
(cherry picked from commit 184b8a164f4ed456c72d58038aa9a0d512be61fa)
058656
---
058656
 ldap/servers/plugins/memberof/memberof.c        | 326 +++---------------------
058656
 ldap/servers/plugins/memberof/memberof.h        |  17 ++
058656
 ldap/servers/plugins/memberof/memberof_config.c | 166 +++++++++++-
058656
 3 files changed, 210 insertions(+), 299 deletions(-)
058656
058656
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
058656
index a0f997ddf..a23c52abe 100644
058656
--- a/ldap/servers/plugins/memberof/memberof.c
058656
+++ b/ldap/servers/plugins/memberof/memberof.c
058656
@@ -48,14 +48,11 @@ static Slapi_PluginDesc pdesc = {"memberof", VENDOR,
058656
 static void *_PluginID = NULL;
058656
 static Slapi_DN *_ConfigAreaDN = NULL;
058656
 static Slapi_RWLock *config_rwlock = NULL;
058656
-static Slapi_DN *_pluginDN = NULL;
058656
-static PRMonitor *memberof_operation_lock = 0;
058656
+static Slapi_DN* _pluginDN = NULL;
058656
 MemberOfConfig *qsortConfig = 0;
058656
 static int usetxn = 0;
058656
 static int premodfn = 0;
058656
-#define MEMBEROF_HASHTABLE_SIZE 1000
058656
-static PLHashTable *fixup_entry_hashtable = NULL;     /* global hash table protected by memberof_lock (memberof_operation_lock) */
058656
-static PLHashTable *group_ancestors_hashtable = NULL; /* global hash table protected by memberof_lock (memberof_operation_lock) */
058656
+
058656
 
058656
 typedef struct _memberofstringll
058656
 {
058656
@@ -73,18 +70,6 @@ typedef struct _memberof_get_groups_data
058656
     PRBool use_cache;
058656
 } memberof_get_groups_data;
058656
 
058656
-/* The key to access the hash table is the normalized DN
058656
- * The normalized DN is stored in the value because:
058656
- *  - It is used in slapi_valueset_find
058656
- *  - It is used to fill the memberof_get_groups_data.group_norm_vals
058656
- */
058656
-typedef struct _memberof_cached_value
058656
-{
058656
-    char *key;
058656
-    char *group_dn_val;
058656
-    char *group_ndn_val;
058656
-    int valid;
058656
-} memberof_cached_value;
058656
 struct cache_stat
058656
 {
058656
     int total_lookup;
058656
@@ -164,14 +149,9 @@ static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
058656
 static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
058656
 static int memberof_add_objectclass(char *auto_add_oc, const char *dn);
058656
 static int memberof_add_memberof_attr(LDAPMod **mods, const char *dn, char *add_oc);
058656
-static PLHashTable *hashtable_new();
058656
-static void fixup_hashtable_empty(char *msg);
058656
-static PLHashTable *hashtable_new();
058656
-static void ancestor_hashtable_empty(char *msg);
058656
-static void ancestor_hashtable_entry_free(memberof_cached_value *entry);
058656
-static memberof_cached_value *ancestors_cache_lookup(const char *ndn);
058656
-static PRBool ancestors_cache_remove(const char *ndn);
058656
-static PLHashEntry *ancestors_cache_add(const void *key, void *value);
058656
+static memberof_cached_value *ancestors_cache_lookup(MemberOfConfig *config, const char *ndn);
058656
+static PRBool ancestors_cache_remove(MemberOfConfig *config, const char *ndn);
058656
+static PLHashEntry *ancestors_cache_add(MemberOfConfig *config, const void *key, void *value);
058656
 
058656
 /*** implementation ***/
058656
 
058656
@@ -344,11 +324,6 @@ memberof_postop_start(Slapi_PBlock *pb)
058656
     slapi_log_err(SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
058656
                   "--> memberof_postop_start\n");
058656
 
058656
-    memberof_operation_lock = PR_NewMonitor();
058656
-    if (0 == memberof_operation_lock) {
058656
-        rc = -1;
058656
-        goto bail;
058656
-    }
058656
     if (config_rwlock == NULL) {
058656
         if ((config_rwlock = slapi_new_rwlock()) == NULL) {
058656
             rc = -1;
058656
@@ -356,9 +331,6 @@ memberof_postop_start(Slapi_PBlock *pb)
058656
         }
058656
     }
058656
 
058656
-    fixup_entry_hashtable = hashtable_new();
058656
-    group_ancestors_hashtable = hashtable_new();
058656
-
058656
     /* Set the alternate config area if one is defined. */
058656
     slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
058656
     if (config_area) {
058656
@@ -413,13 +385,13 @@ memberof_postop_start(Slapi_PBlock *pb)
058656
         goto bail;
058656
     }
058656
 
058656
-/*
058656
+    /*
058656
      * TODO: start up operation actor thread
058656
      * need to get to a point where server failure
058656
-         * or shutdown doesn't hose our operations
058656
-         * so we should create a task entry that contains
058656
+     * or shutdown doesn't hose our operations
058656
+     * so we should create a task entry that contains
058656
      * all required information to complete the operation
058656
-         * then the tasks can be restarted safely if
058656
+     * then the tasks can be restarted safely if
058656
      * interrupted
058656
      */
058656
 
058656
@@ -451,18 +423,7 @@ memberof_postop_close(Slapi_PBlock *pb __attribute__((unused)))
058656
     slapi_sdn_free(&_pluginDN);
058656
     slapi_destroy_rwlock(config_rwlock);
058656
     config_rwlock = NULL;
058656
-    PR_DestroyMonitor(memberof_operation_lock);
058656
-    memberof_operation_lock = NULL;
058656
-
058656
-    if (fixup_entry_hashtable) {
058656
-        fixup_hashtable_empty("memberof_postop_close empty fixup_entry_hastable");
058656
-        PL_HashTableDestroy(fixup_entry_hashtable);
058656
-    }
058656
 
058656
-    if (group_ancestors_hashtable) {
058656
-        ancestor_hashtable_empty("memberof_postop_close empty group_ancestors_hashtable");
058656
-        PL_HashTableDestroy(group_ancestors_hashtable);
058656
-    }
058656
     slapi_log_err(SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
058656
                   "<-- memberof_postop_close\n");
058656
     return 0;
058656
@@ -524,7 +485,7 @@ memberof_postop_del(Slapi_PBlock *pb)
058656
 {
058656
     int ret = SLAPI_PLUGIN_SUCCESS;
058656
     MemberOfConfig *mainConfig = NULL;
058656
-    MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+    MemberOfConfig configCopy = {0};
058656
     Slapi_DN *sdn;
058656
     void *caller_id = NULL;
058656
 
058656
@@ -553,9 +514,6 @@ memberof_postop_del(Slapi_PBlock *pb)
058656
         memberof_copy_config(&configCopy, memberof_get_config());
058656
         memberof_unlock_config();
058656
 
058656
-        /* get the memberOf operation lock */
058656
-        memberof_lock();
058656
-
058656
         /* remove this DN from the
058656
          * membership lists of groups
058656
          */
058656
@@ -563,7 +521,6 @@ memberof_postop_del(Slapi_PBlock *pb)
058656
             slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
058656
                           "memberof_postop_del - Error deleting dn (%s) from group. Error (%d)\n",
058656
                           slapi_sdn_get_dn(sdn), ret);
058656
-            memberof_unlock();
058656
             goto bail;
058656
         }
058656
 
058656
@@ -583,7 +540,6 @@ memberof_postop_del(Slapi_PBlock *pb)
058656
                 }
058656
             }
058656
         }
058656
-        memberof_unlock();
058656
     bail:
058656
         memberof_free_config(&configCopy);
058656
     }
058656
@@ -776,7 +732,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb __attribute__((unused)), Slapi_DN *sdn
058656
         memberof_cached_value *ht_grp = NULL;
058656
         const char *ndn = slapi_sdn_get_ndn(sdn);
058656
 
058656
-        ht_grp = ancestors_cache_lookup((const void *)ndn);
058656
+        ht_grp = ancestors_cache_lookup(config, (const void *)ndn);
058656
         if (ht_grp) {
058656
 #if MEMBEROF_CACHE_DEBUG
058656
             slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_call_foreach_dn: Ancestors of %s already cached (%x)\n", ndn, ht_grp);
058656
@@ -918,7 +874,7 @@ memberof_postop_modrdn(Slapi_PBlock *pb)
058656
 
058656
     if (memberof_oktodo(pb)) {
058656
         MemberOfConfig *mainConfig = 0;
058656
-        MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+        MemberOfConfig configCopy = {0};
058656
         struct slapi_entry *pre_e = NULL;
058656
         struct slapi_entry *post_e = NULL;
058656
         Slapi_DN *pre_sdn = 0;
058656
@@ -944,8 +900,6 @@ memberof_postop_modrdn(Slapi_PBlock *pb)
058656
             goto bail;
058656
         }
058656
 
058656
-        memberof_lock();
058656
-
058656
         /*  update any downstream members */
058656
         if (pre_sdn && post_sdn && configCopy.group_filter &&
058656
             0 == slapi_filter_test_simple(post_e, configCopy.group_filter)) {
058656
@@ -1010,7 +964,6 @@ memberof_postop_modrdn(Slapi_PBlock *pb)
058656
                 }
058656
             }
058656
         }
058656
-        memberof_unlock();
058656
     bail:
058656
         memberof_free_config(&configCopy);
058656
     }
058656
@@ -1166,7 +1119,7 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
     if (memberof_oktodo(pb)) {
058656
         int config_copied = 0;
058656
         MemberOfConfig *mainConfig = 0;
058656
-        MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+        MemberOfConfig configCopy = {0};
058656
 
058656
         /* get the mod set */
058656
         slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods;;
058656
@@ -1209,8 +1162,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
             if (interested) {
058656
                 int op = slapi_mod_get_operation(smod);
058656
 
058656
-                memberof_lock();
058656
-
058656
                 /* the modify op decides the function */
058656
                 switch (op & ~LDAP_MOD_BVALUES) {
058656
                 case LDAP_MOD_ADD: {
058656
@@ -1221,7 +1172,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
                                       "Error (%d)\n",
058656
                                       slapi_sdn_get_dn(sdn), ret);
058656
                         slapi_mod_done(next_mod);
058656
-                        memberof_unlock();
058656
                         goto bail;
058656
                     }
058656
                     break;
058656
@@ -1239,7 +1189,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
                                           "Error (%d)\n",
058656
                                           slapi_sdn_get_dn(sdn), ret);
058656
                             slapi_mod_done(next_mod);
058656
-                            memberof_unlock();
058656
                             goto bail;
058656
                         }
058656
                     } else {
058656
@@ -1250,7 +1199,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
                                           "Error (%d)\n",
058656
                                           slapi_sdn_get_dn(sdn), ret);
058656
                             slapi_mod_done(next_mod);
058656
-                            memberof_unlock();
058656
                             goto bail;
058656
                         }
058656
                     }
058656
@@ -1265,7 +1213,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
                                       "Error (%d)\n",
058656
                                       slapi_sdn_get_dn(sdn), ret);
058656
                         slapi_mod_done(next_mod);
058656
-                        memberof_unlock();
058656
                         goto bail;
058656
                     }
058656
                     break;
058656
@@ -1280,8 +1227,6 @@ memberof_postop_modify(Slapi_PBlock *pb)
058656
                     break;
058656
                 }
058656
                 }
058656
-
058656
-                memberof_unlock();
058656
             }
058656
 
058656
             slapi_mod_done(next_mod);
058656
@@ -1336,7 +1281,7 @@ memberof_postop_add(Slapi_PBlock *pb)
058656
 
058656
     if (memberof_oktodo(pb) && (sdn = memberof_getsdn(pb))) {
058656
         struct slapi_entry *e = NULL;
058656
-        MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+        MemberOfConfig configCopy = {0};
058656
         MemberOfConfig *mainConfig;
058656
         slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
058656
 
058656
@@ -1361,8 +1306,6 @@ memberof_postop_add(Slapi_PBlock *pb)
058656
             int i = 0;
058656
             Slapi_Attr *attr = 0;
058656
 
058656
-            memberof_lock();
058656
-
058656
             for (i = 0; configCopy.groupattrs && configCopy.groupattrs[i]; i++) {
058656
                 if (0 == slapi_entry_attr_find(e, configCopy.groupattrs[i], &attr)) {
058656
                     if ((ret = memberof_add_attr_list(pb, &configCopy, sdn, attr))) {
058656
@@ -1373,8 +1316,6 @@ memberof_postop_add(Slapi_PBlock *pb)
058656
                     }
058656
                 }
058656
             }
058656
-
058656
-            memberof_unlock();
058656
             memberof_free_config(&configCopy);
058656
         }
058656
     }
058656
@@ -2094,7 +2035,7 @@ dump_cache_entry(memberof_cached_value *double_check, const char *msg)
058656
  * the firsts elements of the array has 'valid=1' and the dn/ndn of group it belong to
058656
  */
058656
 static void
058656
-cache_ancestors(Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
058656
+cache_ancestors(MemberOfConfig *config, Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
058656
 {
058656
     Slapi_ValueSet *groupvals = *((memberof_get_groups_data *)groups)->groupvals;
058656
     Slapi_Value *sval;
058656
@@ -2191,14 +2132,14 @@ cache_ancestors(Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
058656
 #if MEMBEROF_CACHE_DEBUG
058656
     dump_cache_entry(cache_entry, key);
058656
 #endif
058656
-    if (ancestors_cache_add((const void *)key_copy, (void *)cache_entry) == NULL) {
058656
-        slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache_ancestors: Failed to cache ancestor of %s\n", key);
058656
+    if (ancestors_cache_add(config, (const void*) key_copy, (void *) cache_entry) == NULL) {
058656
+        slapi_log_err( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache_ancestors: Failed to cache ancestor of %s\n", key);
058656
         ancestor_hashtable_entry_free(cache_entry);
058656
-        slapi_ch_free((void **)&cache_entry);
058656
+        slapi_ch_free ((void**)&cache_entry);
058656
         return;
058656
     }
058656
 #if MEMBEROF_CACHE_DEBUG
058656
-    if (double_check = ancestors_cache_lookup((const void *)key)) {
058656
+    if (double_check = ancestors_cache_lookup(config, (const void*) key)) {
058656
         dump_cache_entry(double_check, "read back");
058656
     }
058656
 #endif
058656
@@ -2283,8 +2224,7 @@ memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn, memberof_get
058656
 
058656
     merge_ancestors(&member_ndn_val, &member_data, data);
058656
     if (!cached && member_data.use_cache)
058656
-        cache_ancestors(&member_ndn_val, &member_data);
058656
-
058656
+        cache_ancestors(config, &member_ndn_val, &member_data);
058656
 
058656
     slapi_value_free(&member_ndn_val);
058656
     slapi_valueset_free(groupvals);
058656
@@ -2825,49 +2765,10 @@ memberof_qsort_compare(const void *a, const void *b)
058656
                                     val1, val2);
058656
 }
058656
 
058656
-/* betxn: This locking mechanism is necessary to guarantee the memberof
058656
- * consistency */
058656
-void
058656
-memberof_lock()
058656
-{
058656
-    if (usetxn) {
058656
-        PR_EnterMonitor(memberof_operation_lock);
058656
-    }
058656
-    if (fixup_entry_hashtable) {
058656
-        fixup_hashtable_empty("memberof_lock");
058656
-    }
058656
-    if (group_ancestors_hashtable) {
058656
-        ancestor_hashtable_empty("memberof_lock empty group_ancestors_hashtable");
058656
-        memset(&cache_stat, 0, sizeof(cache_stat));
058656
-    }
058656
-}
058656
-
058656
-void
058656
-memberof_unlock()
058656
-{
058656
-    if (group_ancestors_hashtable) {
058656
-        ancestor_hashtable_empty("memberof_unlock empty group_ancestors_hashtable");
058656
-#if MEMBEROF_CACHE_DEBUG
058656
-        slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache statistics: total lookup %d (success %d), add %d, remove %d, enum %d\n",
058656
-                      cache_stat.total_lookup, cache_stat.successfull_lookup,
058656
-                      cache_stat.total_add, cache_stat.total_remove, cache_stat.total_enumerate);
058656
-        slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache statistics duration: lookup %ld, add %ld, remove %ld, enum %ld\n",
058656
-                      cache_stat.cumul_duration_lookup, cache_stat.cumul_duration_add,
058656
-                      cache_stat.cumul_duration_remove, cache_stat.cumul_duration_enumerate);
058656
-#endif
058656
-    }
058656
-    if (fixup_entry_hashtable) {
058656
-        fixup_hashtable_empty("memberof_lock");
058656
-    }
058656
-    if (usetxn) {
058656
-        PR_ExitMonitor(memberof_operation_lock);
058656
-    }
058656
-}
058656
-
058656
 void
058656
 memberof_fixup_task_thread(void *arg)
058656
 {
058656
-    MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+    MemberOfConfig configCopy = {0};
058656
     Slapi_Task *task = (Slapi_Task *)arg;
058656
     task_data *td = NULL;
058656
     int rc = 0;
058656
@@ -2933,9 +2834,6 @@ memberof_fixup_task_thread(void *arg)
058656
     /* do real work */
058656
     rc = memberof_fix_memberof(&configCopy, task, td);
058656
 
058656
-    /* release the memberOf operation lock */
058656
-    memberof_unlock();
058656
-
058656
 done:
058656
     if (usetxn && fixup_pb) {
058656
         if (rc) { /* failed */
058656
@@ -3100,7 +2998,7 @@ memberof_fix_memberof(MemberOfConfig *config, Slapi_Task *task, task_data *td)
058656
 }
058656
 
058656
 static memberof_cached_value *
058656
-ancestors_cache_lookup(const char *ndn)
058656
+ancestors_cache_lookup(MemberOfConfig *config, const char *ndn)
058656
 {
058656
     memberof_cached_value *e;
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
@@ -3118,7 +3016,7 @@ ancestors_cache_lookup(const char *ndn)
058656
     }
058656
 #endif
058656
 
058656
-    e = (memberof_cached_value *)PL_HashTableLookupConst(group_ancestors_hashtable, (const void *)ndn);
058656
+    e = (memberof_cached_value *) PL_HashTableLookupConst(config->ancestors_cache, (const void *) ndn);
058656
 
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
     if (start) {
058656
@@ -3133,7 +3031,7 @@ ancestors_cache_lookup(const char *ndn)
058656
     return e;
058656
 }
058656
 static PRBool
058656
-ancestors_cache_remove(const char *ndn)
058656
+ancestors_cache_remove(MemberOfConfig *config, const char *ndn)
058656
 {
058656
     PRBool rc;
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
@@ -3151,7 +3049,8 @@ ancestors_cache_remove(const char *ndn)
058656
     }
058656
 #endif
058656
 
058656
-    rc = PL_HashTableRemove(group_ancestors_hashtable, (const void *)ndn);
058656
+
058656
+    rc = PL_HashTableRemove(config->ancestors_cache, (const void *)ndn);
058656
 
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
     if (start) {
058656
@@ -3164,7 +3063,7 @@ ancestors_cache_remove(const char *ndn)
058656
 }
058656
 
058656
 static PLHashEntry *
058656
-ancestors_cache_add(const void *key, void *value)
058656
+ancestors_cache_add(MemberOfConfig *config, const void *key, void *value)
058656
 {
058656
     PLHashEntry *e;
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
@@ -3181,7 +3080,7 @@ ancestors_cache_add(const void *key, void *value)
058656
     }
058656
 #endif
058656
 
058656
-    e = PL_HashTableAdd(group_ancestors_hashtable, key, value);
058656
+    e = PL_HashTableAdd(config->ancestors_cache, key, value);
058656
 
058656
 #if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
     if (start) {
058656
@@ -3211,7 +3110,6 @@ memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
058656
     const char *ndn;
058656
     char *dn_copy;
058656
 
058656
-
058656
     /*
058656
      * If the server is ordered to shutdown, stop the fixup and return an error.
058656
      */
058656
@@ -3222,7 +3120,7 @@ memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
058656
 
058656
     /* Check if the entry has not already been fixed */
058656
     ndn = slapi_sdn_get_ndn(sdn);
058656
-    if (ndn && fixup_entry_hashtable && PL_HashTableLookupConst(fixup_entry_hashtable, (void *)ndn)) {
058656
+    if (ndn && config->fixup_cache && PL_HashTableLookupConst(config->fixup_cache, (void *)ndn)) {
058656
         slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: Entry %s already fixed up\n", ndn);
058656
         goto bail;
058656
     }
058656
@@ -3240,12 +3138,13 @@ memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
058656
              * so free this memory
058656
              */
058656
             ndn = slapi_sdn_get_ndn(sdn);
058656
+
058656
 #if MEMBEROF_CACHE_DEBUG
058656
             slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: This is NOT a group %s\n", ndn);
058656
 #endif
058656
-            ht_grp = ancestors_cache_lookup((const void *)ndn);
058656
+            ht_grp = ancestors_cache_lookup(config, (const void *)ndn);
058656
             if (ht_grp) {
058656
-                if (ancestors_cache_remove((const void *)ndn)) {
058656
+                if (ancestors_cache_remove(config, (const void *)ndn)) {
058656
                     slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: free cached values for %s\n", ndn);
058656
                     ancestor_hashtable_entry_free(ht_grp);
058656
                     slapi_ch_free((void **)&ht_grp);
058656
@@ -3297,11 +3196,11 @@ memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
058656
     slapi_valueset_free(groups);
058656
 
058656
     /* records that this entry has been fixed up */
058656
-    if (fixup_entry_hashtable) {
058656
+    if (config->fixup_cache) {
058656
         dn_copy = slapi_ch_strdup(ndn);
058656
-        if (PL_HashTableAdd(fixup_entry_hashtable, dn_copy, dn_copy) == NULL) {
058656
+        if (PL_HashTableAdd(config->fixup_cache, dn_copy, dn_copy) == NULL) {
058656
             slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: "
058656
-                                                                      "failed to add dn (%s) in the fixup hashtable; NSPR error - %d\n",
058656
+                          "failed to add dn (%s) in the fixup hashtable; NSPR error - %d\n",
058656
                           dn_copy, PR_GetError());
058656
             slapi_ch_free((void **)&dn_copy);
058656
             /* let consider this as not a fatal error, it just skip an optimization */
058656
@@ -3397,157 +3296,8 @@ memberof_add_objectclass(char *auto_add_oc, const char *dn)
058656
     return rc;
058656
 }
058656
 
058656
-static PRIntn
058656
-memberof_hash_compare_keys(const void *v1, const void *v2)
058656
-{
058656
-    PRIntn rc;
058656
-    if (0 == strcasecmp((const char *)v1, (const char *)v2)) {
058656
-        rc = 1;
058656
-    } else {
058656
-        rc = 0;
058656
-    }
058656
-    return rc;
058656
-}
058656
-
058656
-static PRIntn
058656
-memberof_hash_compare_values(const void *v1, const void *v2)
058656
-{
058656
-    PRIntn rc;
058656
-    if ((char *)v1 == (char *)v2) {
058656
-        rc = 1;
058656
-    } else {
058656
-        rc = 0;
058656
-    }
058656
-    return rc;
058656
-}
058656
-
058656
-/*
058656
- *  Hashing function using Bernstein's method
058656
- */
058656
-static PLHashNumber
058656
-memberof_hash_fn(const void *key)
058656
-{
058656
-    PLHashNumber hash = 5381;
058656
-    unsigned char *x = (unsigned char *)key;
058656
-    int c;
058656
-
058656
-    while ((c = *x++)) {
058656
-        hash = ((hash << 5) + hash) ^ c;
058656
-    }
058656
-    return hash;
058656
-}
058656
-
058656
-/* allocates the plugin hashtable
058656
- * This hash table is used by operation and is protected from
058656
- * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
058656
- * is not implemented and the hash table will be not used.
058656
- *
058656
- * The hash table contains all the DN of the entries for which the memberof
058656
- * attribute has been computed/updated during the current operation
058656
- *
058656
- * hash table should be empty at the beginning and end of the plugin callback
058656
- */
058656
-static PLHashTable *
058656
-hashtable_new()
058656
-{
058656
-    if (!usetxn) {
058656
-        return NULL;
058656
-    }
058656
-
058656
-    return PL_NewHashTable(MEMBEROF_HASHTABLE_SIZE,
058656
-                           memberof_hash_fn,
058656
-                           memberof_hash_compare_keys,
058656
-                           memberof_hash_compare_values, NULL, NULL);
058656
-}
058656
-/* this function called for each hash node during hash destruction */
058656
-static PRIntn
058656
-fixup_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
058656
-{
058656
-    char *dn_copy;
058656
-
058656
-    if (he == NULL) {
058656
-        return HT_ENUMERATE_NEXT;
058656
-    }
058656
-    dn_copy = (char *)he->value;
058656
-    slapi_ch_free_string(&dn_copy);
058656
-
058656
-    return HT_ENUMERATE_REMOVE;
058656
-}
058656
-
058656
-static void
058656
-fixup_hashtable_empty(char *msg)
058656
-{
058656
-    if (fixup_entry_hashtable) {
058656
-        PL_HashTableEnumerateEntries(fixup_entry_hashtable, fixup_hashtable_remove, msg);
058656
-    }
058656
-}
058656
-
058656
-
058656
-/* allocates the plugin hashtable
058656
- * This hash table is used by operation and is protected from
058656
- * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
058656
- * is not implemented and the hash table will be not used.
058656
- *
058656
- * The hash table contains all the DN of the entries for which the memberof
058656
- * attribute has been computed/updated during the current operation
058656
- *
058656
- * hash table should be empty at the beginning and end of the plugin callback
058656
- */
058656
-
058656
-static void
058656
-ancestor_hashtable_entry_free(memberof_cached_value *entry)
058656
-{
058656
-    int i;
058656
-    for (i = 0; entry[i].valid; i++) {
058656
-        slapi_ch_free((void **)&entry[i].group_dn_val);
058656
-        slapi_ch_free((void **)&entry[i].group_ndn_val);
058656
-    }
058656
-    /* Here we are at the ending element containing the key */
058656
-    slapi_ch_free((void **)&entry[i].key);
058656
-}
058656
-/* this function called for each hash node during hash destruction */
058656
-static PRIntn
058656
-ancestor_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
058656
-{
058656
-    memberof_cached_value *group_ancestor_array;
058656
-
058656
-    if (he == NULL) {
058656
-        return HT_ENUMERATE_NEXT;
058656
-    }
058656
-
058656
-
058656
-    group_ancestor_array = (memberof_cached_value *)he->value;
058656
-    ancestor_hashtable_entry_free(group_ancestor_array);
058656
-    slapi_ch_free((void **)&group_ancestor_array);
058656
-
058656
-    return HT_ENUMERATE_REMOVE;
058656
-}
058656
-
058656
-static void
058656
-ancestor_hashtable_empty(char *msg)
058656
+int
058656
+memberof_use_txn()
058656
 {
058656
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
-    long int start;
058656
-    struct timespec tsnow;
058656
-#endif
058656
-
058656
-    if (group_ancestors_hashtable) {
058656
-        cache_stat.total_enumerate++;
058656
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
-        if (clock_gettime(CLOCK_REALTIME, &tsnow) != 0) {
058656
-            start = 0;
058656
-        } else {
058656
-            start = tsnow.tv_nsec;
058656
-        }
058656
-#endif
058656
-        PL_HashTableEnumerateEntries(group_ancestors_hashtable, ancestor_hashtable_remove, msg);
058656
-
058656
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
058656
-        if (start) {
058656
-            if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) {
058656
-                cache_stat.cumul_duration_enumerate += (tsnow.tv_nsec - start);
058656
-            }
058656
-        }
058656
-#endif
058656
-    }
058656
+    return usetxn;
058656
 }
058656
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
058656
index 4833ce221..ba64e9dfa 100644
058656
--- a/ldap/servers/plugins/memberof/memberof.h
058656
+++ b/ldap/servers/plugins/memberof/memberof.h
058656
@@ -64,8 +64,22 @@ typedef struct memberofconfig
058656
     int skip_nested;
058656
     int fixup_task;
058656
     char *auto_add_oc;
058656
+    PLHashTable *ancestors_cache;
058656
+    PLHashTable *fixup_cache;
058656
 } MemberOfConfig;
058656
 
058656
+/* The key to access the hash table is the normalized DN
058656
+ * The normalized DN is stored in the value because:
058656
+ *  - It is used in slapi_valueset_find
058656
+ *  - It is used to fill the memberof_get_groups_data.group_norm_vals
058656
+ */
058656
+typedef struct _memberof_cached_value
058656
+{
058656
+    char *key;
058656
+    char *group_dn_val;
058656
+    char *group_ndn_val;
058656
+    int valid;
058656
+} memberof_cached_value;
058656
 
058656
 /*
058656
  * functions
058656
@@ -89,5 +103,8 @@ int memberof_apply_config(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entr
058656
 void *memberof_get_plugin_id(void);
058656
 void memberof_release_config(void);
058656
 PRUint64 get_plugin_started(void);
058656
+void ancestor_hashtable_entry_free(memberof_cached_value *entry);
058656
+PLHashTable *hashtable_new();
058656
+int memberof_use_txn();
058656
 
058656
 #endif /* _MEMBEROF_H_ */
058656
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
058656
index c5ca4b137..3f22d95d6 100644
058656
--- a/ldap/servers/plugins/memberof/memberof_config.c
058656
+++ b/ldap/servers/plugins/memberof/memberof_config.c
058656
@@ -14,12 +14,12 @@
058656
  * memberof_config.c - configuration-related code for memberOf plug-in
058656
  *
058656
  */
058656
-
058656
+#include "plhash.h"
058656
 #include <plstr.h>
058656
-
058656
 #include "memberof.h"
058656
 
058656
 #define MEMBEROF_CONFIG_FILTER "(objectclass=*)"
058656
+#define MEMBEROF_HASHTABLE_SIZE 1000
058656
 
058656
 /*
058656
  * The configuration attributes are contained in the plugin entry e.g.
058656
@@ -34,14 +34,16 @@
058656
 /*
058656
  * function prototypes
058656
  */
058656
-static int memberof_validate_config(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg);
058656
-static int
058656
-memberof_search(Slapi_PBlock *pb __attribute__((unused)),
058656
-                Slapi_Entry *entryBefore __attribute__((unused)),
058656
-                Slapi_Entry *e __attribute__((unused)),
058656
-                int *returncode __attribute__((unused)),
058656
-                char *returntext __attribute__((unused)),
058656
-                void *arg __attribute__((unused)))
058656
+static void fixup_hashtable_empty( MemberOfConfig *config, char *msg);
058656
+static void ancestor_hashtable_empty(MemberOfConfig *config, char *msg);
058656
+static int memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
058656
+										 int *returncode, char *returntext, void *arg);
058656
+static int memberof_search (Slapi_PBlock *pb __attribute__((unused)),
058656
+                            Slapi_Entry* entryBefore __attribute__((unused)),
058656
+                            Slapi_Entry* e __attribute__((unused)),
058656
+                            int *returncode __attribute__((unused)),
058656
+                            char *returntext __attribute__((unused)),
058656
+                            void *arg __attribute__((unused)))
058656
 {
058656
     return SLAPI_DSE_CALLBACK_OK;
058656
 }
058656
@@ -52,7 +54,7 @@ memberof_search(Slapi_PBlock *pb __attribute__((unused)),
058656
 /* This is the main configuration which is updated from dse.ldif.  The
058656
  * config will be copied when it is used by the plug-in to prevent it
058656
  * being changed out from under a running memberOf operation. */
058656
-static MemberOfConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
058656
+static MemberOfConfig theConfig = {0};
058656
 static Slapi_RWLock *memberof_config_lock = 0;
058656
 static int inited = 0;
058656
 
058656
@@ -693,6 +695,13 @@ void
058656
 memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
058656
 {
058656
     if (dest && src) {
058656
+
058656
+        /* Allocate our caches here since we only copy the config at the start of an op */
058656
+        if (memberof_use_txn() == 1){
058656
+            dest->ancestors_cache = hashtable_new();
058656
+            dest->fixup_cache = hashtable_new();
058656
+        }
058656
+
058656
         /* Check if the copy is already up to date */
058656
         if (src->groupattrs) {
058656
             int i = 0, j = 0;
058656
@@ -787,6 +796,14 @@ memberof_free_config(MemberOfConfig *config)
058656
         slapi_ch_free_string(&config->memberof_attr);
058656
         memberof_free_scope(&(config->entryScopes), &config->entryScopeCount);
058656
         memberof_free_scope(&(config->entryScopeExcludeSubtrees), &config->entryExcludeScopeCount);
058656
+        if (config->fixup_cache) {
058656
+            fixup_hashtable_empty(config, "memberof_free_config empty fixup_entry_hastable");
058656
+            PL_HashTableDestroy(config->fixup_cache);
058656
+        }
058656
+        if (config->ancestors_cache) {
058656
+            ancestor_hashtable_empty(config, "memberof_free_config empty group_ancestors_hashtable");
058656
+            PL_HashTableDestroy(config->ancestors_cache);
058656
+        }
058656
     }
058656
 }
058656
 
058656
@@ -982,3 +999,130 @@ bail:
058656
 
058656
     return ret;
058656
 }
058656
+
058656
+
058656
+static PRIntn memberof_hash_compare_keys(const void *v1, const void *v2)
058656
+{
058656
+    PRIntn rc;
058656
+    if (0 == strcasecmp((const char *) v1, (const char *) v2)) {
058656
+        rc = 1;
058656
+    } else {
058656
+        rc = 0;
058656
+    }
058656
+    return rc;
058656
+}
058656
+
058656
+static PRIntn memberof_hash_compare_values(const void *v1, const void *v2)
058656
+{
058656
+    PRIntn rc;
058656
+    if ((char *) v1 == (char *) v2) {
058656
+        rc = 1;
058656
+    } else {
058656
+        rc = 0;
058656
+    }
058656
+    return rc;
058656
+}
058656
+
058656
+/*
058656
+ *  Hashing function using Bernstein's method
058656
+ */
058656
+static PLHashNumber memberof_hash_fn(const void *key)
058656
+{
058656
+    PLHashNumber hash = 5381;
058656
+    unsigned char *x = (unsigned char *)key;
058656
+    int c;
058656
+
058656
+    while ((c = *x++)){
058656
+        hash = ((hash << 5) + hash) ^ c;
058656
+    }
058656
+    return hash;
058656
+}
058656
+
058656
+/* allocates the plugin hashtable
058656
+ * This hash table is used by operation and is protected from
058656
+ * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
058656
+ * is not implemented and the hash table will be not used.
058656
+ *
058656
+ * The hash table contains all the DN of the entries for which the memberof
058656
+ * attribute has been computed/updated during the current operation
058656
+ *
058656
+ * hash table should be empty at the beginning and end of the plugin callback
058656
+ */
058656
+PLHashTable *hashtable_new(int usetxn)
058656
+{
058656
+    if (!usetxn) {
058656
+        return NULL;
058656
+    }
058656
+
058656
+    return PL_NewHashTable(MEMBEROF_HASHTABLE_SIZE,
058656
+        memberof_hash_fn,
058656
+        memberof_hash_compare_keys,
058656
+        memberof_hash_compare_values, NULL, NULL);
058656
+}
058656
+
058656
+/* this function called for each hash node during hash destruction */
058656
+static PRIntn fixup_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
058656
+{
058656
+	char *dn_copy;
058656
+
058656
+	if (he == NULL) {
058656
+		return HT_ENUMERATE_NEXT;
058656
+	}
058656
+	dn_copy = (char*) he->value;
058656
+	slapi_ch_free_string(&dn_copy);
058656
+
058656
+	return HT_ENUMERATE_REMOVE;
058656
+}
058656
+
058656
+static void fixup_hashtable_empty(MemberOfConfig *config, char *msg)
058656
+{
058656
+    if (config->fixup_cache) {
058656
+        PL_HashTableEnumerateEntries(config->fixup_cache, fixup_hashtable_remove, msg);
058656
+    }
058656
+}
058656
+
058656
+
058656
+/* allocates the plugin hashtable
058656
+ * This hash table is used by operation and is protected from
058656
+ * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
058656
+ * is not implemented and the hash table will be not used.
058656
+ *
058656
+ * The hash table contains all the DN of the entries for which the memberof
058656
+ * attribute has been computed/updated during the current operation
058656
+ *
058656
+ * hash table should be empty at the beginning and end of the plugin callback
058656
+ */
058656
+
058656
+void ancestor_hashtable_entry_free(memberof_cached_value *entry)
058656
+{
058656
+    int i;
058656
+
058656
+    for (i = 0; entry[i].valid; i++) {
058656
+        slapi_ch_free((void **) &entry[i].group_dn_val);
058656
+        slapi_ch_free((void **) &entry[i].group_ndn_val);
058656
+    }
058656
+    /* Here we are at the ending element containing the key */
058656
+    slapi_ch_free((void**) &entry[i].key);
058656
+}
058656
+
058656
+/* this function called for each hash node during hash destruction */
058656
+static PRIntn ancestor_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
058656
+{
058656
+    memberof_cached_value *group_ancestor_array;
058656
+
058656
+    if (he == NULL) {
058656
+        return HT_ENUMERATE_NEXT;
058656
+    }
058656
+    group_ancestor_array = (memberof_cached_value *) he->value;
058656
+    ancestor_hashtable_entry_free(group_ancestor_array);
058656
+    slapi_ch_free((void **)&group_ancestor_array);
058656
+
058656
+    return HT_ENUMERATE_REMOVE;
058656
+}
058656
+
058656
+static void ancestor_hashtable_empty(MemberOfConfig *config, char *msg)
058656
+{
058656
+    if (config->ancestors_cache) {
058656
+        PL_HashTableEnumerateEntries(config->ancestors_cache, ancestor_hashtable_remove, msg);
058656
+    }
058656
+}
058656
-- 
058656
2.13.6
058656