|
|
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#ifndef IDATACACHE_H
#define IDATACACHE_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "appframework/iappsystem.h"
#include "tier3/tier3.h"
class IDataCache;
//-----------------------------------------------------------------------------
//
// Shared Data Cache API
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 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), DC_NO_USER_FORCE_FLUSH = (1 << 4) };
//---------------------------------------------------------
// Cache report types
//---------------------------------------------------------
enum DataCacheReportType_t { DC_SUMMARY_REPORT, DC_DETAIL_REPORT, DC_DETAIL_REPORT_LRU, DC_DETAIL_REPORT_VXCONSOLE, };
//---------------------------------------------------------
// 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 ~IDataCacheSection() { }; //--------------------------------------------------------
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;
virtual unsigned int GetOptions() = 0;
// Batch oriented get/lock
virtual void GetAndLockMultiple( void **ppData, int nCount, DataCacheHandle_t *pHandles ) = 0; };
//-----------------------------------------------------------------------------
// IDataCacheClient
//
// Purpose: Connection between the cache and the owner of a cache section
//
//-----------------------------------------------------------------------------
abstract_class IDataCacheClient { public: virtual ~IDataCacheClient() { }; //--------------------------------------------------------
//
//--------------------------------------------------------
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 ~CDefaultDataCacheClient() { }; 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; case DC_NONE: case DC_RELOCATE: case DC_PRINT_INF0: 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;
virtual int GetSectionCount() = 0; virtual const char *GetSectionName( int iIndex ) = 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()); }
void CacheGetAndLockMultiple( LOCK_TYPE *pData, int nCount, DataCacheHandle_t *pHandles ) { m_pCache->GetAndLockMultiple( (void**)pData, nCount, pHandles ); for ( int i = 0; i < nCount; ++i ) { STORAGE_TYPE *pTypedData = pData[i]; if ( pTypedData ) { pData[i] = (LOCK_TYPE)( pTypedData->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 ); if ( !pStore ) { return DC_INVALID_HANDLE; } DataCacheHandle_t handle; m_pCache->AddEx( (DataCacheClientID_t)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; } break;
case DC_NONE: case DC_RELOCATE: case DC_PRINT_INF0: break; }
return CDefaultDataCacheClient::HandleCacheNotification( notification ); }
protected:
~CManagedDataCacheClient() { Shutdown(); }
IDataCacheSection *GetCacheSection() { return m_pCache; }
private: IDataCacheSection *m_pCache;
};
//-----------------------------------------------------------------------------
#endif // IDataCache
|