#include "portable.h"
#include <stdio.h>
-int strcasecmp( const char *, const char *);
+#include <ac/errno.h>
+#include <ac/string.h>
#include <ac/socket.h>
+
#include "slap.h"
#include "back-ldbm.h"
static int
cache_entrydn_cmp( Entry *e1, Entry *e2 )
{
- return( strcasecmp( e1->e_dn, e2->e_dn ) );
+ /* compare their normalized UPPERCASED dn's */
+ return( strcmp( e1->e_ndn, e2->e_ndn ) );
}
static int
cache_set_state( struct cache *cache, Entry *e, int state )
{
/* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
e->e_state = state;
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
static void
-cache_return_entry( struct cache *cache, Entry *e )
+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);
+
/* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ entry_rdwr_unlock(e, rw);
if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
entry_free( e );
}
/* free 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);
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
void
}
/*
- * cache_create_entry_lock - create an entry in the cache, and lock it.
+ * cache_create_entry - create an entry in the cache, and lock it.
* returns: 0 entry has been created and locked
* 1 entry already existed
* -1 something bad happened
*/
int
-cache_add_entry_lock(
+cache_add_entry(
struct cache *cache,
Entry *e,
int state
Entry *ee;
/* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
if ( avl_insert( &cache->c_dntree, (caddr_t) e,
cache_entrydn_cmp, avl_dup_error ) != 0 )
e->e_dn, e->e_id, 0 );
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( 1 );
}
}
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( -1 );
}
== 0 && cache->c_cursize > cache->c_maxsize ) {
e = cache->c_lrutail;
- /* XXX check for writer lock - should also check no readers pending */
+ /* check for active readers/writer lock */
+#ifdef LDAP_DEBUG
+ assert(!ldap_pvt_thread_rdwr_active( &e->e_rdwr ));
+#endif
+
+ /* delete from cache and lru q */
+ rc = cache_delete_entry_internal( cache, e );
+
+ entry_free( e );
+ }
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( 0 );
+}
+
+/*
+ * cache_update_entry - update an entry in the cache
+ * returns: 0 entry has been created and locked
+ * 1 entry already existed
+ * -1 something bad happened
+ */
+int
+cache_update_entry(
+ struct cache *cache,
+ Entry *e
+)
+{
+ int i, rc;
+ Entry *ee;
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
+ if ( avl_insert( &cache->c_dntree, (caddr_t) e,
+ cache_entrydn_cmp, avl_dup_error ) != 0 )
+ {
+ Debug( LDAP_DEBUG_TRACE,
+ "====> cache_add_entry lock: entry %20s id %lu already in dn cache\n",
+ e->e_dn, e->e_id, 0 );
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( 1 );
+ }
+
+ /* id tree */
+ if ( avl_insert( &cache->c_idtree, (caddr_t) e,
+ cache_entryid_cmp, avl_dup_error ) != 0 )
+ {
+ 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",
+ 0, 0, 0 );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ return( -1 );
+ }
+
+ e->e_state = 0;
+
+ /* 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 && cache->c_lrutail->e_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 && cache->c_lrutail->e_refcnt
+ == 0 && cache->c_cursize > cache->c_maxsize ) {
+ e = cache->c_lrutail;
+
+ /* check for active readers/writer lock */
#ifdef LDAP_DEBUG
- assert(!pthread_rdwr_rwchk_np(&e->e_rdwr));
+ assert(!ldap_pvt_thread_rdwr_active( &e->e_rdwr ));
#endif
/* delete from cache and lru q */
}
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( 0 );
}
ID id;
/* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
e.e_dn = dn;
+ e.e_ndn = dn_normalize_case( ch_strdup( dn ) );
if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
cache_entrydn_cmp )) != NULL )
{
+ /*
+ * 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.
+ */
+ free(e.e_ndn);
+
Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
dn, 0, 0);
ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
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 );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( id );
}
+ free(e.e_ndn);
+
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NOID );
}
Entry e;
Entry *ep;
- /* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
-
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,
cache_entryid_cmp )) != NULL )
{
ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_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);
+ if ( 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 */
- pthread_mutex_unlock( &cache->c_mutex );
- return( NULL );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_yield();
+ goto try_again;
}
- if ( rw ) {
- entry_rdwr_unlock(ep, 0);
- entry_rdwr_lock(ep, 1);
- }
+ /* lru */
+ LRU_DELETE( cache, ep );
+ LRU_ADD( cache, ep );
+
+ ep->e_refcnt++;
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( ep );
}
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NULL );
}
Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry:\n", 0, 0, 0 );
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
/* XXX check for writer lock - should also check no readers pending */
#ifdef LDAP_DEBUG
- assert(pthread_rdwr_wchk_np(&e->e_rdwr));
+ assert(ldap_pvt_thread_rdwr_writers( &e->e_rdwr ) == 1);
#endif
- /* set cache mutex */
- pthread_mutex_lock( &cache->c_mutex );
-
rc = cache_delete_entry_internal( cache, e );
/* free cache mutex */
- pthread_mutex_unlock( &cache->c_mutex );
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( rc );
}
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 */