From fb5176bbd5355b02b7d0e65da3ef3f0105824cd0 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 17 Mar 2013 23:45:21 +0000 Subject: The new cache system has been broken out into it's individual headers, and is now ready for actual use. --- src/tests/cache.cpp | 719 +--------------------------------------------------- 1 file changed, 12 insertions(+), 707 deletions(-) (limited to 'src/tests') diff --git a/src/tests/cache.cpp b/src/tests/cache.cpp index 112d916..dc5dbd0 100644 --- a/src/tests/cache.cpp +++ b/src/tests/cache.cpp @@ -1,707 +1,9 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// -// New Cache Implementation -// - -template class CacheBase; -template class CacheEntry; - -template -class CacheObject -{ -friend class CacheBase; -public: - CacheObject() : - pCache( NULL ), - bChanged( false ) - { - } - - virtual ~CacheObject() - { - } - - typedef CacheBase CacheType; - - virtual keytype getKey() const=0; - virtual int getPersistenceScore() const { return 0; } - - void lock() - { - pEntry->lock(); - } - - void unlock() - { - pEntry->unlock(); - } - - int getRefCount() const - { - return pEntry->getRefCount(); - } - - bool hasChanged() const - { - return bChanged; - } - -protected: - void changed( bool bChanged=true ) - { - if( this->bChanged == false && bChanged == true ) - pCache->objectChanged( getKey() ); - - this->bChanged = bChanged; - } - -private: - typedef CacheEntry Entry; - void setCache( CacheType *pCache, Entry *pEntry ) - { - this->pCache = pCache; - this->pEntry = pEntry; - } - -private: - CacheType *pCache; - Entry *pEntry; - 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(); - } - - Bu::Mutex &getMutex() - { - return mObject; - } - - 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 : protected CachePtrInterface -{ -friend class CacheBase; -private: - typedef CachePtr MyType; - - CachePtr( CacheBase *pCache, - CacheEntry *pEnt, - const keytype &kId ) : - pCache( pCache ), - kId( kId ), - 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 ) - { - } - -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() - { - unbind(); - } - - const keytype &getKey() const - { - return kId; - } - - obtype &operator*() - { - bind(); - return pData; - } - - const obtype &operator*() const - { - bind(); - return pData; - } - - obtype *operator->() - { - bind(); - return pData; - } - - const obtype *operator->() const - { - bind(); - return pData; - } - - MyType operator=( const MyType &rhs ) - { - unbind(); - pCache = rhs.pCache; - kId = rhs.kId; - pEnt = rhs.pEnt; - pData = rhs.pData; - pEnt->incRef(); - - return *this; - } - - template - CachePtr cast() - { - return pCache->cast( *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 bind() - { - CachePtrInterface::checkRef( pCache, kId, pEnt, pData ); - } - - void unbind() - { - CachePtrInterface::releaseRef( pCache, pEnt, pData ); - } - - void lock() - { - bind(); - if( pEnt ) - pEnt->lock(); - } - - void unlock() - { - bind(); - 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; - }; +#include "bu/myriadcache.h" +#include "bu/uuid.h" +#include "bu/string.h" +#include "bu/sio.h" -private: - CacheBase *pCache; - mutable keytype kId; - mutable CacheEntry *pEnt; - mutable obtype *pData; -}; - -template -class CacheBase -{ -friend class CachePtrInterface; -friend class CacheObject; -public: - CacheBase() - { - } - - virtual ~CacheBase() - { - Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); - syncChanges(); - } - - typedef CacheEntry Entry; - typedef Bu::List KeyList; - - CachePtr insert( obtype *pObject ) - { - Entry *pEnt = addEntry( pObject ); - - return CachePtr( - this, pEnt, pObject->getKey() - ); - } - - template - CachePtr insert( supertype *pObject ) - { - obtype *pCast = dynamic_cast( pObject ); - if( pCast == NULL ) - throw std::bad_cast(); - - Entry *pEnt = addEntry( pCast ); - - return CachePtr( - this, pEnt, pObject->getKey() - ); - } - - CachePtr get( const keytype &key ) - { - Entry *pEnt = getEntry( key ); - return CachePtr( this, pEnt, key ); - } - - template - CachePtr get( const keytype &key ) - { - Entry *pEnt = getEntry( key ); - return CachePtr( this, pEnt, key ); - } - - CachePtr getLazy( const keytype &key ) - { - return CachePtr( this, key ); - } - - template - CachePtr getLazy( const keytype &key ) - { - return CachePtr( this, key ); - } - - template - CachePtr cast( CachePtr &ptr ) - { - if( ptr.pEnt ) - return CachePtr( this, ptr.pEnt, ptr.kId ); - else - return CachePtr( this, ptr.kId ); - } - - void erase( const keytype &key ) - { - Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); - if( hCacheEntry.has( key ) ) - { - Entry *pEnt = hCacheEntry.get( key ); - pEnt->mEntry.lock(); - if( pEnt->iRefCount > 0 ) - { - int iCount = pEnt->iRefCount; - pEnt->mEntry.unlock(); - throw Bu::ExceptionBase( Bu::String("Cache entry %1 cannot be erased, there are %2 active references.").arg( key ).arg( iCount ).end().getStr() ); - } - delete pEnt->pObject; - delete pEnt; - hCacheEntry.erase( key ); - } - _erase( key ); - } - - virtual KeyList getKeys() const=0; - virtual int getSize() const=0; - - void sync() - { - Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); - Bu::println("Syncing storage layer..."); - _sync(); - syncChanges(); - } - - void _debug() - { - 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() ); - } - } - -protected: - Entry *getRef( const keytype &k ) - { - Entry *pEnt = getEntry( k ); - return pEnt; - } - - void releaseRef( Entry * )//pEnt ) - { - } - - void objectChanged( const keytype &k ) - { - Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); - hChanged.insert( k, true ); - } - -protected: - virtual void _create( const obtype *o )=0; - virtual void _erase( const keytype &k )=0; - - virtual obtype *_load( const keytype &k )=0; - virtual void _save( const obtype *o )=0; - - virtual void _sync()=0; - -private: - Entry *addEntry( obtype *pObject ) - { - Entry *pEnt = new Entry( pObject ); - mCacheEntry.lockWrite(); - hCacheEntry.insert( pObject->getKey(), pEnt ); - mCacheEntry.unlockWrite(); - _create( pObject ); - pObject->setCache( this, pEnt ); - - return pEnt; - } - - Entry *getEntry( const keytype &k ) - { - Entry *pEnt = NULL; - try - { - Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry ); - pEnt = hCacheEntry.get( k ); - } - catch(...) - { - // try to load the object from the backing store - obtype *pObject = _load( k ); - pEnt = new Entry( pObject ); - pObject->setCache( this, pEnt ); - Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); - hCacheEntry.insert( k, pEnt ); - } - return pEnt; - } - - void syncChanges() - { - Bu::println("Syncing: %1 entries changed.").arg( hChanged.getSize() ); - if( !hChanged.isEmpty() ) - { - for( typename CacheKeySet::iterator i = hChanged.begin(); i; i++ ) - { - Entry *pEnt = hCacheEntry.get( i.getKey() ); - Bu::MutexLocker ml( pEnt->getMutex() ); - _save( pEnt->getPtr() ); - } - hChanged.clear(); - } - } - -private: - typedef Bu::Hash CacheEntryHash; - typedef Bu::Hash CacheKeySet; - CacheEntryHash hCacheEntry; - CacheKeySet hChanged; - Bu::ReadWriteMutex mCacheEntry; -}; - -template -void _cacheObjectSave( Bu::Stream &s, obtype *pObject ) -{ - Bu::Archive ar( s, Bu::Archive::save ); - ar << *pObject; -} - -template -obtype *_cacheObjectLoad( Bu::Stream &s ) -{ - Bu::Archive ar( s, Bu::Archive::load ); - obtype *ret = new obtype(); - ar >> *ret; - return ret; -} - -template -class MyriadCache : public CacheBase -{ -public: - MyriadCache( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ) : - sStore( sStore ), - mStore( sStore, iBlockSize, iPreallocate ), - bStructureChanged( false ) - { - try - { - Bu::ReadWriteMutex::ReadLocker l( rwStore ); - Bu::MyriadStream ms = mStore.openStream( 1 ); - Bu::Archive ar( ms, Bu::Archive::load ); - 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."); - - _sync(); - } - } - - virtual ~MyriadCache() - { - Bu::println("MyriadCache destroying."); - _sync(); - } - - using typename CacheBase::KeyList; - - virtual KeyList getKeys() const - { - Bu::ReadWriteMutex::ReadLocker rl( rwStore ); - return hIndex.getKeys(); - } - - virtual int getSize() const - { - Bu::ReadWriteMutex::ReadLocker rl( rwStore ); - return hIndex.getSize(); - } - -protected: - virtual void _create( const obtype *o ) - { - Bu::ReadWriteMutex::WriteLocker wl( rwStore ); - hIndex.insert( o->getKey(), mStore.createStream() ); - _save( o ); - - bStructureChanged = true; - } - - virtual void _erase( const keytype &k ) - { - Bu::ReadWriteMutex::WriteLocker wl( rwStore ); - mStore.deleteStream( hIndex.get( k ) ); - hIndex.erase( k ); - - bStructureChanged = true; - } - - virtual obtype *_load( const keytype &k ) - { - Bu::MyriadStream ms = mStore.openStream( hIndex.get( k ) ); - return _cacheObjectLoad( ms ); - } - - virtual void _save( const obtype *o ) - { - Bu::MyriadStream ms = mStore.openStream( hIndex.get( o->getKey() ) ); - _cacheObjectSave( ms, o ); - ms.setSize( ms.tell() ); - } - - virtual void _sync() - { - Bu::println("Syncing myriad header."); - Bu::ReadWriteMutex::ReadLocker wl( rwStore ); - if( !bStructureChanged ) - return; - - Bu::println(" --> Header changed, write required."); - Bu::MyriadStream ms = mStore.openStream( 1 ); - Bu::Archive ar( ms, Bu::Archive::save ); - ar << (uint8_t)0 << hIndex; - ar.close(); - ms.setSize( ms.tell() ); - - bStructureChanged = false; - } - -private: - Bu::Stream &sStore; - Bu::Myriad mStore; - Bu::Hash hIndex; - mutable Bu::ReadWriteMutex rwStore; - bool bStructureChanged; -}; - -// -// Test -// - -class Something : public CacheObject +class Something : public Bu::CacheObject { friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, Something &s ); friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s ); @@ -821,6 +123,8 @@ Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingB &s ) return ar << (Something &)s << s.sString; } +namespace Bu +{ template<> void _cacheObjectSave( Bu::Stream &s, const Something *pObject ) { @@ -868,11 +172,12 @@ Something *_cacheObjectLoad( Bu::Stream &s ) throw Bu::ExceptionBase("Flagrant error! Invalid type!"); } } +} -typedef CachePtr SomethingPtr; -typedef CachePtr SomethingAPtr; -typedef CachePtr SomethingBPtr; -typedef MyriadCache SomethingCache; +typedef Bu::CachePtr SomethingPtr; +typedef Bu::CachePtr SomethingAPtr; +typedef Bu::CachePtr SomethingBPtr; +typedef Bu::MyriadCache SomethingCache; int main( int argc, char *argv[] ) { -- cgit v1.2.3