X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldbm%2Fcache.c;h=8cfdeeaac06707bca6664ed4231c7c604faccc6c;hb=2c87d24f31d29bed606b443ef2d8e881b87207c7;hp=1ab9896cca3f59f32e8b2951a5ef23a9f7335b77;hpb=0452bab34f7e47ed4c45cc96cf9902c869f5d7b7;p=openldap diff --git a/servers/slapd/back-ldbm/cache.c b/servers/slapd/back-ldbm/cache.c index 1ab9896cca..8cfdeeaac0 100644 --- a/servers/slapd/back-ldbm/cache.c +++ b/servers/slapd/back-ldbm/cache.c @@ -3,9 +3,11 @@ #include "portable.h" #include -int strcasecmp( const char *, const char *); +#include +#include #include + #include "slap.h" #include "back-ldbm.h" @@ -35,7 +37,8 @@ cache_entry_cmp( Entry *e1, Entry *e2 ) 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 @@ -48,35 +51,31 @@ void 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 @@ -118,13 +117,13 @@ cache_return_entry_w( struct cache *cache, Entry *e ) } /* - * 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 @@ -134,7 +133,7 @@ cache_add_entry_lock( 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 ) @@ -144,7 +143,7 @@ cache_add_entry_lock( 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 ); } @@ -165,7 +164,7 @@ cache_add_entry_lock( } /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); return( -1 ); } @@ -198,9 +197,105 @@ cache_add_entry_lock( == 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 */ @@ -211,7 +306,7 @@ cache_add_entry_lock( } /* free cache mutex */ - pthread_mutex_unlock( &cache->c_mutex ); + ldap_pvt_thread_mutex_unlock( &cache->c_mutex ); return( 0 ); } @@ -231,13 +326,21 @@ cache_find_entry_dn2id( 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); @@ -248,51 +351,27 @@ cache_find_entry_dn2id( 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 ); } @@ -311,11 +390,12 @@ cache_find_entry_id( 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 ) { @@ -330,47 +410,37 @@ cache_find_entry_id( 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 ); } @@ -396,18 +466,18 @@ cache_delete_entry( 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 ); } @@ -417,18 +487,24 @@ cache_delete_entry_internal( 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 */