diff options
Diffstat (limited to 'gcsdk/sharedobjectcache.cpp')
| -rw-r--r-- | gcsdk/sharedobjectcache.cpp | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/gcsdk/sharedobjectcache.cpp b/gcsdk/sharedobjectcache.cpp new file mode 100644 index 0000000..c2bf736 --- /dev/null +++ b/gcsdk/sharedobjectcache.cpp @@ -0,0 +1,397 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A cache of a bunch of CSharedObjects +// +//============================================================================= + +#include "stdafx.h" +#include <time.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +namespace GCSDK +{ + +#ifdef GC +static GCConVar add_object_clean_do_has_element( "add_object_clean_do_has_element", "0", 0, "Enables AddObjectClean() checking that the cache doesn't already have this pointer" ); +#endif + +//---------------------------------------------------------------------------- +// Purpose: Constructor +//---------------------------------------------------------------------------- +CSharedObjectTypeCache::CSharedObjectTypeCache( int nTypeID ) +: m_nTypeID( nTypeID ) +{ + +} + + +//---------------------------------------------------------------------------- +// Purpose: Destructor +//---------------------------------------------------------------------------- +CSharedObjectTypeCache::~CSharedObjectTypeCache() +{ + for ( int i = 0; i < m_vecObjects.Count(); i++ ) + { + // NULL the entry so that this SO isn't found during + // cleanup assertion checking. + CSharedObject *pObj = m_vecObjects[ i ]; + m_vecObjects[ i ] = NULL; + +#ifdef GC + if ( pObj->BShouldDeleteByCache() ) + { +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + --pObj->m_nRefCount; + AssertMsg1( pObj->m_nRefCount == 0, "Destroying shared object %s that's still in use!", pObj->GetDebugString().String() ); +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + delete pObj; + } +#else + delete pObj; +#endif + } + m_vecObjects.Purge(); +} + +//---------------------------------------------------------------------------- +// Purpose: Common shared add-to-cache code shared between AddObject() and +// AddObjectClean(). +//---------------------------------------------------------------------------- +void CSharedObjectTypeCache::AddObjectInternal( CSharedObject *pObject ) +{ + Assert( pObject ); + + m_vecObjects.AddToTail( pObject ); +#ifdef GC +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + AssertMsg1( pObject->m_nRefCount >= 0, "AddObjectInternal(): Invalid ref count for shared object %s", pObject->GetDebugString().String() ); + ++pObject->m_nRefCount; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA +#endif +} + +//---------------------------------------------------------------------------- +// Purpose: Adds a shared object of the appropriate type to this type cache. +//---------------------------------------------------------------------------- +bool CSharedObjectTypeCache::AddObject( CSharedObject *pObject ) +{ + Assert( pObject ); + Assert( m_nTypeID == pObject->GetTypeID() ); + if( m_vecObjects.HasElement( pObject ) ) + return false; + + AddObjectInternal( pObject ); + return true; +} + +//---------------------------------------------------------------------------- +// Purpose: Adds an object without dirtying. This is done when the object +// is just being loaded from SQL or memcached, so it's safe not to do the +// has element check. +//---------------------------------------------------------------------------- +bool CSharedObjectTypeCache::AddObjectClean( CSharedObject *pObject ) +{ + Assert( m_nTypeID == pObject->GetTypeID() ); + +#ifdef GC + if ( add_object_clean_do_has_element.GetBool() ) + { + Assert( !m_vecObjects.HasElement( pObject ) ); + if( m_vecObjects.HasElement( pObject ) ) + return false; + } +#endif + + AddObjectInternal( pObject ); + return true; +} + + +//---------------------------------------------------------------------------- +// Purpose: Destroys the object matching the one passed in. This could be the +// same one or simply one with matching index fields. +//---------------------------------------------------------------------------- +CSharedObject *CSharedObjectTypeCache::RemoveObject( const CSharedObject & soIndex ) +{ + Assert( m_nTypeID == soIndex.GetTypeID() ); // This is probably harmless, but it's most likely a bug + int nIndex = FindSharedObjectIndex( soIndex ); + if( m_vecObjects.IsValidIndex( nIndex ) ) + { + return RemoveObjectByIndex( nIndex ); + } + else + { + return NULL; + } +} + +CSharedObject *CSharedObjectTypeCache::RemoveObjectByIndex( uint32 nObj ) +{ + CSharedObject *pObj = m_vecObjects[nObj]; +#ifdef GC +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + AssertMsg1( pObj->m_nRefCount > 0, "Invalid ref count for shared object %s", pObj->GetDebugString().String() ); + --pObj->m_nRefCount; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA +#endif // GC + m_vecObjects.Remove( nObj ); + return pObj; +} + +//---------------------------------------------------------------------------- +// Purpose: Empties the object lists and deletes all elements +//---------------------------------------------------------------------------- +void CSharedObjectTypeCache::DestroyAllObjects() +{ + for ( int i = 0; i < m_vecObjects.Count(); i++ ) + { +#ifdef GC + if ( m_vecObjects[i]->BShouldDeleteByCache() ) + { +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + --m_vecObjects[i]->m_nRefCount; + AssertMsg1( m_vecObjects[i]->m_nRefCount == 0, "Destroying shared object %s that's still in use!", m_vecObjects[i]->GetDebugString().String() ); +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + delete m_vecObjects[i]; + } +#else + delete m_vecObjects[i]; +#endif + } + m_vecObjects.Purge(); +} + + +//---------------------------------------------------------------------------- +// Purpose: Empties the object lists but doesn't delete any of the objects +//---------------------------------------------------------------------------- +void CSharedObjectTypeCache::RemoveAllObjectsWithoutDeleting() +{ + m_vecObjects.RemoveAll(); +} + + +//---------------------------------------------------------------------------- +// Purpose: Makes sure there's room in the object vector for the suggested +// number of items +//---------------------------------------------------------------------------- +void CSharedObjectTypeCache::EnsureCapacity( uint32 nItems ) +{ + m_vecObjects.EnsureCapacity( nItems ); +} + + +//---------------------------------------------------------------------------- +// Purpose: Searches the object list for an object that matches the provided +// object on its index fields. +//---------------------------------------------------------------------------- +CSharedObject *CSharedObjectTypeCache::FindSharedObject( const CSharedObject & soIndex ) +{ + int nIndex = FindSharedObjectIndex( soIndex ); + if( m_vecObjects.IsValidIndex( nIndex ) ) + return m_vecObjects[nIndex]; + else + return NULL; +} + + +//---------------------------------------------------------------------------- +// Purpose: Searches the object list for an object that matches the provided +// object on its index fields. +//---------------------------------------------------------------------------- +int CSharedObjectTypeCache::FindSharedObjectIndex( const CSharedObject & soIndex ) const +{ + FOR_EACH_VEC( m_vecObjects, nObj ) + { + if( m_vecObjects[nObj]->BIsKeyEqual( soIndex ) ) + return nObj; + } + + return -1; +} + + +//---------------------------------------------------------------------------- +// Purpose: Dumps all the objects in the type cache +//---------------------------------------------------------------------------- +void CSharedObjectTypeCache::Dump() const +{ + EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\tTypeCache for %d (%d objects):\n", GetTypeID(), m_vecObjects.Count() ); + FOR_EACH_VEC( m_vecObjects, nObj ) + { + m_vecObjects[nObj]->Dump(); + } +} + + +//---------------------------------------------------------------------------- +// Purpose: Claims all the memory for the cache and its objects +//---------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +void CSharedObjectTypeCache::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + ValidateObj( m_vecObjects ); + + FOR_EACH_VEC( m_vecObjects, nIndex ) + { + m_vecObjects[nIndex]->Validate( validator, "m_vecObjects[n]" ); + } +} +#endif + + +//---------------------------------------------------------------------------- +// Purpose: Constructor +//---------------------------------------------------------------------------- +CSharedObjectCache::CSharedObjectCache( ) +: m_mapObjects( DefLessFunc(int) ) +, m_ulVersion( 0 ) +{ + +} + + +//---------------------------------------------------------------------------- +// Purpose: Destructor +//---------------------------------------------------------------------------- +CSharedObjectCache::~CSharedObjectCache() +{ + FOR_EACH_MAP( m_mapObjects, nTypeIndex ) + { + delete m_mapObjects[nTypeIndex]; + } + m_mapObjects.Purge(); +} + + +//---------------------------------------------------------------------------- +// Purpose: Returns the type cache for the specified type ID, returning NULL +// if the cache didn't previously exist. +//---------------------------------------------------------------------------- +CSharedObjectTypeCache *CSharedObjectCache::FindBaseTypeCache( int nClassID ) const +{ + int nIndex = m_mapObjects.Find( nClassID ); + CSharedObjectTypeCache *pTypeCache = NULL; + if( m_mapObjects.IsValidIndex( nIndex ) ) + { + pTypeCache = m_mapObjects[nIndex]; + } + return pTypeCache; +} + +//---------------------------------------------------------------------------- +// Purpose: Returns the type cache for the specified type ID, creating a new +// cache and returning it if one didn't previously exist. Never intended +// to return NULL. +//---------------------------------------------------------------------------- +CSharedObjectTypeCache *CSharedObjectCache::CreateBaseTypeCache( int nClassID ) +{ + //see if we already have an existing one + CSharedObjectTypeCache *pCache = FindBaseTypeCache( nClassID ); + if( pCache ) + return pCache; + + //nope, need to create one + CSharedObjectTypeCache* pTypeCache = AllocateTypeCache( nClassID ); + m_mapObjects.Insert( nClassID, pTypeCache ); +#if 0 + // Kyle says: this is the newer way of managing caches on Dota but we haven't + // brought any of it over yet + m_CacheObjects.AddToTail( pTypeCache ); + //sort this cache for faster access + std::sort( m_CacheObjects.begin(), m_CacheObjects.end(), SortCacheByTypeID ); +#endif + return pTypeCache; +} + + +//---------------------------------------------------------------------------- +// Purpose: Adds a shared object to the cache. +//---------------------------------------------------------------------------- +bool CSharedObjectCache::AddObject( CSharedObject *pSharedObject ) +{ + CSharedObjectTypeCache *pTypeCache = CreateBaseTypeCache( pSharedObject->GetTypeID() ); + if ( !pTypeCache->AddObject( pSharedObject ) ) + return false; + + MarkDirty(); + return true; +} + + +//---------------------------------------------------------------------------- +// Purpose: Removes the object matching the one passed in from this cache, +// without destroying the actual object. +//---------------------------------------------------------------------------- +CSharedObject *CSharedObjectCache::RemoveObject( const CSharedObject & soIndex ) +{ + CSharedObjectTypeCache *pTypeCache = FindBaseTypeCache( soIndex.GetTypeID() ); + if( !pTypeCache ) + return NULL; + + MarkDirty(); + + return pTypeCache->RemoveObject( soIndex ); +} + + +//---------------------------------------------------------------------------- +// Purpose: Empties the object lists but doesn't delete any of the objects +//---------------------------------------------------------------------------- +void CSharedObjectCache::RemoveAllObjectsWithoutDeleting() +{ + FOR_EACH_MAP_FAST( m_mapObjects, nType ) + { + m_mapObjects[nType]->RemoveAllObjectsWithoutDeleting(); + } + MarkDirty(); +} + + +//---------------------------------------------------------------------------- +// Purpose: Searches the object list for an object that matches the provided +// object on its index fields. +//---------------------------------------------------------------------------- +CSharedObject *CSharedObjectCache::FindSharedObject( const CSharedObject & soIndex ) +{ + CSharedObjectTypeCache *pTypeCache = FindBaseTypeCache( soIndex.GetTypeID() ); + if( pTypeCache ) + return pTypeCache->FindSharedObject( soIndex ); + else + return NULL; +} + +//---------------------------------------------------------------------------- +// Purpose: Dumps all the objects in the type cache +//---------------------------------------------------------------------------- +void CSharedObjectCache::Dump() const +{ + EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SharedObjectCache for %s (%d types):\n", GetOwner().Render(), m_mapObjects.Count() ); + FOR_EACH_MAP( m_mapObjects, nTypeIndex ) + { + m_mapObjects[nTypeIndex]->Dump(); + } +} + + +//---------------------------------------------------------------------------- +// Purpose: Claims all the memory for the cache +//---------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +void CSharedObjectCache::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + + ValidateObj( m_mapObjects ); + FOR_EACH_MAP( m_mapObjects, nTypeIndex ) + { + m_mapObjects[nTypeIndex]->Validate( validator, "m_mapObjects[n]" ); + } +} +#endif + + +} // namespace GCSDK |