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.
545 lines
18 KiB
545 lines
18 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef IDATACACHE_H |
|
#define IDATACACHE_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
|
|
#include "tier0/dbg.h" |
|
#include "appframework/IAppSystem.h" |
|
|
|
class IDataCache; |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Shared Data Cache API |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
#define DATACACHE_INTERFACE_VERSION "VDataCache003" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Support types and enums |
|
//----------------------------------------------------------------------------- |
|
|
|
//--------------------------------------------------------- |
|
// Unique (per section) identifier for a cache item defined by client |
|
//--------------------------------------------------------- |
|
typedef uintp DataCacheClientID_t; |
|
|
|
|
|
//--------------------------------------------------------- |
|
// Cache-defined handle for a cache item |
|
//--------------------------------------------------------- |
|
FORWARD_DECLARE_HANDLE( memhandle_t ); |
|
typedef memhandle_t DataCacheHandle_t; |
|
#define DC_INVALID_HANDLE ((DataCacheHandle_t)0) |
|
|
|
//--------------------------------------------------------- |
|
// Cache Limits |
|
//--------------------------------------------------------- |
|
struct DataCacheLimits_t |
|
{ |
|
DataCacheLimits_t( unsigned _nMaxBytes = (unsigned)-1, unsigned _nMaxItems = (unsigned)-1, unsigned _nMinBytes = 0, unsigned _nMinItems = 0 ) |
|
: nMaxBytes(_nMaxBytes), |
|
nMaxItems(_nMaxItems), |
|
nMinBytes(_nMinBytes), |
|
nMinItems(_nMinItems) |
|
{ |
|
} |
|
|
|
// Maximum levels permitted |
|
unsigned nMaxBytes; |
|
unsigned nMaxItems; |
|
|
|
// Minimum levels permitted |
|
unsigned nMinBytes; |
|
unsigned nMinItems; |
|
}; |
|
|
|
//--------------------------------------------------------- |
|
// Cache status |
|
//--------------------------------------------------------- |
|
struct DataCacheStatus_t |
|
{ |
|
// Current state of the cache |
|
unsigned nBytes; |
|
unsigned nItems; |
|
|
|
unsigned nBytesLocked; |
|
unsigned nItemsLocked; |
|
|
|
// Diagnostics |
|
unsigned nFindRequests; |
|
unsigned nFindHits; |
|
}; |
|
|
|
//--------------------------------------------------------- |
|
// Cache options |
|
//--------------------------------------------------------- |
|
enum DataCacheOptions_t |
|
{ |
|
DC_TRACE_ACTIVITY = (1 << 0), |
|
DC_FORCE_RELOCATE = (1 << 1), |
|
DC_ALWAYS_MISS = (1 << 2), |
|
DC_VALIDATE = (1 << 3), |
|
}; |
|
|
|
|
|
//--------------------------------------------------------- |
|
// Cache report types |
|
//--------------------------------------------------------- |
|
enum DataCacheReportType_t |
|
{ |
|
DC_SUMMARY_REPORT, |
|
DC_DETAIL_REPORT, |
|
DC_DETAIL_REPORT_LRU, |
|
}; |
|
|
|
|
|
//--------------------------------------------------------- |
|
// Notifications to section clients on cache events |
|
//--------------------------------------------------------- |
|
enum DataCacheNotificationType_t |
|
{ |
|
// Used internally to prohibit notifications |
|
DC_NONE, |
|
|
|
// Item is falling off the LRU and should be deleted, return false to block |
|
DC_AGE_DISCARD, |
|
|
|
// Item is being explicitly flushed and should be deleted, return false to block |
|
DC_FLUSH_DISCARD, |
|
|
|
// Item is being explicitly removed and should be deleted. Failure is not an option |
|
DC_REMOVED, |
|
|
|
// Cache is requesting item be relocated for debugging purposes |
|
DC_RELOCATE, |
|
|
|
// Item info should be output to console, return false to accept default handling |
|
DC_PRINT_INF0, |
|
}; |
|
|
|
//------------------------------------- |
|
|
|
struct DataCacheNotification_t |
|
{ |
|
DataCacheNotificationType_t type; |
|
const char * pszSectionName; |
|
DataCacheClientID_t clientId; |
|
const void * pItemData; |
|
unsigned nItemSize; |
|
}; |
|
|
|
//--------------------------------------------------------- |
|
|
|
const int DC_MAX_CLIENT_NAME = 15; |
|
const int DC_MAX_ITEM_NAME = 511; |
|
|
|
//--------------------------------------------------------- |
|
// Result codes |
|
//--------------------------------------------------------- |
|
enum DataCacheRemoveResult_t |
|
{ |
|
DC_OK, |
|
DC_NOT_FOUND, |
|
DC_LOCKED, |
|
}; |
|
|
|
//--------------------------------------------------------- |
|
// Add flags |
|
//--------------------------------------------------------- |
|
enum DataCacheAddFlags_t |
|
{ |
|
DCAF_LOCK = ( 1 << 0 ), |
|
DCAF_DEFAULT = 0, |
|
}; |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// IDataCacheSection |
|
// |
|
// Purpose: Implements a sub-section of the global cache. Subsections are |
|
// areas of the cache with thier own memory constraints and common |
|
// management. |
|
//----------------------------------------------------------------------------- |
|
abstract_class IDataCacheSection |
|
{ |
|
public: |
|
//-------------------------------------------------------- |
|
|
|
virtual IDataCache *GetSharedCache() = 0; |
|
virtual const char *GetName() = 0; |
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Controls cache size & options |
|
//-------------------------------------------------------- |
|
virtual void SetLimits( const DataCacheLimits_t &limits ) = 0; |
|
virtual void SetOptions( unsigned options ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Get the current state of the section |
|
//-------------------------------------------------------- |
|
virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. |
|
//-------------------------------------------------------- |
|
virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. |
|
//-------------------------------------------------------- |
|
virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle ) = 0; |
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Finds an item in the cache, returns NULL if item is not in cache. Not a cheap operation if section not configured for fast find. |
|
//-------------------------------------------------------- |
|
virtual DataCacheHandle_t Find( DataCacheClientID_t clientId ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Get an item out of the cache and remove it. No callbacks are executed unless explicity specified. |
|
//-------------------------------------------------------- |
|
virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData, unsigned *pItemSize = NULL, bool bNotify = false ) = 0; |
|
DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, bool bNotify = false ) { return Remove( handle, NULL, NULL, bNotify ); } |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Returns if the data is currently in memory, but does *not* change its location in the LRU |
|
//-------------------------------------------------------- |
|
virtual bool IsPresent( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Lock an item in the cache, returns NULL if item is not in the cache. |
|
//-------------------------------------------------------- |
|
virtual void *Lock( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Unlock a previous lock. |
|
//-------------------------------------------------------- |
|
virtual int Unlock( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Get an item without locking it, returns NULL if item is not in the cache. Use with care! |
|
//-------------------------------------------------------- |
|
virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false ) = 0; |
|
virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false ) = 0; |
|
|
|
//-------------------------------------------------------- |
|
// Purpose: "Frame locking" (not game frame). A crude way to manage locks over relatively |
|
// short periods. Does not affect normal locks/unlocks |
|
//-------------------------------------------------------- |
|
virtual int BeginFrameLocking() = 0; |
|
virtual bool IsFrameLocking() = 0; |
|
virtual void *FrameLock( DataCacheHandle_t handle ) = 0; |
|
virtual int EndFrameLocking() = 0; |
|
virtual int *GetFrameUnlockCounterPtr() = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Lock management, not for the feint of heart |
|
//-------------------------------------------------------- |
|
virtual int GetLockCount( DataCacheHandle_t handle ) = 0; |
|
virtual int BreakLock( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Explicitly mark an item as "recently used" |
|
//-------------------------------------------------------- |
|
virtual bool Touch( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Explicitly mark an item as "least recently used". |
|
//-------------------------------------------------------- |
|
virtual bool Age( DataCacheHandle_t handle ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified |
|
//-------------------------------------------------------- |
|
virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed |
|
//-------------------------------------------------------- |
|
virtual unsigned Purge( unsigned nBytes ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Output the state of the section |
|
//-------------------------------------------------------- |
|
virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT ) = 0; |
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Updates the size used by a specific item (locks the item, kicks |
|
// other items out to make room as necessary, unlocks the item). |
|
//-------------------------------------------------------- |
|
virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Access to the mutex. More explicit control during get-then-lock sequences |
|
// to ensure object stays valid during "then" |
|
//-------------------------------------------------------- |
|
virtual void LockMutex() = 0; |
|
virtual void UnlockMutex() = 0; |
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache. |
|
//-------------------------------------------------------- |
|
virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle ) = 0; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// IDataCacheClient |
|
// |
|
// Purpose: Connection between the cache and the owner of a cache section |
|
// |
|
//----------------------------------------------------------------------------- |
|
abstract_class IDataCacheClient |
|
{ |
|
public: |
|
//-------------------------------------------------------- |
|
// |
|
//-------------------------------------------------------- |
|
virtual bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// |
|
//-------------------------------------------------------- |
|
virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) = 0; |
|
}; |
|
|
|
//------------------------------------- |
|
|
|
class CDefaultDataCacheClient : public IDataCacheClient |
|
{ |
|
public: |
|
virtual bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) |
|
{ |
|
switch ( notification.type ) |
|
{ |
|
case DC_AGE_DISCARD: |
|
case DC_FLUSH_DISCARD: |
|
case DC_REMOVED: |
|
default: |
|
Assert ( 0 ); |
|
return false; |
|
} |
|
return false; |
|
} |
|
|
|
virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) |
|
{ |
|
return false; |
|
} |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// IDataCache |
|
// |
|
// Purpose: The global shared cache. Manages sections and overall budgets. |
|
// |
|
//----------------------------------------------------------------------------- |
|
abstract_class IDataCache : public IAppSystem |
|
{ |
|
public: |
|
//-------------------------------------------------------- |
|
// Purpose: Controls cache size. |
|
//-------------------------------------------------------- |
|
virtual void SetSize( int nMaxBytes ) = 0; |
|
virtual void SetOptions( unsigned options ) = 0; |
|
virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Get the current state of the cache |
|
//-------------------------------------------------------- |
|
virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Add a section to the cache |
|
//-------------------------------------------------------- |
|
virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Remove a section from the cache |
|
//-------------------------------------------------------- |
|
virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true ) = 0; |
|
void RemoveSection( IDataCacheSection *pSection, bool bCallFlush = true ) { if ( pSection) RemoveSection( pSection->GetName() ); } |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Find a section of the cache |
|
//-------------------------------------------------------- |
|
virtual IDataCacheSection *FindSection( const char *pszClientName ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed |
|
//-------------------------------------------------------- |
|
virtual unsigned Purge( unsigned nBytes ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified |
|
//-------------------------------------------------------- |
|
virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0; |
|
|
|
|
|
//-------------------------------------------------------- |
|
// Purpose: Output the state of the cache |
|
//-------------------------------------------------------- |
|
virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL ) = 0; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Helper class to support usage pattern similar to CDataManager |
|
//----------------------------------------------------------------------------- |
|
|
|
template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE * > |
|
class CManagedDataCacheClient : public CDefaultDataCacheClient |
|
{ |
|
public: |
|
typedef CManagedDataCacheClient<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE> CCacheClientBaseClass; |
|
|
|
CManagedDataCacheClient() |
|
: m_pCache( NULL ) |
|
{ |
|
} |
|
|
|
void Init( IDataCache *pSharedCache, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ) |
|
{ |
|
if ( !m_pCache ) |
|
{ |
|
m_pCache = pSharedCache->AddSection( this, pszSectionName, limits, bSupportFastFind ); |
|
} |
|
} |
|
|
|
void Shutdown() |
|
{ |
|
if ( m_pCache ) |
|
{ |
|
m_pCache->GetSharedCache()->RemoveSection( m_pCache ); |
|
m_pCache = NULL; |
|
} |
|
} |
|
|
|
LOCK_TYPE CacheGet( DataCacheHandle_t handle, bool bFrameLock = true ) |
|
{ |
|
return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Get( handle, bFrameLock ))->GetData()); |
|
} |
|
|
|
LOCK_TYPE CacheGetNoTouch( DataCacheHandle_t handle ) |
|
{ |
|
return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->GetNoTouch( handle ))->GetData()); |
|
} |
|
|
|
LOCK_TYPE CacheLock( DataCacheHandle_t handle ) |
|
{ |
|
return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Lock( handle ))->GetData()); |
|
} |
|
|
|
int CacheUnlock( DataCacheHandle_t handle ) |
|
{ |
|
return m_pCache->Unlock( handle ); |
|
} |
|
|
|
void CacheTouch( DataCacheHandle_t handle ) |
|
{ |
|
m_pCache->Touch( handle ); |
|
} |
|
|
|
void CacheRemove( DataCacheHandle_t handle, bool bNotify = true ) |
|
{ |
|
m_pCache->Remove( handle, bNotify ); |
|
} |
|
|
|
void CacheFlush() |
|
{ |
|
m_pCache->Flush(); |
|
} |
|
|
|
DataCacheHandle_t CacheCreate( const CREATE_PARAMS &createParams, unsigned flags = DCAF_DEFAULT ) |
|
{ |
|
m_pCache->EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); |
|
STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); |
|
DataCacheHandle_t handle; |
|
m_pCache->AddEx( (DataCacheClientID_t)(uintp)pStore, pStore, pStore->Size(), flags, &handle); |
|
return handle; |
|
} |
|
|
|
void CacheLockMutex() |
|
{ |
|
m_pCache->LockMutex(); |
|
} |
|
|
|
void CacheUnlockMutex() |
|
{ |
|
m_pCache->UnlockMutex(); |
|
} |
|
|
|
bool HandleCacheNotification( const DataCacheNotification_t ¬ification ) |
|
{ |
|
switch ( notification.type ) |
|
{ |
|
case DC_AGE_DISCARD: |
|
case DC_FLUSH_DISCARD: |
|
case DC_REMOVED: |
|
{ |
|
STORAGE_TYPE *p = (STORAGE_TYPE *)notification.clientId; |
|
p->DestroyResource(); |
|
} |
|
return true; |
|
default: |
|
return CDefaultDataCacheClient::HandleCacheNotification( notification ); |
|
} |
|
} |
|
|
|
|
|
protected: |
|
|
|
~CManagedDataCacheClient() |
|
{ |
|
Shutdown(); |
|
} |
|
|
|
IDataCacheSection *GetCacheSection() |
|
{ |
|
return m_pCache; |
|
} |
|
|
|
private: |
|
IDataCacheSection *m_pCache; |
|
|
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#endif // IDataCache
|
|
|