From 21a4337dc2f969dc3ec81e6ba3170119bcb67016 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 22 Jul 2014 16:39:01 +0000 Subject: Deferred erase now works on cache entries. You can erase a cache entry while it still has active references, and it will be safely cleaned up when the last reference is released. --- src/unstable/cachebase.h | 76 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) (limited to 'src/unstable/cachebase.h') diff --git a/src/unstable/cachebase.h b/src/unstable/cachebase.h index 1584246..b17d377 100644 --- a/src/unstable/cachebase.h +++ b/src/unstable/cachebase.h @@ -29,6 +29,7 @@ namespace Bu private: CacheEntry( obtype *pObject ) : iRefCount( 0 ), + bDeleted( false ), pObject( pObject ) { } @@ -78,10 +79,29 @@ namespace Bu return bRet; } + bool isDeleted() + { + mEntry.lock(); + bool bRet = bDeleted; + mEntry.unlock(); + return bRet; + } + + // Indicates that the entry was both deleted + // and has a refcount of zero + bool isReadyForCleanup() + { + mEntry.lock(); + bool bRet = bDeleted && iRefCount == 0; + mEntry.unlock(); + return bRet; + } + private: mutable Bu::Mutex mEntry; mutable Bu::Mutex mObject; int iRefCount; + bool bDeleted; obtype *pObject; }; @@ -104,7 +124,7 @@ namespace Bu obtype * &rpData ) { if( pCache == NULL ) - throw Bu::ExceptionBase("Invalid pointer"); + throw Bu::ExceptionBase("Invalid cache pointer"); if( !rpData ) { @@ -241,6 +261,12 @@ namespace Bu return pCache->template cast( *this ); } + template + CachePtr cast() const + { + return pCache->template cast( *this ); + } + bool operator==( const MyType &rhs ) const { return pCache == rhs.pCache && @@ -410,19 +436,46 @@ namespace Bu else return CachePtr( this, ptr.kId ); } + + template + CachePtr cast( const CachePtr &ptr ) + { + if( ptr.pEnt ) + return CachePtr( this, ptr.pEnt, ptr.kId ); + else + return CachePtr( this, ptr.kId ); + } /** * Removes an item from the cache. - * This routine calls eraseNow for now. Later the intention is that - * this function will always succeed. It will remove the object from - * the backing store and the active tables. It will not be able to - * be requested again, and all changes will be ignored. When the - * object's last references are released the memory will be freed - * automatically. + * The object in question can have references to it, and those + * references will still work after the erase is called. When erase + * is called the object is immediately removed from the backing store + * as well as from the main index. At that point existing references + * can be used as normal, but when the last reference is released + * the memory will be automatically cleaned up. */ void erase( const keytype &key ) { - eraseNow( key ); + Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); + if( hCacheEntry.has( key ) ) + { + Entry *pEnt = hCacheEntry.get( key ); + pEnt->mEntry.lock(); + if( pEnt->iRefCount == 0 ) + { + pEnt->mEntry.unlock(); + delete pEnt->pObject; + delete pEnt; + } + else + { + pEnt->bDeleted = true; + pEnt->mEntry.unlock(); + } + hCacheEntry.erase( key ); + } + _erase( key ); } /** @@ -467,8 +520,13 @@ namespace Bu return pEnt; } - void releaseRef( Entry * )//pEnt ) + void releaseRef( Entry *pEnt ) { + if( pEnt->isReadyForCleanup() ) + { + delete pEnt->pObject; + delete pEnt; + } } void objectChanged( const keytype &k ) -- cgit v1.2.3