From 0ac226c809b6495d5dbc09c2f847638e10aca315 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 13 Mar 2013 02:50:06 +0000 Subject: The new caching system is almost there. It's more elaborate internally, and it works very, very differently, but the interface is proving much easier to use and it should be much faster, not to mention thread-safe. --- src/tests/cache.cpp | 419 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 335 insertions(+), 84 deletions(-) (limited to 'src/tests/cache.cpp') diff --git a/src/tests/cache.cpp b/src/tests/cache.cpp index 6fc4e4a..15662af 100644 --- a/src/tests/cache.cpp +++ b/src/tests/cache.cpp @@ -55,22 +55,148 @@ private: bool bChanged; }; +template +class CacheBase; + +template +class CacheEntry +{ +friend class CacheBase; +private: + CacheEntry( obtype *pObject ) : + iRefCount( 0 ), + pObject( pObject ) + { + } + +public: + int getRefCount() const + { + mEntry.lock(); + int ret = iRefCount; + mEntry.unlock(); + return ret; + } + + obtype *getPtr() const + { + return pObject; + } + + void lock() const + { + mObject.lock(); + } + + void unlock() const + { + mObject.unlock(); + } + + void incRef() + { + mEntry.lock(); + iRefCount++; + mEntry.unlock(); + } + + bool decRef() + { + mEntry.lock(); + iRefCount--; + bool bRet = iRefCount > 0; + mEntry.unlock(); + return bRet; + } + +private: + mutable Bu::Mutex mEntry; + mutable Bu::Mutex mObject; + int iRefCount; + obtype *pObject; +}; + +template +class CachePtrInterface +{ +protected: + CachePtrInterface() + { + } + + virtual ~CachePtrInterface() + { + } + + template + void checkRef( CacheBase *pCache, + const keytype &kId, + CacheEntry * &rpEnt, + obtype * &rpData ) + { + if( pCache == NULL ) + throw Bu::ExceptionBase("Invalid pointer"); + + if( !rpData ) + { + rpEnt = pCache->getRef( kId ); + rpEnt->incRef(); + rpData = dynamic_cast(rpEnt->getPtr()); + if( rpData == NULL ) + { + rpEnt->decRef(); + rpEnt = NULL; + throw std::bad_cast(); + } + } + } + + template + void releaseRef( CacheBase *pCache, + CacheEntry * &rpEnt, + obtype * &rpData ) + { + if( pCache == NULL ) + return; + + if( rpData == NULL ) + return; + + rpData = NULL; + rpEnt->decRef(); + pCache->releaseRef( rpEnt ); + rpEnt = NULL; + } +}; + template -class CachePtr +class CachePtr : protected CachePtrInterface { friend class CacheBase; private: - CachePtr( CacheBase *pCache, obtype *pData, + typedef CachePtr MyType; + + CachePtr( CacheBase *pCache, + CacheEntry *pEnt, const keytype &kId ) : pCache( pCache ), kId( kId ), - pData( pData ) + pEnt( pEnt ), + pData( NULL ) { + pEnt->incRef(); + pData = dynamic_cast( pEnt->getPtr() ); + if( pData == NULL ) + { + pEnt->decRef(); + throw std::bad_cast(); + } } CachePtr( CacheBase *pCache, const keytype &kId ) : pCache( pCache ), kId( kId ), + pEnt( NULL ), pData( NULL ) { } @@ -78,12 +204,23 @@ private: public: CachePtr() : pCache( NULL ), + pEnt( NULL ), pData( NULL ) { } + CachePtr( const MyType &rhs ) : + pCache( rhs.pCache ), + kId( rhs.kId ), + pEnt( rhs.pEnt ), + pData( rhs.pData ) + { + pEnt->incRef(); + } + virtual ~CachePtr() { + release(); } const keytype &getKey() const @@ -96,34 +233,113 @@ public: checkRef(); return pData; } + + const obtype &operator*() const + { + checkRef(); + return pData; + } obtype *operator->() { checkRef(); return pData; } + + const obtype *operator->() const + { + checkRef(); + return pData; + } + + MyType operator=( const MyType &rhs ) + { + release(); + pCache = rhs.pCache; + kId = rhs.kId; + pEnt = rhs.pEnt; + pData = rhs.pData; + pEnt->incRef(); + + return *this; + } + + bool operator==( const MyType &rhs ) const + { + return pCache == rhs.pCache && + kId == rhs.kId; + } + + bool operator!=( const MyType &rhs ) const + { + return pCache != rhs.pCache || + kId != rhs.kId; + } + + void release() + { + CachePtrInterface::releaseRef( pCache, pEnt, pData ); + } + + void lock() + { + checkRef(); + if( pEnt ) + pEnt->lock(); + } + + void unlock() + { + checkRef(); + if( pEnt ) + pEnt->unlock(); + } + + class Locker + { + public: + Locker( MyType &rPtr ) : + rPtr( rPtr ), + bLocked( true ) + { + rPtr.lock(); + } + + ~Locker() + { + unlock(); + } + + void unlock() + { + if( !bLocked ) + return; + rPtr.unlock(); + bLocked = false; + } + + private: + MyType &rPtr; + bool bLocked; + }; private: void checkRef() { - if( pCache == NULL ) - throw Bu::ExceptionBase("Invalid pointer"); - - if( !pData ) - pData = pCache->getRef( kId ); + CachePtrInterface::checkRef( pCache, kId, pEnt, pData ); } private: CacheBase *pCache; mutable keytype kId; + mutable CacheEntry *pEnt; mutable obtype *pData; - }; template class CacheBase { -friend class CachePtr; +friend class CachePtrInterface; public: CacheBase() { @@ -133,14 +349,17 @@ public: { } + typedef CacheEntry Entry; typedef Bu::List KeyList; + CachePtr insert( const obtype *pObject ) { - CacheEntry *pEnt = addEntry( pObject ); + Entry *pEnt = addEntry( pObject ); - pEnt->incRef(); - return CachePtr( this, pEnt->getPtr(), pObject->getKey() ); + return CachePtr( + this, pEnt, pObject->getKey() + ); } template @@ -150,84 +369,68 @@ public: if( pCast == NULL ) throw std::bad_cast(); - CacheEntry *pEnt = addEntry( pCast ); + Entry *pEnt = addEntry( pCast ); - pEnt->incRef(); - return CachePtr( this, pObject, pObject->getKey() ); + return CachePtr( + this, pEnt, pObject->getKey() + ); } CachePtr get( const keytype &key ) { - CacheEntry *pEnt = getEntry( key ); - pEnt->incRef(); - return CachePtr( this, pEnt->getPtr(), key ); + Entry *pEnt = getEntry( key ); + return CachePtr( this, pEnt, key ); } template CachePtr get( const keytype &key ) { - CacheEntry *pEnt = getEntry( key ); - pEnt->incRef(); - supertype *pCast = dynamic_cast( pEnt->getPtr() ); - if( pCast == NULL ) - { - pEnt->decRef(); - throw std::bad_cast(); - } - return CachePtr( this, pCast, key ); + Entry *pEnt = getEntry( key ); + return CachePtr( this, pEnt, key ); } - virtual KeyList getKeys() const=0; - - virtual void sync()=0; - -protected: - obtype *getRef( const keytype &k ) + CachePtr getLazy( const keytype &key ) { - CacheEntry *pEnt = getEntry( k ); - pEnt->incRef(); - return pEnt->getPtr(); + return CachePtr( this, key ); } - void objectChanged( const keytype &k ) + template + CachePtr getLazy( const keytype &key ) { + return CachePtr( this, key ); } - class CacheEntry + virtual KeyList getKeys() const=0; + + virtual void sync()=0; + + void _debug() { - public: - CacheEntry( obtype *pObject ) : - iRefCount( 0 ), - pObject( pObject ) + Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry ); + Bu::println("Cache entries:"); + for( typename CacheEntryHash::iterator i = hCacheEntry.begin(); i; i++ ) { + Bu::println(" %1: refs=%2"). + arg( i.getKey() ). + arg( i.getValue()->getRefCount() ); } + } - void incRef() - { - mEntry.lock(); - iRefCount++; - mEntry.unlock(); - } +protected: + Entry *getRef( const keytype &k ) + { + Entry *pEnt = getEntry( k ); + return pEnt; + } - bool decRef() - { - mEntry.lock(); - iRefCount--; - bool bRet = iRefCount > 0; - mEntry.unlock(); - return bRet; - } + void releaseRef( Entry * )//pEnt ) + { + } - obtype *getPtr() - { - return pObject; - } + void objectChanged( const keytype &k ) + { + } - private: - Bu::Mutex mEntry; - int iRefCount; - obtype *pObject; - }; protected: virtual void _create( const obtype *o )=0; @@ -237,9 +440,9 @@ protected: virtual void _save( const obtype *o )=0; private: - CacheEntry *addEntry( const obtype *pObject ) + Entry *addEntry( const obtype *pObject ) { - CacheEntry *pEnt = new CacheEntry( const_cast(pObject) ); + Entry *pEnt = new Entry( const_cast(pObject) ); mCacheEntry.lockWrite(); hCacheEntry.insert( pObject->getKey(), pEnt ); mCacheEntry.unlockWrite(); @@ -248,9 +451,9 @@ private: return pEnt; } - CacheEntry *getEntry( const keytype &k ) + Entry *getEntry( const keytype &k ) { - CacheEntry *pEnt = NULL; + Entry *pEnt = NULL; try { Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry ); @@ -260,7 +463,7 @@ private: { // try to load the object from the backing store obtype *pObject = _load( k ); - pEnt = new CacheEntry( pObject ); + pEnt = new Entry( pObject ); Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); hCacheEntry.insert( k, pEnt ); } @@ -268,10 +471,9 @@ private: } private: - typedef Bu::Hash CacheEntryHash; + typedef Bu::Hash CacheEntryHash; CacheEntryHash hCacheEntry; Bu::ReadWriteMutex mCacheEntry; - }; template @@ -282,21 +484,26 @@ public: sStore( sStore ), mStore( sStore, iBlockSize, iPreallocate ) { - Bu::ReadWriteMutex::WriteLocker wl( rwStore ); try { + Bu::ReadWriteMutex::ReadLocker l( rwStore ); Bu::MyriadStream ms = mStore.openStream( 1 ); Bu::Archive ar( ms, Bu::Archive::load ); - ar >> hIndex; + uint8_t uVer; + ar >> uVer; + switch( uVer ) + { + case 0: + ar >> hIndex; + break; + } } catch(...) { if( mStore.createStreamWithId( 1 ) != 1 ) throw Bu::ExceptionBase("Error creating index stream."); - Bu::MyriadStream ms = mStore.openStream( 1 ); - Bu::Archive ar( ms, Bu::Archive::save ); - ar << hIndex; + sync(); } } @@ -318,7 +525,7 @@ public: Bu::ReadWriteMutex::ReadLocker wl( rwStore ); Bu::MyriadStream ms = mStore.openStream( 1 ); Bu::Archive ar( ms, Bu::Archive::save ); - ar << hIndex; + ar << (uint8_t)0 << hIndex; ar.close(); ms.setSize( ms.tell() ); } @@ -413,21 +620,65 @@ Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s ) typedef CachePtr SomethingPtr; typedef MyriadCache SomethingCache; -int main() +int main( int argc, char *argv[] ) { Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite); SomethingCache c( fStore ); - SomethingPtr ptr = c.insert( new Something("Bob") ); - - Bu::println("Something[%1]: %2").arg( ptr.getKey() ).arg(ptr->getName()); + for( int j = 1; j < argc; j++ ) + { + SomethingPtr ptr = c.insert( new Something(argv[j]) ); + Bu::println("Something[%1]: %2"). + arg( ptr.getKey() ). + arg( ptr->getName() ); + } + SomethingCache::KeyList lKeys = c.getKeys(); for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ ) { - Bu::println(" - %1").arg( *i ); + Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->getName() ); } + c._debug(); + + SomethingPtr p2; + SomethingPtr p1( c.get( lKeys.first() ) ); + + c._debug(); + + { + SomethingPtr p2( p1 ); + c._debug(); + } + + c._debug(); + + p2 = p1; + + c._debug(); + + p1.release(); + + c._debug(); + + Bu::println("Name: %1").arg( p1->getName() ); + + p1.release(); + p1.lock(); + p1.unlock(); + + c._debug(); + + SomethingPtr p3 = c.getLazy( lKeys.first() ); + + c._debug(); + + SomethingPtr::Locker l( p3 ); + + Bu::println("Name again: %1").arg( p3->getName() ); + + c._debug(); return 0; } -- cgit v1.2.3