/* cache.c - routines to maintain an in-core cache of entries */
+#include "portable.h"
+
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+int strcasecmp( const char *, const char *);
+
+#include <ac/socket.h>
#include "slap.h"
+
#include "back-ldbm.h"
-static int cache_delete_entry_internal();
+static int cache_delete_entry_internal(struct cache *cache, Entry *e);
#ifdef LDAP_DEBUG
-static void lru_print();
+static void lru_print(struct cache *cache);
#endif
/*
pthread_mutex_unlock( &cache->c_mutex );
}
-void
+static void
cache_return_entry( struct cache *cache, Entry *e )
{
/* set cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
}
+static void
+cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
+{
+ Debug( LDAP_DEBUG_TRACE, "====> cache_return_entry_%s\n",
+ rw ? "w" : "r", 0, 0);
+ entry_rdwr_unlock(e, rw);;
+ cache_return_entry(cache, e);
+}
+
+void
+cache_return_entry_r( struct cache *cache, Entry *e )
+{
+ cache_return_entry_rw(cache, e, 0);
+}
+
+void
+cache_return_entry_w( struct cache *cache, Entry *e )
+{
+ cache_return_entry_rw(cache, e, 1);
+}
+
+
#define LRU_DELETE( cache, e ) { \
if ( e->e_lruprev != NULL ) { \
e->e_lruprev->e_lrunext = e->e_lrunext; \
cache_entrydn_cmp, avl_dup_error ) != 0 )
{
Debug( LDAP_DEBUG_TRACE,
- "entry %20s id %d already in dn cache\n", e->e_dn,
- e->e_id, 0 );
+ "====> cache_add_entry lock: entry %20s id %lu already in dn cache\n",
+ e->e_dn, e->e_id, 0 );
/* free cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
if ( avl_insert( &cache->c_idtree, (caddr_t) e,
cache_entryid_cmp, avl_dup_error ) != 0 )
{
- Debug( LDAP_DEBUG_ANY, "entry %20s id %d already in id cache\n",
+ Debug( LDAP_DEBUG_ANY,
+ "====> entry %20s id %lu already in id cache\n",
e->e_dn, e->e_id, 0 );
/* delete from dn tree inserted above */
if ( avl_delete( &cache->c_dntree, (caddr_t) e,
cache_entrydn_cmp ) == NULL )
{
- Debug( LDAP_DEBUG_ANY, "can't delete from dn cache\n",
+ Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
0, 0, 0 );
}
== 0 && cache->c_cursize > cache->c_maxsize ) {
e = cache->c_lrutail;
+ /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+ assert(!pthread_rdwr_rwchk_np(&e->e_rdwr));
+#endif
+
/* delete from cache and lru q */
rc = cache_delete_entry_internal( cache, e );
}
/*
- * cache_find_entry_dn - find an entry in the cache, given dn
+ * cache_find_entry_dn2id - find an entry in the cache, given dn
*/
-Entry *
-cache_find_entry_dn(
+ID
+cache_find_entry_dn2id(
+ Backend *be,
struct cache *cache,
char *dn
)
{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry e, *ep;
+ ID id;
/* set cache mutex */
pthread_mutex_lock( &cache->c_mutex );
e.e_dn = dn;
+
if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
cache_entrydn_cmp )) != NULL )
{
+ Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
+ dn, 0, 0);
+
/*
* entry is deleted or not fully created yet
*/
if ( ep->e_state == ENTRY_STATE_DELETED ||
- ep->e_state == ENTRY_STATE_CREATING )
+ ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
- return( NULL );
+ return( NOID );
}
+
+ /* XXX is this safe without writer lock? */
ep->e_refcnt++;
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
+
+ /* acquire reader lock */
+ entry_rdwr_lock(ep, 0);
+
+ /* re-check */
+ if ( ep->e_state == ENTRY_STATE_DELETED ||
+ ep->e_state == ENTRY_STATE_CREATING )
+ {
+ /* XXX check that is is required */
+ ep->e_refcnt--;
+
+ /* free reader lock */
+ entry_rdwr_unlock(ep, 0);
+ /* free cache mutex */
+ pthread_mutex_unlock( &cache->c_mutex );
+
+ return( NOID );
+ }
+
+ /* save id */
+ id = ep->e_id;
+
+ /* free reader lock */
+ entry_rdwr_unlock(ep, 0);
+
+ /* free cache mutex */
+ pthread_mutex_unlock( &cache->c_mutex );
+
+ cache_return_entry( &li->li_cache, ep );
+
+ return( id );
}
/* free cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
- return( ep );
+ return( NOID );
}
/*
Entry *
cache_find_entry_id(
- struct cache *cache,
- ID id
+ struct cache *cache,
+ ID id,
+ int rw
)
{
Entry e;
pthread_mutex_lock( &cache->c_mutex );
e.e_id = id;
+
if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
cache_entryid_cmp )) != NULL )
{
+ Debug(LDAP_DEBUG_TRACE,
+ "====> cache_find_entry_dn2id: found id: %ld rw: %d\n",
+ id, rw, 0);
+
/*
* entry is deleted or not fully created yet
*/
if ( ep->e_state == ENTRY_STATE_DELETED ||
- ep->e_state == ENTRY_STATE_CREATING )
+ ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
return( NULL );
}
+ /* XXX is this safe without writer lock? */
ep->e_refcnt++;
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
+
+ /* acquire reader lock */
+ entry_rdwr_lock(ep, 0);
+
+ /* re-check */
+ if ( ep->e_state == ENTRY_STATE_DELETED ||
+ ep->e_state == ENTRY_STATE_CREATING ) {
+
+ /* XXX check that is is required */
+ ep->e_refcnt--;
+
+ /* free reader lock */
+ entry_rdwr_unlock(ep, 0);
+
+ /* free cache mutex */
+ pthread_mutex_unlock( &cache->c_mutex );
+ return( NULL );
+ }
+
+ if ( rw ) {
+ entry_rdwr_unlock(ep, 0);
+ entry_rdwr_lock(ep, 1);
+ }
+
+ /* free cache mutex */
+ pthread_mutex_unlock( &cache->c_mutex );
+
+ return( ep );
}
/* free cache mutex */
pthread_mutex_unlock( &cache->c_mutex );
- return( ep );
+ return( NULL );
}
/*
{
int rc;
+ Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry:\n", 0, 0, 0 );
+
+ /* XXX check for writer lock - should also check no readers pending */
+#ifdef LDAP_DEBUG
+ assert(pthread_rdwr_wchk_np(&e->e_rdwr));
+#endif
+
/* set cache mutex */
pthread_mutex_lock( &cache->c_mutex );
Entry *e
)
{
+ int rc = 0; /* return code */
+
/* dn tree */
if ( avl_delete( &cache->c_dntree, (caddr_t) e, cache_entrydn_cmp )
== NULL )
{
- return( -1 );
+ rc = -1;
}
/* id tree */
if ( avl_delete( &cache->c_idtree, (caddr_t) e, cache_entryid_cmp )
== NULL )
{
- return( -1 );
+ rc = -1;
+ }
+
+ if (rc != 0) {
+ return rc;
}
/* lru */
fprintf( stderr, "LRU queue (head to tail):\n" );
for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) {
- fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+ fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
e->e_id, e->e_refcnt );
}
fprintf( stderr, "LRU queue (tail to head):\n" );
for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) {
- fprintf( stderr, "\tdn %20s id %d refcnt %d\n", e->e_dn,
+ fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
e->e_id, e->e_refcnt );
}
}
#endif
+