Counter Strike : Global Offensive Source Code
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.

582 lines
19 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #ifndef IDATACACHE_H
  10. #define IDATACACHE_H
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "tier0/platform.h"
  15. #include "tier0/dbg.h"
  16. #include "appframework/iappsystem.h"
  17. #include "tier3/tier3.h"
  18. class IDataCache;
  19. //-----------------------------------------------------------------------------
  20. //
  21. // Shared Data Cache API
  22. //
  23. //-----------------------------------------------------------------------------
  24. //-----------------------------------------------------------------------------
  25. // Support types and enums
  26. //-----------------------------------------------------------------------------
  27. //---------------------------------------------------------
  28. // Unique (per section) identifier for a cache item defined by client
  29. //---------------------------------------------------------
  30. typedef uintp DataCacheClientID_t;
  31. //---------------------------------------------------------
  32. // Cache-defined handle for a cache item
  33. //---------------------------------------------------------
  34. FORWARD_DECLARE_HANDLE( memhandle_t );
  35. typedef memhandle_t DataCacheHandle_t;
  36. #define DC_INVALID_HANDLE ((DataCacheHandle_t)0)
  37. //---------------------------------------------------------
  38. // Cache Limits
  39. //---------------------------------------------------------
  40. struct DataCacheLimits_t
  41. {
  42. DataCacheLimits_t( unsigned _nMaxBytes = (unsigned)-1, unsigned _nMaxItems = (unsigned)-1, unsigned _nMinBytes = 0, unsigned _nMinItems = 0 )
  43. : nMaxBytes(_nMaxBytes),
  44. nMaxItems(_nMaxItems),
  45. nMinBytes(_nMinBytes),
  46. nMinItems(_nMinItems)
  47. {
  48. }
  49. // Maximum levels permitted
  50. unsigned nMaxBytes;
  51. unsigned nMaxItems;
  52. // Minimum levels permitted
  53. unsigned nMinBytes;
  54. unsigned nMinItems;
  55. };
  56. //---------------------------------------------------------
  57. // Cache status
  58. //---------------------------------------------------------
  59. struct DataCacheStatus_t
  60. {
  61. // Current state of the cache
  62. unsigned nBytes;
  63. unsigned nItems;
  64. unsigned nBytesLocked;
  65. unsigned nItemsLocked;
  66. // Diagnostics
  67. unsigned nFindRequests;
  68. unsigned nFindHits;
  69. };
  70. //---------------------------------------------------------
  71. // Cache options
  72. //---------------------------------------------------------
  73. enum DataCacheOptions_t
  74. {
  75. DC_TRACE_ACTIVITY = (1 << 0),
  76. DC_FORCE_RELOCATE = (1 << 1),
  77. DC_ALWAYS_MISS = (1 << 2),
  78. DC_VALIDATE = (1 << 3),
  79. DC_NO_USER_FORCE_FLUSH = (1 << 4)
  80. };
  81. //---------------------------------------------------------
  82. // Cache report types
  83. //---------------------------------------------------------
  84. enum DataCacheReportType_t
  85. {
  86. DC_SUMMARY_REPORT,
  87. DC_DETAIL_REPORT,
  88. DC_DETAIL_REPORT_LRU,
  89. DC_DETAIL_REPORT_VXCONSOLE,
  90. };
  91. //---------------------------------------------------------
  92. // Notifications to section clients on cache events
  93. //---------------------------------------------------------
  94. enum DataCacheNotificationType_t
  95. {
  96. // Used internally to prohibit notifications
  97. DC_NONE,
  98. // Item is falling off the LRU and should be deleted, return false to block
  99. DC_AGE_DISCARD,
  100. // Item is being explicitly flushed and should be deleted, return false to block
  101. DC_FLUSH_DISCARD,
  102. // Item is being explicitly removed and should be deleted. Failure is not an option
  103. DC_REMOVED,
  104. // Cache is requesting item be relocated for debugging purposes
  105. DC_RELOCATE,
  106. // Item info should be output to console, return false to accept default handling
  107. DC_PRINT_INF0,
  108. };
  109. //-------------------------------------
  110. struct DataCacheNotification_t
  111. {
  112. DataCacheNotificationType_t type;
  113. const char * pszSectionName;
  114. DataCacheClientID_t clientId;
  115. const void * pItemData;
  116. unsigned nItemSize;
  117. };
  118. //---------------------------------------------------------
  119. const int DC_MAX_CLIENT_NAME = 15;
  120. const int DC_MAX_ITEM_NAME = 511;
  121. //---------------------------------------------------------
  122. // Result codes
  123. //---------------------------------------------------------
  124. enum DataCacheRemoveResult_t
  125. {
  126. DC_OK,
  127. DC_NOT_FOUND,
  128. DC_LOCKED,
  129. };
  130. //---------------------------------------------------------
  131. // Add flags
  132. //---------------------------------------------------------
  133. enum DataCacheAddFlags_t
  134. {
  135. DCAF_LOCK = ( 1 << 0 ),
  136. DCAF_DEFAULT = 0,
  137. };
  138. //-----------------------------------------------------------------------------
  139. // IDataCacheSection
  140. //
  141. // Purpose: Implements a sub-section of the global cache. Subsections are
  142. // areas of the cache with thier own memory constraints and common
  143. // management.
  144. //-----------------------------------------------------------------------------
  145. abstract_class IDataCacheSection
  146. {
  147. public:
  148. virtual ~IDataCacheSection() { };
  149. //--------------------------------------------------------
  150. virtual IDataCache *GetSharedCache() = 0;
  151. virtual const char *GetName() = 0;
  152. //--------------------------------------------------------
  153. // Purpose: Controls cache size & options
  154. //--------------------------------------------------------
  155. virtual void SetLimits( const DataCacheLimits_t &limits ) = 0;
  156. virtual void SetOptions( unsigned options ) = 0;
  157. //--------------------------------------------------------
  158. // Purpose: Get the current state of the section
  159. //--------------------------------------------------------
  160. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0;
  161. //--------------------------------------------------------
  162. // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache.
  163. //--------------------------------------------------------
  164. virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 ) = 0;
  165. //--------------------------------------------------------
  166. // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache.
  167. //--------------------------------------------------------
  168. virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle ) = 0;
  169. //--------------------------------------------------------
  170. // 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.
  171. //--------------------------------------------------------
  172. virtual DataCacheHandle_t Find( DataCacheClientID_t clientId ) = 0;
  173. //--------------------------------------------------------
  174. // Purpose: Get an item out of the cache and remove it. No callbacks are executed unless explicity specified.
  175. //--------------------------------------------------------
  176. virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData, unsigned *pItemSize = NULL, bool bNotify = false ) = 0;
  177. DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, bool bNotify = false ) { return Remove( handle, NULL, NULL, bNotify ); }
  178. //--------------------------------------------------------
  179. // Purpose: Returns if the data is currently in memory, but does *not* change its location in the LRU
  180. //--------------------------------------------------------
  181. virtual bool IsPresent( DataCacheHandle_t handle ) = 0;
  182. //--------------------------------------------------------
  183. // Purpose: Lock an item in the cache, returns NULL if item is not in the cache.
  184. //--------------------------------------------------------
  185. virtual void *Lock( DataCacheHandle_t handle ) = 0;
  186. //--------------------------------------------------------
  187. // Purpose: Unlock a previous lock.
  188. //--------------------------------------------------------
  189. virtual int Unlock( DataCacheHandle_t handle ) = 0;
  190. //--------------------------------------------------------
  191. // Purpose: Get an item without locking it, returns NULL if item is not in the cache. Use with care!
  192. //--------------------------------------------------------
  193. virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false ) = 0;
  194. virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false ) = 0;
  195. //--------------------------------------------------------
  196. // Purpose: "Frame locking" (not game frame). A crude way to manage locks over relatively
  197. // short periods. Does not affect normal locks/unlocks
  198. //--------------------------------------------------------
  199. virtual int BeginFrameLocking() = 0;
  200. virtual bool IsFrameLocking() = 0;
  201. virtual void *FrameLock( DataCacheHandle_t handle ) = 0;
  202. virtual int EndFrameLocking() = 0;
  203. virtual int *GetFrameUnlockCounterPtr() = 0;
  204. //--------------------------------------------------------
  205. // Purpose: Lock management, not for the feint of heart
  206. //--------------------------------------------------------
  207. virtual int GetLockCount( DataCacheHandle_t handle ) = 0;
  208. virtual int BreakLock( DataCacheHandle_t handle ) = 0;
  209. //--------------------------------------------------------
  210. // Purpose: Explicitly mark an item as "recently used"
  211. //--------------------------------------------------------
  212. virtual bool Touch( DataCacheHandle_t handle ) = 0;
  213. //--------------------------------------------------------
  214. // Purpose: Explicitly mark an item as "least recently used".
  215. //--------------------------------------------------------
  216. virtual bool Age( DataCacheHandle_t handle ) = 0;
  217. //--------------------------------------------------------
  218. // Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified
  219. //--------------------------------------------------------
  220. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0;
  221. //--------------------------------------------------------
  222. // Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed
  223. //--------------------------------------------------------
  224. virtual unsigned Purge( unsigned nBytes ) = 0;
  225. //--------------------------------------------------------
  226. // Purpose: Output the state of the section
  227. //--------------------------------------------------------
  228. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT ) = 0;
  229. //--------------------------------------------------------
  230. // Purpose: Updates the size used by a specific item (locks the item, kicks
  231. // other items out to make room as necessary, unlocks the item).
  232. //--------------------------------------------------------
  233. virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize ) = 0;
  234. //--------------------------------------------------------
  235. // Purpose: Access to the mutex. More explicit control during get-then-lock sequences
  236. // to ensure object stays valid during "then"
  237. //--------------------------------------------------------
  238. virtual void LockMutex() = 0;
  239. virtual void UnlockMutex() = 0;
  240. //--------------------------------------------------------
  241. // Purpose: Add an item to the cache. Purges old items if over budget, returns false if item was already in cache.
  242. //--------------------------------------------------------
  243. virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle ) = 0;
  244. virtual unsigned int GetOptions() = 0;
  245. // Batch oriented get/lock
  246. virtual void GetAndLockMultiple( void **ppData, int nCount, DataCacheHandle_t *pHandles ) = 0;
  247. };
  248. //-----------------------------------------------------------------------------
  249. // IDataCacheClient
  250. //
  251. // Purpose: Connection between the cache and the owner of a cache section
  252. //
  253. //-----------------------------------------------------------------------------
  254. abstract_class IDataCacheClient
  255. {
  256. public:
  257. virtual ~IDataCacheClient() { };
  258. //--------------------------------------------------------
  259. //
  260. //--------------------------------------------------------
  261. virtual bool HandleCacheNotification( const DataCacheNotification_t &notification ) = 0;
  262. //--------------------------------------------------------
  263. //
  264. //--------------------------------------------------------
  265. virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen ) = 0;
  266. };
  267. //-------------------------------------
  268. class CDefaultDataCacheClient : public IDataCacheClient
  269. {
  270. public:
  271. virtual ~CDefaultDataCacheClient() { };
  272. virtual bool HandleCacheNotification( const DataCacheNotification_t &notification )
  273. {
  274. switch ( notification.type )
  275. {
  276. case DC_AGE_DISCARD:
  277. case DC_FLUSH_DISCARD:
  278. case DC_REMOVED:
  279. default:
  280. Assert ( 0 );
  281. return false;
  282. case DC_NONE:
  283. case DC_RELOCATE:
  284. case DC_PRINT_INF0:
  285. return false;
  286. }
  287. return false;
  288. }
  289. virtual bool GetItemName( DataCacheClientID_t clientId, const void *pItem, char *pDest, unsigned nMaxLen )
  290. {
  291. return false;
  292. }
  293. };
  294. //-----------------------------------------------------------------------------
  295. // IDataCache
  296. //
  297. // Purpose: The global shared cache. Manages sections and overall budgets.
  298. //
  299. //-----------------------------------------------------------------------------
  300. abstract_class IDataCache : public IAppSystem
  301. {
  302. public:
  303. //--------------------------------------------------------
  304. // Purpose: Controls cache size.
  305. //--------------------------------------------------------
  306. virtual void SetSize( int nMaxBytes ) = 0;
  307. virtual void SetOptions( unsigned options ) = 0;
  308. virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits ) = 0;
  309. //--------------------------------------------------------
  310. // Purpose: Get the current state of the cache
  311. //--------------------------------------------------------
  312. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL ) = 0;
  313. //--------------------------------------------------------
  314. // Purpose: Add a section to the cache
  315. //--------------------------------------------------------
  316. virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false ) = 0;
  317. //--------------------------------------------------------
  318. // Purpose: Remove a section from the cache
  319. //--------------------------------------------------------
  320. virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true ) = 0;
  321. void RemoveSection( IDataCacheSection *pSection, bool bCallFlush = true ) { if ( pSection) RemoveSection( pSection->GetName() ); }
  322. //--------------------------------------------------------
  323. // Purpose: Find a section of the cache
  324. //--------------------------------------------------------
  325. virtual IDataCacheSection *FindSection( const char *pszClientName ) = 0;
  326. //--------------------------------------------------------
  327. // Purpose: Dump the oldest items to free the specified amount of memory. Returns amount actually freed
  328. //--------------------------------------------------------
  329. virtual unsigned Purge( unsigned nBytes ) = 0;
  330. //--------------------------------------------------------
  331. // Purpose: Empty the cache. Returns bytes released, will remove locked items if force specified
  332. //--------------------------------------------------------
  333. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true ) = 0;
  334. //--------------------------------------------------------
  335. // Purpose: Output the state of the cache
  336. //--------------------------------------------------------
  337. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL ) = 0;
  338. virtual int GetSectionCount() = 0;
  339. virtual const char *GetSectionName( int iIndex ) = 0;
  340. };
  341. //-----------------------------------------------------------------------------
  342. // Helper class to support usage pattern similar to CDataManager
  343. //-----------------------------------------------------------------------------
  344. template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE * >
  345. class CManagedDataCacheClient : public CDefaultDataCacheClient
  346. {
  347. public:
  348. typedef CManagedDataCacheClient<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE> CCacheClientBaseClass;
  349. CManagedDataCacheClient()
  350. : m_pCache( NULL )
  351. {
  352. }
  353. void Init( IDataCache *pSharedCache, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false )
  354. {
  355. if ( !m_pCache )
  356. {
  357. m_pCache = pSharedCache->AddSection( this, pszSectionName, limits, bSupportFastFind );
  358. }
  359. }
  360. void Shutdown()
  361. {
  362. if ( m_pCache )
  363. {
  364. m_pCache->GetSharedCache()->RemoveSection( m_pCache );
  365. m_pCache = NULL;
  366. }
  367. }
  368. LOCK_TYPE CacheGet( DataCacheHandle_t handle, bool bFrameLock = true )
  369. {
  370. return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Get( handle, bFrameLock ))->GetData());
  371. }
  372. void CacheGetAndLockMultiple( LOCK_TYPE *pData, int nCount, DataCacheHandle_t *pHandles )
  373. {
  374. m_pCache->GetAndLockMultiple( (void**)pData, nCount, pHandles );
  375. for ( int i = 0; i < nCount; ++i )
  376. {
  377. STORAGE_TYPE *pTypedData = pData[i];
  378. if ( pTypedData )
  379. {
  380. pData[i] = (LOCK_TYPE)( pTypedData->GetData() );
  381. }
  382. }
  383. }
  384. LOCK_TYPE CacheGetNoTouch( DataCacheHandle_t handle )
  385. {
  386. return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->GetNoTouch( handle ))->GetData());
  387. }
  388. LOCK_TYPE CacheLock( DataCacheHandle_t handle )
  389. {
  390. return (LOCK_TYPE)(((STORAGE_TYPE *)m_pCache->Lock( handle ))->GetData());
  391. }
  392. int CacheUnlock( DataCacheHandle_t handle )
  393. {
  394. return m_pCache->Unlock( handle );
  395. }
  396. void CacheTouch( DataCacheHandle_t handle )
  397. {
  398. m_pCache->Touch( handle );
  399. }
  400. void CacheRemove( DataCacheHandle_t handle, bool bNotify = true )
  401. {
  402. m_pCache->Remove( handle, bNotify );
  403. }
  404. void CacheFlush()
  405. {
  406. m_pCache->Flush();
  407. }
  408. DataCacheHandle_t CacheCreate( const CREATE_PARAMS &createParams, unsigned flags = DCAF_DEFAULT )
  409. {
  410. m_pCache->EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
  411. STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams );
  412. if ( !pStore )
  413. {
  414. return DC_INVALID_HANDLE;
  415. }
  416. DataCacheHandle_t handle;
  417. m_pCache->AddEx( (DataCacheClientID_t)pStore, pStore, pStore->Size(), flags, &handle);
  418. return handle;
  419. }
  420. void CacheLockMutex()
  421. {
  422. m_pCache->LockMutex();
  423. }
  424. void CacheUnlockMutex()
  425. {
  426. m_pCache->UnlockMutex();
  427. }
  428. bool HandleCacheNotification( const DataCacheNotification_t &notification )
  429. {
  430. switch ( notification.type )
  431. {
  432. case DC_AGE_DISCARD:
  433. case DC_FLUSH_DISCARD:
  434. case DC_REMOVED:
  435. {
  436. STORAGE_TYPE *p = (STORAGE_TYPE *)notification.clientId;
  437. p->DestroyResource();
  438. return true;
  439. }
  440. break;
  441. case DC_NONE:
  442. case DC_RELOCATE:
  443. case DC_PRINT_INF0:
  444. break;
  445. }
  446. return CDefaultDataCacheClient::HandleCacheNotification( notification );
  447. }
  448. protected:
  449. ~CManagedDataCacheClient()
  450. {
  451. Shutdown();
  452. }
  453. IDataCacheSection *GetCacheSection()
  454. {
  455. return m_pCache;
  456. }
  457. private:
  458. IDataCacheSection *m_pCache;
  459. };
  460. //-----------------------------------------------------------------------------
  461. #endif // IDataCache