andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone

Blame 0286-Ticket-408-Backport-of-Normalized-DN-Cache.patch

dc8c34
From e1775dcabc1cc88be12703ad62bbaf5341b8f8a4 Mon Sep 17 00:00:00 2001
dc8c34
From: Mark Reynolds <mreynolds@redhat.com>
dc8c34
Date: Fri, 19 Dec 2014 16:36:11 -0500
dc8c34
Subject: [PATCH 286/305] Ticket 408 - Backport of Normalized DN Cache
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/408
dc8c34
(cherry picked from commit 2a8da7ea76d15906fdb98b47534fc3447f12c752)
dc8c34
---
dc8c34
 ldap/ldif/template-dse.ldif.in         |   3 +-
dc8c34
 ldap/servers/slapd/attrsyntax.c        |  23 --
dc8c34
 ldap/servers/slapd/back-ldbm/monitor.c |  26 ++-
dc8c34
 ldap/servers/slapd/dn.c                | 401 +++++++++++++++++++++++++++++++++
dc8c34
 ldap/servers/slapd/libglobs.c          |  76 ++++++-
dc8c34
 ldap/servers/slapd/main.c              |   4 +
dc8c34
 ldap/servers/slapd/proto-slap.h        |  12 +
dc8c34
 ldap/servers/slapd/schema.c            |  17 --
dc8c34
 ldap/servers/slapd/slap.h              |  10 +
dc8c34
 ldap/servers/slapd/slapi-private.h     |   8 +-
dc8c34
 10 files changed, 532 insertions(+), 48 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
dc8c34
index ddf2b35..c626726 100644
dc8c34
--- a/ldap/ldif/template-dse.ldif.in
dc8c34
+++ b/ldap/ldif/template-dse.ldif.in
dc8c34
@@ -53,9 +53,10 @@ nsslapd-auditlog-maxlogsize: 100
dc8c34
 nsslapd-auditlog-logrotationtime: 1
dc8c34
 nsslapd-auditlog-logrotationtimeunit: day
dc8c34
 nsslapd-rootdn: %rootdn%
dc8c34
+nsslapd-rootpw: %ds_passwd%
dc8c34
 nsslapd-maxdescriptors: 1024
dc8c34
 nsslapd-max-filter-nest-level: 40
dc8c34
-nsslapd-rootpw: %ds_passwd%
dc8c34
+nsslapd-ndn-cache-enabled: off
dc8c34
 
dc8c34
 dn: cn=features,cn=config
dc8c34
 objectclass: top
dc8c34
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
dc8c34
index 79736b5..75114e0 100644
dc8c34
--- a/ldap/servers/slapd/attrsyntax.c
dc8c34
+++ b/ldap/servers/slapd/attrsyntax.c
dc8c34
@@ -219,29 +219,6 @@ attr_syntax_new()
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
- * hashNocaseString - used for case insensitive hash lookups
dc8c34
- */
dc8c34
-static PLHashNumber
dc8c34
-hashNocaseString(const void *key)
dc8c34
-{
dc8c34
-    PLHashNumber h = 0;
dc8c34
-    const unsigned char *s;
dc8c34
- 
dc8c34
-    for (s = key; *s; s++)
dc8c34
-        h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
dc8c34
-    return h;
dc8c34
-}
dc8c34
-
dc8c34
-/*
dc8c34
- * hashNocaseCompare - used for case insensitive hash key comparisons
dc8c34
- */
dc8c34
-static PRIntn
dc8c34
-hashNocaseCompare(const void *v1, const void *v2)
dc8c34
-{
dc8c34
-	return (strcasecmp((char *)v1, (char *)v2) == 0);
dc8c34
-}
dc8c34
-
dc8c34
-/*
dc8c34
  * Given an OID, return the syntax info.  If there is more than one
dc8c34
  * attribute syntax with the same OID (i.e. aliases), the first one
dc8c34
  * will be returned.  This is usually the "canonical" one, but it may
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/monitor.c b/ldap/servers/slapd/back-ldbm/monitor.c
dc8c34
index e3e1fb5..52a8ace 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/monitor.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/monitor.c
dc8c34
@@ -70,8 +70,8 @@ int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
dc8c34
     struct berval *vals[2];
dc8c34
     char buf[BUFSIZ];
dc8c34
     PRUint64 hits, tries;
dc8c34
-    long nentries,maxentries;
dc8c34
-    size_t size,maxsize;
dc8c34
+    long nentries, maxentries, count;
dc8c34
+    size_t size, maxsize;
dc8c34
 /* NPCTE fix for bugid 544365, esc 0. <P.R> <04-Jul-2001> */
dc8c34
     struct stat astat;
dc8c34
 /* end of NPCTE fix for bugid 544365 */
dc8c34
@@ -145,6 +145,28 @@ int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
dc8c34
         sprintf(buf, "%ld", maxentries);
dc8c34
         MSET("maxDnCacheCount");
dc8c34
     }
