Team Fortress 2 Source Code as on 22/4/2020
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

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