]> git.sur5r.net Git - openldap/commitdiff
Entry caching. Based on ITS#1545 from Jong Hyuk Choi, jongchoi@us.ibm.com
authorHoward Chu <hyc@openldap.org>
Fri, 25 Jan 2002 07:19:01 +0000 (07:19 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 25 Jan 2002 07:19:01 +0000 (07:19 +0000)
20 files changed:
servers/slapd/back-bdb/Makefile.in
servers/slapd/back-bdb/add.c
servers/slapd/back-bdb/attribute.c
servers/slapd/back-bdb/back-bdb.h
servers/slapd/back-bdb/bind.c
servers/slapd/back-bdb/cache.c [new file with mode: 0644]
servers/slapd/back-bdb/compare.c
servers/slapd/back-bdb/config.c
servers/slapd/back-bdb/delete.c
servers/slapd/back-bdb/dn2entry.c
servers/slapd/back-bdb/dn2id.c
servers/slapd/back-bdb/group.c
servers/slapd/back-bdb/id2entry.c
servers/slapd/back-bdb/init.c
servers/slapd/back-bdb/modify.c
servers/slapd/back-bdb/modrdn.c
servers/slapd/back-bdb/passwd.c
servers/slapd/back-bdb/proto-bdb.h
servers/slapd/back-bdb/referral.c
servers/slapd/back-bdb/search.c

index edba6a3a17c5ad91ab05ec559cb793e90de69785..764b0de6c5c520283c3e65175dfefdd76db266e3 100644 (file)
@@ -4,12 +4,12 @@ SRCS = init.c tools.c config.c \
        add.c bind.c compare.c delete.c modify.c modrdn.c search.c \
        extended.c passwd.c referral.c attribute.c group.c \
        attr.c index.c key.c dbcache.c filterindex.c \
-       dn2entry.c dn2id.c error.c id2entry.c idl.c nextid.c
+       dn2entry.c dn2id.c error.c id2entry.c idl.c nextid.c cache.c
 OBJS = init.lo tools.lo config.lo \
        add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \
        extended.lo passwd.lo referral.lo attribute.lo group.lo \
        attr.lo index.lo key.lo dbcache.lo filterindex.lo \
-       dn2entry.lo dn2id.lo error.lo id2entry.lo idl.lo nextid.lo
+       dn2entry.lo dn2id.lo error.lo id2entry.lo idl.lo nextid.lo cache.lo
 
 LDAP_INCDIR= ../../../include       
 LDAP_LIBDIR= ../../../libraries
index ce179385ddf39e0c14411e12bb720e2db50702ab..c401aae548ce5a0c2851562cd5b55eb838665734 100644 (file)
@@ -64,8 +64,8 @@ bdb_add(
        }
 
        if( 0 ) {
-               /* transaction retry */
-retry: rc = txn_abort( ltid );
+retry:          /* transaction retry */
+                rc = txn_abort( ltid );
                ltid = NULL;
                op->o_private = NULL;
                if( rc != 0 ) {
@@ -130,7 +130,7 @@ retry:      rc = txn_abort( ltid );
 #endif
 
                /* get parent */
-               rc = bdb_dn2entry( be, ltid, &pdn, &p, &matched, 0 );
+               rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 );
 
                switch( rc ) {
                case 0:
@@ -154,7 +154,7 @@ retry:      rc = txn_abort( ltid );
                                refs = is_entry_referral( matched )
                                        ? get_entry_referrals( be, conn, op, matched )
                                        : NULL;
-                               bdb_entry_return( be, matched );
+                               bdb_cache_return_entry_r(&bdb->bi_cache, matched);
                                matched = NULL;
 
                        } else {
@@ -180,8 +180,8 @@ retry:      rc = txn_abort( ltid );
                switch( opinfo.boi_err ) {
                case DB_LOCK_DEADLOCK:
                case DB_LOCK_NOTGRANTED:
-                       /* free parent and writer lock */
-                       bdb_entry_return( be, p );
+                       /* free parent and reader lock */
+                       bdb_cache_return_entry_r( &bdb->bi_cache, p );
                        p = NULL;
                        goto retry;
                }
@@ -214,10 +214,8 @@ retry:     rc = txn_abort( ltid );
 
                if ( is_entry_referral( p ) ) {
                        /* parent is a referral, don't allow add */
-                       char *matched_dn = ch_strdup( p->e_dn );
-                       BerVarray refs = is_entry_referral( p )
-                               ? get_entry_referrals( be, conn, op, p )
-                               : NULL;
+                       char *matched_dn = p->e_dn;
+                       BerVarray refs = get_entry_referrals( be, conn, op, p );
 
                        Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
                                0, 0, 0 );
@@ -226,7 +224,8 @@ retry:      rc = txn_abort( ltid );
                                matched_dn, NULL, refs, NULL );
 
                        ber_bvarray_free( refs );
-                       free( matched_dn );
+                       bdb_cache_return_entry_r( be, p );
+                       p = NULL;
                        goto done;
                }
 
@@ -235,8 +234,8 @@ retry:      rc = txn_abort( ltid );
                        /* parent must be an administrative point of the required kind */
                }
 
-               /* free parent and writer lock */
-               bdb_entry_return( be, p );
+               /* free parent and reader lock */
+               bdb_cache_return_entry_r( be, p );
                p = NULL;
 
        } else {
@@ -361,6 +360,13 @@ retry:     rc = txn_abort( ltid );
                text = "commit failed";
 
        } else {
+                /* add the entry to the entry cache */
+                /* we should add to cache only upon free of txn-abort */
+                if (bdb_cache_add_entry_rw(&bdb->bi_cache, e, CACHE_WRITE_LOCK) != 0) {
+                        text = "cache add failed";
+                        goto return_results;
+                }
                Debug( LDAP_DEBUG_TRACE,
                        "bdb_add: added id=%08lx dn=\"%s\"\n",
                        e->e_id, e->e_dn, 0 );
@@ -368,6 +374,8 @@ retry:      rc = txn_abort( ltid );
                text = NULL;
        }
 
+       bdb_cache_entry_commit (e);
+
 return_results:
        send_ldap_result( conn, op, rc,
                NULL, text, NULL, NULL );
@@ -379,10 +387,6 @@ return_results:
        }
 
 done:
-       if (p != NULL) {
-               /* free parent and writer lock */
-               bdb_entry_return( be, p ); 
-       }
 
        if( ltid != NULL ) {
                txn_abort( ltid );
index f2481638307ecf949d0cda91058b87bc0056f6f4..298c6f5fdc6a89ad293c4b77bb4cbdc668e822a6 100644 (file)
@@ -29,7 +29,7 @@ bdb_attribute(
        AttributeDescription *entry_at,
        BerVarray *vals )
 {
-       struct bdbinfo *li = (struct bdbinfo *) be->be_private;
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        struct bdb_op_info *boi = (struct bdb_op_info *) op->o_private;
        DB_TXN *txn = NULL;
        Entry *e;
@@ -79,7 +79,7 @@ bdb_attribute(
 
        } else {
                /* can we find entry */
-               rc = bdb_dn2entry( be, txn, entry_ndn, &e, NULL, 0 );
+               rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0 );
                switch( rc ) {
                case DB_NOTFOUND:
                case 0:
@@ -200,7 +200,7 @@ bdb_attribute(
 return_results:
        if( target != e ) {
                /* free entry */
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r(&bdb->bi_cache, e);
        }
 
 #ifdef NEW_LOGGING
index 3ef79b443797521b5f2625b0fcab73d75ca3879b..6de08bc2ad20e1daeda0b881a17a9b42dcf9d95a 100644 (file)
@@ -75,6 +75,22 @@ LDAP_BEGIN_DECL
 #endif
 #endif
 
+#define DEFAULT_CACHE_SIZE     1000
+
+/* for the in-core cache of entries */
+typedef struct bdb_cache {
+        int             c_maxsize;
+        int             c_cursize;
+        Avlnode         *c_dntree;
+        Avlnode         *c_idtree;
+        Entry           *c_lruhead;     /* lru - add accessed entries here */
+        Entry           *c_lrutail;     /* lru - rem lru entries from here */
+        ldap_pvt_thread_mutex_t c_mutex;
+} Cache;
+#define CACHE_READ_LOCK                0
+#define CACHE_WRITE_LOCK       1
 #define BDB_INDICES            128
 
 struct bdb_db_info {
@@ -97,6 +113,7 @@ struct bdb_info {
        int             bi_db_opflags;  /* db-specific flags */
 
        slap_mask_t     bi_defaultmask;
+       Cache           bi_cache;
        Avlnode         *bi_attrs;
 #ifdef BDB_HIER
        Avlnode         *bi_tree;
index 3ec89f1f036863382773032b99b13a962ac3d4be..1c682e4b4b89485b5babb678c34cc1e863b4e824 100644 (file)
@@ -43,7 +43,7 @@ bdb_bind(
        Debug( LDAP_DEBUG_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val, 0, 0);
 
        /* get entry */
-       rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
+       rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
 
        switch(rc) {
        case DB_NOTFOUND:
@@ -67,7 +67,7 @@ bdb_bind(
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
 
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r( &bdb->bi_cache, matched );
                        matched = NULL;
 
                } else {
@@ -240,7 +240,7 @@ bdb_bind(
 done:
        /* free entry and reader lock */
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r( &bdb->bi_cache, e );
        }
 
        /* front end with send result on success (rc==0) */
diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c
new file mode 100644 (file)
index 0000000..e850a34
--- /dev/null
@@ -0,0 +1,907 @@
+/* cache.c - routines to maintain an in-core cache of entries */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/errno.h>
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+#include "back-bdb.h"
+
+/* BDB backend specific entry info -- visible only to the cache */
+typedef struct bdb_entry_info {
+       ldap_pvt_thread_rdwr_t  bei_rdwr;       /* reader/writer lock */
+
+       /*
+        * remaining fields require backend cache lock to access
+        * These items are specific to the LDBM backend and should
+        * be hidden.
+        */
+       int             bei_state;      /* for the cache */
+#define        CACHE_ENTRY_UNDEFINED   0
+#define CACHE_ENTRY_CREATING   1
+#define CACHE_ENTRY_READY      2
+#define CACHE_ENTRY_DELETED    3
+#define CACHE_ENTRY_COMMITTED  4
+       
+       int             bei_refcnt;     /* # threads ref'ing this entry */
+       Entry   *bei_lrunext;   /* for cache lru list */
+       Entry   *bei_lruprev;
+} EntryInfo;
+#undef BEI
+#define BEI(e) ((EntryInfo *) ((e)->e_private))
+
+static int     bdb_cache_delete_entry_internal(Cache *cache, Entry *e);
+#ifdef LDAP_DEBUG
+static void    lru_print(Cache *cache);
+#endif
+
+static int
+bdb_cache_entry_rdwr_lock(Entry *e, int rw)
+{
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n",
+                  rw ? "w" : "r", e->e_id ));
+#else
+       Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n",
+               rw ? "w" : "r", e->e_id, 0);
+#endif
+
+       if (rw)
+               return ldap_pvt_thread_rdwr_wlock(&BEI(e)->bei_rdwr);
+       else
+               return ldap_pvt_thread_rdwr_rlock(&BEI(e)->bei_rdwr);
+}
+
+static int
+bdb_cache_entry_rdwr_trylock(Entry *e, int rw)
+{
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_entry_rdwr_trylock: try %s lock on ID: %ld.\n",
+                  rw ? "w" : "r", e->e_id ));
+#else
+       Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%strylock: ID: %ld\n",
+               rw ? "w" : "r", e->e_id, 0);
+#endif
+
+
+       if (rw)
+               return ldap_pvt_thread_rdwr_wtrylock(&BEI(e)->bei_rdwr);
+       else
+               return ldap_pvt_thread_rdwr_rtrylock(&BEI(e)->bei_rdwr);
+}
+
+static int
+bdb_cache_entry_rdwr_unlock(Entry *e, int rw)
+{
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_entry_rdwr_unlock: remove %s lock on ID %ld.\n",
+                  rw ? "w" : "r", e->e_id ));
+#else
+       Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%sunlock: ID: %ld\n",
+               rw ? "w" : "r", e->e_id, 0);
+#endif
+
+
+       if (rw)
+               return ldap_pvt_thread_rdwr_wunlock(&BEI(e)->bei_rdwr);
+       else
+               return ldap_pvt_thread_rdwr_runlock(&BEI(e)->bei_rdwr);
+}
+
+static int
+bdb_cache_entry_rdwr_init(Entry *e)
+{
+       return ldap_pvt_thread_rdwr_init( &BEI(e)->bei_rdwr );
+}
+
+static int
+bdb_cache_entry_rdwr_destroy(Entry *e)
+{
+       return ldap_pvt_thread_rdwr_destroy( &BEI(e)->bei_rdwr );
+}
+
+static int
+bdb_cache_entry_private_init( Entry *e )
+{
+       assert( e->e_private == NULL );
+
+       if( e->e_private != NULL ) {
+               /* this should never happen */
+               return 1;
+       }
+
+       e->e_private = ch_calloc(1, sizeof(struct bdb_entry_info));
+
+       if( bdb_cache_entry_rdwr_init( e ) != 0 ) {
+               free( BEI(e) );
+               e->e_private = NULL;
+               return 1;
+       } 
+
+       return 0;
+}
+
+/*
+ * marks an entry in CREATING state as committed, so it is really returned
+ * to the cache. Otherwise an entry in CREATING state is removed.
+ * Makes e_private be destroyed at the following cache_return_entry_w,
+ * but lets the entry untouched (owned by someone else)
+ */
+void
+bdb_cache_entry_commit( Entry *e )
+{
+       assert( e );
+       assert( e->e_private );
+       assert( BEI(e)->bei_state == CACHE_ENTRY_CREATING );
+       /* assert( BEI(e)->bei_refcnt == 1 ); */
+
+       BEI(e)->bei_state = CACHE_ENTRY_COMMITTED;
+}
+
+static int
+bdb_cache_entry_private_destroy( Entry *e )
+{
+       assert( e->e_private );
+
+       bdb_cache_entry_rdwr_destroy( e );
+
+       free( e->e_private );
+       e->e_private = NULL;
+       return 0;
+}
+
+void
+bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
+{
+       ID id;
+       int refcnt, freeit = 1;
+
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       assert( e->e_private );
+
+       bdb_cache_entry_rdwr_unlock(e, rw);
+
+       id = e->e_id;
+       refcnt = --BEI(e)->bei_refcnt;
+
+       /*
+        * if the entry is returned when in CREATING state, it is deleted
+        * but not freed because it may belong to someone else (do_add,
+        * for instance)
+        */
+       if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
+               bdb_cache_delete_entry_internal( cache, e );
+               freeit = 0;
+               /* now the entry is in DELETED state */
+       }
+
+       if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
+               BEI(e)->bei_state = CACHE_ENTRY_READY;
+
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
+                          id, rw ? "w" : "r", refcnt ));
+#else
+               Debug( LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n",
+                       rw ? "w" : "r", id, refcnt );
+#endif
+
+
+       } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
+               if( refcnt > 0 ) {
+                       /* free cache mutex */
+                       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                                  "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
+                                  id, refcnt ));
+#else
+                       Debug( LDAP_DEBUG_TRACE,
+                               "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n",
+                               rw ? "w" : "r", id, refcnt );
+#endif
+
+
+               } else {
+                       bdb_cache_entry_private_destroy( e );
+                       if ( freeit ) {
+                               bdb_entry_return( e );
+                       }
+
+                       /* free cache mutex */
+                       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                                  "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
+                                  id, refcnt ));
+#else
+                       Debug( LDAP_DEBUG_TRACE,
+                               "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n",
+                               rw ? "w" : "r", id, refcnt );
+#endif
+
+               }
+
+       } else {
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
+                          id, rw ? "w": "r", refcnt ));
+#else
+               Debug( LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n",
+                       rw ? "w" : "r", id, refcnt);
+#endif
+
+       }
+}
+
+#define LRU_DELETE( cache, e ) do { \
+       if ( BEI(e)->bei_lruprev != NULL ) { \
+               BEI(BEI(e)->bei_lruprev)->bei_lrunext = BEI(e)->bei_lrunext; \
+       } else { \
+               (cache)->c_lruhead = BEI(e)->bei_lrunext; \
+       } \
+       if ( BEI(e)->bei_lrunext != NULL ) { \
+               BEI(BEI(e)->bei_lrunext)->bei_lruprev = BEI(e)->bei_lruprev; \
+       } else { \
+               (cache)->c_lrutail = BEI(e)->bei_lruprev; \
+       } \
+} while(0)
+
+#define LRU_ADD( cache, e ) do { \
+       BEI(e)->bei_lrunext = (cache)->c_lruhead; \
+       if ( BEI(e)->bei_lrunext != NULL ) { \
+               BEI(BEI(e)->bei_lrunext)->bei_lruprev = (e); \
+       } \
+       (cache)->c_lruhead = (e); \
+       BEI(e)->bei_lruprev = NULL; \
+       if ( (cache)->c_lrutail == NULL ) { \
+               (cache)->c_lrutail = (e); \
+       } \
+} while(0)
+
+/*
+ * cache_add_entry_rw - create and lock an entry in the cache
+ * returns:    0       entry has been created and locked
+ *             1       entry already existed
+ *             -1      something bad happened
+ */
+int
+bdb_cache_add_entry_rw(
+    Cache      *cache,
+    Entry      *e,
+    int                rw
+)
+{
+       int     i, rc;
+       Entry   *ee;
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_add_entry_rw: add (%s):%s to cache\n",
+                  e->e_dn, rw ? "w" : "r" ));
+#endif
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       assert( e->e_private == NULL );
+
+       if( bdb_cache_entry_private_init(e) != 0 ) {
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
+                          "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
+                          e->e_dn, e->e_id ));
+#else
+               Debug( LDAP_DEBUG_ANY,
+                       "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n",
+                   e->e_id, e->e_dn, 0 );
+#endif
+
+
+               return( -1 );
+       }
+
+       if ( avl_insert( &cache->c_dntree, (caddr_t) e,
+               (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
+       {
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_add_entry: (%s):%ld already in cache.\n",
+                          e->e_dn, e->e_id ));
+#else
+               Debug( LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n",
+                   e->e_id, e->e_dn, 0 );
+#endif
+
+
+               bdb_cache_entry_private_destroy(e);
+
+               return( 1 );
+       }
+
+       /* id tree */
+       if ( avl_insert( &cache->c_idtree, (caddr_t) e,
+               (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
+       {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_add_entry: (%s):%ls already in cache.\n",
+                          e->e_dn, e->e_id ));
+#else
+               Debug( LDAP_DEBUG_ANY,
+                       "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n",
+                   e->e_id, e->e_dn, 0 );
+#endif
+
+
+
+               /* delete from dn tree inserted above */
+               if ( avl_delete( &cache->c_dntree, (caddr_t) e,
+                       (AVL_CMP) entry_dn_cmp ) == NULL )
+               {
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                                  "bdb_cache_add_entry: can't delete (%s) from cache.\n",
+                                  e->e_dn ));
+#else
+                       Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
+                           0, 0, 0 );
+#endif
+
+               }
+
+               bdb_cache_entry_private_destroy(e);
+
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+               return( -1 );
+       }
+
+       bdb_cache_entry_rdwr_lock( e, rw );
+
+       /* put the entry into 'CREATING' state */
+       /* will be marked after when entry is returned */
+       BEI(e)->bei_state = CACHE_ENTRY_CREATING;
+       BEI(e)->bei_refcnt = 1;
+
+       /* lru */
+       LRU_ADD( cache, e );
+       if ( ++cache->c_cursize > cache->c_maxsize ) {
+               /*
+                * find the lru entry not currently in use and delete it.
+                * in case a lot of entries are in use, only look at the
+                * first 10 on the tail of the list.
+                */
+               i = 0;
+               while ( cache->c_lrutail != NULL &&
+                       BEI(cache->c_lrutail)->bei_refcnt != 0 &&
+                       i < 10 )
+               {
+                       /* move this in-use entry to the front of the q */
+                       ee = cache->c_lrutail;
+                       LRU_DELETE( cache, ee );
+                       LRU_ADD( cache, ee );
+                       i++;
+               }
+
+               /*
+                * found at least one to delete - try to get back under
+                * the max cache size.
+                */
+               while ( cache->c_lrutail != NULL &&
+                       BEI(cache->c_lrutail)->bei_refcnt == 0 &&
+                       cache->c_cursize > cache->c_maxsize )
+               {
+                       e = cache->c_lrutail;
+
+                       /* delete from cache and lru q */
+                       /* XXX do we need rc ? */
+                       rc = bdb_cache_delete_entry_internal( cache, e );
+                       bdb_cache_entry_private_destroy( e );
+                       bdb_entry_return( e );
+               }
+       }
+
+       /* free cache mutex */
+       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+       return( 0 );
+}
+
+/*
+ * cache_update_entry - update a LOCKED entry which has been deleted.
+ * returns:    0       entry has been created and locked
+ *             1       entry already existed
+ *             -1      something bad happened
+ */
+int
+bdb_cache_update_entry(
+    Cache      *cache,
+    Entry              *e
+)
+{
+       int     i, rc;
+       Entry   *ee;
+
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       assert( e->e_private );
+
+       if ( avl_insert( &cache->c_dntree, (caddr_t) e,
+               (AVL_CMP) entry_dn_cmp, avl_dup_error ) != 0 )
+       {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_update_entry: (%s):%ld already in dn cache\n",
+                          e->e_dn, e->e_id ));
+#else
+               Debug( LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n",
+                   e->e_id, e->e_dn, 0 );
+#endif
+
+
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+               return( 1 );
+       }
+
+       /* id tree */
+       if ( avl_insert( &cache->c_idtree, (caddr_t) e,
+               (AVL_CMP) entry_id_cmp, avl_dup_error ) != 0 )
+       {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_update_entry: (%s)%ld already in id cache\n",
+                          e->e_dn, e->e_id ));
+#else
+               Debug( LDAP_DEBUG_ANY,
+                       "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n",
+                   e->e_id, e->e_dn, 0 );
+#endif
+
+
+               /* delete from dn tree inserted above */
+               if ( avl_delete( &cache->c_dntree, (caddr_t) e,
+                       (AVL_CMP) entry_dn_cmp ) == NULL )
+               {
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                                  "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n",
+                                  e->e_dn, e->e_id ));
+#else
+                       Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
+                           0, 0, 0 );
+#endif
+
+               }
+
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+               return( -1 );
+       }
+
+
+       /* put the entry into 'CREATING' state */
+       /* will be marked after when entry is returned */
+       BEI(e)->bei_state = CACHE_ENTRY_CREATING;
+
+       /* lru */
+       LRU_ADD( cache, e );
+       if ( ++cache->c_cursize > cache->c_maxsize ) {
+               /*
+                * find the lru entry not currently in use and delete it.
+                * in case a lot of entries are in use, only look at the
+                * first 10 on the tail of the list.
+                */
+               i = 0;
+               while ( cache->c_lrutail != NULL &&
+                       BEI(cache->c_lrutail)->bei_refcnt != 0 &&
+                       i < 10 )
+               {
+                       /* move this in-use entry to the front of the q */
+                       ee = cache->c_lrutail;
+                       LRU_DELETE( cache, ee );
+                       LRU_ADD( cache, ee );
+                       i++;
+               }
+
+               /*
+                * found at least one to delete - try to get back under
+                * the max cache size.
+                */
+               while ( cache->c_lrutail != NULL &&
+                       BEI(cache->c_lrutail)->bei_refcnt == 0 &&
+                       cache->c_cursize > cache->c_maxsize )
+               {
+                       e = cache->c_lrutail;
+
+                       /* delete from cache and lru q */
+                       /* XXX do we need rc ? */
+                       rc = bdb_cache_delete_entry_internal( cache, e );
+                       bdb_cache_entry_private_destroy( e );
+                       bdb_entry_return( e );
+               }
+       }
+
+       /* free cache mutex */
+       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+       return( 0 );
+}
+
+ID
+bdb_cache_find_entry_ndn2id(
+       Backend         *be,
+    Cache      *cache,
+    struct berval      *ndn
+)
+{
+       Entry           e, *ep;
+       ID                      id;
+       int count = 0;
+
+       /* this function is always called with normalized DN */
+       e.e_nname = *ndn;
+
+try_again:
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
+               (AVL_CMP) entry_dn_cmp )) != NULL )
+       {
+               int state;
+               count++;
+
+               /*
+                * ep now points to an unlocked entry
+                * we do not need to lock the entry if we only
+                * check the state, refcnt, LRU, and id.
+                */
+
+               assert( ep->e_private );
+
+               /* save id */
+               id = ep->e_id;
+               state = BEI(ep)->bei_state;
+
+               /*
+                * entry is deleted or not fully created yet
+                */
+               if ( state != CACHE_ENTRY_READY ) {
+                       assert(state != CACHE_ENTRY_UNDEFINED);
+
+                       /* free cache mutex */
+                       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                                  "bdb_cache_find_entry_dn2id: (%s) %ld not ready: %d\n",
+                                  ndn->bv_val, id, state ));
+#else
+                       Debug(LDAP_DEBUG_TRACE,
+                               "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (not ready) %d\n",
+                               ndn->bv_val, id, state);
+#endif
+
+
+                       ldap_pvt_thread_yield();
+                       goto try_again;
+               }
+
+               /* lru */
+               LRU_DELETE( cache, ep );
+               LRU_ADD( cache, ep );
+               
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_find_entry_dn2id: (%s): %ld %d tries\n",
+                          ndn->bv_val, id, count ));
+#else
+               Debug(LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_find_entry_dn2id(\"%s\"): %ld (%d tries)\n",
+                       ndn->bv_val, id, count);
+#endif
+
+
+       } else {
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+               id = NOID;
+       }
+
+       return( id );
+}
+
+/*
+ * cache_find_entry_id - find an entry in the cache, given id
+ */
+
+Entry *
+bdb_cache_find_entry_id(
+       Cache   *cache,
+       ID                              id,
+       int                             rw
+)
+{
+       Entry   e;
+       Entry   *ep;
+       int     count = 0;
+
+       e.e_id = id;
+
+try_again:
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
+               (AVL_CMP) entry_id_cmp )) != NULL )
+       {
+               int state;
+               ID      ep_id;
+
+               count++;
+
+               assert( ep->e_private );
+
+               ep_id = ep->e_id; 
+               state = BEI(ep)->bei_state;
+
+               /*
+                * entry is deleted or not fully created yet
+                */
+               if ( state != CACHE_ENTRY_READY ) {
+
+                       assert(state != CACHE_ENTRY_UNDEFINED);
+
+                       /* free cache mutex */
+                       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                                  "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n",
+                                  id, ep_id, state ));
+                                  
+#else
+                       Debug(LDAP_DEBUG_TRACE,
+                               "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n",
+                               id, ep_id, state);
+#endif
+
+
+                       ldap_pvt_thread_yield();
+                       goto try_again;
+               }
+
+               /* acquire reader lock */
+               if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
+                       /* could not acquire entry lock...
+                        * owner cannot free as we have the cache locked.
+                        * so, unlock the cache, yield, and try again.
+                        */
+
+                       /* free cache mutex */
+                       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                                  "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n",
+                                  id, ep_id, state ));
+#else
+                       Debug(LDAP_DEBUG_TRACE,
+                               "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
+                               id, ep_id, state);
+#endif
+
+
+                       ldap_pvt_thread_yield();
+                       goto try_again;
+               }
+
+               /* lru */
+               LRU_DELETE( cache, ep );
+               LRU_ADD( cache, ep );
+               
+               BEI(ep)->bei_refcnt++;
+
+               /* free cache mutex */
+               ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+                          "bdb_cache_find_entry_id: %ld -> %s  found %d tries.\n",
+                          ep_id, ep->e_dn, count ));
+#else
+               Debug(LDAP_DEBUG_TRACE,
+                       "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n",
+                       ep_id, ep->e_dn, count);
+#endif
+
+
+               return( ep );
+       }
+
+       /* free cache mutex */
+       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+
+       return( NULL );
+}
+
+/*
+ * cache_delete_entry - delete the entry e from the cache.  the caller
+ * should have obtained e (increasing its ref count) via a call to one
+ * of the cache_find_* routines.  the caller should *not* call the
+ * cache_return_entry() routine prior to calling cache_delete_entry().
+ * it performs this function.
+ *
+ * returns:    0       e was deleted ok
+ *             1       e was not in the cache
+ *             -1      something bad happened
+ */
+int
+bdb_cache_delete_entry(
+    Cache      *cache,
+    Entry              *e
+)
+{
+       int     rc;
+
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+       assert( e->e_private );
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_delete_entry: delete %ld.\n", e->e_id ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n",
+               e->e_id, 0, 0 );
+#endif
+
+
+       rc = bdb_cache_delete_entry_internal( cache, e );
+
+       /* free cache mutex */
+       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+       return( rc );
+}
+
+static int
+bdb_cache_delete_entry_internal(
+    Cache      *cache,
+    Entry              *e
+)
+{
+       int rc = 0;     /* return code */
+
+       /* dn tree */
+       if ( avl_delete( &cache->c_dntree, (caddr_t) e, (AVL_CMP) entry_dn_cmp )
+               == NULL )
+       {
+               rc = -1;
+       }
+
+       /* id tree */
+       if ( avl_delete( &cache->c_idtree, (caddr_t) e, (AVL_CMP) entry_id_cmp )
+               == NULL )
+       {
+               rc = -1;
+       }
+
+       if (rc != 0) {
+               return rc;
+       }
+
+       /* lru */
+       LRU_DELETE( cache, e );
+       cache->c_cursize--;
+
+       /*
+        * flag entry to be freed later by a call to cache_return_entry()
+        */
+       BEI(e)->bei_state = CACHE_ENTRY_DELETED;
+
+       return( 0 );
+}
+
+void
+bdb_cache_release_all( Cache *cache )
+{
+       Entry *e;
+       int rc;
+
+       /* set cache mutex */
+       ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+                  "bdb_cache_release_all: enter\n" ));
+#else
+       Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 );
+#endif
+
+
+       while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) {
+#ifdef LDAP_RDWR_DEBUG
+               assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr));
+#endif
+
+               /* delete from cache and lru q */
+               /* XXX do we need rc ? */
+               rc = bdb_cache_delete_entry_internal( cache, e );
+               bdb_cache_entry_private_destroy( e );
+               bdb_entry_return( e );
+       }
+
+       if ( cache->c_cursize ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+                          "bdb_cache_release_all: Entry cache could not be emptied.\n" ));
+#else
+               Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 );
+#endif
+
+       }
+
+       /* free cache mutex */
+       ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+}
+
+#ifdef LDAP_DEBUG
+
+static void
+bdb_lru_print( Cache *cache )
+{
+       Entry   *e;
+
+       fprintf( stderr, "LRU queue (head to tail):\n" );
+       for ( e = cache->c_lruhead; e != NULL; e = BEI(e)->bei_lrunext ) {
+               fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
+                       e->e_dn, e->e_id, BEI(e)->bei_refcnt );
+       }
+       fprintf( stderr, "LRU queue (tail to head):\n" );
+       for ( e = cache->c_lrutail; e != NULL; e = BEI(e)->bei_lruprev ) {
+               fprintf( stderr, "\tdn \"%20s\" id %ld refcnt %d\n",
+                       e->e_dn, e->e_id, BEI(e)->bei_refcnt );
+       }
+}
+
+#endif
index b493dd4c3ae467e1cdeca6ac0fa5c4877b5105fe..d8abfd40f75f71b65a65400df76f3d6fcc8a371f 100644 (file)
@@ -32,7 +32,7 @@ bdb_compare(
        int             manageDSAit = get_manageDSAit( op );
 
        /* get entry */
-       rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
+       rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
 
        switch( rc ) {
        case DB_NOTFOUND:
@@ -53,7 +53,7 @@ bdb_compare(
                        refs = is_entry_referral( matched )
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r( &bdb->bi_cache, matched );
                        matched = NULL;
 
                } else {
@@ -119,7 +119,7 @@ return_results:
 done:
        /* free entry */
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r( &bdb->bi_cache, e );
        }
 
        return rc;
index f6ab841ba4adafbcb792be14e90a1f7af2256fc1..6de743254e60ca3ac8267d97aaaf55358069c699 100644 (file)
@@ -147,6 +147,16 @@ bdb_db_config(
                if( rc != LDAP_SUCCESS ) return 1;
 #endif
 
+       /* size of the cache in entries */
+         } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) {
+                 if ( argc < 2 ) {
+                         fprintf( stderr,
+                 "%s: line %d: missing size in \"cachesize <size>\" line\n",
+                             fname, lineno );
+                         return( 1 );
+                 }
+                 bdb->bi_cache.c_maxsize = atoi( argv[1] );
+
        /* anything else */
        } else {
                fprintf( stderr, "%s: line %d: "
index 135afd0bcd42d9f7409fc714f0deb6987c8ee3ca..5c1588ae16799badb6c35d1879a477610ceb4181 100644 (file)
@@ -42,6 +42,9 @@ bdb_delete(
 
        if( 0 ) {
 retry: /* transaction retry */
+               if( e != NULL ) {
+                       bdb_cache_return_entry_w(&bdb->bi_cache, e);
+               }
                Debug( LDAP_DEBUG_TRACE, "==> bdb_delete: retrying...\n",
                        0, 0, 0 );
                rc = txn_abort( ltid );
@@ -100,7 +103,7 @@ retry:      /* transaction retry */
                }
 #endif
                /* get parent */
-               rc = bdb_dn2entry( be, ltid, &pdn, &p, NULL, 0 );
+               rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0 );
 
                switch( rc ) {
                case 0:
@@ -128,7 +131,7 @@ retry:      /* transaction retry */
                rc = access_allowed( be, conn, op, p,
                        children, NULL, ACL_WRITE );
 
-               bdb_entry_return( be, p );
+               bdb_cache_return_entry_r(&bdb->bi_cache, p);
                p = NULL;
 
                switch( opinfo.boi_err ) {
@@ -191,7 +194,7 @@ retry:      /* transaction retry */
        }
 
        /* get entry for read/modify/write */
-       rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, DB_RMW );
+       rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW );
 
        switch( rc ) {
        case 0:
@@ -219,7 +222,7 @@ retry:      /* transaction retry */
                        refs = is_entry_referral( matched )
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r(&bdb->bi_cache, matched );
                        matched = NULL;
 
                } else {
@@ -297,7 +300,7 @@ retry:      /* transaction retry */
        }
 
        /* delete from id2entry */
-       rc = bdb_id2entry_delete( be, ltid, e->e_id );
+       rc = bdb_id2entry_delete( be, ltid, e );
        if ( rc != 0 ) {
                switch( rc ) {
                case DB_LOCK_DEADLOCK:
@@ -371,7 +374,7 @@ return_results:
 done:
        /* free entry */
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_w(&bdb->bi_cache, e);
        }
 
        if( ltid != NULL ) {
index 767c1571dbe85e22ddceedd7b2f75127d39f8742..a4cffd8b2ddb577b18e8e24be9acbe5825efa26e 100644 (file)
  */
 
 int
-bdb_dn2entry(
+bdb_dn2entry_rw(
        BackendDB       *be,
        DB_TXN *tid,
        struct berval *dn,
        Entry **e,
        Entry **matched,
-       int flags )
+       int flags,
+       int rw )
 {
        int rc;
        ID              id, id2 = 0;
 
-       Debug(LDAP_DEBUG_TRACE, "bdb_dn2entry(\"%s\")\n",
+       Debug(LDAP_DEBUG_TRACE, "bdb_dn2entry_rw(\"%s\")\n",
                dn->bv_val, 0, 0 );
 
        *e = NULL;
@@ -46,9 +47,9 @@ bdb_dn2entry(
        }
 
        if( id2 == 0 ) {
-               rc = bdb_id2entry( be, tid, id, e );
+               rc = bdb_id2entry_rw( be, tid, id, e, rw );
        } else {
-               rc = bdb_id2entry( be, tid, id2, matched );
+               rc = bdb_id2entry_r( be, tid, id2, matched);
        }
 
        return rc;
index c05dcae2231238ae1742f843f3491ff8406a753c..f3360752161b83f7181ea263febc8fb93bc475ba 100644 (file)
@@ -223,6 +223,12 @@ bdb_dn2id(
 
        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id( \"%s\" )\n", dn->bv_val, 0, 0 );
 
+       assert (id);
+       if ((*id = bdb_cache_find_entry_ndn2id(be,&bdb->bi_cache,dn)) != NOID) {
+               return 0;
+       }
+
        DBTzero( &key );
        key.size = dn->bv_len + 2;
        key.data = ch_malloc( key.size );
@@ -263,6 +269,7 @@ bdb_dn2id_matched(
        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        DB *db = bdb->bi_dn2id->bdi_db;
        char            *buf, *dn;
+       ID              cached_id;
 
        Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_matched( \"%s\" )\n", in->bv_val, 0, 0 );
 
@@ -284,8 +291,20 @@ bdb_dn2id_matched(
 
                *id = NOID;
 
-               /* fetch it */
-               rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
+               /* lookup cache */
+               cached_id = bdb_cache_find_entry_ndn2id(be,&bdb->bi_cache,dn);
+               if (cached_id != NOID) {
+                       rc = 0;
+                       *id = cached_id;
+                       if ( dn != buf+1 ) {
+                               *id2 = *id;
+                       }
+                       break;
+               } else {
+                       /* fetch it */
+                       rc = db->get(db, txn, &key, &data, bdb->bi_db_opflags );
+               }
 
                if( rc == DB_NOTFOUND ) {
                        char    *pdn = NULL;
index c108c8c546a321a88a3ce5283c4d6af40efb1060..b754c31f14cfe128940b0fc8cab44c795a14b2d3 100644 (file)
@@ -33,7 +33,7 @@ bdb_group(
        AttributeDescription *group_at
 )
 {
-       struct bdbinfo *li = (struct bdbinfo *) be->be_private;
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        struct bdb_op_info *boi = (struct bdb_op_info *) op->o_private;
        DB_TXN *txn;
        Entry *e;
@@ -88,7 +88,7 @@ bdb_group(
 #endif
        } else {
                /* can we find group entry */
-               rc = bdb_dn2entry( be, txn, gr_ndn, &e, NULL, 0 );
+               rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0 ); 
                if( rc ) {
                        if( txn ) {
                                boi->boi_err = rc;
@@ -208,7 +208,7 @@ bdb_group(
 return_results:
        if( target != e ) {
                /* free entry */
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r( &bdb->bi_cache, e );
        }
 
 #ifdef NEW_LOGGING
index 2de0ad47f72e472d1c5bed846a5f597c7758e1d6..c67359c339e8152be83ee6d341e430bb9df4ab41 100644 (file)
@@ -53,6 +53,12 @@ int bdb_id2entry_put(
        return rc;
 }
 
+/*
+ * This routine adds (or updates) an entry on disk.
+ * The cache should be already be updated.
+ */
+
+
 int bdb_id2entry_add(
        BackendDB *be,
        DB_TXN *tid,
@@ -69,17 +75,18 @@ int bdb_id2entry_update(
        return bdb_id2entry_put(be, tid, e, 0);
 }
 
-int bdb_id2entry(
+int bdb_id2entry_rw(
        BackendDB *be,
        DB_TXN *tid,
        ID id,
-       Entry **e )
+       Entry **e,
+       int rw )
 {
        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        DB *db = bdb->bi_id2entry->bdi_db;
        DBT key, data;
        struct berval bv;
-       int rc;
+       int rc = 0;
 
        *e = NULL;
 
@@ -90,6 +97,10 @@ int bdb_id2entry(
        DBTzero( &data );
        data.flags = DB_DBT_MALLOC;
 
+       if ((*e = bdb_cache_find_entry_id(&bdb->bi_cache, id, rw)) != NULL) {
+               return 0;
+       }
+
        /* fetch it */
        rc = db->get( db, tid, &key, &data, bdb->bi_db_opflags );
 
@@ -109,53 +120,85 @@ int bdb_id2entry(
                 */
                ch_free( data.data );
        }
+
+       if (rc == 0 && bdb_cache_add_entry_rw(&bdb->bi_cache, *e, rw) != 0) {
+               if ((*e)->e_private != NULL)
+                       free ((*e)->e_private);
+               (*e)->e_private = NULL;
+               bdb_entry_return (*e);
+               if ((*e=bdb_cache_find_entry_id(&bdb->bi_cache,id,rw)) != NULL) {
+                       return 0;
+               }
+       }
+
 #ifdef BDB_HIER
        bdb_fix_dn(be, id, *e);
 #endif
+
+       if (rc == 0)
+               bdb_cache_entry_commit(*e);
+
        return rc;
 }
 
 int bdb_id2entry_delete(
        BackendDB *be,
        DB_TXN *tid,
-       ID id )
+       Entry *e )
 {
        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        DB *db = bdb->bi_id2entry->bdi_db;
        DBT key;
        int rc;
 
+       bdb_cache_delete_entry(&bdb->bi_cache, e);
+
        DBTzero( &key );
-       key.data = (char *) &id;
+       key.data = (char *) &e->e_id;
        key.size = sizeof(ID);
 
+       /* delete from database */
        rc = db->del( db, tid, &key, 0 );
 
        return rc;
 }
 
 int bdb_entry_return(
-       BackendDB *be,
        Entry *e )
 {
        /* Our entries are allocated in two blocks; the data comes from
         * the db itself and the Entry structure and associated pointers
         * are allocated in entry_decode. The db data pointer is saved
-        * in e_private. Since the Entry structure is allocated as a single
+        * in e_bv. Since the Entry structure is allocated as a single
         * block, e_attrs is always a fixed offset from e. The exception
         * is when an entry has been modified, in which case we also need
         * to free e_attrs.
         */
+       if( !e->e_bv.bv_val ) { /* A regular entry, from do_add */
+               entry_free( e );
+               return 0;
+       }
        if( (void *) e->e_attrs != (void *) (e+1)) {
                attrs_free( e->e_attrs );
        }
+
+       /* See if the DNs were changed by modrdn */
+       if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val >
+               e->e_bv.bv_val + e->e_bv.bv_len ) {
+               ch_free(e->e_name.bv_val);
+               ch_free(e->e_nname.bv_val);
+               e->e_name.bv_val = NULL;
+               e->e_nname.bv_val = NULL;
+       }
 #ifdef BDB_HIER
        /* We had to construct the dn and ndn as well, in a single block */
-       free( e->e_dn );
+       if( e->e_name.bv_val ) {
+               free( e->e_name.bv_val );
+       }
 #endif
-       /* In tool mode the e_private buffer is realloc'd, leave it alone */
-       if( e->e_private && !(slapMode & SLAP_TOOL_MODE) ) {
-               free( e->e_private );
+       /* In tool mode the e_bv buffer is realloc'd, leave it alone */
+       if( !(slapMode & SLAP_TOOL_MODE) ) {
+               free( e->e_bv.bv_val );
        }
 
        free( e );
@@ -170,12 +213,20 @@ int bdb_entry_release(
        Entry *e,
        int rw )
 {
-       int retval = 0;
-
-       if (o && o->o_tag == LDAP_REQ_ADD)
-               entry_free(e);
-       else
-               retval = bdb_entry_return( be, e );
-
-       return retval;
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
+                       SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
+       if ( slapMode == SLAP_SERVER_MODE ) {
+               /* free entry and reader or writer lock */
+               bdb_cache_return_entry_rw( &bdb->bi_cache, e, rw );
+       } else {
+               if (e->e_private != NULL)
+                       free (e->e_private);
+               e->e_private = NULL;
+               bdb_entry_return ( e );
+       }
+       return 0;
 }
index cecf9d6ddb08943ce3d79f30e685ea788c87b40f..36638ed27dbdea79c66d244216ff678bed1a9e07 100644 (file)
@@ -78,6 +78,8 @@ bdb_db_init( BackendDB *be )
        bdb->bi_dbenv_mode = DEFAULT_MODE;
        bdb->bi_txn = 1;        /* default to using transactions */
 
+       bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE;
+
 #ifndef NO_THREADS
 #if 0
        bdb->bi_lock_detect = DB_LOCK_NORUN;
@@ -88,6 +90,7 @@ bdb_db_init( BackendDB *be )
 
        ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex );
        ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex );
+       ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_mutex );
 #ifdef BDB_HIER
        ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr );
 #endif
@@ -349,6 +352,8 @@ bdb_db_close( BackendDB *be )
        free( bdb->bi_databases );
        bdb_attr_index_destroy( bdb->bi_attrs );
 
+       bdb_cache_release_all (&bdb->bi_cache);
+
        return 0;
 }
 
@@ -370,6 +375,8 @@ bdb_db_destroy( BackendDB *be )
                        }
                }
 
+               bdb_cache_release_all (&bdb->bi_cache);
+
                rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 );
                bdb->bi_dbenv = NULL;
                if( rc != 0 ) {
index b00b60236c36116fbc6f2c90a483af970aa38a13..2f48cb40ebf5988463a87e0facc07c9c01704542 100644 (file)
@@ -198,6 +198,10 @@ bdb_modify(
 
        if( 0 ) {
 retry: /* transaction retry */
+               if( e != NULL ) {
+                       bdb_cache_delete_entry(&bdb->bi_cache, e);
+                       bdb_cache_return_entry_w(&bdb->bi_cache, e);
+               }
                Debug(LDAP_DEBUG_TRACE,
                        "bdb_modify: retrying...\n", 0, 0, 0);
                rc = txn_abort( ltid );
@@ -232,7 +236,7 @@ retry:      /* transaction retry */
        op->o_private = &opinfo;
 
        /* get entry */
-       rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 );
+       rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 );
 
        if ( rc != 0 ) {
                Debug( LDAP_DEBUG_TRACE,
@@ -261,7 +265,7 @@ retry:      /* transaction retry */
                        refs = is_entry_referral( matched )
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r (&bdb->bi_cache, matched);
                        matched = NULL;
 
                } else {
@@ -364,8 +368,7 @@ done:
        }
 
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_w (&bdb->bi_cache, e);
        }
        return rc;
 }
-
index d1398ab308dadafc4f13aa0965527760eed62231..e3f3e44a4d2da686fd51d3f62d40e144723a53fb 100644 (file)
@@ -46,7 +46,7 @@ bdb_modrdn(
        LDAPRDN         *new_rdn = NULL;
        LDAPRDN         *old_rdn = NULL;
 
-       Entry           *np = NULL;                             /* newSuperior Entry */
+       Entry           *np = NULL;                     /* newSuperior Entry */
        struct berval   *np_dn = NULL;                  /* newSuperior dn */
        struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
        struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
@@ -70,6 +70,16 @@ bdb_modrdn(
 
        if( 0 ) {
 retry: /* transaction retry */
+               if (e != NULL) {
+                       bdb_cache_delete_entry(&bdb->bi_cache, e);
+                       bdb_cache_return_entry_w(&bdb->bi_cache, e);
+               }
+               if (p != NULL) {
+                       bdb_cache_return_entry_r(&bdb->bi_cache, p);
+               }
+               if (np != NULL) {
+                       bdb_cache_return_entry_r(&bdb->bi_cache, np);
+               }
                Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
                rc = txn_abort( ltid );
                ltid = NULL;
@@ -103,7 +113,7 @@ retry:      /* transaction retry */
        op->o_private = &opinfo;
 
        /* get entry */
-       rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 );
+       rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 );
 
        switch( rc ) {
        case 0:
@@ -123,11 +133,11 @@ retry:    /* transaction retry */
                BerVarray refs;
 
                if( matched != NULL ) {
-                       matched_dn = strdup( matched->e_dn );
+                       matched_dn = ch_strdup( matched->e_dn );
                        refs = is_entry_referral( matched )
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r( &bdb->bi_cache, matched );
                        matched = NULL;
 
                } else {
@@ -176,7 +186,7 @@ retry:      /* transaction retry */
                /* Make sure parent entry exist and we can write its 
                 * children.
                 */
-               rc = bdb_dn2entry( be, ltid, &p_ndn, &p, NULL, 0 );
+               rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0 );
 
                switch( rc ) {
                case 0:
@@ -291,7 +301,7 @@ retry:      /* transaction retry */
                        /* newSuperior == entry being moved?, if so ==> ERROR */
                        /* Get Entry with dn=newSuperior. Does newSuperior exist? */
 
-                       rc = bdb_dn2entry( be, ltid, nnewSuperior, &np, NULL, 0 );
+                       rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0 );
 
                        switch( rc ) {
                        case 0:
@@ -571,6 +581,8 @@ retry:      /* transaction retry */
                goto return_results;
        }
 
+       (void) bdb_cache_delete_entry(&bdb->bi_cache, e);
+
        /* Binary format uses a single contiguous block, cannot
         * free individual fields. Leave new_dn/new_ndn set so
         * they can be individually freed later.
@@ -578,6 +590,9 @@ retry:      /* transaction retry */
        e->e_name = new_dn;
        e->e_nname = new_ndn;
 
+       new_dn.bv_val = NULL;
+        new_ndn.bv_val = NULL;
+
        /* add new one */
        rc = bdb_dn2id_add( be, ltid, np_ndn, e );
        if ( rc != 0 ) {
@@ -630,11 +645,13 @@ retry:    /* transaction retry */
                rc = LDAP_OTHER;
                text = "commit failed";
        } else {
+               (void) bdb_cache_update_entry(&bdb->bi_cache, e);
                Debug( LDAP_DEBUG_TRACE,
                        "bdb_modrdn: added id=%08lx dn=\"%s\"\n",
                        e->e_id, e->e_dn, 0 );
                rc = LDAP_SUCCESS;
                text = NULL;
+               bdb_cache_entry_commit( e );
        }
 
 return_results:
@@ -664,18 +681,18 @@ done:
 
        /* LDAP v3 Support */
        if( np != NULL ) {
-               /* free new parent and writer lock */
-               bdb_entry_return( be, np );
+               /* free new parent and reader lock */
+               bdb_cache_return_entry_r(&bdb->bi_cache, np);
        }
 
        if( p != NULL ) {
-               /* free parent and writer lock */
-               bdb_entry_return( be, p );
+               /* free parent and reader lock */
+               bdb_cache_return_entry_r(&bdb->bi_cache, p);
        }
 
        /* free entry */
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_w( &bdb->bi_cache, e );
        }
 
        if( ltid != NULL ) {
index 3858ac29cb004fc41f0442c95ca93297803d8bb6..c0a38fe920485d581c384abccf27e35b6aabf6f8 100644 (file)
@@ -86,6 +86,10 @@ bdb_exop_passwd(
 
        if( 0 ) {
 retry: /* transaction retry */
+               if ( e != NULL ) {
+                       bdb_cache_delete_entry(&bdb->bi_cache, e);
+                       bdb_cache_return_entry_w(&bdb->bi_cache, e);
+               }
                Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: retrying...\n", 0, 0, 0 );
                rc = txn_abort( ltid );
                ltid = NULL;
@@ -119,7 +123,7 @@ retry:      /* transaction retry */
        op->o_private = &opinfo;
 
        /* get entry */
-       rc = bdb_dn2entry( be, ltid, dn, &e, NULL, 0 );
+       rc = bdb_dn2entry_w( be, ltid, dn, &e, NULL, 0 );
 
        switch(rc) {
        case DB_LOCK_DEADLOCK:
@@ -174,8 +178,6 @@ retry:      /* transaction retry */
                case DB_LOCK_DEADLOCK:
                case DB_LOCK_NOTGRANTED:
                        *text = NULL;
-                       bdb_entry_return( be, e );
-                       e = NULL;
                        goto retry;
                case 0:
                        break;
@@ -191,8 +193,6 @@ retry:      /* transaction retry */
                        switch(rc) {
                        case DB_LOCK_DEADLOCK:
                        case DB_LOCK_NOTGRANTED:
-                               bdb_entry_return( be, e );
-                               e = NULL;
                                goto retry;
                        }
                        *text = "entry update failed";
@@ -212,9 +212,9 @@ retry:      /* transaction retry */
 
 done:
        if( e != NULL ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_w( &bdb->bi_cache, e );
        }
-
+               
        if( hash.bv_val != NULL ) {
                free( hash.bv_val );
        }
index 64b83c2cdfcb36efead3c95d6da2f26523add6d8..86d7e1bf5d5b2c2d0723e086eb1588fa6c87c4a8 100644 (file)
@@ -57,8 +57,10 @@ bdb_db_cache(
 /*
  * dn2entry.c
  */
-int bdb_dn2entry LDAP_P(( BackendDB *be, DB_TXN *tid,
-       struct berval *dn, Entry **e, Entry **matched, int flags ));
+int bdb_dn2entry_rw LDAP_P(( BackendDB *be, DB_TXN *tid,
+       struct berval *dn, Entry **e, Entry **matched, int flags, int rw ));
+#define bdb_dn2entry_r(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0)
+#define bdb_dn2entry_w(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1)
 
 /*
  * dn2id.c
@@ -103,7 +105,7 @@ bdb_dn2idl(
 /*
  * entry.c
  */
-int bdb_entry_return( BackendDB *be, Entry *e );
+int bdb_entry_return( Entry *e );
 BI_entry_release_rw bdb_entry_release;
 
 /*
@@ -127,7 +129,7 @@ int bdb_filter_candidates(
 BI_acl_group bdb_group;
 
 /*
- * id2entry
+ * id2entry.c
  */
 int bdb_id2entry_add(
        BackendDB *be,
@@ -142,13 +144,18 @@ int bdb_id2entry_update(
 int bdb_id2entry_delete(
        BackendDB *be,
        DB_TXN *tid,
-       ID id );
+       Entry *e);
 
-int bdb_id2entry(
+int bdb_id2entry_rw(
        BackendDB *be,
        DB_TXN *tid,
        ID id,
-       Entry **e );
+       Entry **e,
+       int rw );
+#define bdb_id2entry_r(be, tid, id, e)      bdb_id2entry_rw((be), (tid), (id), (e), 0)
+#define bdb_id2entry_w(be, tid, id, e)      bdb_id2entry_rw((be), (tid), (id), (e), 1)
+
+void bdb_entry_free ( Entry *e );
 
 /*
  * idl.c
@@ -282,6 +289,40 @@ int bdb_modify_internal(
  */
 BI_op_extended bdb_exop_passwd;
 
+
+/*
+ * cache.c
+ */
+
+void bdb_cache_entry_commit( Entry *e );
+void bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw );
+#define bdb_cache_return_entry_r(c, e) bdb_cache_return_entry_rw((c), (e), 0)
+#define bdb_cache_return_entry_w(c, e) bdb_cache_return_entry_rw((c), (e), 1)
+int bdb_cache_add_entry_rw(
+       Cache   *cache,
+       Entry   *e,
+       int     rw
+);
+int bdb_cache_update_entry(
+       Cache   *cache,
+       Entry   *e
+);
+ID bdb_cache_find_entry_ndn2id(
+       Backend *be,
+       Cache   *cache,
+       struct berval   *ndn
+);
+Entry* bdb_cache_find_entry_id(
+       Cache   *cache,
+       ID      id,
+       int     rw
+);
+int bdb_cache_delete_entry(
+       Cache   *cache,
+       Entry   *e
+);
+void bdb_cache_release_all( Cache *cache );
+
 LDAP_END_DECL
 
 #endif /* _PROTO_BDB_H */
index 64ee0caace11298c54673f799a01f1586556da7a..64f61825669ce012b5a6062d9163addbb1d95cb2 100644 (file)
@@ -36,7 +36,7 @@ bdb_referrals(
        } 
 
        /* get entry */
-       rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
+       rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
 
        switch(rc) {
        case DB_NOTFOUND:
@@ -47,6 +47,12 @@ bdb_referrals(
                Debug( LDAP_DEBUG_TRACE,
                        "bdb_referrals: dn2entry failed: %s (%d)\n",
                        db_strerror(rc), rc, 0 ); 
+               if (e != NULL) {
+                        bdb_cache_return_entry_r(&bdb->bi_cache, e);
+               }
+                if (matched != NULL) {
+                        bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+               }
                send_ldap_result( conn, op, rc=LDAP_OTHER,
                        NULL, "internal error", NULL, NULL );
                return rc;
@@ -68,7 +74,7 @@ bdb_referrals(
                                refs = get_entry_referrals( be, conn, op, matched );
                        }
 
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r (&bdb->bi_cache, matched);
                        matched = NULL;
                } else if ( default_referral != NULL ) {
                        rc = LDAP_OTHER;
@@ -113,6 +119,6 @@ bdb_referrals(
                ber_bvarray_free( refs );
        }
 
-       bdb_entry_return( be, e );
+       bdb_cache_return_entry_r(&bdb->bi_cache, e);
        return rc;
 }
index 9b9272610b9e4874bf96e441e6a8c92a836ddeab..7645674c15db539ddb39589d2d4460863f767248 100644 (file)
@@ -78,7 +78,7 @@ bdb_search(
        } else
 #endif
        {
-               rc = bdb_dn2entry( be, NULL, nbase, &e, &matched, 0 );
+               rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0 );
        }
 
        switch(rc) {
@@ -86,6 +86,12 @@ bdb_search(
        case 0:
                break;
        default:
+               if (e != NULL) {
+                       bdb_cache_return_entry_w(&bdb->bi_cache, e);
+               }
+               if (matched != NULL) {
+                       bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+               }
                send_ldap_result( conn, op, rc=LDAP_OTHER,
                        NULL, "internal error", NULL, NULL );
                return rc;
@@ -104,7 +110,7 @@ bdb_search(
                                ? get_entry_referrals( be, conn, op, matched )
                                : NULL;
 
-                       bdb_entry_return( be, matched );
+                       bdb_cache_return_entry_r (&bdb->bi_cache, matched);
                        matched = NULL;
 
                        if( erefs ) {
@@ -135,7 +141,7 @@ bdb_search(
                erefs = get_entry_referrals( be, conn, op, e );
                refs = NULL;
 
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r( &bdb->bi_cache, e );
                e = NULL;
 
                if( erefs ) {
@@ -245,7 +251,7 @@ bdb_search(
        cursor = e->e_id == NOID ? 1 : e->e_id;
 
        if ( e != &slap_entry_root ) {
-               bdb_entry_return( be, e );
+               bdb_cache_return_entry_r(&bdb->bi_cache, e);
        }
        e = NULL;
 
@@ -296,7 +302,7 @@ bdb_search(
                }
 
                /* get the entry with reader lock */
-               rc = bdb_id2entry( be, NULL, id, &e );
+               rc = bdb_id2entry_r( be, NULL, id, &e );
 
                if ( e == NULL ) {
                        if( !BDB_IDL_IS_RANGE(candidates) ) {
@@ -418,7 +424,7 @@ bdb_search(
                        if ( scopeok ) {
                                /* check size limit */
                                if ( --slimit == -1 ) {
-                                       bdb_entry_return( be, e );
+                                       bdb_cache_return_entry_r (&bdb->bi_cache, e);
                                        e = NULL;
                                        send_search_result( conn, op,
                                                rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
@@ -437,7 +443,7 @@ bdb_search(
                                        case 1:         /* entry not sent */
                                                break;
                                        case -1:        /* connection closed */
-                                               bdb_entry_return( be, e );
+                                               bdb_cache_return_entry_r(&bdb->bi_cache, e);
                                                e = NULL;
                                                rc = LDAP_OTHER;
                                                goto done;
@@ -457,7 +463,8 @@ bdb_search(
 loop_continue:
                if( e != NULL ) {
                        /* free reader lock */
-                       bdb_entry_return( be, e );
+                        bdb_cache_return_entry_r ( &bdb->bi_cache, e );
+                        e = NULL;
                }
 
                ldap_pvt_thread_yield();
@@ -469,6 +476,11 @@ loop_continue:
        rc = 0;
 
 done:
+       if( e != NULL ) {
+               /* free reader lock */
+               bdb_cache_return_entry_r ( &bdb->bi_cache, e );
+       }
+
        if( v2refs ) ber_bvarray_free( v2refs );
        if( realbase.bv_val ) ch_free( realbase.bv_val );