dc8c34
+    /* normalized dn cache stats */
dc8c34
+    if(ndn_cache_started()){
dc8c34
+        ndn_cache_get_stats(&hits, &tries, &size, &maxsize, &count);
dc8c34
+        sprintf(buf, "%" NSPRIu64, tries);
dc8c34
+        MSET("normalizedDnCacheTries");
dc8c34
+        sprintf(buf, "%" NSPRIu64, hits);
dc8c34
+        MSET("normalizedDnCacheHits");
dc8c34
+        sprintf(buf, "%" NSPRIu64, tries - hits);
dc8c34
+        MSET("normalizedDnCacheMisses");
dc8c34
+        sprintf(buf, "%lu", (unsigned long)(100.0*(double)hits / (double)(tries > 0 ? tries : 1)));
dc8c34
+        MSET("normalizedDnCacheHitRatio");
dc8c34
+        sprintf(buf, "%lu", size);
dc8c34
+        MSET("currentNormalizedDnCacheSize");
dc8c34
+        if(maxsize == 0){
dc8c34
+            sprintf(buf, "%d", -1);
dc8c34
+        } else {
dc8c34
+            sprintf(buf, "%lu", maxsize);
dc8c34
+        }
dc8c34
+        MSET("maxNormalizedDnCacheSize");
dc8c34
+        sprintf(buf, "%ld", count);
dc8c34
+        MSET("currentNormalizedDnCacheCount");
dc8c34
+    }
dc8c34
 
dc8c34
 #ifdef DEBUG
dc8c34
     {
dc8c34
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
dc8c34
index 804d56e..283f265 100644
dc8c34
--- a/ldap/servers/slapd/dn.c
dc8c34
+++ b/ldap/servers/slapd/dn.c
dc8c34
@@ -51,6 +51,7 @@
dc8c34
 #include <sys/socket.h>
dc8c34
 #endif
dc8c34
 #include "slap.h"
dc8c34
+#include <plhash.h>
dc8c34
 
dc8c34
 #undef SDN_DEBUG
dc8c34
 
dc8c34
@@ -61,6 +62,53 @@ static void sort_rdn_avs( struct berval *avs, int count, int escape );
dc8c34
 static int rdn_av_cmp( struct berval *av1, struct berval *av2 );
dc8c34
 static void rdn_av_swap( struct berval *av1, struct berval *av2, int escape );
dc8c34
 
dc8c34
+/* normalized dn cache related definitions*/
dc8c34
+struct
dc8c34
+ndn_cache_lru
dc8c34
+{
dc8c34
+    struct ndn_cache_lru *prev;
dc8c34
+    struct ndn_cache_lru *next;
dc8c34
+    char *key;
dc8c34
+};
dc8c34
+
dc8c34
+struct
dc8c34
+ndn_cache_ctx
dc8c34
+{
dc8c34
+    struct ndn_cache_lru *head;
dc8c34
+    struct ndn_cache_lru *tail;
dc8c34
+    Slapi_Counter *cache_hits;
dc8c34
+    Slapi_Counter *cache_tries;
dc8c34
+    Slapi_Counter *cache_misses;
dc8c34
+    size_t cache_size;
dc8c34
+    size_t cache_max_size;
dc8c34
+    long cache_count;
dc8c34
+};
dc8c34
+
dc8c34
+struct
dc8c34
+ndn_hash_val
dc8c34
+{
dc8c34
+    char *ndn;
dc8c34
+    size_t len;
dc8c34
+    int size;
dc8c34
+    struct ndn_cache_lru *lru_node; /* used to speed up lru shuffling */
dc8c34
+};
dc8c34
+
dc8c34
+#define NDN_FLUSH_COUNT 10000 /* number of DN's to remove when cache fills up */
dc8c34
+#define NDN_MIN_COUNT 1000 /* the minimum number of DN's to keep in the cache */
dc8c34
+#define NDN_CACHE_BUCKETS 2053 /* prime number */
dc8c34
+
dc8c34
+static PLHashNumber ndn_hash_string(const void *key);
dc8c34
+static int ndn_cache_lookup(char *dn, size_t dn_len, char **result, char **udn, int *rc);
dc8c34
+static void ndn_cache_update_lru(struct ndn_cache_lru **node);
dc8c34
+static void ndn_cache_add(char *dn, size_t dn_len, char *ndn, size_t ndn_len);
dc8c34
+static void ndn_cache_delete(char *dn);
dc8c34
+static void ndn_cache_flush();
dc8c34
+static void ndn_cache_free();
dc8c34
+static int ndn_started = 0;
dc8c34
+static PRLock *lru_lock = NULL;
dc8c34
+static Slapi_RWLock *ndn_cache_lock = NULL;
dc8c34
+static struct ndn_cache_ctx *ndn_cache = NULL;
dc8c34
+static PLHashTable *ndn_cache_hashtable = NULL;
dc8c34
 
dc8c34
 #define ISBLANK(c)	((c) == ' ')
dc8c34
 #define ISBLANKSTR(s)	(((*(s)) == '2') && (*((s)+1) == '0'))
dc8c34
@@ -487,6 +535,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
dc8c34
     char *ends = NULL;
dc8c34
     char *endd = NULL;
dc8c34
     char *lastesc = NULL;
dc8c34
+    char *udn;
dc8c34
     /* rdn avs for the main DN */
dc8c34
     char *typestart = NULL;
dc8c34
     int rdn_av_count = 0;
dc8c34
@@ -511,6 +560,14 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
dc8c34
     if (0 == src_len) {
dc8c34
         src_len = strlen(src);
dc8c34
     }
dc8c34
+    /*
dc8c34
+     *  Check the normalized dn cache
dc8c34
+     */
dc8c34
+    if(ndn_cache_lookup(src, src_len, dest, &udn, &rc)){
dc8c34
+        *dest_len = strlen(*dest);
dc8c34
+        return rc;
dc8c34
+    }
dc8c34
+
dc8c34
     s = PL_strnchr(src, '\\', src_len);
dc8c34
     if (s) {
dc8c34
         *dest_len = src_len * 3;
dc8c34
@@ -1072,6 +1129,10 @@ bail:
dc8c34
         /* We terminate the str with NULL only when we allocate the str */
dc8c34
         *d = '\0';
dc8c34
     }
dc8c34
+    /* add this dn to the normalized dn cache */
dc8c34
+    if(*dest)
dc8c34
+        ndn_cache_add(udn, src_len, *dest, *dest_len);
dc8c34
+
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
@@ -2622,3 +2683,343 @@ slapi_sdn_get_size(const Slapi_DN *sdn)
dc8c34
     return sz;
dc8c34
 }
