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