summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/back-ldbm/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/back-ldbm/cache.c')
-rw-r--r--ldap/servers/slapd/back-ldbm/cache.c905
1 files changed, 765 insertions, 140 deletions
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index 84e935c9..be45ddc9 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -46,7 +46,7 @@
#ifdef DEBUG
#define LDAP_CACHE_DEBUG
-/* #define LDAP_CACHE_DEBUG_LRU */ /* causes slowdown */
+/* #define LDAP_CACHE_DEBUG_LRU * causes slowdown */
#endif
/* cache can't get any smaller than this (in bytes) */
@@ -82,6 +82,38 @@
#define LOG(_a, _x1, _x2, _x3) ;
#endif
+#define LRU_DETACH(cache, e) lru_detach((cache), (void *)(e))
+
+#define CACHE_LRU_HEAD(cache, type) ((type)((cache)->c_lruhead))
+#define CACHE_LRU_TAIL(cache, type) ((type)((cache)->c_lrutail))
+
+#define BACK_LRU_NEXT(entry, type) ((type)((entry)->ep_lrunext))
+#define BACK_LRU_PREV(entry, type) ((type)((entry)->ep_lruprev))
+
+/* static functions */
+static void entrycache_clear_int(struct cache *cache);
+static void entrycache_set_max_size(struct cache *cache, size_t bytes);
+static int entrycache_remove_int(struct cache *cache, struct backentry *e);
+static void entrycache_return(struct cache *cache, struct backentry **bep);
+static int entrycache_replace(struct cache *cache, struct backentry *olde, struct backentry *newe);
+static int entrycache_add_int(struct cache *cache, struct backentry *e, int state, struct backentry **alt);
+static struct backentry *entrycache_flush(struct cache *cache);
+#ifdef LDAP_CACHE_DEBUG_LRU
+static void entry_lru_verify(struct cache *cache, struct backentry *e, int in);
+#endif
+
+static int dn_same_id(const void *bdn, const void *k);
+static void dncache_clear_int(struct cache *cache);
+static void dncache_set_max_size(struct cache *cache, size_t bytes);
+static int dncache_remove_int(struct cache *cache, struct backdn *dn);
+static void dncache_return(struct cache *cache, struct backdn **bdn);
+static int dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn);
+static int dncache_add_int(struct cache *cache, struct backdn *bdn, int state, struct backdn **alt);
+static struct backdn *dncache_flush(struct cache *cache);
+#ifdef LDAP_CACHE_DEBUG_LRU
+static void dn_lru_verify(struct cache *cache, struct backdn *dn, int in);
+#endif
+
/***** tiny hashtable implementation *****/
@@ -284,42 +316,67 @@ static void hash_stats(Hashtable *ht, u_long *slots, int *total_entries,
/***** add/remove entries to/from the LRU list *****/
#ifdef LDAP_CACHE_DEBUG_LRU
+static void
+lru_verify(struct cache *cache, void *ptr, int in)
+{
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> lru_verify\n<= lru_verify (null entry)\n", 0, 0, 0);
+ return;
+ }
+ e = (struct backcommon *)ptr;
+ if (CACHE_TYPE_ENTRY == e->ep_type) {
+ entry_lru_verify(cache, (struct backentry *)e, in);
+ } else {
+ dn_lru_verify(cache, (struct backdn *)e, in);
+ }
+}
+
/* for debugging -- painstakingly verify the lru list is ok -- if 'in' is
* true, then entry 'e' should be in the list right now; otherwise, it
* should NOT be in the list.
*/
-static void lru_verify(struct cache *cache, struct backentry *e, int in)
+static void
+entry_lru_verify(struct cache *cache, struct backentry *e, int in)
{
int is_in = 0;
int count = 0;
struct backentry *ep;
- ep = cache->c_lruhead;
+ ep = CACHE_LRU_HEAD(cache, struct backentry *);
while (ep) {
- count++;
- if (ep == e) {
+ count++;
+ if (ep == e) {
is_in = 1;
}
- if (ep->ep_lruprev) {
- ASSERT(ep->ep_lruprev->ep_lrunext == ep);
+ if (ep->ep_lruprev) {
+ ASSERT(BACK_LRU_NEXT(BACK_LRU_PREV(ep, struct backentry *), struct backentry *)== ep);
} else {
- ASSERT(ep == cache->c_lruhead);
+ ASSERT(ep == CACHE_LRU_HEAD(cache, struct backentry *));
}
- if (ep->ep_lrunext) {
- ASSERT(ep->ep_lrunext->ep_lruprev == ep);
+ if (ep->ep_lrunext) {
+ ASSERT(BACK_LRU_PREV(BACK_LRU_NEXT(ep, struct backentry *), struct backentry *) == ep);
} else {
- ASSERT(ep == cache->c_lrutail);
+ ASSERT(ep == CACHE_LRU_TAIL(cache, struct backentry *));
}
- ep = ep->ep_lrunext;
+ ep = BACK_LRU_NEXT(ep, struct backentry *);
}
ASSERT(is_in == in);
}
#endif
/* assume lock is held */
-static void lru_detach(struct cache *cache, struct backentry *e)
+static void lru_detach(struct cache *cache, void *ptr)
{
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> lru_detach\n<= lru_detach (null entry)\n", 0, 0, 0);
+ return;
+ }
+ e = (struct backcommon *)ptr;
#ifdef LDAP_CACHE_DEBUG_LRU
lru_verify(cache, e, 1);
#endif
@@ -339,8 +396,15 @@ static void lru_detach(struct cache *cache, struct backentry *e)
}
/* assume lock is held */
-static void lru_delete(struct cache *cache, struct backentry *e)
+static void lru_delete(struct cache *cache, void *ptr)
{
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> lru_delete\n<= lru_delete (null entry)\n", 0, 0, 0);
+ return;
+ }
+ e = (struct backcommon *)ptr;
#ifdef LDAP_CACHE_DEBUG_LRU
lru_verify(cache, e, 1);
#endif
@@ -359,8 +423,15 @@ static void lru_delete(struct cache *cache, struct backentry *e)
}
/* assume lock is held */
-static void lru_add(struct cache *cache, struct backentry *e)
+static void lru_add(struct cache *cache, void *ptr)
{
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> lru_add\n<= lru_add (null entry)\n", 0, 0, 0);
+ return;
+ }
+ e = (struct backcommon *)ptr;
#ifdef LDAP_CACHE_DEBUG_LRU
lru_verify(cache, e, 0);
#endif
@@ -379,28 +450,36 @@ static void lru_add(struct cache *cache, struct backentry *e)
/***** cache overhead *****/
-static int cache_remove_int(struct cache *cache, struct backentry *e);
-
-static void cache_make_hashes(struct cache *cache)
+static void cache_make_hashes(struct cache *cache, int type)
{
u_long hashsize = (cache->c_maxentries > 0) ? cache->c_maxentries :
(cache->c_maxsize/512);
- cache->c_dntable = new_hash(hashsize,
- HASHLOC(struct backentry, ep_dn_link),
- dn_hash, entry_same_dn);
- cache->c_idtable = new_hash(hashsize,
- HASHLOC(struct backentry, ep_id_link),
- NULL, entry_same_id);
+ if (CACHE_TYPE_ENTRY == type) {
+ cache->c_dntable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_dn_link),
+ dn_hash, entry_same_dn);
+ cache->c_idtable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_id_link),
+ NULL, entry_same_id);
+#ifdef UUIDCACHE_ON
+ cache->c_uuidtable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_uuid_link),
+ uuid_hash, entry_same_uuid);
+#endif
+ } else if (CACHE_TYPE_DN == type) {
+ cache->c_dntable = NULL;
+ cache->c_idtable = new_hash(hashsize,
+ HASHLOC(struct backdn, dn_id_link),
+ NULL, dn_same_id);
#ifdef UUIDCACHE_ON
- cache->c_uuidtable = new_hash(hashsize,
- HASHLOC(struct backentry, ep_uuid_link),
- uuid_hash, entry_same_uuid);
+ cache->c_uuidtable = NULL;
#endif
+ }
}
/* initialize the cache */
-int cache_init(struct cache *cache, size_t maxsize, long maxentries)
+int cache_init(struct cache *cache, size_t maxsize, long maxentries, int type)
{
LDAPDebug(LDAP_DEBUG_TRACE, "=> cache_init\n", 0, 0, 0);
cache->c_maxsize = maxsize;
@@ -415,7 +494,7 @@ int cache_init(struct cache *cache, size_t maxsize, long maxentries)
cache->c_tries = NULL;
}
cache->c_lruhead = cache->c_lrutail = NULL;
- cache_make_hashes(cache);
+ cache_make_hashes(cache, type);
if (((cache->c_mutex = PR_NewLock()) == NULL) ||
((cache->c_emutexalloc_mutex = PR_NewLock()) == NULL)) {
@@ -439,11 +518,12 @@ int cache_init(struct cache *cache, size_t maxsize, long maxentries)
* of the cache.
* These entries should be freed outside of the cache->c_mutex
*/
-static struct backentry * cache_flush(struct cache *cache)
+static struct backentry *
+entrycache_flush(struct cache *cache)
{
struct backentry *e = NULL;
- LOG("=> cache_flush\n", 0, 0, 0);
+ LOG("=> entrycache_flush\n", 0, 0, 0);
/* all entries on the LRU list are guaranteed to have a refcnt = 0
* (iow, nobody's using them), so just delete from the tail down
@@ -453,62 +533,71 @@ static struct backentry * cache_flush(struct cache *cache)
while ((cache->c_lrutail != NULL) && CACHE_FULL(cache)) {
if (e == NULL)
{
- e = cache->c_lrutail;
+ e = CACHE_LRU_TAIL(cache, struct backentry *);
}
else
{
- e = e->ep_lruprev;
+ e = BACK_LRU_PREV(e, struct backentry *);
}
ASSERT(e->ep_refcnt == 0);
e->ep_refcnt++;
- if (cache_remove_int(cache, e) < 0) {
- LDAPDebug(LDAP_DEBUG_ANY, "cache flush: unable to delete entry\n",
- 0, 0, 0);
+ if (entrycache_remove_int(cache, e) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "entry cache flush: unable to delete entry\n", 0, 0, 0);
break;
}
- if(e == cache->c_lruhead) {
+ if(e == CACHE_LRU_HEAD(cache, struct backentry *)) {
break;
}
}
if (e)
- lru_detach(cache, e);
- LOG("<= cache_flush (down to %lu entries, %lu bytes)\n", cache->c_curentries,
- slapi_counter_get_value(cache->c_cursize), 0);
+ LRU_DETACH(cache, e);
+ LOG("<= entrycache_flush (down to %lu entries, %lu bytes)\n",
+ cache->c_curentries, slapi_counter_get_value(cache->c_cursize), 0);
return e;
}
/* remove everything from the cache */
-static void cache_clear_int(struct cache *cache)
+static void entrycache_clear_int(struct cache *cache)
{
struct backentry *eflush = NULL;
struct backentry *eflushtemp = NULL;
size_t size = cache->c_maxsize;
cache->c_maxsize = 0;
- eflush = cache_flush(cache);
+ eflush = entrycache_flush(cache);
while (eflush)
{
- eflushtemp = eflush->ep_lrunext;
+ eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
backentry_free(&eflush);
eflush = eflushtemp;
}
cache->c_maxsize = size;
if (cache->c_curentries > 0) {
- LDAPDebug(LDAP_DEBUG_ANY, "somehow, there are still %ld entries "
- "in the entry cache. :/\n", cache->c_curentries, 0, 0);
+ LDAPDebug1Arg(LDAP_DEBUG_ANY,
+ "entrycache_clear_int: there are still %ld entries "
+ "in the entry cache. :/\n", cache->c_curentries);
}
}
-void cache_clear(struct cache *cache)
+void cache_clear(struct cache *cache, int type)
{
PR_Lock(cache->c_mutex);
- cache_clear_int(cache);
+ if (CACHE_TYPE_ENTRY == type) {
+ entrycache_clear_int(cache);
+ } else if (CACHE_TYPE_DN == type) {
+ dncache_clear_int(cache);
+ }
PR_Unlock(cache->c_mutex);
}
-static void erase_cache(struct cache *cache)
+static void erase_cache(struct cache *cache, int type)
{
- cache_clear_int(cache);
+ if (CACHE_TYPE_ENTRY == type) {
+ entrycache_clear_int(cache);
+ } else if (CACHE_TYPE_DN == type) {
+ dncache_clear_int(cache);
+ }
slapi_ch_free((void **)&cache->c_dntable);
slapi_ch_free((void **)&cache->c_idtable);
#ifdef UUIDCACHE_ON
@@ -517,14 +606,23 @@ static void erase_cache(struct cache *cache)
}
/* to be used on shutdown or when destroying a backend instance */
-void cache_destroy_please(struct cache *cache)
+void cache_destroy_please(struct cache *cache, int type)
{
- erase_cache(cache);
+ erase_cache(cache, type);
PR_DestroyLock(cache->c_mutex);
PR_DestroyLock(cache->c_emutexalloc_mutex);
}
-void cache_set_max_size(struct cache *cache, size_t bytes)
+void cache_set_max_size(struct cache *cache, size_t bytes, int type)
+{
+ if (CACHE_TYPE_ENTRY == type) {
+ entrycache_set_max_size(cache, bytes);
+ } else if (CACHE_TYPE_DN == type) {
+ dncache_set_max_size(cache, bytes);
+ }
+}
+
+static void entrycache_set_max_size(struct cache *cache, size_t bytes)
{
struct backentry *eflush = NULL;
struct backentry *eflushtemp = NULL;
@@ -540,10 +638,10 @@ void cache_set_max_size(struct cache *cache, size_t bytes)
LOG("entry cache size set to %lu\n", bytes, 0, 0);
/* check for full cache, and clear out if necessary */
if (CACHE_FULL(cache))
- eflush = cache_flush(cache);
+ eflush = entrycache_flush(cache);
while (eflush)
{
- eflushtemp = eflush->ep_lrunext;
+ eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
backentry_free(&eflush);
eflush = eflushtemp;
}
@@ -551,8 +649,8 @@ void cache_set_max_size(struct cache *cache, size_t bytes)
/* there's hardly anything left in the cache -- clear it out and
* resize the hashtables for efficiency.
*/
- erase_cache(cache);
- cache_make_hashes(cache);
+ erase_cache(cache, CACHE_TYPE_ENTRY);
+ cache_make_hashes(cache, CACHE_TYPE_ENTRY);
}
PR_Unlock(cache->c_mutex);
if (! dblayer_is_cachesize_sane(&bytes)) {
@@ -582,11 +680,11 @@ void cache_set_max_entries(struct cache *cache, long entries)
/* check for full cache, and clear out if necessary */
if (CACHE_FULL(cache))
- eflush = cache_flush(cache);
+ eflush = entrycache_flush(cache);
PR_Unlock(cache->c_mutex);
while (eflush)
{
- eflushtemp = eflush->ep_lrunext;
+ eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
backentry_free(&eflush);
eflush = eflushtemp;
}
@@ -594,7 +692,7 @@ void cache_set_max_entries(struct cache *cache, long entries)
size_t cache_get_max_size(struct cache *cache)
{
- size_t n;
+ size_t n = 0;
PR_Lock(cache->c_mutex);
n = cache->c_maxsize;
@@ -649,41 +747,44 @@ void cache_debug_hash(struct cache *cache, char **out)
u_long slots;
int total_entries, max_entries_per_slot, *slot_stats;
int i, j;
- Hashtable *ht;
- char *name;
+ Hashtable *ht = NULL;
+ char *name = "unknown";
PR_Lock(cache->c_mutex);
*out = (char *)slapi_ch_malloc(1024);
**out = 0;
for (i = 0; i < 3; i++) {
- if (i > 0)
- sprintf(*out + strlen(*out), "; ");
- switch(i) {
- case 0:
- ht = cache->c_dntable;
- name = "dn";
- break;
- case 1:
- ht = cache->c_idtable;
- name = "id";
- break;
+ if (i > 0)
+ sprintf(*out + strlen(*out), "; ");
+ switch(i) {
+ case 0:
+ ht = cache->c_dntable;
+ name = "dn";
+ break;
+ case 1:
+ ht = cache->c_idtable;
+ name = "id";
+ break;
#ifdef UUIDCACHE_ON
- case 2:
+ case 2:
default:
- ht = cache->c_uuidtable;
- name = "uuid";
- break;
+ ht = cache->c_uuidtable;
+ name = "uuid";
+ break;
#endif
- }
- hash_stats(ht, &slots, &total_entries, &max_entries_per_slot,
- &slot_stats);
- sprintf(*out + strlen(*out), "%s hash: %lu slots, %d entries (%d max "
- "entries per slot) -- ", name, slots, total_entries,
- max_entries_per_slot);
- for (j = 0; j <= max_entries_per_slot; j++)
- sprintf(*out + strlen(*out), "%d[%d] ", j, slot_stats[j]);
- slapi_ch_free((void **)&slot_stats);
+ }
+ if (NULL == ht) {
+ continue;
+ }
+ hash_stats(ht, &slots, &total_entries, &max_entries_per_slot,
+ &slot_stats);
+ sprintf(*out + strlen(*out), "%s hash: %lu slots, %d items (%d max "
+ "items per slot) -- ", name, slots, total_entries,
+ max_entries_per_slot);
+ for (j = 0; j <= max_entries_per_slot; j++)
+ sprintf(*out + strlen(*out), "%d[%d] ", j, slot_stats[j]);
+ slapi_ch_free((void **)&slot_stats);
}
PR_Unlock(cache->c_mutex);
}
@@ -693,7 +794,8 @@ void cache_debug_hash(struct cache *cache, char **out)
/* remove an entry from the cache */
/* you must be holding c_mutex !! */
-static int cache_remove_int(struct cache *cache, struct backentry *e)
+static int
+entrycache_remove_int(struct cache *cache, struct backentry *e)
{
int ret = 1; /* assume not in cache */
const char *ndn;
@@ -701,7 +803,7 @@ static int cache_remove_int(struct cache *cache, struct backentry *e)
const char *uuid;
#endif
- LOG("=> cache_remove (%s)\n", backentry_get_ndn(e), 0, 0);
+ LOG("=> entrycache_remove_int (%s)\n", backentry_get_ndn(e), 0, 0);
if (e->ep_state & ENTRY_STATE_NOTINCACHE)
{
return ret;
@@ -742,20 +844,20 @@ static int cache_remove_int(struct cache *cache, struct backentry *e)
if (ret == 0) {
/* won't be on the LRU list since it has a refcount on it */
/* adjust cache size */
- slapi_counter_subtract(cache->c_cursize, e->size);
+ slapi_counter_subtract(cache->c_cursize, e->ep_size);
cache->c_curentries--;
- LOG("<= cache_remove (size %lu): cache now %lu entries, %lu bytes\n",
- e->size, cache->c_curentries,
+ LOG("<= entrycache_remove_int (size %lu): cache now %lu entries, "
+ "%lu bytes\n", e->ep_size, cache->c_curentries,
slapi_counter_get_value(cache->c_cursize));
}
/* mark for deletion (will be erased when refcount drops to zero) */
e->ep_state |= ENTRY_STATE_DELETED;
- LOG("<= cache_remove: %d\n", ret, 0, 0);
+ LOG("<= entrycache_remove_int: %d\n", ret, 0, 0);
return ret;
}
-/* remove an entry from the cache.
+/* remove an entry/a dn from the cache.
* you must have a refcount on e (iow, fetched via cache_find_*). the
* entry is removed from the cache, but NOT freed! you are responsible
* for freeing the entry yourself when done with it, preferrably via
@@ -765,23 +867,54 @@ static int cache_remove_int(struct cache *cache, struct backentry *e)
* returns: 0 on success
* 1 if the entry wasn't in the cache at all (not even partially)
*/
-int cache_remove(struct cache *cache, struct backentry *e)
+int cache_remove(struct cache *cache, void *ptr)
{
- int ret;
+ int ret = 0;
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> lru_remove\n<= lru_remove (null entry)\n", 0, 0, 0);
+ return ret;
+ }
+ e = (struct backcommon *)ptr;
PR_Lock(cache->c_mutex);
- ASSERT(e->ep_refcnt > 0);
- ret = cache_remove_int(cache, e);
+ if (CACHE_TYPE_ENTRY == e->ep_type) {
+ ASSERT(e->ep_refcnt > 0);
+ ret = entrycache_remove_int(cache, (struct backentry *)e);
+ } else if (CACHE_TYPE_DN == e->ep_type) {
+ ret = dncache_remove_int(cache, (struct backdn *)e);
+ }
PR_Unlock(cache->c_mutex);
return ret;
}
/* replace an entry in the cache.
* returns: 0 on success
- * 1 if the entry wasn't in the cache
+ * 1 if the entry wasn't in the cache
*/
-int cache_replace(struct cache *cache, struct backentry *olde,
- struct backentry *newe)
+int cache_replace(struct cache *cache, void *oldptr, void *newptr)
+{
+ struct backcommon *olde;
+ if (NULL == oldptr || NULL == newptr)
+ {
+ LOG("=> lru_replace\n<= lru_replace (null entry)\n", 0, 0, 0);
+ return 0;
+ }
+ olde = (struct backcommon *)oldptr;
+
+ if (CACHE_TYPE_ENTRY == olde->ep_type) {
+ return entrycache_replace(cache, (struct backentry *)oldptr,
+ (struct backentry *)newptr);
+ } else if (CACHE_TYPE_DN == olde->ep_type) {
+ return dncache_replace(cache, (struct backdn *)oldptr,
+ (struct backdn *)newptr);
+ }
+ return 0;
+}
+
+static int entrycache_replace(struct cache *cache, struct backentry *olde,
+ struct backentry *newe)
{
int found;
const char *oldndn;
@@ -791,7 +924,7 @@ int cache_replace(struct cache *cache, struct backentry *olde,
const char *newuuid;
#endif
- LOG("=> cache_replace (%s) -> (%s)\n", backentry_get_ndn(olde),
+ LOG("=> entrycache_replace (%s) -> (%s)\n", backentry_get_ndn(olde),
backentry_get_ndn(newe), 0);
/* remove from all hashtables -- this function may be called from places
@@ -819,7 +952,7 @@ int cache_replace(struct cache *cache, struct backentry *olde,
found &= remove_hash(cache->c_uuidtable, (void *)olduuid, strlen(olduuid));
#endif
if (!found) {
- LOG("cache replace: cache index tables out of sync\n", 0, 0, 0);
+ LOG("entry cache replace: cache index tables out of sync\n", 0, 0, 0);
PR_Unlock(cache->c_mutex);
return 1;
}
@@ -831,9 +964,9 @@ int cache_replace(struct cache *cache, struct backentry *olde,
*/
if (remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)))
{
- slapi_counter_subtract(cache->c_cursize, newe->size);
+ slapi_counter_subtract(cache->c_cursize, newe->ep_size);
cache->c_curentries--;
- LOG("cache replace remove entry size %lu\n", newe->size, 0, 0);
+ LOG("entry cache replace remove entry size %lu\n", newe->ep_size, 0, 0);
}
}
@@ -842,12 +975,12 @@ int cache_replace(struct cache *cache, struct backentry *olde,
* tested enough that we believe it works.)
*/
if (!add_hash(cache->c_dntable, (void *)newndn, strlen(newndn), newe, NULL)) {
- LOG("cache replace: can't add dn\n", 0, 0, 0);
+ LOG("entry cache replace: can't add dn\n", 0, 0, 0);
PR_Unlock(cache->c_mutex);
return 1;
}
if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, NULL)) {
- LOG("cache replace: can't add id\n", 0, 0, 0);
+ LOG("entry cache replace: can't add id\n", 0, 0, 0);
remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn));
PR_Unlock(cache->c_mutex);
return 1;
@@ -855,7 +988,7 @@ int cache_replace(struct cache *cache, struct backentry *olde,
#ifdef UUIDCACHE_ON
if (newuuid && !add_hash(cache->c_uuidtable, (void *)newuuid, strlen(newuuid),
newe, NULL)) {
- LOG("cache replace: can't add uuid\n", 0, 0, 0);
+ LOG("entry cache replace: can't add uuid\n", 0, 0, 0);
remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn));
remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID));
PR_Unlock(cache->c_mutex);
@@ -864,16 +997,16 @@ int cache_replace(struct cache *cache, struct backentry *olde,
#endif
/* adjust cache meta info */
newe->ep_refcnt = 1;
- newe->size = cache_entry_size(newe);
- if (newe->size > olde->size) {
- slapi_counter_add(cache->c_cursize, newe->size - olde->size);
- } else if (newe->size < olde->size) {
- slapi_counter_subtract(cache->c_cursize, olde->size - newe->size);
+ newe->ep_size = cache_entry_size(newe);
+ if (newe->ep_size > olde->ep_size) {
+ slapi_counter_add(cache->c_cursize, newe->ep_size - olde->ep_size);
+ } else if (newe->ep_size < olde->ep_size) {
+ slapi_counter_subtract(cache->c_cursize, olde->ep_size - newe->ep_size);
}
olde->ep_state = ENTRY_STATE_DELETED;
newe->ep_state = 0;
PR_Unlock(cache->c_mutex);
- LOG("<= cache_replace OK, cache size now %lu cache count now %ld\n",
+ LOG("<= entrycache_replace OK, cache size now %lu cache count now %ld\n",
slapi_counter_get_value(cache->c_cursize), cache->c_curentries, 0);
return 0;
}
@@ -881,18 +1014,33 @@ int cache_replace(struct cache *cache, struct backentry *olde,
/* call this when you're done with an entry that was fetched via one of
* the cache_find_* calls.
*/
-void cache_return(struct cache *cache, struct backentry **bep)
+void cache_return(struct cache *cache, void **ptr)
{
- struct backentry *eflush = NULL;
- struct backentry *eflushtemp = NULL;
- struct backentry *e;
- if (NULL == bep || NULL == *bep)
+ struct backcommon *bep;
+
+ if (NULL == ptr || NULL == *ptr)
{
- LOG("=> cache_return (null entry)\n", 0, 0, 0);
+ LOG("=> cache_return\n<= cache_return (null entry)\n", 0, 0, 0);
return;
}
+ bep = *(struct backcommon **)ptr;
+ if (CACHE_TYPE_ENTRY == bep->ep_type) {
+ entrycache_return(cache, (struct backentry **)ptr);
+ } else if (CACHE_TYPE_DN == bep->ep_type) {
+ dncache_return(cache, (struct backdn **)ptr);
+ }
+}
+
+static void
+entrycache_return(struct cache *cache, struct backentry **bep)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+ struct backentry *e;
+
e = *bep;
- LOG("=> cache_return (%s) entry count: %d, entry in cache:%ld\n", backentry_get_ndn(e), e->ep_refcnt, cache->c_curentries);
+ LOG("=> entrycache_return (%s) entry count: %d, entry in cache:%ld\n",
+ backentry_get_ndn(e), e->ep_refcnt, cache->c_curentries);
PR_Lock(cache->c_mutex);
if (e->ep_state & ENTRY_STATE_NOTINCACHE)
@@ -909,17 +1057,18 @@ void cache_return(struct cache *cache, struct backentry **bep)
lru_add(cache, e);
/* the cache might be overfull... */
if (CACHE_FULL(cache))
- eflush = cache_flush(cache);
+ eflush = entrycache_flush(cache);
}
}
}
PR_Unlock(cache->c_mutex);
while (eflush)
{
- eflushtemp = eflush->ep_lrunext;
+ eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
backentry_free(&eflush);
eflush = eflushtemp;
}
+ LOG("<= entrycache_return\n", 0, 0, 0);
}
@@ -941,7 +1090,7 @@ struct backentry *cache_find_dn(struct cache *cache, const char *dn, unsigned lo
return NULL;
}
if (e->ep_refcnt == 0)
- lru_delete(cache, e);
+ lru_delete(cache, (void *)e);
e->ep_refcnt++;
PR_Unlock(cache->c_mutex);
slapi_counter_increment(cache->c_hits);
@@ -972,7 +1121,7 @@ struct backentry *cache_find_id(struct cache *cache, ID id)
return NULL;
}
if (e->ep_refcnt == 0)
- lru_delete(cache, e);
+ lru_delete(cache, (void *)e);
e->ep_refcnt++;
PR_Unlock(cache->c_mutex);
slapi_counter_increment(cache->c_hits);
@@ -1003,7 +1152,7 @@ struct backentry *cache_find_uuid(struct cache *cache, const char *uuid)
return NULL;
}
if (e->ep_refcnt == 0)
- lru_delete(cache, e);
+ lru_delete(cache, (void *)e);
e->ep_refcnt++;
PR_Unlock(cache->c_mutex);
slapi_counter_increment(cache->c_hits);
@@ -1018,8 +1167,9 @@ struct backentry *cache_find_uuid(struct cache *cache, const char *uuid)
#endif
/* add an entry to the cache */
-static int cache_add_int(struct cache *cache, struct backentry *e, int state,
- struct backentry **alt)
+static int
+entrycache_add_int(struct cache *cache, struct backentry *e, int state,
+ struct backentry **alt)
{
struct backentry *eflush = NULL;
struct backentry *eflushtemp = NULL;
@@ -1030,7 +1180,7 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
struct backentry *my_alt;
int already_in = 0;
- LOG("=> cache_add_int( \"%s\", %ld )\n", backentry_get_ndn(e),
+ LOG("=> entrycache_add_int( \"%s\", %ld )\n", backentry_get_ndn(e),
e->ep_id, 0);
PR_Lock(cache->c_mutex);
@@ -1061,7 +1211,7 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
* ==> increase the refcnt
*/
if (e->ep_refcnt == 0)
- lru_delete(cache, e);
+ lru_delete(cache, (void *)e);
e->ep_refcnt++;
e->ep_state = state; /* might be CREATING */
/* returning 1 (entry already existed), but don't set to alt
@@ -1093,7 +1243,7 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
if (alt) {
*alt = my_alt;
if ((*alt)->ep_refcnt == 0)
- lru_delete(cache, *alt);
+ lru_delete(cache, (void *)*alt);
(*alt)->ep_refcnt++;
}
PR_Unlock(cache->c_mutex);
@@ -1126,7 +1276,7 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
* remove the old entry and add the new one, and all will be
* fine (i think).
*/
- LOG("<= cache_add_int (ignoring)\n", 0, 0, 0);
+ LOG("<= entrycache_add_int (ignoring)\n", 0, 0, 0);
PR_Unlock(cache->c_mutex);
return 0;
}
@@ -1156,30 +1306,30 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
if (! already_in) {
e->ep_refcnt = 1;
- e->size = cache_entry_size(e);
+ e->ep_size = cache_entry_size(e);
- slapi_counter_add(cache->c_cursize, e->size);
+ slapi_counter_add(cache->c_cursize, e->ep_size);
cache->c_curentries++;
/* don't add to lru since refcnt = 1 */
LOG("added entry of size %lu -> total now %lu out of max %lu\n",
- e->size, slapi_counter_get_value(cache->c_cursize), cache->c_maxsize);
+ e->ep_size, slapi_counter_get_value(cache->c_cursize), cache->c_maxsize);
if (cache->c_maxentries >= 0) {
LOG(" total entries %ld out of %ld\n",
cache->c_curentries, cache->c_maxentries, 0);
}
/* check for full cache, and clear out if necessary */
if (CACHE_FULL(cache))
- eflush = cache_flush(cache);
+ eflush = entrycache_flush(cache);
}
PR_Unlock(cache->c_mutex);
while (eflush)
{
- eflushtemp = eflush->ep_lrunext;
+ eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
backentry_free(&eflush);
eflush = eflushtemp;
}
- LOG("<= cache_add_int OK\n", 0, 0, 0);
+ LOG("<= entrycache_add_int OK\n", 0, 0, 0);
return 0;
}
@@ -1194,10 +1344,23 @@ static int cache_add_int(struct cache *cache, struct backentry *e, int state,
* (this means code which suffered from race conditions between multiple
* entry modifiers can now work.)
*/
-int cache_add(struct cache *cache, struct backentry *e,
- struct backentry **alt)
+int cache_add(struct cache *cache, void *ptr, void **alt)
{
- return cache_add_int(cache, e, 0, alt);
+ struct backcommon *e;
+ if (NULL == ptr)
+ {
+ LOG("=> cache_add\n<= cache_add (null entry)\n", 0, 0, 0);
+ return 0;
+ }
+ e = (struct backcommon *)ptr;
+ if (CACHE_TYPE_ENTRY == e->ep_type) {
+ return entrycache_add_int(cache, (struct backentry *)e,
+ 0, (struct backentry **)alt);
+ } else if (CACHE_TYPE_DN == e->ep_type) {
+ return dncache_add_int(cache, (struct backdn *)e,
+ 0, (struct backdn **)alt);
+ }
+ return 0;
}
/* same as above, but add it tentatively: nobody else can use this entry
@@ -1206,7 +1369,7 @@ int cache_add(struct cache *cache, struct backentry *e,
int cache_add_tentative(struct cache *cache, struct backentry *e,
struct backentry **alt)
{
- return cache_add_int(cache, e, ENTRY_STATE_CREATING, alt);
+ return entrycache_add_int(cache, e, ENTRY_STATE_CREATING, alt);
}
/* locks an entry so that it can be modified (you should have gotten the
@@ -1248,3 +1411,465 @@ void cache_unlock_entry(struct cache *cache, struct backentry *e)
LOG("=> cache_unlock_entry\n", 0, 0, 0);
PR_Unlock(e->ep_mutexp);
}
+
+/* DN cache */
+/* remove everything from the cache */
+static void
+dncache_clear_int(struct cache *cache)
+{
+ struct backdn *dnflush = NULL;
+ struct backdn *dnflushtemp = NULL;
+ size_t size = cache->c_maxsize;
+
+ if (!entryrdn_get_switch()) {
+ return;
+ }
+
+ cache->c_maxsize = 0;
+ dnflush = dncache_flush(cache);
+ while (dnflush)
+ {
+ dnflushtemp = BACK_LRU_NEXT(dnflush, struct backdn *);
+ backdn_free(&dnflush);
+ dnflush = dnflushtemp;
+ }
+ cache->c_maxsize = size;
+ if (cache->c_curentries > 0) {
+ LDAPDebug1Arg(LDAP_DEBUG_ANY,
+ "dncache_clear_int: there are still %ld dn's "
+ "in the dn cache. :/\n", cache->c_curentries);
+ }
+}
+
+static int
+dn_same_id(const void *bdn, const void *k)
+{
+ return (((struct backdn *)bdn)->ep_id == *(ID *)k);
+}
+
+static void
+dncache_set_max_size(struct cache *cache, size_t bytes)
+{
+ struct backdn *dnflush = NULL;
+ struct backdn *dnflushtemp = NULL;
+
+ if (!entryrdn_get_switch()) {
+ return;
+ }
+
+ if (bytes < MINCACHESIZE) {
+ bytes = MINCACHESIZE;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING -- Minimum cache size is %lu -- rounding up\n",
+ MINCACHESIZE, 0, 0);
+ }
+ PR_Lock(cache->c_mutex);
+ cache->c_maxsize = bytes;
+ LOG("entry cache size set to %lu\n", bytes, 0, 0);
+ /* check for full cache, and clear out if necessary */
+ if (CACHE_FULL(cache)) {
+ dnflush = dncache_flush(cache);
+ }
+ while (dnflush)
+ {
+ dnflushtemp = BACK_LRU_NEXT(dnflush, struct backdn *);
+ backdn_free(&dnflush);
+ dnflush = dnflushtemp;
+ }
+ if (cache->c_curentries < 50) {
+ /* there's hardly anything left in the cache -- clear it out and
+ * resize the hashtables for efficiency.
+ */
+ erase_cache(cache, CACHE_TYPE_DN);
+ cache_make_hashes(cache, CACHE_TYPE_DN);
+ }
+ PR_Unlock(cache->c_mutex);
+ if (! dblayer_is_cachesize_sane(&bytes)) {
+ LDAPDebug1Arg(LDAP_DEBUG_ANY,
+ "WARNING -- Possible CONFIGURATION ERROR -- cachesize "
+ "(%lu) may be configured to use more than the available "
+ "physical memory.\n", bytes);
+ }
+}
+
+/* remove a dn from the cache */
+/* you must be holding c_mutex !! */
+static int
+dncache_remove_int(struct cache *cache, struct backdn *bdn)
+{
+ int ret = 1; /* assume not in cache */
+
+ if (!entryrdn_get_switch()) {
+ return 0;
+ }
+
+ LOG("=> dncache_remove_int (%s)\n", slapi_sdn_get_dn(bdn->dn_sdn), 0, 0);
+ if (bdn->ep_state & ENTRY_STATE_NOTINCACHE)
+ {
+ return ret;
+ }
+
+ /* remove from id hashtable */
+ if (remove_hash(cache->c_idtable, &(bdn->ep_id), sizeof(ID)))
+ {
+ ret = 0;
+ }
+ else
+ {
+ LOG("remove %d from id hash failed\n", bdn->ep_id, 0, 0);
+ }
+ if (ret == 0) {
+ /* won't be on the LRU list since it has a refcount on it */
+ /* adjust cache size */
+ slapi_counter_subtract(cache->c_cursize, bdn->ep_size);
+ cache->c_curentries--;
+ LOG("<= dncache_remove_int (size %lu): cache now %lu dn's, %lu bytes\n",
+ bdn->ep_size, cache->c_curentries,
+ slapi_counter_get_value(cache->c_cursize));
+ }
+
+ /* mark for deletion (will be erased when refcount drops to zero) */
+ bdn->ep_state |= ENTRY_STATE_DELETED;
+ LOG("<= dncache_remove_int: %d\n", ret, 0, 0);
+ return ret;
+}
+
+static void
+dncache_return(struct cache *cache, struct backdn **bdn)
+{
+ struct backdn *dnflush = NULL;
+ struct backdn *dnflushtemp = NULL;
+
+ if (!entryrdn_get_switch()) {
+ return;
+ }
+
+ LOG("=> dncache_return (%s) reference count: %d, dn in cache:%ld\n",
+ slapi_sdn_get_dn((*bdn)->dn_sdn), (*bdn)->ep_refcnt, cache->c_curentries);
+
+ PR_Lock(cache->c_mutex);
+ if ((*bdn)->ep_state & ENTRY_STATE_NOTINCACHE)
+ {
+ backdn_free(bdn);
+ }
+ else
+ {
+ ASSERT((*bdn)->ep_refcnt > 0);
+ if (! --(*bdn)->ep_refcnt) {
+ if ((*bdn)->ep_state & ENTRY_STATE_DELETED) {
+ backdn_free(bdn);
+ } else {
+ lru_add(cache, (void *)*bdn);
+ /* the cache might be overfull... */
+ if (CACHE_FULL(cache)) {
+ dnflush = dncache_flush(cache);
+ }
+ }
+ }
+ }
+ PR_Unlock(cache->c_mutex);
+ while (dnflush)
+ {
+ dnflushtemp = BACK_LRU_NEXT(dnflush, struct backdn *);
+ backdn_free(&dnflush);
+ dnflush = dnflushtemp;
+ }
+}
+
+/* lookup a dn in the cache by its id# (you must return it later) */
+struct backdn *
+dncache_find_id(struct cache *cache, ID id)
+{
+ struct backdn *bdn = NULL;
+
+ if (!entryrdn_get_switch()) {
+ return bdn;
+ }
+
+ LOG("=> dncache_find_id (%lu)\n", (u_long)id, 0, 0);
+
+ PR_Lock(cache->c_mutex);
+ if (find_hash(cache->c_idtable, &id, sizeof(ID), (void **)&bdn)) {
+ /* need to check entry state */
+ if (bdn->ep_state != 0) {
+ /* entry is deleted or not fully created yet */
+ PR_Unlock(cache->c_mutex);
+ LOG("<= dncache_find_id (NOT FOUND)\n", 0, 0, 0);
+ return NULL;
+ }
+ if (bdn->ep_refcnt == 0)
+ lru_delete(cache, (void *)bdn);
+ bdn->ep_refcnt++;
+ PR_Unlock(cache->c_mutex);
+ slapi_counter_increment(cache->c_hits);
+ } else {
+ PR_Unlock(cache->c_mutex);
+ }
+ slapi_counter_increment(cache->c_tries);
+
+ LOG("<= cache_find_id (%sFOUND)\n", bdn ? "" : "NOT ", 0, 0);
+ return bdn;
+}
+
+/* add a dn to the cache */
+static int
+dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
+ struct backdn **alt)
+{
+ struct backdn *dnflush = NULL;
+ struct backdn *dnflushtemp = NULL;
+ struct backdn *my_alt;
+ int already_in = 0;
+
+ if (!entryrdn_get_switch()) {
+ return 0;
+ }
+
+ LOG("=> dncache_add_int( \"%s\", %ld )\n", slapi_sdn_get_dn(bdn->dn_sdn),
+ bdn->ep_id, 0);
+
+ PR_Lock(cache->c_mutex);
+
+ if (! add_hash(cache->c_idtable, &(bdn->ep_id), sizeof(ID), bdn,
+ (void **)&my_alt)) {
+ LOG("entry %s already in id cache!\n", slapi_sdn_get_dn(bdn->dn_sdn), 0, 0);
+ if (my_alt == bdn)
+ {
+ if ((bdn->ep_state & ENTRY_STATE_CREATING) && (state == 0))
+ {
+ /* attempting to "add" a dn that's already in the cache,
+ * and the old entry was a placeholder and the new one isn't?
+ * sounds like a confirmation of a previous add!
+ */
+ LOG("confirming a previous add\n", 0, 0, 0);
+ already_in = 1;
+ }
+ else
+ {
+ /* the entry already in the cache and either one of these:
+ * 1) ep_state: CREATING && state: CREATING
+ * ==> keep protecting the entry; increase the refcnt
+ * 2) ep_state: 0 && state: CREATING
+ * ==> change the state to CREATING (protect it);
+ * increase the refcnt
+ * 3) ep_state: 0 && state: 0
+ * ==> increase the refcnt
+ */
+ if (bdn->ep_refcnt == 0)
+ lru_delete(cache, (void *)bdn);
+ bdn->ep_refcnt++;
+ bdn->ep_state = state; /* might be CREATING */
+ /* returning 1 (entry already existed), but don't set to alt
+ * to prevent that the caller accidentally thinks the existing
+ * entry is not the same one the caller has and releases it.
+ */
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+ else
+ {
+ if (my_alt->ep_state & ENTRY_STATE_CREATING)
+ {
+ LOG("the entry is reserved\n", 0, 0, 0);
+ bdn->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+ else if (state != 0)
+ {
+ LOG("the entry already exists. cannot reserve it.\n", 0, 0, 0);
+ bdn->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+ else
+ {
+ if (alt) {
+ *alt = my_alt;
+ if ((*alt)->ep_refcnt == 0)
+ lru_delete(cache, (void *)*alt);
+ (*alt)->ep_refcnt++;
+ }
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+ }
+
+ bdn->ep_state = state;
+
+ if (! already_in) {
+ bdn->ep_refcnt = 1;
+ if (0 == bdn->ep_size) {
+ bdn->ep_size = slapi_sdn_get_size(bdn->dn_sdn);
+ }
+
+ slapi_counter_add(cache->c_cursize, bdn->ep_size);
+ cache->c_curentries++;
+ /* don't add to lru since refcnt = 1 */
+ LOG("added entry of size %lu -> total now %lu out of max %lu\n",
+ bdn->ep_size, slapi_counter_get_value(cache->c_cursize),
+ cache->c_maxsize);
+ if (cache->c_maxentries >= 0) {
+ LOG(" total entries %ld out of %ld\n",
+ cache->c_curentries, cache->c_maxentries, 0);
+ }
+ /* check for full cache, and clear out if necessary */
+ if (CACHE_FULL(cache)) {
+ dnflush = dncache_flush(cache);
+ }
+ }
+ PR_Unlock(cache->c_mutex);
+
+ while (dnflush)
+ {
+ dnflushtemp = BACK_LRU_NEXT(dnflush, struct backdn *);
+ backdn_free(&dnflush);
+ dnflush = dnflushtemp;
+ }
+ LOG("<= dncache_add_int OK\n", 0, 0, 0);
+ return 0;
+}
+
+static int
+dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn)
+{
+ int found;
+ const char *oldndn;
+ const char *newndn;
+
+ if (!entryrdn_get_switch()) {
+ return 0;
+ }
+
+ LOG("=> dncache_replace (%s) -> (%s)\n",
+ slapi_sdn_get_dn(olddn->dn_sdn), slapi_sdn_get_dn(newdn->dn_sdn), 0);
+
+ /* remove from all hashtable -- this function may be called from places
+ * where the entry isn't in all the table yet, so we don't care if any
+ * of these return errors.
+ */
+ oldndn = slapi_sdn_get_ndn(olddn->dn_sdn);
+ newndn = slapi_sdn_get_ndn(newdn->dn_sdn);
+ PR_Lock(cache->c_mutex);
+
+ /*
+ * First, remove the old entry from the hashtable.
+ * If the old entry is in cache but not in at least one of the
+ * cache tables, operation error
+ */
+ if ( (olddn->ep_state & ENTRY_STATE_NOTINCACHE) == 0 ) {
+
+ found = remove_hash(cache->c_idtable, &(olddn->ep_id), sizeof(ID));
+ if (!found) {
+ LOG("dn cache replace: cache index tables out of sync\n", 0, 0, 0);
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+
+ /* now, add the new entry to the hashtables */
+ /* (probably don't need such extensive error handling, once this has been
+ * tested enough that we believe it works.)
+ */
+ if (!add_hash(cache->c_idtable, &(newdn->ep_id), sizeof(ID), newdn, NULL)) {
+ LOG("dn cache replace: can't add id\n", 0, 0, 0);
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ /* adjust cache meta info */
+ newdn->ep_refcnt = 1;
+ if (0 == newdn->ep_size) {
+ newdn->ep_size = slapi_sdn_get_size(newdn->dn_sdn);
+ }
+ if (newdn->ep_size > olddn->ep_size) {
+ slapi_counter_add(cache->c_cursize, newdn->ep_size - olddn->ep_size);
+ } else if (newdn->ep_size < olddn->ep_size) {
+ slapi_counter_subtract(cache->c_cursize, olddn->ep_size - newdn->ep_size);
+ }
+ olddn->ep_state = ENTRY_STATE_DELETED;
+ newdn->ep_state = 0;
+ PR_Unlock(cache->c_mutex);
+ LOG("<= dncache_replace OK, cache size now %lu cache count now %ld\n",
+ slapi_counter_get_value(cache->c_cursize), cache->c_curentries, 0);
+ return 0;
+}
+
+static struct backdn *
+dncache_flush(struct cache *cache)
+{
+ struct backdn *dn = NULL;
+
+ if (!entryrdn_get_switch()) {
+ return dn;
+ }
+
+ LOG("=> dncache_flush\n", 0, 0, 0);
+
+ /* all entries on the LRU list are guaranteed to have a refcnt = 0
+ * (iow, nobody's using them), so just delete from the tail down
+ * until the cache is a managable size again.
+ * (cache->c_mutex is locked when we enter this)
+ */
+ while ((cache->c_lrutail != NULL) && CACHE_FULL(cache)) {
+ if (dn == NULL)
+ {
+ dn = CACHE_LRU_TAIL(cache, struct backdn *);
+ }
+ else
+ {
+ dn = BACK_LRU_PREV(dn, struct backdn *);
+ }
+ ASSERT(dn->ep_refcnt == 0);
+ dn->ep_refcnt++;
+ if (dncache_remove_int(cache, dn) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dn cache flush: unable to delete entry\n",
+ 0, 0, 0);
+ break;
+ }
+ if(dn == CACHE_LRU_HEAD(cache, struct backdn *)) {
+ break;
+ }
+ }
+ if (dn)
+ LRU_DETACH(cache, dn);
+ LOG("<= dncache_flush (down to %lu dns, %lu bytes)\n", cache->c_curentries,
+ slapi_counter_get_value(cache->c_cursize), 0);
+ return dn;
+}
+
+#ifdef LDAP_CACHE_DEBUG_LRU
+/* for debugging -- painstakingly verify the lru list is ok -- if 'in' is
+ * true, then dn 'dn' should be in the list right now; otherwise, it
+ * should NOT be in the list.
+ */
+static void
+dn_lru_verify(struct cache *cache, struct backdn *dn, int in)
+{
+ int is_in = 0;
+ int count = 0;
+ struct backdn *dnp;
+
+ dnp = CACHE_LRU_HEAD(cache, struct backdn *);
+ while (dnp) {
+ count++;
+ if (dnp == dn) {
+ is_in = 1;
+ }
+ if (dnp->ep_lruprev) {
+ ASSERT(BACK_LRU_NEXT(BACK_LRU_PREV(dnp, struct backdn *), struct backdn *)== dnp);
+ } else {
+ ASSERT(dnp == CACHE_LRU_HEAD(cache, struct backdn *));
+ }
+ if (dnp->ep_lrunext) {
+ ASSERT(BACK_LRU_PREV(BACK_LRU_NEXT(dnp, struct backdn *), struct backdn *) == dnp);
+ } else {
+ ASSERT(dnp == CACHE_LRU_TAIL(cache, struct backdn *));
+ }
+
+ dnp = BACK_LRU_NEXT(dnp, struct backdn *);
+ }
+ ASSERT(is_in == in);
+}
+#endif