dc8c34
 
dc8c34
+/*
dc8c34
+ *
dc8c34
+ *  Normalized DN Cache
dc8c34
+ *
dc8c34
+ */
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Hashing function using Bernstein's method
dc8c34
+ */
dc8c34
+static PLHashNumber
dc8c34
+ndn_hash_string(const void *key)
dc8c34
+{
dc8c34
+    PLHashNumber hash = 5381;
dc8c34
+    unsigned char *x = (unsigned char *)key;
dc8c34
+    int c;
dc8c34
+
dc8c34
+    while ((c = *x++)){
dc8c34
+        hash = ((hash << 5) + hash) ^ c;
dc8c34
+    }
dc8c34
+    return hash;
dc8c34
+}
dc8c34
+
dc8c34
+void
dc8c34
+ndn_cache_init()
dc8c34
+{
dc8c34
+    if(!config_get_ndn_cache_enabled() || ndn_started){
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    ndn_cache_hashtable = PL_NewHashTable( NDN_CACHE_BUCKETS, ndn_hash_string, PL_CompareStrings, PL_CompareValues, 0, 0);
dc8c34
+    ndn_cache = (struct ndn_cache_ctx *)slapi_ch_malloc(sizeof(struct ndn_cache_ctx));
dc8c34
+    ndn_cache->cache_max_size = config_get_ndn_cache_size();
dc8c34
+    ndn_cache->cache_hits = slapi_counter_new();
dc8c34
+    ndn_cache->cache_tries = slapi_counter_new();
dc8c34
+    ndn_cache->cache_misses = slapi_counter_new();
dc8c34
+    ndn_cache->cache_count = 0;
dc8c34
+    ndn_cache->cache_size = sizeof(struct ndn_cache_ctx) + sizeof(PLHashTable) + sizeof(PLHashTable);
dc8c34
+    ndn_cache->head = NULL;
dc8c34
+    ndn_cache->tail = NULL;
dc8c34
+    ndn_started = 1;
dc8c34
+    if ( NULL == ( lru_lock = PR_NewLock()) ||  NULL == ( ndn_cache_lock = slapi_new_rwlock())) {
dc8c34
+        ndn_cache_destroy();
dc8c34
+        slapi_log_error( SLAPI_LOG_FATAL, "ndn_cache_init", "Failed to create locks.  Disabling cache.\n" );
dc8c34
+    }
dc8c34
+}
dc8c34
+
dc8c34
+void
dc8c34
+ndn_cache_destroy()
dc8c34
+{
dc8c34
+    char *errorbuf = NULL;
dc8c34
+
dc8c34
+    if(!ndn_started){
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    if(lru_lock){
dc8c34
+        PR_DestroyLock(lru_lock);
dc8c34
+        lru_lock = NULL;
dc8c34
+    }
dc8c34
+    if(ndn_cache_lock){
dc8c34
+        slapi_destroy_rwlock(ndn_cache_lock);
dc8c34
+        ndn_cache_lock = NULL;
dc8c34
+    }
dc8c34
+    if(ndn_cache_hashtable){
dc8c34
+        ndn_cache_free();
dc8c34
+        PL_HashTableDestroy(ndn_cache_hashtable);
dc8c34
+        ndn_cache_hashtable = NULL;
dc8c34
+    }
dc8c34
+    config_set_ndn_cache_enabled(CONFIG_NDN_CACHE, "off", errorbuf, 1 );
dc8c34
+    slapi_counter_destroy(&ndn_cache->cache_hits);
dc8c34
+    slapi_counter_destroy(&ndn_cache->cache_tries);
dc8c34
+    slapi_counter_destroy(&ndn_cache->cache_misses);
dc8c34
+    slapi_ch_free((void **)&ndn_cache);
dc8c34
+
dc8c34
+    ndn_started = 0;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+ndn_cache_started()
dc8c34
+{
dc8c34
+    return ndn_started;
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Look up this dn in the ndn cache
dc8c34
+ */
dc8c34
+static int
dc8c34
+ndn_cache_lookup(char *dn, size_t dn_len, char **result, char **udn, int *rc)
dc8c34
+{
dc8c34
+    struct ndn_hash_val *ndn_ht_val = NULL;
dc8c34
+    char *ndn, *key;
dc8c34
+    int rv = 0;
dc8c34
+
dc8c34
+    if(ndn_started == 0){
dc8c34
+        return rv;
dc8c34
+    }
dc8c34
+    if(dn_len == 0){
dc8c34
+        *result = dn;
dc8c34
+        *rc = 0;
dc8c34
+        return 1;
dc8c34
+    }
dc8c34
+    slapi_counter_increment(ndn_cache->cache_tries);
dc8c34
+    slapi_rwlock_rdlock(ndn_cache_lock);
dc8c34
+    ndn_ht_val = (struct ndn_hash_val *)PL_HashTableLookupConst(ndn_cache_hashtable, dn);
dc8c34
+    if(ndn_ht_val){
dc8c34
+        ndn_cache_update_lru(&ndn_ht_val->lru_node);
dc8c34
+        slapi_counter_increment(ndn_cache->cache_hits);
dc8c34
+        if(ndn_ht_val->len == dn_len ){
dc8c34
+            /* the dn was already normalized, just return the dn as the result */
dc8c34
+            *result = dn;
dc8c34
+            *rc = 0;
dc8c34
+        } else {
dc8c34
+            *rc = 1; /* free result */
dc8c34
+            ndn = slapi_ch_malloc(ndn_ht_val->len + 1);
dc8c34
+            memcpy(ndn, ndn_ht_val->ndn, ndn_ht_val->len);
dc8c34
+            ndn[ndn_ht_val->len] = '\0';
dc8c34
+            *result = ndn;
dc8c34
+        }
dc8c34
+        rv = 1;
dc8c34
+    } else {
dc8c34
+        /* copy/preserve the udn, so we can use it as the key when we add dn's to the hashtable */
dc8c34
+        key = slapi_ch_malloc(dn_len + 1);
dc8c34
+        memcpy(key, dn, dn_len);
dc8c34
+        key[dn_len] = '\0';
dc8c34
+        *udn = key;
dc8c34
+    }
dc8c34
+    slapi_rwlock_unlock(ndn_cache_lock);
dc8c34
+
dc8c34
+    return rv;
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Move this lru node to the top of the list
dc8c34
+ */
dc8c34
+static void
dc8c34
+ndn_cache_update_lru(struct ndn_cache_lru **node)
dc8c34
+{
dc8c34
+    struct ndn_cache_lru *prev, *next, *curr_node = *node;
dc8c34
+
dc8c34
+    if(curr_node == NULL){
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    PR_Lock(lru_lock);
dc8c34
+    if(curr_node->prev == NULL){
dc8c34
+        /* already the top node */
dc8c34
+        PR_Unlock(lru_lock);
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    prev = curr_node->prev;
dc8c34
+    next = curr_node->next;
dc8c34
+    if(next){
dc8c34
+        next->prev = prev;
dc8c34
+        prev->next = next;
dc8c34
+    } else {
dc8c34
+        /* this was the tail, so reset the tail */
dc8c34
+        ndn_cache->tail = prev;
dc8c34
+        prev->next = NULL;
dc8c34
+    }
dc8c34
+    curr_node->prev = NULL;
dc8c34
+    curr_node->next = ndn_cache->head;
dc8c34
+    ndn_cache->head->prev = curr_node;
dc8c34
+    ndn_cache->head = curr_node;
dc8c34
+    PR_Unlock(lru_lock);
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  Add a ndn to the cache.  Try and do as much as possible before taking the write lock.
dc8c34
+ */
dc8c34
+static void
dc8c34
+ndn_cache_add(char *dn, size_t dn_len, char *ndn, size_t ndn_len)
dc8c34
+{
dc8c34
+    struct ndn_hash_val *ht_entry;
dc8c34
+    struct ndn_cache_lru *new_node = NULL;
dc8c34
+    PLHashEntry *he;
dc8c34
+    int size;
dc8c34
+
dc8c34
+    if(ndn_started == 0 || dn_len == 0){
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    if(strlen(ndn) > ndn_len){
dc8c34
+        /* we need to null terminate the ndn */
dc8c34
+        *(ndn + ndn_len) = '\0';
dc8c34
+    }
dc8c34
+    /*
dc8c34
+     *  Calculate the approximate memory footprint of the hash entry, key, and lru entry.
dc8c34
+     */
dc8c34
+    size = (dn_len * 2) + ndn_len + sizeof(PLHashEntry) + sizeof(struct ndn_hash_val) + sizeof(struct ndn_cache_lru);
dc8c34
+    /*
dc8c34
+     *  Create our LRU node
dc8c34
+     */
dc8c34
+    new_node = (struct ndn_cache_lru *)slapi_ch_malloc(sizeof(struct ndn_cache_lru));
dc8c34
+    if(new_node == NULL){
dc8c34
+        slapi_log_error( SLAPI_LOG_FATAL, "ndn_cache_add", "Failed to allocate new lru node.\n");
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    new_node->prev = NULL;
dc8c34
+    new_node->key = dn; /* dn has already been allocated */
dc8c34
+    /*
dc8c34
+     *  Its possible this dn was added to the hash by another thread.
dc8c34
+     */
dc8c34
+    slapi_rwlock_wrlock(ndn_cache_lock);
dc8c34
+    ht_entry = (struct ndn_hash_val *)PL_HashTableLookupConst(ndn_cache_hashtable, dn);
dc8c34
+    if(ht_entry){
dc8c34
+        /* already exists, free the node and return */
dc8c34
+        slapi_rwlock_unlock(ndn_cache_lock);
dc8c34
+        slapi_ch_free_string(&new_node->key);
dc8c34
+        slapi_ch_free((void **)&new_node);
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    /*
dc8c34
+     *  Create the hash entry
dc8c34
+     */
dc8c34
+    ht_entry = (struct ndn_hash_val *)slapi_ch_malloc(sizeof(struct ndn_hash_val));
dc8c34
+    if(ht_entry == NULL){
dc8c34
+        slapi_rwlock_unlock(ndn_cache_lock);
dc8c34
+        slapi_log_error( SLAPI_LOG_FATAL, "ndn_cache_add", "Failed to allocate new hash entry.\n");
dc8c34
+        slapi_ch_free_string(&new_node->key);
dc8c34
+        slapi_ch_free((void **)&new_node);
dc8c34
+        return;
dc8c34
+    }
dc8c34
+    ht_entry->ndn = slapi_ch_malloc(ndn_len + 1);
dc8c34
+    memcpy(ht_entry->ndn, ndn, ndn_len);
dc8c34
+    ht_entry->ndn[ndn_len] = '\0';
dc8c34
+    ht_entry->len = ndn_len;
dc8c34
+    ht_entry->size = size;
dc8c34
+    ht_entry->lru_node = new_node;
dc8c34
+    /*
dc8c34
+     *  Check if our cache is full
dc8c34
+     */
dc8c34
+    PR_Lock(lru_lock); /* grab the lru lock now, as ndn_cache_flush needs it */
dc8c34
+    if(ndn_cache->cache_max_size != 0 && ((ndn_cache->cache_size + size) > ndn_cache->cache_max_size)){
dc8c34
+        ndn_cache_flush();
dc8c34
+    }
dc8c34
+    /*
dc8c34
+     * Set the ndn cache lru nodes
dc8c34
+     */
dc8c34
+    if(ndn_cache->head == NULL && ndn_cache->tail == NULL){
dc8c34
+        /* this is the first node */
dc8c34
+        ndn_cache->head = new_node;
dc8c34
+        ndn_cache->tail = new_node;
dc8c34
+        new_node->next = NULL;
dc8c34
+    } else {
dc8c34
+        new_node->next = ndn_cache->head;
dc8c34
+        ndn_cache->head->prev = new_node;
dc8c34
+    }
dc8c34
+    ndn_cache->head = new_node;
dc8c34
+    PR_Unlock(lru_lock);
dc8c34
+    /*
dc8c34
+     *  Add the new object to the hashtable, and update our stats
dc8c34
+     */
dc8c34
+    he = PL_HashTableAdd(ndn_cache_hashtable, new_node->key, (void *)ht_entry);
dc8c34
+    if(he == NULL){
dc8c34
+        slapi_log_error( SLAPI_LOG_FATAL, "ndn_cache_add", "Failed to add new entry to hash(%s)\n",dn);
dc8c34
+    } else {
dc8c34
+        ndn_cache->cache_count++;
dc8c34
+        ndn_cache->cache_size += size;
dc8c34
+    }
dc8c34
+    slapi_rwlock_unlock(ndn_cache_lock);
dc8c34
+}
dc8c34
+
dc8c34
+/*
dc8c34
+ *  cache is full, remove the least used dn's.  lru_lock/ndn_cache write lock are already taken
dc8c34
+ */
dc8c34
+static void
dc8c34
+ndn_cache_flush()
dc8c34
+{
dc8c34
+    struct ndn_cache_lru *node, *next, *flush_node;
dc8c34
+    int i;
dc8c34
+
dc8c34
+    node = ndn_cache->tail;
dc8c34
+    for(i = 0; node && i < NDN_FLUSH_COUNT && ndn_cache->cache_count > NDN_MIN_COUNT; i++){
dc8c34
+        flush_node = node;
dc8c34
+        /* update the lru */
dc8c34
+        next = node->prev;
dc8c34
+        next->next = NULL;
dc8c34
+        ndn_cache->tail = next;
dc8c34
+        node = next;
dc8c34
+        /* now update the hash */
dc8c34
+        ndn_cache->cache_count--;
dc8c34
+        ndn_cache_delete(flush_node->key);
dc8c34
+        slapi_ch_free_string(&flush_node->key);
dc8c34
+        slapi_ch_free((void **)&flush_node);
dc8c34
+    }
dc8c34
+
dc8c34
+    slapi_log_error( SLAPI_LOG_CACHE, "ndn_cache_flush","Flushed cache.\n");
dc8c34
+}
dc8c34
+
dc8c34
+static void
dc8c34
+ndn_cache_free()
dc8c34
+{
dc8c34
+    struct ndn_cache_lru *node, *next, *flush_node;
dc8c34
+
dc8c34
+    if(!ndn_cache){
dc8c34
+        return;
dc8c34
+    }
dc8c34
+
dc8c34
+    node = ndn_cache->tail;
dc8c34
+    while(node && ndn_cache->cache_count){
dc8c34
+        flush_node = node;
dc8c34
+        /* update the lru */
dc8c34
+        next = node->prev;
dc8c34
+        if(next){
dc8c34
+            next->next = NULL;
dc8c34
+        }
dc8c34
+        ndn_cache->tail = next;
dc8c34
+        node = next;
dc8c34
+        /* now update the hash */
dc8c34
+        ndn_cache->cache_count--;
dc8c34
+        ndn_cache_delete(flush_node->key);
dc8c34
+        slapi_ch_free_string(&flush_node->key);
dc8c34
+        slapi_ch_free((void **)&flush_node);
dc8c34
+    }
dc8c34
+}
dc8c34
+
dc8c34
+/* this is already "write" locked from ndn_cache_add */
dc8c34
+static void
dc8c34
+ndn_cache_delete(char *dn)
dc8c34
+{
dc8c34
+    struct ndn_hash_val *ht_entry;
dc8c34
+
dc8c34
+    ht_entry = (struct ndn_hash_val *)PL_HashTableLookupConst(ndn_cache_hashtable, dn);
dc8c34
+    if(ht_entry){
dc8c34
+        ndn_cache->cache_size -= ht_entry->size;
dc8c34
+        slapi_ch_free_string(&ht_entry->ndn);
dc8c34
+        slapi_ch_free((void **)&ht_entry);
dc8c34
+        PL_HashTableRemove(ndn_cache_hashtable, dn);
dc8c34
+    }
dc8c34
+}
dc8c34
+
dc8c34
+/* stats for monitor */
dc8c34
+void
dc8c34
+ndn_cache_get_stats(PRUint64 *hits, PRUint64 *tries, size_t *size, size_t *max_size, long *count)
dc8c34
+{
dc8c34
+    slapi_rwlock_rdlock(ndn_cache_lock);
dc8c34
+    *hits = slapi_counter_get_value(ndn_cache->cache_hits);
dc8c34
+    *tries = slapi_counter_get_value(ndn_cache->cache_tries);
dc8c34
+    *size = ndn_cache->cache_size;
dc8c34
+    *max_size = ndn_cache->cache_max_size;
dc8c34
+    *count = ndn_cache->cache_count;
dc8c34
+    slapi_rwlock_unlock(ndn_cache_lock);
dc8c34
+}
dc8c34
+
dc8c34
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
dc8c34
index 79ca2bd..3c0c9f4 100644
dc8c34
--- a/ldap/servers/slapd/libglobs.c
dc8c34
+++ b/ldap/servers/slapd/libglobs.c
dc8c34
@@ -1035,7 +1035,15 @@ static struct config_get_and_set {
dc8c34
 	{CONFIG_IGNORE_TIME_SKEW, config_set_ignore_time_skew,
dc8c34
 		NULL, 0,
dc8c34
 		(void**)&global_slapdFrontendConfig.ignore_time_skew,
dc8c34
-		CONFIG_ON_OFF, (ConfigGetFunc)config_get_ignore_time_skew, &init_ignore_time_skew}
dc8c34
+		CONFIG_ON_OFF, (ConfigGetFunc)config_get_ignore_time_skew, &init_ignore_time_skew},
dc8c34
+	{CONFIG_NDN_CACHE, config_set_ndn_cache_enabled,
dc8c34
+		NULL, 0,
dc8c34
+		(void**)&global_slapdFrontendConfig.ndn_cache_enabled, CONFIG_INT,
dc8c34
+		(ConfigGetFunc)config_get_ndn_cache_enabled},
dc8c34
+	{CONFIG_NDN_CACHE_SIZE, config_set_ndn_cache_max_size,
dc8c34
+		NULL, 0,
dc8c34
+		(void**)&global_slapdFrontendConfig.ndn_cache_max_size,
dc8c34
+		CONFIG_INT, (ConfigGetFunc)config_get_ndn_cache_size},
dc8c34
 #ifdef MEMPOOL_EXPERIMENTAL
dc8c34
 	,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
dc8c34
 		NULL, 0,
dc8c34
@@ -1053,7 +1061,7 @@ static struct config_get_and_set {
dc8c34
 /*
dc8c34
  * hashNocaseString - used for case insensitive hash lookups
dc8c34
  */
dc8c34
-static PLHashNumber
dc8c34
+PLHashNumber
dc8c34
 hashNocaseString(const void *key)
dc8c34
 {
dc8c34
     PLHashNumber h = 0;
dc8c34
@@ -1067,7 +1075,7 @@ hashNocaseString(const void *key)
dc8c34
 /*
dc8c34
  * hashNocaseCompare - used for case insensitive hash key comparisons
dc8c34
  */
dc8c34
-static PRIntn
dc8c34
+PRIntn
dc8c34
 hashNocaseCompare(const void *v1, const void *v2)
dc8c34
 {
dc8c34
 	return (strcasecmp((char *)v1, (char *)v2) == 0);
dc8c34
@@ -1463,6 +1471,11 @@ FrontendConfig_init () {
dc8c34
   init_malloc_mmap_threshold = cfg->malloc_mmap_threshold = DEFAULT_MALLOC_UNSET;
dc8c34
 #endif
dc8c34
 
dc8c34
+  cfg->disk_logging_critical = LDAP_OFF;
dc8c34
+  cfg->ndn_cache_enabled = LDAP_OFF;
dc8c34
+  cfg->ndn_cache_max_size = NDN_DEFAULT_SIZE;
dc8c34
+
dc8c34
+
dc8c34
 #ifdef MEMPOOL_EXPERIMENTAL
dc8c34
   init_mempool_switch = cfg->mempool_switch = LDAP_ON;
dc8c34
   cfg->mempool_maxfreelist = 1024;
dc8c34
@@ -1694,6 +1707,42 @@ config_set_sasl_maxbufsize(const char *attrname, char *value, char *errorbuf, in
dc8c34
     return retVal;
dc8c34
 }
dc8c34
 
dc8c34
+int
dc8c34
+config_set_ndn_cache_enabled(const char *attrname, char *value, char *errorbuf, int apply )
dc8c34
+{
dc8c34
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
dc8c34
+    int retVal;
dc8c34
+
dc8c34
+    retVal = config_set_onoff ( attrname, value, &(slapdFrontendConfig->ndn_cache_enabled), errorbuf, apply);
dc8c34
+
dc8c34
+    return retVal;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+config_set_ndn_cache_max_size(const char *attrname, char *value, char *errorbuf, int apply )
dc8c34
+{
dc8c34
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
dc8c34
+    long size;
dc8c34
+    int retVal = LDAP_SUCCESS;
dc8c34
+
dc8c34
+    size = atol(value);
dc8c34
+    if(size < 0){
dc8c34
+        size = 0; /* same as -1 */
dc8c34
+    }
dc8c34
+    if(size > 0 && size < 1024000){
dc8c34
+        PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "ndn_cache_max_size too low(%d), changing to "
dc8c34
+            "%d bytes.\n",(int)size, NDN_DEFAULT_SIZE);
dc8c34
+        size = NDN_DEFAULT_SIZE;
dc8c34
+    }
dc8c34
+    if(apply){
dc8c34
+        CFG_LOCK_WRITE(slapdFrontendConfig);
dc8c34
+        slapdFrontendConfig->ndn_cache_max_size = size;
dc8c34
+        CFG_UNLOCK_WRITE(slapdFrontendConfig);
dc8c34
+    }
dc8c34
+
dc8c34
+    return retVal;
dc8c34
+}
dc8c34
+
dc8c34
 int 
dc8c34
 config_set_port( const char *attrname, char *port, char *errorbuf, int apply ) {
dc8c34
   long nPort;
dc8c34
@@ -5626,6 +5675,27 @@ config_get_max_filter_nest_level()
dc8c34
 	return retVal;
dc8c34
 }
dc8c34
 
dc8c34
+size_t
dc8c34
+config_get_ndn_cache_size(){
dc8c34
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
dc8c34
+    size_t retVal;
dc8c34
+
dc8c34
+    CFG_LOCK_READ(slapdFrontendConfig);
dc8c34
+    retVal = slapdFrontendConfig->ndn_cache_max_size;
dc8c34
+    CFG_UNLOCK_READ(slapdFrontendConfig);
dc8c34
+    return retVal;
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
+config_get_ndn_cache_enabled(){
dc8c34
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
dc8c34
+    int retVal;
dc8c34
+
dc8c34
+    CFG_LOCK_READ(slapdFrontendConfig);
dc8c34
+    retVal = slapdFrontendConfig->ndn_cache_enabled;
dc8c34
+    CFG_UNLOCK_READ(slapdFrontendConfig);
dc8c34
+    return retVal;
dc8c34
+}
dc8c34
 
dc8c34
 char *
dc8c34
 config_get_basedn() {
dc8c34
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
dc8c34
index bc07cbb..5d3e7e7 100644
dc8c34
--- a/ldap/servers/slapd/main.c
dc8c34
+++ b/ldap/servers/slapd/main.c
dc8c34
@@ -1046,6 +1046,9 @@ main( int argc, char **argv)
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
+	/* initialize the normalized DN cache */
dc8c34
+	ndn_cache_init();
dc8c34
+
dc8c34
 	/*
dc8c34
 	 * Detach ourselves from the terminal (unless running in debug mode).
dc8c34
 	 * We must detach before we start any threads since detach forks() on
dc8c34
@@ -1267,6 +1270,7 @@ main( int argc, char **argv)
dc8c34
 cleanup:
dc8c34
 	SSL_ShutdownServerSessionIDCache();
dc8c34
 	SSL_ClearSessionCache();
dc8c34
+	ndn_cache_destroy();
dc8c34
 	NSS_Shutdown();
dc8c34
 	PR_Cleanup();
dc8c34
 #ifdef _WIN32
dc8c34
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
dc8c34
index ce09260..0891608 100644
dc8c34
--- a/ldap/servers/slapd/proto-slap.h
dc8c34
+++ b/ldap/servers/slapd/proto-slap.h
dc8c34
@@ -389,6 +389,7 @@ int config_set_disk_threshold( const char *attrname, char *value, char *errorbuf
dc8c34
 int config_set_disk_grace_period( const char *attrname, char *value, char *errorbuf, int apply );
dc8c34
 int config_set_disk_logging_critical( const char *attrname, char *value, char *errorbuf, int apply );
dc8c34
 int config_set_auditlog_unhashed_pw(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
+
dc8c34
 int config_set_sasl_maxbufsize(const char *attrname, char *value, char *errorbuf, int apply );
dc8c34
 int config_set_listen_backlog_size(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
 int config_set_ignore_time_skew(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
@@ -398,6 +399,10 @@ int config_set_malloc_trim_threshold(const char *attrname, char *value, char *er
dc8c34
 int config_set_malloc_mmap_threshold(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
 #endif
dc8c34
 
dc8c34
+int config_set_ndn_cache_enabled(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
+int config_set_ndn_cache_max_size(const char *attrname, char *value, char *errorbuf, int apply);
dc8c34
+
dc8c34
+
dc8c34
 #if !defined(_WIN32) && !defined(AIX)
dc8c34
 int config_set_maxdescriptors( const char *attrname, char *value, char *errorbuf, int apply );
dc8c34
 #endif /* !_WIN_32 && !AIX */
dc8c34
@@ -562,6 +567,13 @@ int config_get_malloc_trim_threshold();
dc8c34
 int config_get_malloc_mmap_threshold();
dc8c34
 #endif
dc8c34
 
dc8c34
+int config_get_ndn_cache_count();
dc8c34
+size_t config_get_ndn_cache_size();
dc8c34
+int config_get_ndn_cache_enabled();
dc8c34
+PLHashNumber hashNocaseString(const void *key);
dc8c34
+PRIntn hashNocaseCompare(const void *v1, const void *v2);
dc8c34
+
dc8c34
+
dc8c34
 int is_abspath(const char *);
dc8c34
 char* rel2abspath( char * );
dc8c34
 char* rel2abspath_ext( char *, char * );
dc8c34
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
dc8c34
index 28c1ffc..18ae152 100644
dc8c34
--- a/ldap/servers/slapd/schema.c
dc8c34
+++ b/ldap/servers/slapd/schema.c
dc8c34
@@ -250,22 +250,6 @@ dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int
dc8c34
     return SLAPI_DSE_CALLBACK_ERROR;
dc8c34
 }
dc8c34
 
dc8c34
-#if 0
dc8c34
-/*
dc8c34
- * hashNocaseString - used for case insensitive hash lookups
dc8c34
- */
dc8c34
-static PLHashNumber
dc8c34
-hashNocaseString(const void *key)
dc8c34
-{
dc8c34
-    PLHashNumber h = 0;
dc8c34
-    const unsigned char *s;
dc8c34
-
dc8c34
-    for (s = key; *s; s++)
dc8c34
-        h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
dc8c34
-    return h;
dc8c34
-}
dc8c34
-#endif
dc8c34
-
dc8c34
 static const char *
dc8c34
 skipWS(const char *s)
dc8c34
 {
dc8c34
@@ -278,7 +262,6 @@ skipWS(const char *s)
dc8c34
 	return s;
dc8c34
 }
dc8c34
 
dc8c34
-
dc8c34
 /*
dc8c34
  * like strchr() but strings within single quotes are skipped.
dc8c34
  */
dc8c34
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
dc8c34
index 33cfeb4..70e8a51 100644
dc8c34
--- a/ldap/servers/slapd/slap.h
dc8c34
+++ b/ldap/servers/slapd/slap.h
dc8c34
@@ -2015,6 +2015,7 @@ typedef struct _slapdEntryPoints {
dc8c34
 #define CONFIG_DISK_THRESHOLD "nsslapd-disk-monitoring-threshold"
dc8c34
 #define CONFIG_DISK_GRACE_PERIOD "nsslapd-disk-monitoring-grace-period"
dc8c34
 #define CONFIG_DISK_LOGGING_CRITICAL "nsslapd-disk-monitoring-logging-critical"
dc8c34
+
dc8c34
 #define CONFIG_SASL_MAXBUFSIZE "nsslapd-sasl-max-buffer-size"
dc8c34
 #define CONFIG_LISTEN_BACKLOG_SIZE	"nsslapd-listen-backlog-size"
dc8c34
 #define CONFIG_IGNORE_TIME_SKEW "nsslapd-ignore-time-skew"
dc8c34
@@ -2035,6 +2036,10 @@ typedef struct _slapdEntryPoints {
dc8c34
 #define DAEMON_LISTEN_SIZE 128
dc8c34
 #endif
dc8c34
 
dc8c34
+#define CONFIG_NDN_CACHE "nsslapd-ndn-cache-enabled"
dc8c34
+#define CONFIG_NDN_CACHE_SIZE "nsslapd-ndn-cache-max-size"
dc8c34
+
dc8c34
+
dc8c34
 #ifdef MEMPOOL_EXPERIMENTAL
dc8c34
 #define CONFIG_MEMPOOL_SWITCH_ATTRIBUTE "nsslapd-mempool"
dc8c34
 #define CONFIG_MEMPOOL_MAXFREELIST_ATTRIBUTE "nsslapd-mempool-maxfreelist"
dc8c34
@@ -2272,12 +2277,17 @@ typedef struct _slapdFrontendConfig {
dc8c34
   PRInt64 disk_threshold;
dc8c34
   int disk_grace_period;
dc8c34
   int disk_logging_critical;
dc8c34
+
dc8c34
   int ignore_time_skew;
dc8c34
 #if defined(LINUX)
dc8c34
   int malloc_mxfast;            /* mallopt M_MXFAST */
dc8c34
   int malloc_trim_threshold;    /* mallopt M_TRIM_THRESHOLD */
dc8c34
   int malloc_mmap_threshold;    /* mallopt M_MMAP_THRESHOLD */
dc8c34
 #endif
dc8c34
+
dc8c34
+  /* normalized dn cache */
dc8c34
+  int ndn_cache_enabled;
dc8c34
+  size_t ndn_cache_max_size;
dc8c34
 } slapdFrontendConfig_t;
dc8c34
 
dc8c34
 /* possible values for slapdFrontendConfig_t.schemareplace */
dc8c34
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
dc8c34
index 940260f..8507f47 100644
dc8c34
--- a/ldap/servers/slapd/slapi-private.h
dc8c34
+++ b/ldap/servers/slapd/slapi-private.h
dc8c34
@@ -387,12 +387,16 @@ Slapi_DN *slapi_sdn_init_normdn_ndn_passin(Slapi_DN *sdn, const char *dn);
dc8c34
 Slapi_DN *slapi_sdn_init_normdn_passin(Slapi_DN *sdn, const char *dn);
dc8c34
 char *slapi_dn_normalize_original( char *dn );
dc8c34
 char *slapi_dn_normalize_case_original( char *dn );
dc8c34
+void ndn_cache_init();
dc8c34
+void ndn_cache_destroy();
dc8c34
+int ndn_cache_started();
dc8c34
+void ndn_cache_get_stats(PRUint64 *hits, PRUint64 *tries, size_t *size, size_t *max_size, long *count);
dc8c34
+#define NDN_DEFAULT_SIZE 20971520 /* 20mb - size of normalized dn cache */
dc8c34
 
dc8c34
 /* filter.c */
dc8c34
 int filter_flag_is_set(const Slapi_Filter *f,unsigned char flag);
dc8c34
 char *slapi_filter_to_string(const Slapi_Filter *f, char *buffer, size_t bufsize);
dc8c34
-char *
dc8c34
-slapi_filter_to_string_internal( const struct slapi_filter *f, char *buf, size_t *bufsize );
dc8c34
+char *slapi_filter_to_string_internal( const struct slapi_filter *f, char *buf, size_t *bufsize );
dc8c34
 
dc8c34
 /* operation.c */
dc8c34
 
dc8c34
-- 
dc8c34
1.9.3
dc8c34