|
|
b69e47 |
From 229f61f5f54aeb9e1a1756f731dfe7bcedbf148c Mon Sep 17 00:00:00 2001
|
|
|
b69e47 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
b69e47 |
Date: Fri, 13 Oct 2017 07:09:08 -0400
|
|
|
b69e47 |
Subject: [PATCH 06/10] Ticket 48235 - Remove memberOf global lock
|
|
|
b69e47 |
|
|
|
b69e47 |
Bug Description: The memberOf global lock no longer servers a purpose since
|
|
|
b69e47 |
the plugin is BETXN. This was causing potential deadlocks
|
|
|
b69e47 |
when multiple backends are used.
|
|
|
b69e47 |
|
|
|
b69e47 |
Fix Description: Remove the lock, and rework the fixup/ancestors caches/hashtables.
|
|
|
b69e47 |
Instead of reusing a single cache, we create a fresh cache
|
|
|
b69e47 |
when we copy the plugin config (which only happens at the start
|
|
|
b69e47 |
of an operation). Then we destroy the caches when we free
|
|
|
b69e47 |
the config.
|
|
|
b69e47 |
|
|
|
b69e47 |
https://pagure.io/389-ds-base/issue/48235
|
|
|
b69e47 |
|
|
|
b69e47 |
Reviewed by: tbordaz & firstyear(Thanks!!)
|
|
|
b69e47 |
---
|
|
|
b69e47 |
ldap/servers/plugins/memberof/memberof.c | 312 +++---------------------
|
|
|
b69e47 |
ldap/servers/plugins/memberof/memberof.h | 17 ++
|
|
|
b69e47 |
ldap/servers/plugins/memberof/memberof_config.c | 152 +++++++++++-
|
|
|
b69e47 |
3 files changed, 200 insertions(+), 281 deletions(-)
|
|
|
b69e47 |
|
|
|
b69e47 |
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
|
|
|
b69e47 |
index 9bbe13c9c..bbf47dd49 100644
|
|
|
b69e47 |
--- a/ldap/servers/plugins/memberof/memberof.c
|
|
|
b69e47 |
+++ b/ldap/servers/plugins/memberof/memberof.c
|
|
|
b69e47 |
@@ -49,13 +49,10 @@ static void* _PluginID = NULL;
|
|
|
b69e47 |
static Slapi_DN* _ConfigAreaDN = NULL;
|
|
|
b69e47 |
static Slapi_RWLock *config_rwlock = NULL;
|
|
|
b69e47 |
static Slapi_DN* _pluginDN = NULL;
|
|
|
b69e47 |
-static PRMonitor *memberof_operation_lock = 0;
|
|
|
b69e47 |
MemberOfConfig *qsortConfig = 0;
|
|
|
b69e47 |
static int usetxn = 0;
|
|
|
b69e47 |
static int premodfn = 0;
|
|
|
b69e47 |
-#define MEMBEROF_HASHTABLE_SIZE 1000
|
|
|
b69e47 |
-static PLHashTable *fixup_entry_hashtable = NULL; /* global hash table protected by memberof_lock (memberof_operation_lock) */
|
|
|
b69e47 |
-static PLHashTable *group_ancestors_hashtable = NULL; /* global hash table protected by memberof_lock (memberof_operation_lock) */
|
|
|
b69e47 |
+
|
|
|
b69e47 |
|
|
|
b69e47 |
typedef struct _memberofstringll
|
|
|
b69e47 |
{
|
|
|
b69e47 |
@@ -73,18 +70,7 @@ typedef struct _memberof_get_groups_data
|
|
|
b69e47 |
PRBool use_cache;
|
|
|
b69e47 |
} memberof_get_groups_data;
|
|
|
b69e47 |
|
|
|
b69e47 |
-/* The key to access the hash table is the normalized DN
|
|
|
b69e47 |
- * The normalized DN is stored in the value because:
|
|
|
b69e47 |
- * - It is used in slapi_valueset_find
|
|
|
b69e47 |
- * - It is used to fill the memberof_get_groups_data.group_norm_vals
|
|
|
b69e47 |
- */
|
|
|
b69e47 |
-typedef struct _memberof_cached_value
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- char *key;
|
|
|
b69e47 |
- char *group_dn_val;
|
|
|
b69e47 |
- char *group_ndn_val;
|
|
|
b69e47 |
- int valid;
|
|
|
b69e47 |
-} memberof_cached_value;
|
|
|
b69e47 |
+
|
|
|
b69e47 |
struct cache_stat
|
|
|
b69e47 |
{
|
|
|
b69e47 |
int total_lookup;
|
|
|
b69e47 |
@@ -189,14 +175,9 @@ static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
|
|
|
b69e47 |
static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
|
|
|
b69e47 |
static int memberof_add_objectclass(char *auto_add_oc, const char *dn);
|
|
|
b69e47 |
static int memberof_add_memberof_attr(LDAPMod **mods, const char *dn, char *add_oc);
|
|
|
b69e47 |
-static PLHashTable *hashtable_new();
|
|
|
b69e47 |
-static void fixup_hashtable_empty(char *msg);
|
|
|
b69e47 |
-static PLHashTable *hashtable_new();
|
|
|
b69e47 |
-static void ancestor_hashtable_empty(char *msg);
|
|
|
b69e47 |
-static void ancestor_hashtable_entry_free(memberof_cached_value *entry);
|
|
|
b69e47 |
-static memberof_cached_value *ancestors_cache_lookup(const char *ndn);
|
|
|
b69e47 |
-static PRBool ancestors_cache_remove(const char *ndn);
|
|
|
b69e47 |
-static PLHashEntry *ancestors_cache_add(const void *key, void *value);
|
|
|
b69e47 |
+static memberof_cached_value *ancestors_cache_lookup(MemberOfConfig *config, const char *ndn);
|
|
|
b69e47 |
+static PRBool ancestors_cache_remove(MemberOfConfig *config, const char *ndn);
|
|
|
b69e47 |
+static PLHashEntry *ancestors_cache_add(MemberOfConfig *config, const void *key, void *value);
|
|
|
b69e47 |
|
|
|
b69e47 |
/*** implementation ***/
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -375,12 +356,6 @@ int memberof_postop_start(Slapi_PBlock *pb)
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
|
|
|
b69e47 |
"--> memberof_postop_start\n" );
|
|
|
b69e47 |
|
|
|
b69e47 |
- memberof_operation_lock = PR_NewMonitor();
|
|
|
b69e47 |
- if(0 == memberof_operation_lock)
|
|
|
b69e47 |
- {
|
|
|
b69e47 |
- rc = -1;
|
|
|
b69e47 |
- goto bail;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
if(config_rwlock == NULL){
|
|
|
b69e47 |
if((config_rwlock = slapi_new_rwlock()) == NULL){
|
|
|
b69e47 |
rc = -1;
|
|
|
b69e47 |
@@ -388,9 +363,6 @@ int memberof_postop_start(Slapi_PBlock *pb)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
- fixup_entry_hashtable = hashtable_new();
|
|
|
b69e47 |
- group_ancestors_hashtable = hashtable_new();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
/* Set the alternate config area if one is defined. */
|
|
|
b69e47 |
slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
|
|
|
b69e47 |
if (config_area)
|
|
|
b69e47 |
@@ -482,18 +454,7 @@ int memberof_postop_close(Slapi_PBlock *pb)
|
|
|
b69e47 |
slapi_sdn_free(&_pluginDN);
|
|
|
b69e47 |
slapi_destroy_rwlock(config_rwlock);
|
|
|
b69e47 |
config_rwlock = NULL;
|
|
|
b69e47 |
- PR_DestroyMonitor(memberof_operation_lock);
|
|
|
b69e47 |
- memberof_operation_lock = NULL;
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- if (fixup_entry_hashtable) {
|
|
|
b69e47 |
- fixup_hashtable_empty("memberof_postop_close empty fixup_entry_hastable");
|
|
|
b69e47 |
- PL_HashTableDestroy(fixup_entry_hashtable);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
|
|
|
b69e47 |
- if (group_ancestors_hashtable) {
|
|
|
b69e47 |
- ancestor_hashtable_empty("memberof_postop_close empty group_ancestors_hashtable");
|
|
|
b69e47 |
- PL_HashTableDestroy(group_ancestors_hashtable);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
|
|
|
b69e47 |
"<-- memberof_postop_close\n" );
|
|
|
b69e47 |
return 0;
|
|
|
b69e47 |
@@ -554,7 +515,7 @@ int memberof_postop_del(Slapi_PBlock *pb)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
int ret = SLAPI_PLUGIN_SUCCESS;
|
|
|
b69e47 |
MemberOfConfig *mainConfig = NULL;
|
|
|
b69e47 |
- MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+ MemberOfConfig configCopy = {0};
|
|
|
b69e47 |
Slapi_DN *sdn;
|
|
|
b69e47 |
void *caller_id = NULL;
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -583,9 +544,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
memberof_copy_config(&configCopy, memberof_get_config());
|
|
|
b69e47 |
memberof_unlock_config();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- /* get the memberOf operation lock */
|
|
|
b69e47 |
- memberof_lock();
|
|
|
b69e47 |
|
|
|
b69e47 |
/* remove this DN from the
|
|
|
b69e47 |
* membership lists of groups
|
|
|
b69e47 |
@@ -594,7 +552,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
|
|
|
b69e47 |
"memberof_postop_del - Error deleting dn (%s) from group. Error (%d)\n",
|
|
|
b69e47 |
slapi_sdn_get_dn(sdn),ret);
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -618,7 +575,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
bail:
|
|
|
b69e47 |
memberof_free_config(&configCopy);
|
|
|
b69e47 |
}
|
|
|
b69e47 |
@@ -813,7 +769,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb __attribute__((unused)), Slapi_DN *sdn
|
|
|
b69e47 |
memberof_cached_value *ht_grp = NULL;
|
|
|
b69e47 |
const char *ndn = slapi_sdn_get_ndn(sdn);
|
|
|
b69e47 |
|
|
|
b69e47 |
- ht_grp = ancestors_cache_lookup((const void *) ndn);
|
|
|
b69e47 |
+ ht_grp = ancestors_cache_lookup(config, (const void *) ndn);
|
|
|
b69e47 |
if (ht_grp) {
|
|
|
b69e47 |
#if MEMBEROF_CACHE_DEBUG
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_call_foreach_dn: Ancestors of %s already cached (%x)\n", ndn, ht_grp);
|
|
|
b69e47 |
@@ -960,7 +916,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
|
|
|
b69e47 |
if(memberof_oktodo(pb))
|
|
|
b69e47 |
{
|
|
|
b69e47 |
MemberOfConfig *mainConfig = 0;
|
|
|
b69e47 |
- MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+ MemberOfConfig configCopy = {0};
|
|
|
b69e47 |
struct slapi_entry *pre_e = NULL;
|
|
|
b69e47 |
struct slapi_entry *post_e = NULL;
|
|
|
b69e47 |
Slapi_DN *pre_sdn = 0;
|
|
|
b69e47 |
@@ -988,8 +944,6 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
- memberof_lock();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
/* update any downstream members */
|
|
|
b69e47 |
if(pre_sdn && post_sdn && configCopy.group_filter &&
|
|
|
b69e47 |
0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
|
|
|
b69e47 |
@@ -1060,7 +1014,6 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
bail:
|
|
|
b69e47 |
memberof_free_config(&configCopy);
|
|
|
b69e47 |
}
|
|
|
b69e47 |
@@ -1220,7 +1173,7 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
int config_copied = 0;
|
|
|
b69e47 |
MemberOfConfig *mainConfig = 0;
|
|
|
b69e47 |
- MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+ MemberOfConfig configCopy = {0};
|
|
|
b69e47 |
|
|
|
b69e47 |
/* get the mod set */
|
|
|
b69e47 |
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods;;
|
|
|
b69e47 |
@@ -1267,8 +1220,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
int op = slapi_mod_get_operation(smod);
|
|
|
b69e47 |
|
|
|
b69e47 |
- memberof_lock();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
/* the modify op decides the function */
|
|
|
b69e47 |
switch(op & ~LDAP_MOD_BVALUES)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
@@ -1280,7 +1231,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
"memberof_postop_modify - Failed to add dn (%s) to target. "
|
|
|
b69e47 |
"Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
|
|
|
b69e47 |
slapi_mod_done(next_mod);
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
break;
|
|
|
b69e47 |
@@ -1299,7 +1249,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
"memberof_postop_modify - Failed to replace list (%s). "
|
|
|
b69e47 |
"Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
|
|
|
b69e47 |
slapi_mod_done(next_mod);
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
@@ -1311,7 +1260,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
"memberof_postop_modify: failed to remove dn (%s). "
|
|
|
b69e47 |
"Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
|
|
|
b69e47 |
slapi_mod_done(next_mod);
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
@@ -1326,7 +1274,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
"memberof_postop_modify - Failed to replace values in dn (%s). "
|
|
|
b69e47 |
"Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
|
|
|
b69e47 |
slapi_mod_done(next_mod);
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
break;
|
|
|
b69e47 |
@@ -1342,8 +1289,6 @@ int memberof_postop_modify(Slapi_PBlock *pb)
|
|
|
b69e47 |
break;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
slapi_mod_done(next_mod);
|
|
|
b69e47 |
@@ -1398,7 +1343,7 @@ int memberof_postop_add(Slapi_PBlock *pb)
|
|
|
b69e47 |
if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
|
|
|
b69e47 |
{
|
|
|
b69e47 |
struct slapi_entry *e = NULL;
|
|
|
b69e47 |
- MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+ MemberOfConfig configCopy = {0};
|
|
|
b69e47 |
MemberOfConfig *mainConfig;
|
|
|
b69e47 |
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e );
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -1424,8 +1369,6 @@ int memberof_postop_add(Slapi_PBlock *pb)
|
|
|
b69e47 |
int i = 0;
|
|
|
b69e47 |
Slapi_Attr *attr = 0;
|
|
|
b69e47 |
|
|
|
b69e47 |
- memberof_lock();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
for (i = 0; configCopy.groupattrs && configCopy.groupattrs[i]; i++)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
if(0 == slapi_entry_attr_find(e, configCopy.groupattrs[i], &attr))
|
|
|
b69e47 |
@@ -1438,8 +1381,6 @@ int memberof_postop_add(Slapi_PBlock *pb)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
memberof_free_config(&configCopy);
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
@@ -2201,7 +2142,7 @@ dump_cache_entry(memberof_cached_value *double_check, const char *msg)
|
|
|
b69e47 |
* the firsts elements of the array has 'valid=1' and the dn/ndn of group it belong to
|
|
|
b69e47 |
*/
|
|
|
b69e47 |
static void
|
|
|
b69e47 |
-cache_ancestors(Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
|
|
|
b69e47 |
+cache_ancestors(MemberOfConfig *config, Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)groups)->groupvals;
|
|
|
b69e47 |
Slapi_Value *sval;
|
|
|
b69e47 |
@@ -2298,14 +2239,14 @@ cache_ancestors(Slapi_Value **member_ndn_val, memberof_get_groups_data *groups)
|
|
|
b69e47 |
#if MEMBEROF_CACHE_DEBUG
|
|
|
b69e47 |
dump_cache_entry(cache_entry, key);
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
- if (ancestors_cache_add((const void*) key_copy, (void *) cache_entry) == NULL) {
|
|
|
b69e47 |
+ if (ancestors_cache_add(config, (const void*) key_copy, (void *) cache_entry) == NULL) {
|
|
|
b69e47 |
slapi_log_err( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache_ancestors: Failed to cache ancestor of %s\n", key);
|
|
|
b69e47 |
ancestor_hashtable_entry_free(cache_entry);
|
|
|
b69e47 |
slapi_ch_free ((void**)&cache_entry);
|
|
|
b69e47 |
return;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
#if MEMBEROF_CACHE_DEBUG
|
|
|
b69e47 |
- if (double_check = ancestors_cache_lookup((const void*) key)) {
|
|
|
b69e47 |
+ if (double_check = ancestors_cache_lookup(config, (const void*) key)) {
|
|
|
b69e47 |
dump_cache_entry(double_check, "read back");
|
|
|
b69e47 |
}
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
@@ -2390,9 +2331,9 @@ memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
|
|
|
b69e47 |
memberof_get_groups_callback, &member_data, &cached, member_data.use_cache);
|
|
|
b69e47 |
|
|
|
b69e47 |
merge_ancestors(&member_ndn_val, &member_data, data);
|
|
|
b69e47 |
- if (!cached && member_data.use_cache)
|
|
|
b69e47 |
- cache_ancestors(&member_ndn_val, &member_data);
|
|
|
b69e47 |
-
|
|
|
b69e47 |
+ if (!cached && member_data.use_cache) {
|
|
|
b69e47 |
+ cache_ancestors(config, &member_ndn_val, &member_data);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
|
|
|
b69e47 |
slapi_value_free(&member_ndn_val);
|
|
|
b69e47 |
slapi_valueset_free(groupvals);
|
|
|
b69e47 |
@@ -2969,46 +2910,9 @@ int memberof_qsort_compare(const void *a, const void *b)
|
|
|
b69e47 |
val1, val2);
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
-/* betxn: This locking mechanism is necessary to guarantee the memberof
|
|
|
b69e47 |
- * consistency */
|
|
|
b69e47 |
-void memberof_lock()
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- if (usetxn) {
|
|
|
b69e47 |
- PR_EnterMonitor(memberof_operation_lock);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- if (fixup_entry_hashtable) {
|
|
|
b69e47 |
- fixup_hashtable_empty("memberof_lock");
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- if (group_ancestors_hashtable) {
|
|
|
b69e47 |
- ancestor_hashtable_empty("memberof_lock empty group_ancestors_hashtable");
|
|
|
b69e47 |
- memset(&cache_stat, 0, sizeof(cache_stat));
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-void memberof_unlock()
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- if (group_ancestors_hashtable) {
|
|
|
b69e47 |
- ancestor_hashtable_empty("memberof_unlock empty group_ancestors_hashtable");
|
|
|
b69e47 |
-#if MEMBEROF_CACHE_DEBUG
|
|
|
b69e47 |
- slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache statistics: total lookup %d (success %d), add %d, remove %d, enum %d\n",
|
|
|
b69e47 |
- cache_stat.total_lookup, cache_stat.successfull_lookup,
|
|
|
b69e47 |
- cache_stat.total_add, cache_stat.total_remove, cache_stat.total_enumerate);
|
|
|
b69e47 |
- slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "cache statistics duration: lookup %ld, add %ld, remove %ld, enum %ld\n",
|
|
|
b69e47 |
- cache_stat.cumul_duration_lookup, cache_stat.cumul_duration_add,
|
|
|
b69e47 |
- cache_stat.cumul_duration_remove, cache_stat.cumul_duration_enumerate);
|
|
|
b69e47 |
-#endif
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- if (fixup_entry_hashtable) {
|
|
|
b69e47 |
- fixup_hashtable_empty("memberof_lock");
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- if (usetxn) {
|
|
|
b69e47 |
- PR_ExitMonitor(memberof_operation_lock);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
void memberof_fixup_task_thread(void *arg)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
- MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+ MemberOfConfig configCopy = {0};
|
|
|
b69e47 |
Slapi_Task *task = (Slapi_Task *)arg;
|
|
|
b69e47 |
task_data *td = NULL;
|
|
|
b69e47 |
int rc = 0;
|
|
|
b69e47 |
@@ -3068,14 +2972,8 @@ void memberof_fixup_task_thread(void *arg)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
- /* get the memberOf operation lock */
|
|
|
b69e47 |
- memberof_lock();
|
|
|
b69e47 |
-
|
|
|
b69e47 |
/* do real work */
|
|
|
b69e47 |
rc = memberof_fix_memberof(&configCopy, task, td);
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- /* release the memberOf operation lock */
|
|
|
b69e47 |
- memberof_unlock();
|
|
|
b69e47 |
|
|
|
b69e47 |
done:
|
|
|
b69e47 |
if (usetxn && fixup_pb) {
|
|
|
b69e47 |
@@ -3240,7 +3138,7 @@ int memberof_fix_memberof(MemberOfConfig *config, Slapi_Task *task, task_data *t
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
static memberof_cached_value *
|
|
|
b69e47 |
-ancestors_cache_lookup(const char *ndn)
|
|
|
b69e47 |
+ancestors_cache_lookup(MemberOfConfig *config, const char *ndn)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
memberof_cached_value *e;
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
@@ -3258,7 +3156,7 @@ ancestors_cache_lookup(const char *ndn)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
|
|
|
b69e47 |
- e = (memberof_cached_value *) PL_HashTableLookupConst(group_ancestors_hashtable, (const void *) ndn);
|
|
|
b69e47 |
+ e = (memberof_cached_value *) PL_HashTableLookupConst(config->ancestors_cache, (const void *) ndn);
|
|
|
b69e47 |
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
if (start) {
|
|
|
b69e47 |
@@ -3274,7 +3172,7 @@ ancestors_cache_lookup(const char *ndn)
|
|
|
b69e47 |
|
|
|
b69e47 |
}
|
|
|
b69e47 |
static PRBool
|
|
|
b69e47 |
-ancestors_cache_remove(const char *ndn)
|
|
|
b69e47 |
+ancestors_cache_remove(MemberOfConfig *config, const char *ndn)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
PRBool rc;
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
@@ -3292,7 +3190,7 @@ ancestors_cache_remove(const char *ndn)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
|
|
|
b69e47 |
- rc = PL_HashTableRemove(group_ancestors_hashtable, (const void *) ndn);
|
|
|
b69e47 |
+ rc = PL_HashTableRemove(config->ancestors_cache, (const void *) ndn);
|
|
|
b69e47 |
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
if (start) {
|
|
|
b69e47 |
@@ -3305,7 +3203,7 @@ ancestors_cache_remove(const char *ndn)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
static PLHashEntry *
|
|
|
b69e47 |
-ancestors_cache_add(const void *key, void *value)
|
|
|
b69e47 |
+ancestors_cache_add(MemberOfConfig *config, const void *key, void *value)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
PLHashEntry *e;
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
@@ -3322,7 +3220,7 @@ ancestors_cache_add(const void *key, void *value)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
|
|
|
b69e47 |
- e = PL_HashTableAdd(group_ancestors_hashtable, key, value);
|
|
|
b69e47 |
+ e = PL_HashTableAdd(config->ancestors_cache, key, value);
|
|
|
b69e47 |
|
|
|
b69e47 |
#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
if (start) {
|
|
|
b69e47 |
@@ -3360,10 +3258,11 @@ int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
- /* Check if the entry has not already been fixed */
|
|
|
b69e47 |
+ /* Check if the entry has not already been fixed */
|
|
|
b69e47 |
ndn = slapi_sdn_get_ndn(sdn);
|
|
|
b69e47 |
- if (ndn && fixup_entry_hashtable && PL_HashTableLookupConst(fixup_entry_hashtable, (void*) ndn)) {
|
|
|
b69e47 |
- slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: Entry %s already fixed up\n", ndn);
|
|
|
b69e47 |
+ if (ndn && config->fixup_cache && PL_HashTableLookupConst(config->fixup_cache, (void*) ndn)) {
|
|
|
b69e47 |
+ slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM,
|
|
|
b69e47 |
+ "memberof_fix_memberof_callback: Entry %s already fixed up\n", ndn);
|
|
|
b69e47 |
goto bail;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -3383,9 +3282,9 @@ int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
|
|
|
b69e47 |
#if MEMBEROF_CACHE_DEBUG
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: This is NOT a group %s\n", ndn);
|
|
|
b69e47 |
#endif
|
|
|
b69e47 |
- ht_grp = ancestors_cache_lookup((const void *) ndn);
|
|
|
b69e47 |
+ ht_grp = ancestors_cache_lookup(config, (const void *) ndn);
|
|
|
b69e47 |
if (ht_grp) {
|
|
|
b69e47 |
- if (ancestors_cache_remove((const void *) ndn)) {
|
|
|
b69e47 |
+ if (ancestors_cache_remove(config, (const void *) ndn)) {
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: free cached values for %s\n", ndn);
|
|
|
b69e47 |
ancestor_hashtable_entry_free(ht_grp);
|
|
|
b69e47 |
slapi_ch_free((void **) &ht_grp);
|
|
|
b69e47 |
@@ -3400,6 +3299,7 @@ int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
/* If we found some groups, replace the existing memberOf attribute
|
|
|
b69e47 |
* with the found values. */
|
|
|
b69e47 |
if (groups && slapi_valueset_count(groups))
|
|
|
b69e47 |
@@ -3439,9 +3339,9 @@ int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
|
|
|
b69e47 |
slapi_valueset_free(groups);
|
|
|
b69e47 |
|
|
|
b69e47 |
/* records that this entry has been fixed up */
|
|
|
b69e47 |
- if (fixup_entry_hashtable) {
|
|
|
b69e47 |
+ if (config->fixup_cache) {
|
|
|
b69e47 |
dn_copy = slapi_ch_strdup(ndn);
|
|
|
b69e47 |
- if (PL_HashTableAdd(fixup_entry_hashtable, dn_copy, dn_copy) == NULL) {
|
|
|
b69e47 |
+ if (PL_HashTableAdd(config->fixup_cache, dn_copy, dn_copy) == NULL) {
|
|
|
b69e47 |
slapi_log_err(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_fix_memberof_callback: "
|
|
|
b69e47 |
"failed to add dn (%s) in the fixup hashtable; NSPR error - %d\n",
|
|
|
b69e47 |
dn_copy, PR_GetError());
|
|
|
b69e47 |
@@ -3539,150 +3439,8 @@ memberof_add_objectclass(char *auto_add_oc, const char *dn)
|
|
|
b69e47 |
return rc;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
-static PRIntn memberof_hash_compare_keys(const void *v1, const void *v2)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- PRIntn rc;
|
|
|
b69e47 |
- if (0 == strcasecmp((const char *) v1, (const char *) v2)) {
|
|
|
b69e47 |
- rc = 1;
|
|
|
b69e47 |
- } else {
|
|
|
b69e47 |
- rc = 0;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- return rc;
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-static PRIntn memberof_hash_compare_values(const void *v1, const void *v2)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- PRIntn rc;
|
|
|
b69e47 |
- if ((char *) v1 == (char *) v2) {
|
|
|
b69e47 |
- rc = 1;
|
|
|
b69e47 |
- } else {
|
|
|
b69e47 |
- rc = 0;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- return rc;
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-/*
|
|
|
b69e47 |
- * Hashing function using Bernstein's method
|
|
|
b69e47 |
- */
|
|
|
b69e47 |
-static PLHashNumber memberof_hash_fn(const void *key)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- PLHashNumber hash = 5381;
|
|
|
b69e47 |
- unsigned char *x = (unsigned char *)key;
|
|
|
b69e47 |
- int c;
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- while ((c = *x++)){
|
|
|
b69e47 |
- hash = ((hash << 5) + hash) ^ c;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- return hash;
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-/* allocates the plugin hashtable
|
|
|
b69e47 |
- * This hash table is used by operation and is protected from
|
|
|
b69e47 |
- * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
|
|
|
b69e47 |
- * is not implemented and the hash table will be not used.
|
|
|
b69e47 |
- *
|
|
|
b69e47 |
- * The hash table contains all the DN of the entries for which the memberof
|
|
|
b69e47 |
- * attribute has been computed/updated during the current operation
|
|
|
b69e47 |
- *
|
|
|
b69e47 |
- * hash table should be empty at the beginning and end of the plugin callback
|
|
|
b69e47 |
- */
|
|
|
b69e47 |
-static PLHashTable *hashtable_new()
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- if (!usetxn) {
|
|
|
b69e47 |
- return NULL;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- return PL_NewHashTable(MEMBEROF_HASHTABLE_SIZE,
|
|
|
b69e47 |
- memberof_hash_fn,
|
|
|
b69e47 |
- memberof_hash_compare_keys,
|
|
|
b69e47 |
- memberof_hash_compare_values, NULL, NULL);
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-/* this function called for each hash node during hash destruction */
|
|
|
b69e47 |
-static PRIntn fixup_hashtable_remove(PLHashEntry *he, PRIntn index, void *arg)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- char *dn_copy;
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- if (he == NULL) {
|
|
|
b69e47 |
- return HT_ENUMERATE_NEXT;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- dn_copy = (char*) he->value;
|
|
|
b69e47 |
- slapi_ch_free_string(&dn_copy);
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- return HT_ENUMERATE_REMOVE;
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-static void fixup_hashtable_empty(char *msg)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- if (fixup_entry_hashtable) {
|
|
|
b69e47 |
- PL_HashTableEnumerateEntries(fixup_entry_hashtable, fixup_hashtable_remove, msg);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-/* allocates the plugin hashtable
|
|
|
b69e47 |
- * This hash table is used by operation and is protected from
|
|
|
b69e47 |
- * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
|
|
|
b69e47 |
- * is not implemented and the hash table will be not used.
|
|
|
b69e47 |
- *
|
|
|
b69e47 |
- * The hash table contains all the DN of the entries for which the memberof
|
|
|
b69e47 |
- * attribute has been computed/updated during the current operation
|
|
|
b69e47 |
- *
|
|
|
b69e47 |
- * hash table should be empty at the beginning and end of the plugin callback
|
|
|
b69e47 |
- */
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-static
|
|
|
b69e47 |
-void ancestor_hashtable_entry_free(memberof_cached_value *entry)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
- int i;
|
|
|
b69e47 |
- for (i = 0; entry[i].valid; i++) {
|
|
|
b69e47 |
- slapi_ch_free((void **) &entry[i].group_dn_val);
|
|
|
b69e47 |
- slapi_ch_free((void **) &entry[i].group_ndn_val);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- /* Here we are at the ending element containing the key */
|
|
|
b69e47 |
- slapi_ch_free((void**) &entry[i].key);
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-/* this function called for each hash node during hash destruction */
|
|
|
b69e47 |
-static PRIntn ancestor_hashtable_remove(PLHashEntry *he, PRIntn index, void *arg)
|
|
|
b69e47 |
+int
|
|
|
b69e47 |
+memberof_use_txn()
|
|
|
b69e47 |
{
|
|
|
b69e47 |
- memberof_cached_value *group_ancestor_array;
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- if (he == NULL)
|
|
|
b69e47 |
- return HT_ENUMERATE_NEXT;
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- group_ancestor_array = (memberof_cached_value *) he->value;
|
|
|
b69e47 |
- ancestor_hashtable_entry_free(group_ancestor_array);
|
|
|
b69e47 |
- slapi_ch_free((void **)&group_ancestor_array);
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- return HT_ENUMERATE_REMOVE;
|
|
|
b69e47 |
+ return usetxn;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-static void ancestor_hashtable_empty(char *msg)
|
|
|
b69e47 |
-{
|
|
|
b69e47 |
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
- long int start;
|
|
|
b69e47 |
- struct timespec tsnow;
|
|
|
b69e47 |
-#endif
|
|
|
b69e47 |
-
|
|
|
b69e47 |
- if (group_ancestors_hashtable) {
|
|
|
b69e47 |
- cache_stat.total_enumerate++;
|
|
|
b69e47 |
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
- if (clock_gettime(CLOCK_REALTIME, &tsnow) != 0) {
|
|
|
b69e47 |
- start = 0;
|
|
|
b69e47 |
- } else {
|
|
|
b69e47 |
- start = tsnow.tv_nsec;
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-#endif
|
|
|
b69e47 |
- PL_HashTableEnumerateEntries(group_ancestors_hashtable, ancestor_hashtable_remove, msg);
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-#if defined(DEBUG) && defined(HAVE_CLOCK_GETTIME)
|
|
|
b69e47 |
- if (start) {
|
|
|
b69e47 |
- if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) {
|
|
|
b69e47 |
- cache_stat.cumul_duration_enumerate += (tsnow.tv_nsec - start);
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-#endif
|
|
|
b69e47 |
- }
|
|
|
b69e47 |
-
|
|
|
b69e47 |
-}
|
|
|
b69e47 |
-
|
|
|
b69e47 |
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
|
|
|
b69e47 |
index 9a3a6a25d..a01c4d247 100644
|
|
|
b69e47 |
--- a/ldap/servers/plugins/memberof/memberof.h
|
|
|
b69e47 |
+++ b/ldap/servers/plugins/memberof/memberof.h
|
|
|
b69e47 |
@@ -62,8 +62,22 @@ typedef struct memberofconfig {
|
|
|
b69e47 |
int skip_nested;
|
|
|
b69e47 |
int fixup_task;
|
|
|
b69e47 |
char *auto_add_oc;
|
|
|
b69e47 |
+ PLHashTable *ancestors_cache;
|
|
|
b69e47 |
+ PLHashTable *fixup_cache;
|
|
|
b69e47 |
} MemberOfConfig;
|
|
|
b69e47 |
|
|
|
b69e47 |
+/* The key to access the hash table is the normalized DN
|
|
|
b69e47 |
+ * The normalized DN is stored in the value because:
|
|
|
b69e47 |
+ * - It is used in slapi_valueset_find
|
|
|
b69e47 |
+ * - It is used to fill the memberof_get_groups_data.group_norm_vals
|
|
|
b69e47 |
+ */
|
|
|
b69e47 |
+typedef struct _memberof_cached_value
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ char *key;
|
|
|
b69e47 |
+ char *group_dn_val;
|
|
|
b69e47 |
+ char *group_ndn_val;
|
|
|
b69e47 |
+ int valid;
|
|
|
b69e47 |
+} memberof_cached_value;
|
|
|
b69e47 |
|
|
|
b69e47 |
/*
|
|
|
b69e47 |
* functions
|
|
|
b69e47 |
@@ -88,5 +102,8 @@ int memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Ent
|
|
|
b69e47 |
void *memberof_get_plugin_id(void);
|
|
|
b69e47 |
void memberof_release_config(void);
|
|
|
b69e47 |
PRUint64 get_plugin_started(void);
|
|
|
b69e47 |
+void ancestor_hashtable_entry_free(memberof_cached_value *entry);
|
|
|
b69e47 |
+PLHashTable *hashtable_new();
|
|
|
b69e47 |
+int memberof_use_txn();
|
|
|
b69e47 |
|
|
|
b69e47 |
#endif /* _MEMBEROF_H_ */
|
|
|
b69e47 |
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
|
|
|
b69e47 |
index c3474bf2c..3cc7c4d9c 100644
|
|
|
b69e47 |
--- a/ldap/servers/plugins/memberof/memberof_config.c
|
|
|
b69e47 |
+++ b/ldap/servers/plugins/memberof/memberof_config.c
|
|
|
b69e47 |
@@ -14,12 +14,12 @@
|
|
|
b69e47 |
* memberof_config.c - configuration-related code for memberOf plug-in
|
|
|
b69e47 |
*
|
|
|
b69e47 |
*/
|
|
|
b69e47 |
-
|
|
|
b69e47 |
+#include "plhash.h"
|
|
|
b69e47 |
#include <plstr.h>
|
|
|
b69e47 |
-
|
|
|
b69e47 |
#include "memberof.h"
|
|
|
b69e47 |
|
|
|
b69e47 |
#define MEMBEROF_CONFIG_FILTER "(objectclass=*)"
|
|
|
b69e47 |
+#define MEMBEROF_HASHTABLE_SIZE 1000
|
|
|
b69e47 |
|
|
|
b69e47 |
/*
|
|
|
b69e47 |
* The configuration attributes are contained in the plugin entry e.g.
|
|
|
b69e47 |
@@ -33,7 +33,9 @@
|
|
|
b69e47 |
|
|
|
b69e47 |
/*
|
|
|
b69e47 |
* function prototypes
|
|
|
b69e47 |
- */
|
|
|
b69e47 |
+ */
|
|
|
b69e47 |
+static void fixup_hashtable_empty( MemberOfConfig *config, char *msg);
|
|
|
b69e47 |
+static void ancestor_hashtable_empty(MemberOfConfig *config, char *msg);
|
|
|
b69e47 |
static int memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
|
|
|
b69e47 |
int *returncode, char *returntext, void *arg);
|
|
|
b69e47 |
static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
|
|
|
b69e47 |
@@ -48,7 +50,7 @@ static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_En
|
|
|
b69e47 |
/* This is the main configuration which is updated from dse.ldif. The
|
|
|
b69e47 |
* config will be copied when it is used by the plug-in to prevent it
|
|
|
b69e47 |
* being changed out from under a running memberOf operation. */
|
|
|
b69e47 |
-static MemberOfConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
b69e47 |
+static MemberOfConfig theConfig = {0};
|
|
|
b69e47 |
static Slapi_RWLock *memberof_config_lock = 0;
|
|
|
b69e47 |
static int inited = 0;
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -696,6 +698,12 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
if (dest && src)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
+ /* Allocate our caches here since we only copy the config at the start of an op */
|
|
|
b69e47 |
+ if (memberof_use_txn() == 1){
|
|
|
b69e47 |
+ dest->ancestors_cache = hashtable_new();
|
|
|
b69e47 |
+ dest->fixup_cache = hashtable_new();
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+
|
|
|
b69e47 |
/* Check if the copy is already up to date */
|
|
|
b69e47 |
if (src->groupattrs)
|
|
|
b69e47 |
{
|
|
|
b69e47 |
@@ -799,6 +807,14 @@ memberof_free_config(MemberOfConfig *config)
|
|
|
b69e47 |
slapi_ch_free_string(&config->memberof_attr);
|
|
|
b69e47 |
memberof_free_scope(config->entryScopes, &config->entryScopeCount);
|
|
|
b69e47 |
memberof_free_scope(config->entryScopeExcludeSubtrees, &config->entryExcludeScopeCount);
|
|
|
b69e47 |
+ if (config->fixup_cache) {
|
|
|
b69e47 |
+ fixup_hashtable_empty(config, "memberof_free_config empty fixup_entry_hastable");
|
|
|
b69e47 |
+ PL_HashTableDestroy(config->fixup_cache);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ if (config->ancestors_cache) {
|
|
|
b69e47 |
+ ancestor_hashtable_empty(config, "memberof_free_config empty group_ancestors_hashtable");
|
|
|
b69e47 |
+ PL_HashTableDestroy(config->ancestors_cache);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
}
|
|
|
b69e47 |
}
|
|
|
b69e47 |
|
|
|
b69e47 |
@@ -1001,3 +1017,131 @@ bail:
|
|
|
b69e47 |
|
|
|
b69e47 |
return ret;
|
|
|
b69e47 |
}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+static PRIntn memberof_hash_compare_keys(const void *v1, const void *v2)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ PRIntn rc;
|
|
|
b69e47 |
+ if (0 == strcasecmp((const char *) v1, (const char *) v2)) {
|
|
|
b69e47 |
+ rc = 1;
|
|
|
b69e47 |
+ } else {
|
|
|
b69e47 |
+ rc = 0;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ return rc;
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+static PRIntn memberof_hash_compare_values(const void *v1, const void *v2)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ PRIntn rc;
|
|
|
b69e47 |
+ if ((char *) v1 == (char *) v2) {
|
|
|
b69e47 |
+ rc = 1;
|
|
|
b69e47 |
+ } else {
|
|
|
b69e47 |
+ rc = 0;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ return rc;
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+/*
|
|
|
b69e47 |
+ * Hashing function using Bernstein's method
|
|
|
b69e47 |
+ */
|
|
|
b69e47 |
+static PLHashNumber memberof_hash_fn(const void *key)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ PLHashNumber hash = 5381;
|
|
|
b69e47 |
+ unsigned char *x = (unsigned char *)key;
|
|
|
b69e47 |
+ int c;
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ while ((c = *x++)){
|
|
|
b69e47 |
+ hash = ((hash << 5) + hash) ^ c;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ return hash;
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+/* allocates the plugin hashtable
|
|
|
b69e47 |
+ * This hash table is used by operation and is protected from
|
|
|
b69e47 |
+ * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
|
|
|
b69e47 |
+ * is not implemented and the hash table will be not used.
|
|
|
b69e47 |
+ *
|
|
|
b69e47 |
+ * The hash table contains all the DN of the entries for which the memberof
|
|
|
b69e47 |
+ * attribute has been computed/updated during the current operation
|
|
|
b69e47 |
+ *
|
|
|
b69e47 |
+ * hash table should be empty at the beginning and end of the plugin callback
|
|
|
b69e47 |
+ */
|
|
|
b69e47 |
+PLHashTable *hashtable_new(int usetxn)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ if (!usetxn) {
|
|
|
b69e47 |
+ return NULL;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ return PL_NewHashTable(MEMBEROF_HASHTABLE_SIZE,
|
|
|
b69e47 |
+ memberof_hash_fn,
|
|
|
b69e47 |
+ memberof_hash_compare_keys,
|
|
|
b69e47 |
+ memberof_hash_compare_values, NULL, NULL);
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+/* this function called for each hash node during hash destruction */
|
|
|
b69e47 |
+static PRIntn fixup_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ char *dn_copy;
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ if (he == NULL) {
|
|
|
b69e47 |
+ return HT_ENUMERATE_NEXT;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ dn_copy = (char*) he->value;
|
|
|
b69e47 |
+ slapi_ch_free_string(&dn_copy);
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ return HT_ENUMERATE_REMOVE;
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+static void fixup_hashtable_empty(MemberOfConfig *config, char *msg)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ if (config->fixup_cache) {
|
|
|
b69e47 |
+ PL_HashTableEnumerateEntries(config->fixup_cache, fixup_hashtable_remove, msg);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+/* allocates the plugin hashtable
|
|
|
b69e47 |
+ * This hash table is used by operation and is protected from
|
|
|
b69e47 |
+ * concurrent operations with the memberof_lock (if not usetxn, memberof_lock
|
|
|
b69e47 |
+ * is not implemented and the hash table will be not used.
|
|
|
b69e47 |
+ *
|
|
|
b69e47 |
+ * The hash table contains all the DN of the entries for which the memberof
|
|
|
b69e47 |
+ * attribute has been computed/updated during the current operation
|
|
|
b69e47 |
+ *
|
|
|
b69e47 |
+ * hash table should be empty at the beginning and end of the plugin callback
|
|
|
b69e47 |
+ */
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+void ancestor_hashtable_entry_free(memberof_cached_value *entry)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ int i;
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ for (i = 0; entry[i].valid; i++) {
|
|
|
b69e47 |
+ slapi_ch_free((void **) &entry[i].group_dn_val);
|
|
|
b69e47 |
+ slapi_ch_free((void **) &entry[i].group_ndn_val);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ /* Here we are at the ending element containing the key */
|
|
|
b69e47 |
+ slapi_ch_free((void**) &entry[i].key);
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+/* this function called for each hash node during hash destruction */
|
|
|
b69e47 |
+static PRIntn ancestor_hashtable_remove(PLHashEntry *he, PRIntn index __attribute__((unused)), void *arg __attribute__((unused)))
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ memberof_cached_value *group_ancestor_array;
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ if (he == NULL) {
|
|
|
b69e47 |
+ return HT_ENUMERATE_NEXT;
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+ group_ancestor_array = (memberof_cached_value *) he->value;
|
|
|
b69e47 |
+ ancestor_hashtable_entry_free(group_ancestor_array);
|
|
|
b69e47 |
+ slapi_ch_free((void **)&group_ancestor_array);
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+ return HT_ENUMERATE_REMOVE;
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+static void ancestor_hashtable_empty(MemberOfConfig *config, char *msg)
|
|
|
b69e47 |
+{
|
|
|
b69e47 |
+ if (config->ancestors_cache) {
|
|
|
b69e47 |
+ PL_HashTableEnumerateEntries(config->ancestors_cache, ancestor_hashtable_remove, msg);
|
|
|
b69e47 |
+ }
|
|
|
b69e47 |
+
|
|
|
b69e47 |
+}
|
|
|
b69e47 |
--
|
|
|
b69e47 |
2.13.6
|
|
|
b69e47 |
|