Blob Blame Raw
From f649d36ecf04926704add30a9f3179bd862de4c1 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Thu, 16 Jan 2014 15:21:28 -0500
Subject: [PATCH 80/83] Ticket 408 - Fix crash when disabling/enabling the
 setting

Bug Description:  Enabling/disabling can lead to crash as the setting
                  was not designed to be dynamically updated.

Fix Description:  Do not use the actual config setting to determine if the
                  cache is enabled.  Instead we record when the cache is
                  initialized.  The server still needs to be restarted for
                  the config change to take effect.

                  Also freed the cache at server shtudown.

https://fedorahosted.org/389/ticket/408

Reviewed by: rmeggins(Thanks!)
(cherry picked from commit 03c90f04065059ee310e9fa7d98228e0aa39fa50)
(cherry picked from commit 50ad64a442495810a84558c6c17dcc2263b815b6)
(cherry picked from commit e0d85bead832c6aa7a2ec01157ab786a53fb5272)
---
 ldap/servers/slapd/back-ldbm/monitor.c |  2 +-
 ldap/servers/slapd/dn.c                | 93 +++++++++++++++++++++++++++-------
 ldap/servers/slapd/main.c              |  1 +
 ldap/servers/slapd/slapi-private.h     |  2 +
 4 files changed, 78 insertions(+), 20 deletions(-)

diff --git a/ldap/servers/slapd/back-ldbm/monitor.c b/ldap/servers/slapd/back-ldbm/monitor.c
index 3427809..409c771 100644
--- a/ldap/servers/slapd/back-ldbm/monitor.c
+++ b/ldap/servers/slapd/back-ldbm/monitor.c
@@ -146,7 +146,7 @@ int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
         MSET("maxDnCacheCount");
     }
     /* normalized dn cache stats */
