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.

383 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef DATACACHE_H
  7. #define DATACACHE_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "datamanager.h"
  12. #include "utlhash.h"
  13. #include "mempool.h"
  14. #include "tier0/tslist.h"
  15. #include "datacache_common.h"
  16. #include "tier3/tier3.h"
  17. //-----------------------------------------------------------------------------
  18. //
  19. // Data Cache class declarations
  20. //
  21. //-----------------------------------------------------------------------------
  22. class CDataCache;
  23. class CDataCacheSection;
  24. //-----------------------------------------------------------------------------
  25. struct DataCacheItemData_t
  26. {
  27. const void * pItemData;
  28. unsigned size;
  29. DataCacheClientID_t clientId;
  30. CDataCacheSection * pSection;
  31. };
  32. //-------------------------------------
  33. #define DC_NO_NEXT_LOCKED ((DataCacheItem_t *)0xffffffff)
  34. #define DC_MAX_THREADS_FRAMELOCKED 4
  35. struct DataCacheItem_t : DataCacheItemData_t
  36. {
  37. DataCacheItem_t( const DataCacheItemData_t &data )
  38. : DataCacheItemData_t( data ),
  39. hLRU( INVALID_MEMHANDLE )
  40. {
  41. memset( pNextFrameLocked, 0xff, sizeof(pNextFrameLocked) );
  42. }
  43. static DataCacheItem_t *CreateResource( const DataCacheItemData_t &data ) { return new DataCacheItem_t(data); }
  44. static unsigned int EstimatedSize( const DataCacheItemData_t &data ) { return data.size; }
  45. void DestroyResource();
  46. DataCacheItem_t *GetData() { return this; }
  47. unsigned int Size() { return size; }
  48. memhandle_t hLRU;
  49. DataCacheItem_t *pNextFrameLocked[DC_MAX_THREADS_FRAMELOCKED];
  50. DECLARE_FIXEDSIZE_ALLOCATOR_MT(DataCacheItem_t);
  51. };
  52. //-------------------------------------
  53. typedef CDataManager<DataCacheItem_t, DataCacheItemData_t, DataCacheItem_t *, CThreadFastMutex> CDataCacheLRU;
  54. //-----------------------------------------------------------------------------
  55. // CDataCacheSection
  56. //
  57. // Purpose: Implements a sub-section of the global cache. Subsections are
  58. // areas of the cache with thier own memory constraints and common
  59. // management.
  60. //-----------------------------------------------------------------------------
  61. class CDataCacheSection : public IDataCacheSection
  62. {
  63. public:
  64. CDataCacheSection( CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName );
  65. ~CDataCacheSection();
  66. IDataCache *GetSharedCache();
  67. IDataCacheClient *GetClient() { return m_pClient; }
  68. const char *GetName() { return szName; }
  69. //--------------------------------------------------------
  70. // IDataCacheSection methods
  71. //--------------------------------------------------------
  72. virtual void SetLimits( const DataCacheLimits_t &limits );
  73. const DataCacheLimits_t &GetLimits();
  74. virtual void SetOptions( unsigned options );
  75. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL );
  76. inline unsigned GetNumBytes() { return m_status.nBytes; }
  77. inline unsigned GetNumItems() { return m_status.nItems; }
  78. inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; }
  79. inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; }
  80. inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; }
  81. inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; }
  82. virtual void EnsureCapacity( unsigned nBytes, unsigned nItems = 1 );
  83. //--------------------------------------------------------
  84. virtual bool Add( DataCacheClientID_t clientId, const void *pItemData, unsigned size, DataCacheHandle_t *pHandle );
  85. virtual bool AddEx( DataCacheClientID_t clientId, const void *pItemData, unsigned size, unsigned flags, DataCacheHandle_t *pHandle );
  86. virtual DataCacheHandle_t Find( DataCacheClientID_t clientId );
  87. virtual DataCacheRemoveResult_t Remove( DataCacheHandle_t handle, const void **ppItemData = NULL, unsigned *pItemSize = NULL, bool bNotify = false );
  88. virtual bool IsPresent( DataCacheHandle_t handle );
  89. //--------------------------------------------------------
  90. virtual void *Lock( DataCacheHandle_t handle );
  91. virtual int Unlock( DataCacheHandle_t handle );
  92. virtual void *Get( DataCacheHandle_t handle, bool bFrameLock = false );
  93. virtual void *GetNoTouch( DataCacheHandle_t handle, bool bFrameLock = false );
  94. virtual void LockMutex();
  95. virtual void UnlockMutex();
  96. //--------------------------------------------------------
  97. virtual int BeginFrameLocking();
  98. virtual bool IsFrameLocking();
  99. virtual void *FrameLock( DataCacheHandle_t handle );
  100. virtual int EndFrameLocking();
  101. //--------------------------------------------------------
  102. virtual int GetLockCount( DataCacheHandle_t handle );
  103. virtual int BreakLock( DataCacheHandle_t handle );
  104. //--------------------------------------------------------
  105. virtual int *GetFrameUnlockCounterPtr();
  106. int m_nFrameUnlockCounter;
  107. //--------------------------------------------------------
  108. virtual bool Touch( DataCacheHandle_t handle );
  109. virtual bool Age( DataCacheHandle_t handle );
  110. //--------------------------------------------------------
  111. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true );
  112. virtual unsigned Purge( unsigned nBytes );
  113. unsigned PurgeItems( unsigned nItems );
  114. //--------------------------------------------------------
  115. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT );
  116. virtual void UpdateSize( DataCacheHandle_t handle, unsigned int nNewSize );
  117. private:
  118. friend void DataCacheItem_t::DestroyResource();
  119. virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem ) {}
  120. virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId );
  121. virtual void OnRemove( DataCacheClientID_t clientId ) {}
  122. memhandle_t GetFirstUnlockedItem();
  123. memhandle_t GetFirstLockedItem();
  124. memhandle_t GetNextItem( memhandle_t );
  125. DataCacheItem_t *AccessItem( memhandle_t hCurrent );
  126. bool DiscardItem( memhandle_t hItem, DataCacheNotificationType_t type );
  127. bool DiscardItemData( DataCacheItem_t *pItem, DataCacheNotificationType_t type );
  128. void NoteAdd( int size );
  129. void NoteRemove( int size );
  130. void NoteLock( int size );
  131. void NoteUnlock( int size );
  132. void NoteSizeChanged( int oldSize, int newSize );
  133. struct FrameLock_t
  134. {
  135. //$ WARNING: This needs a TSLNodeBase_t as the first item in here.
  136. TSLNodeBase_t base;
  137. int m_iLock;
  138. DataCacheItem_t *m_pFirst;
  139. int m_iThread;
  140. };
  141. typedef CThreadLocal<FrameLock_t *> CThreadFrameLock;
  142. CDataCacheLRU & m_LRU;
  143. CThreadFrameLock m_ThreadFrameLock;
  144. DataCacheStatus_t m_status;
  145. DataCacheLimits_t m_limits;
  146. IDataCacheClient * m_pClient;
  147. unsigned m_options;
  148. CDataCache * m_pSharedCache;
  149. char szName[DC_MAX_CLIENT_NAME + 1];
  150. CTSSimpleList<FrameLock_t> m_FreeFrameLocks;
  151. protected:
  152. CThreadFastMutex & m_mutex;
  153. };
  154. //-----------------------------------------------------------------------------
  155. // CDataCacheSectionFastFind
  156. //
  157. // Purpose: A section variant that allows clients to have cache support tracking
  158. // efficiently (a true cache, not just an LRU)
  159. //-----------------------------------------------------------------------------
  160. class CDataCacheSectionFastFind : public CDataCacheSection
  161. {
  162. public:
  163. CDataCacheSectionFastFind(CDataCache *pSharedCache, IDataCacheClient *pClient, const char *pszName )
  164. : CDataCacheSection( pSharedCache, pClient, pszName )
  165. {
  166. m_Handles.Init( 1024 );
  167. }
  168. private:
  169. virtual DataCacheHandle_t DoFind( DataCacheClientID_t clientId );
  170. virtual void OnAdd( DataCacheClientID_t clientId, DataCacheHandle_t hCacheItem );
  171. virtual void OnRemove( DataCacheClientID_t clientId );
  172. CUtlHashFast<DataCacheHandle_t> m_Handles;
  173. };
  174. //-----------------------------------------------------------------------------
  175. // CDataCache
  176. //
  177. // Purpose: The global shared cache. Manages sections and overall budgets.
  178. //
  179. //-----------------------------------------------------------------------------
  180. class CDataCache : public CTier3AppSystem< IDataCache >
  181. {
  182. typedef CTier3AppSystem< IDataCache > BaseClass;
  183. public:
  184. CDataCache();
  185. //--------------------------------------------------------
  186. // IAppSystem methods
  187. //--------------------------------------------------------
  188. virtual bool Connect( CreateInterfaceFn factory );
  189. virtual void Disconnect();
  190. virtual void *QueryInterface( const char *pInterfaceName );
  191. virtual InitReturnVal_t Init();
  192. virtual void Shutdown();
  193. //--------------------------------------------------------
  194. // IDataCache methods
  195. //--------------------------------------------------------
  196. virtual void SetSize( int nMaxBytes );
  197. virtual void SetOptions( unsigned options );
  198. virtual void SetSectionLimits( const char *pszSectionName, const DataCacheLimits_t &limits );
  199. virtual void GetStatus( DataCacheStatus_t *pStatus, DataCacheLimits_t *pLimits = NULL );
  200. //--------------------------------------------------------
  201. virtual IDataCacheSection *AddSection( IDataCacheClient *pClient, const char *pszSectionName, const DataCacheLimits_t &limits = DataCacheLimits_t(), bool bSupportFastFind = false );
  202. virtual void RemoveSection( const char *pszClientName, bool bCallFlush = true );
  203. virtual IDataCacheSection *FindSection( const char *pszClientName );
  204. //--------------------------------------------------------
  205. void EnsureCapacity( unsigned nBytes );
  206. virtual unsigned Purge( unsigned nBytes );
  207. virtual unsigned Flush( bool bUnlockedOnly = true, bool bNotify = true );
  208. //--------------------------------------------------------
  209. virtual void OutputReport( DataCacheReportType_t reportType = DC_SUMMARY_REPORT, const char *pszSection = NULL );
  210. //--------------------------------------------------------
  211. inline unsigned GetNumBytes() { return m_status.nBytes; }
  212. inline unsigned GetNumItems() { return m_status.nItems; }
  213. inline unsigned GetNumBytesLocked() { return m_status.nBytesLocked; }
  214. inline unsigned GetNumItemsLocked() { return m_status.nItemsLocked; }
  215. inline unsigned GetNumBytesUnlocked() { return m_status.nBytes - m_status.nBytesLocked; }
  216. inline unsigned GetNumItemsUnlocked() { return m_status.nItems - m_status.nItemsLocked; }
  217. private:
  218. //-----------------------------------------------------
  219. friend class CDataCacheSection;
  220. //-----------------------------------------------------
  221. DataCacheItem_t *AccessItem( memhandle_t hCurrent );
  222. bool IsInFlush() { return m_bInFlush; }
  223. int FindSectionIndex( const char *pszSection );
  224. // Utilities used by the data cache report
  225. void OutputItemReport( memhandle_t hItem );
  226. static bool SortMemhandlesBySizeLessFunc( const memhandle_t& lhs, const memhandle_t& rhs );
  227. //-----------------------------------------------------
  228. CDataCacheLRU m_LRU;
  229. DataCacheStatus_t m_status;
  230. CUtlVector<CDataCacheSection *> m_Sections;
  231. bool m_bInFlush;
  232. CThreadFastMutex & m_mutex;
  233. };
  234. //---------------------------------------------------------
  235. extern CDataCache g_DataCache;
  236. //-----------------------------------------------------------------------------
  237. inline DataCacheItem_t *CDataCache::AccessItem( memhandle_t hCurrent )
  238. {
  239. return m_LRU.GetResource_NoLockNoLRUTouch( hCurrent );
  240. }
  241. //-----------------------------------------------------------------------------
  242. inline IDataCache *CDataCacheSection::GetSharedCache()
  243. {
  244. return m_pSharedCache;
  245. }
  246. inline DataCacheItem_t *CDataCacheSection::AccessItem( memhandle_t hCurrent )
  247. {
  248. return m_pSharedCache->AccessItem( hCurrent );
  249. }
  250. // Note: if status updates are moved out of a mutexed section, will need to change these to use interlocked instructions
  251. inline void CDataCacheSection::NoteSizeChanged( int oldSize, int newSize )
  252. {
  253. int nBytes = ( newSize - oldSize );
  254. m_status.nBytes += nBytes;
  255. m_status.nBytesLocked += nBytes;
  256. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, nBytes );
  257. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, nBytes );
  258. }
  259. inline void CDataCacheSection::NoteAdd( int size )
  260. {
  261. m_status.nBytes += size;
  262. m_status.nItems++;
  263. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, size );
  264. ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItems );
  265. }
  266. inline void CDataCacheSection::NoteRemove( int size )
  267. {
  268. m_status.nBytes -= size;
  269. m_status.nItems--;
  270. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytes, -size );
  271. ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItems );
  272. }
  273. inline void CDataCacheSection::NoteLock( int size )
  274. {
  275. m_status.nBytesLocked += size;
  276. m_status.nItemsLocked++;
  277. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, size );
  278. ThreadInterlockedIncrement( &m_pSharedCache->m_status.nItemsLocked );
  279. }
  280. inline void CDataCacheSection::NoteUnlock( int size )
  281. {
  282. m_status.nBytesLocked -= size;
  283. m_status.nItemsLocked--;
  284. ThreadInterlockedExchangeAdd( &m_pSharedCache->m_status.nBytesLocked, -size );
  285. ThreadInterlockedDecrement( &m_pSharedCache->m_status.nItemsLocked );
  286. // something has been unlocked, assume cached pointers are now invalid
  287. m_nFrameUnlockCounter++;
  288. }
  289. //-----------------------------------------------------------------------------
  290. #endif // DATACACHE_H