You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
13 KiB
384 lines
13 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//===========================================================================// |
|
|
|
#ifndef DATACACHE_H |
|
#define DATACACHE_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "datamanager.h" |
|
#include "utlhash.h" |
|
#include "mempool.h" |
|
#include "tier0/tslist.h" |
|
#include "datacache_common.h" |
|
#include "tier3/tier3.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Data Cache class declarations |
|
// |
|
//----------------------------------------------------------------------------- |
|
class CDataCache; |
|
class CDataCacheSection; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
struct DataCacheItemData_t |
|
{ |
|
const void * pItemData; |
|
unsigned size; |
|
DataCacheClientID_t clientId; |
|
CDataCacheSection * pSection; |
|
}; |
|
|
|
//------------------------------------- |
|
|
|
#define DC_NO_NEXT_LOCKED ((DataCacheItem_t *)-1) |
|
#define DC_MAX_THREADS_FRAMELOCKED 4 |
|
|
|
struct DataCacheItem_t : DataCacheItemData_t |
|
{ |
|
DataCacheItem_t( const DataCacheItemData_t &data ) |
|
: DataCacheItemData_t( data ), |
|
hLRU( INVALID_MEMHANDLE ) |
|
{ |
|
memset( pNextFrameLocked, 0xff, sizeof(pNextFrameLocked) ); |
|
} |
|
|
|
static DataCacheItem_t *CreateResource( const DataCacheItemData_t &data ) { return new DataCacheItem_t(data); } |
|
static unsigned int EstimatedSize( const DataCacheItemData_t &data ) { return data.size; } |
|
void DestroyResource(); |
|
DataCacheItem_t *GetData() { return this; } |
|
unsigned int Size() { return size; } |
|
|
|
memhandle_t hLRU; |
|
DataCacheItem_t *pNextFrameLocked[DC_MAX_THREADS_FRAMELOCKED]; |
|
|
|
DECLARE_FIXEDSIZE_ALLOCATOR_MT(DataCacheItem_t); |
|
}; |
|
|
|
//------------------------------------- |
|
|
|
typedef CDataManager<DataCacheItem_t, DataCacheItemData_t, DataCacheItem_t *, CThreadFastMutex> CDataCacheLRU; |
|
|
|
//----------------------------------------------------------------------------- |
|
// CDataCacheSection |
|
// |
|
// Purpose: Implements a sub-section of the global cache. Subsections are |
|
// areas of the cache with thier own memory constraints and common |
|
// management. |
|
//----------------------------------------------------------------------------- |
|
class CDataCacheSection : public IDataCacheSection |
|
{ |
|
public: |
|
CDataCacheSection( CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName ); |
|
~CDataCacheSection(); |
|
|
|
IDataCache *GetSharedCache(); |
|
IDataCacheClient *GetClient() { return m_pClient; } |
|
const char *GetName() { return szName; } |
|
|
|
//-------------------------------------------------------- |
|
// IDataCacheSection methods |
|
//-------------------------------------------------------- |
|
virtual void SetLimits( const DataCacheLimits_t &limits ); |
|
const DataCacheLimits_t &GetLimits(); |
|
virtual void SetOptions( unsigned options ); |
|
virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ); |
|
|
|
inline unsigned GetNumBytes() { return m_status.nBytes; } |
|
inline unsigned GetNumItems() { return m_status.nItems; } |
|
|
|
inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; } |
|
inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; } |
|
|
|
inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; } |
|
inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; } |
|
|
|
virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle ); |
|
virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle ); |
|
virtual DataCacheHandle_t Find( DataCacheClientID_t clientId ); |
|
virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData = NULL, unsigned *pItemSize = NULL, bool bNotify = false ); |
|
virtual bool IsPresent( DataCacheHandle_t handle ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual void *Lock( DataCacheHandle_t handle ); |
|
virtual int Unlock( DataCacheHandle_t handle ); |
|
virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false ); |
|
virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false ); |
|
virtual void LockMutex(); |
|
virtual void UnlockMutex(); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual int BeginFrameLocking(); |
|
virtual bool IsFrameLocking(); |
|
virtual void *FrameLock( DataCacheHandle_t handle ); |
|
virtual int EndFrameLocking(); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual int GetLockCount( DataCacheHandle_t handle ); |
|
virtual int BreakLock( DataCacheHandle_t handle ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual int *GetFrameUnlockCounterPtr(); |
|
int m_nFrameUnlockCounter; |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual bool Touch( DataCacheHandle_t handle ); |
|
virtual bool Age( DataCacheHandle_t handle ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ); |
|
virtual unsigned Purge( unsigned nBytes ); |
|
unsigned PurgeItems( unsigned nItems ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT ); |
|
|
|
virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize ); |
|
|
|
private: |
|
friend void DataCacheItem_t::DestroyResource(); |
|
|
|
virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem ) {} |
|
virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId ); |
|
virtual void OnRemove( DataCacheClientID_t clientId ) {} |
|
|
|
memhandle_t GetFirstUnlockedItem(); |
|
memhandle_t GetFirstLockedItem(); |
|
memhandle_t GetNextItem( memhandle_t ); |
|
DataCacheItem_t *AccessItem( memhandle_t hCurrent ); |
|
bool DiscardItem( memhandle_t hItem, DataCacheNotificationType_t type ); |
|
bool DiscardItemData( DataCacheItem_t *pItem, DataCacheNotificationType_t type ); |
|
void NoteAdd( int size ); |
|
void NoteRemove( int size ); |
|
void NoteLock( int size ); |
|
void NoteUnlock( int size ); |
|
void NoteSizeChanged( int oldSize, int newSize ); |
|
|
|
struct FrameLock_t |
|
{ |
|
//$ WARNING: This needs a TSLNodeBase_t as the first item in here. |
|
TSLNodeBase_t base; |
|
int m_iLock; |
|
DataCacheItem_t *m_pFirst; |
|
int m_iThread; |
|
}; |
|
typedef CThreadLocal<FrameLock_t *> CThreadFrameLock; |
|
|
|
CDataCacheLRU & m_LRU; |
|
CThreadFrameLock m_ThreadFrameLock; |
|
DataCacheStatus_t m_status; |
|
DataCacheLimits_t m_limits; |
|
IDataCacheClient * m_pClient; |
|
unsigned m_options; |
|
CDataCache * m_pSharedCache; |
|
char szName[DC_MAX_CLIENT_NAME + 1]; |
|
CTSSimpleList<FrameLock_t> m_FreeFrameLocks; |
|
|
|
protected: |
|
CThreadFastMutex & m_mutex; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CDataCacheSectionFastFind |
|
// |
|
// Purpose: A section variant that allows clients to have cache support tracking |
|
// efficiently (a true cache, not just an LRU) |
|
//----------------------------------------------------------------------------- |
|
class CDataCacheSectionFastFind : public CDataCacheSection |
|
{ |
|
public: |
|
CDataCacheSectionFastFind(CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName ) |
|
: CDataCacheSection( pSharedCache, pClient, pszName ) |
|
{ |
|
m_Handles.Init( 1024 ); |
|
} |
|
|
|
private: |
|
virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId ); |
|
virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem ); |
|
virtual void OnRemove( DataCacheClientID_t clientId ); |
|
|
|
CUtlHashFast<DataCacheHandle_t> m_Handles; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CDataCache |
|
// |
|
// Purpose: The global shared cache. Manages sections and overall budgets. |
|
// |
|
//----------------------------------------------------------------------------- |
|
class CDataCache : public CTier3AppSystem< IDataCache > |
|
{ |
|
typedef CTier3AppSystem< IDataCache > BaseClass; |
|
|
|
public: |
|
CDataCache(); |
|
|
|
//-------------------------------------------------------- |
|
// IAppSystem methods |
|
//-------------------------------------------------------- |
|
virtual bool Connect( CreateInterfaceFn factory ); |
|
virtual void Disconnect(); |
|
virtual void *QueryInterface( const char *pInterfaceName ); |
|
virtual InitReturnVal_t Init(); |
|
virtual void Shutdown(); |
|
|
|
//-------------------------------------------------------- |
|
// IDataCache methods |
|
//-------------------------------------------------------- |
|
|
|
virtual void SetSize( int nMaxBytes ); |
|
virtual void SetOptions( unsigned options ); |
|
virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits ); |
|
virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ); |
|
virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true ); |
|
virtual IDataCacheSection *FindSection( const char *pszClientName ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
void EnsureCapacity( unsigned nBytes ); |
|
virtual unsigned Purge( unsigned nBytes ); |
|
virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL ); |
|
|
|
//-------------------------------------------------------- |
|
|
|
inline unsigned GetNumBytes() { return m_status.nBytes; } |
|
inline unsigned GetNumItems() { return m_status.nItems; } |
|
|
|
inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; } |
|
inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; } |
|
|
|
inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; } |
|
inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; } |
|
|
|
private: |
|
//----------------------------------------------------- |
|
|
|
friend class CDataCacheSection; |
|
|
|
//----------------------------------------------------- |
|
|
|
DataCacheItem_t *AccessItem( memhandle_t hCurrent ); |
|
|
|
bool IsInFlush() { return m_bInFlush; } |
|
int FindSectionIndex( const char *pszSection ); |
|
|
|
// Utilities used by the data cache report |
|
void OutputItemReport( memhandle_t hItem ); |
|
static bool SortMemhandlesBySizeLessFunc( const memhandle_t& lhs, const memhandle_t& rhs ); |
|
|
|
//----------------------------------------------------- |
|
|
|
CDataCacheLRU m_LRU; |
|
DataCacheStatus_t m_status; |
|
CUtlVector<CDataCacheSection *> m_Sections; |
|
bool m_bInFlush; |
|
CThreadFastMutex & m_mutex; |
|
}; |
|
|
|
//--------------------------------------------------------- |
|
|
|
extern CDataCache g_DataCache; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
inline DataCacheItem_t *CDataCache::AccessItem( memhandle_t hCurrent ) |
|
{ |
|
return m_LRU.GetResource_NoLockNoLRUTouch( hCurrent ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
inline IDataCache *CDataCacheSection::GetSharedCache() |
|
{ |
|
return m_pSharedCache; |
|
} |
|
|
|
inline DataCacheItem_t *CDataCacheSection::AccessItem( memhandle_t hCurrent ) |
|
{ |
|
return m_pSharedCache->AccessItem( hCurrent ); |
|
} |
|
|
|
// Note: if status updates are moved out of a mutexed section, will need to change these to use interlocked instructions |
|
|
|
inline void CDataCacheSection::NoteSizeChanged( int oldSize, int newSize ) |
|
{ |
|
int nBytes = ( newSize - oldSize ); |
|
|
|
m_status.nBytes += nBytes; |
|
m_status.nBytesLocked += nBytes; |
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, nBytes ); |
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, nBytes ); |
|
} |
|
|
|
inline void CDataCacheSection::NoteAdd( int size ) |
|
{ |
|
m_status.nBytes += size; |
|
m_status.nItems++; |
|
|
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, size ); |
|
ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItems ); |
|
} |
|
|
|
inline void CDataCacheSection::NoteRemove( int size ) |
|
{ |
|
m_status.nBytes -= size; |
|
m_status.nItems--; |
|
|
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, -size ); |
|
ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItems ); |
|
} |
|
|
|
inline void CDataCacheSection::NoteLock( int size ) |
|
{ |
|
m_status.nBytesLocked += size; |
|
m_status.nItemsLocked++; |
|
|
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, size ); |
|
ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItemsLocked ); |
|
} |
|
|
|
inline void CDataCacheSection::NoteUnlock( int size ) |
|
{ |
|
m_status.nBytesLocked -= size; |
|
m_status.nItemsLocked--; |
|
|
|
ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, -size ); |
|
ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItemsLocked ); |
|
|
|
// something has been unlocked, assume cached pointers are now invalid |
|
m_nFrameUnlockCounter++; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#endif // DATACACHE_H
|