-    if(config_get_ndn_cache_enabled()){
+    if(ndn_cache_started()){
         ndn_cache_get_stats(&hits, &tries, &size, &maxsize, &count);
         sprintf(buf, "%" NSPRIu64, (long long unsigned int)tries);
         MSET("normalizedDnCacheTries");
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 9530b84..1eab631 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -103,6 +103,7 @@ static void ndn_cache_update_lru(struct ndn_cache_lru **node);
 static void ndn_cache_add(char *dn, size_t dn_len, char *ndn, size_t ndn_len);
 static void ndn_cache_delete(char *dn);
 static void ndn_cache_flush();
+static void ndn_cache_free();
 static int ndn_started = 0;
 static PRLock *lru_lock = NULL;
 static Slapi_RWLock *ndn_cache_lock = NULL;
@@ -2751,7 +2752,7 @@ ndn_hash_string(const void *key)
 void
 ndn_cache_init()
 {
-    if(!config_get_ndn_cache_enabled()){
+    if(!config_get_ndn_cache_enabled() || ndn_started){
         return;
     }
     ndn_cache_hashtable = PL_NewHashTable( NDN_CACHE_BUCKETS, ndn_hash_string, PL_CompareStrings, PL_CompareValues, 0, 0);
@@ -2764,24 +2765,49 @@ ndn_cache_init()
     ndn_cache->cache_size = sizeof(struct ndn_cache_ctx) + sizeof(PLHashTable) + sizeof(PLHashTable);
     ndn_cache->head = NULL;
     ndn_cache->tail = NULL;
-
+    ndn_started = 1;
     if ( NULL == ( lru_lock = PR_NewLock()) ||  NULL == ( ndn_cache_lock = slapi_new_rwlock())) {
-        char *errorbuf = NULL;
-        if(ndn_cache_hashtable){
-            PL_HashTableDestroy(ndn_cache_hashtable);
-        }
-        ndn_cache_hashtable = NULL;
-        config_set_ndn_cache_enabled(CONFIG_NDN_CACHE, "off", errorbuf, 1 );
-        slapi_counter_destroy(&ndn_cache->cache_hits);
-        slapi_counter_destroy(&ndn_cache->cache_tries);
-        slapi_counter_destroy(&ndn_cache->cache_misses);
-        slapi_ch_free((void **)&ndn_cache);
+        ndn_cache_destroy();
         slapi_log_error( SLAPI_LOG_FATAL, "ndn_cache_init", "Failed to create locks.  Disabling cache.\n" );
-    } else {
-        ndn_started = 1;
     }
 }
 
+void
+ndn_cache_destroy()
+{
+    char *errorbuf = NULL;
+
+    if(!ndn_started){
+        return;
+    }
+    if(lru_lock){
+        PR_DestroyLock(lru_lock);
+        lru_lock = NULL;
+    }
+    if(ndn_cache_lock){
+        slapi_destroy_rwlock(ndn_cache_lock);
+        ndn_cache_lock = NULL;
+    }
+    if(ndn_cache_hashtable){
+    	ndn_cache_free();
+        PL_HashTableDestroy(ndn_cache_hashtable);
+        ndn_cache_hashtable = NULL;
+    }
+    config_set_ndn_cache_enabled(CONFIG_NDN_CACHE, "off", errorbuf, 1 );
+    slapi_counter_destroy(&ndn_cache->cache_hits);
+    slapi_counter_destroy(&ndn_cache->cache_tries);
+    slapi_counter_destroy(&ndn_cache->cache_misses);
+    slapi_ch_free((void **)&ndn_cache);
+
+    ndn_started = 0;
+}
+
+int
+ndn_cache_started()
+{
+    return ndn_started;
+}
+
 /*
  *  Look up this dn in the ndn cache
  */
@@ -2994,19 +3020,48 @@ ndn_cache_flush()
     slapi_log_error( SLAPI_LOG_CACHE, "ndn_cache_flush","Flushed cache.\n");
 }
 
+static void
+ndn_cache_free()
+{
+    struct ndn_cache_lru *node, *next, *flush_node;
+
+    if(!ndn_cache){
+        return;
+    }
+
+    node = ndn_cache->tail;
+    while(ndn_cache->cache_count){
+        flush_node = node;
+        /* update the lru */
+        next = node->prev;
+        if(next){
+            next->next = NULL;
+        }
+        ndn_cache->tail = next;
+        node = next;
+        /* now update the hash */
+        ndn_cache->cache_count--;
+        ndn_cache_delete(flush_node->key);
+        slapi_ch_free_string(&flush_node->key);
+        slapi_ch_free((void **)&flush_node);
+    }
+}
+
 /* this is already "write" locked from ndn_cache_add */
 static void
 ndn_cache_delete(char *dn)
 {
-    struct ndn_hash_val *ht_val;
+    struct ndn_hash_val *ht_entry;
 
-    ht_val = (struct ndn_hash_val *)PL_HashTableLookupConst(ndn_cache_hashtable, dn);
-    if(ht_val){
-        ndn_cache->cache_size -= ht_val->size;
-        slapi_ch_free_string(&ht_val->ndn);
+    ht_entry = (struct ndn_hash_val *)PL_HashTableLookupConst(ndn_cache_hashtable, dn);
+    if(ht_entry){
+        ndn_cache->cache_size -= ht_entry->size;
+        slapi_ch_free_string(&ht_entry->ndn);
+        slapi_ch_free((void **)&ht_entry);
         PL_HashTableRemove(ndn_cache_hashtable, dn);
     }
 }
+
 /* stats for monitor */
 void
 ndn_cache_get_stats(PRUint64 *hits, PRUint64 *tries, size_t *size, size_t *max_size, long *count)
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index a17a2c5..ad8dd83 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -1280,6 +1280,7 @@ main( int argc, char **argv)
 cleanup:
 	SSL_ShutdownServerSessionIDCache();
 	SSL_ClearSessionCache();
+	ndn_cache_destroy();
 	NSS_Shutdown();
 	PR_Cleanup();
 #ifdef _WIN32
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 194f3fd..eaa5f98 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -392,6 +392,8 @@ Slapi_DN *slapi_sdn_init_normdn_passin(Slapi_DN *sdn, const char *dn);
 char *slapi_dn_normalize_original( char *dn );
 char *slapi_dn_normalize_case_original( char *dn );
 void ndn_cache_init();
+void ndn_cache_destroy();
+int ndn_cache_started();
 void ndn_cache_get_stats(PRUint64 *hits, PRUint64 *tries, size_t *size, size_t *max_size, long *count);
 #define NDN_DEFAULT_SIZE 20971520 /* 20mb - size of normalized dn cache */
 
-- 
1.8.1.4