Entry caching. Based on ITS#1545 from Jong Hyuk Choi, jongchoi@us.ibm.com

This commit is contained in:
Howard Chu 2002-01-25 07:19:01 +00:00
parent 1226d620e0
commit 713e6beb8d
20 changed files with 1201 additions and 103 deletions

View 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

View 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 );

View 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

View 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;

View 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) */

View file

@ -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

View 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;

View 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: "

View 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 ) {

View file

@ -18,18 +18,19 @@
*/
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;

View 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;

View 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

View 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;
}

View 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 ) {

View 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;
}

View 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 ) {

View 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 );
}

View 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 */

View 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;
}

View 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 );