607 lines
11 KiB
C++
607 lines
11 KiB
C++
#ifndef _USERCACHE_HXX_
|
|
#define _USERCACHE_HXX_
|
|
|
|
#include <lkrhash.h>
|
|
#include <dirmon.h>
|
|
#include <reftrace.h>
|
|
|
|
#define CACHE_INVALIDATION_DIRMON_SPECIFIC 0x1
|
|
#define CACHE_INVALIDATION_DIRMON_FLUSH 0x2
|
|
#define CACHE_INVALIDATION_METADATA 0x4
|
|
|
|
//
|
|
// Configuration for dir monitoring
|
|
//
|
|
|
|
struct DIRMON_CONFIG
|
|
{
|
|
HANDLE hToken;
|
|
WCHAR * pszDirPath;
|
|
};
|
|
|
|
//
|
|
// Key used to lookup any of the caches
|
|
//
|
|
|
|
class CACHE_KEY
|
|
{
|
|
public:
|
|
|
|
CACHE_KEY()
|
|
{
|
|
}
|
|
|
|
virtual ~CACHE_KEY()
|
|
{
|
|
}
|
|
|
|
virtual
|
|
WCHAR *
|
|
QueryHintKey(
|
|
VOID
|
|
)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
virtual
|
|
DWORD
|
|
QueryKeyHash(
|
|
VOID
|
|
) const = 0;
|
|
|
|
virtual
|
|
BOOL
|
|
QueryIsEqual(
|
|
const CACHE_KEY * pCacheCompareKey
|
|
) const = 0;
|
|
};
|
|
|
|
class OBJECT_CACHE;
|
|
|
|
#define CACHE_ENTRY_SIGNATURE 'STEC'
|
|
#define CACHE_ENTRY_SIGNATURE_FREE 'xtec'
|
|
|
|
class dllexp CACHE_ENTRY
|
|
{
|
|
public:
|
|
|
|
CACHE_ENTRY( OBJECT_CACHE * pObjectCache );
|
|
|
|
VOID
|
|
ReferenceCacheEntry(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DereferenceCacheEntry(
|
|
VOID
|
|
);
|
|
|
|
virtual
|
|
STRU *
|
|
QueryMetadataPath(
|
|
VOID
|
|
)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT
|
|
AddDirmonInvalidator(
|
|
DIRMON_CONFIG * pDirmonConfig
|
|
);
|
|
|
|
BOOL
|
|
QueryIsFlushed(
|
|
VOID
|
|
) const
|
|
{
|
|
return _fFlushed;
|
|
}
|
|
|
|
BOOL
|
|
Checkout(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SetCached(
|
|
BOOL fCached
|
|
)
|
|
{
|
|
_fCached = fCached;
|
|
}
|
|
|
|
BOOL
|
|
QueryCached(
|
|
VOID
|
|
) const
|
|
{
|
|
return _fCached;
|
|
}
|
|
|
|
VOID
|
|
SetFlushed(
|
|
VOID
|
|
)
|
|
{
|
|
_fFlushed = TRUE;
|
|
}
|
|
|
|
VOID
|
|
LockCacheEntry(
|
|
VOID
|
|
)
|
|
{
|
|
_lock.WriteLock();
|
|
}
|
|
|
|
VOID
|
|
UnlockCacheEntry(
|
|
VOID
|
|
)
|
|
{
|
|
_lock.WriteUnlock();
|
|
}
|
|
|
|
OBJECT_CACHE *
|
|
QueryCache(
|
|
VOID
|
|
) const
|
|
{
|
|
return _pObjectCache;
|
|
}
|
|
|
|
virtual
|
|
BOOL
|
|
QueryIsOkToFlushTTL(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
QueryIsOkToFlushMetadata(
|
|
WCHAR * pszPath,
|
|
DWORD cchPath
|
|
);
|
|
|
|
virtual
|
|
BOOL
|
|
QueryIsOkToFlushDirmon(
|
|
WCHAR * pszPath,
|
|
DWORD cchPath
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
virtual
|
|
CACHE_KEY *
|
|
QueryCacheKey(
|
|
VOID
|
|
) const = 0;
|
|
|
|
BOOL
|
|
CheckSignature(
|
|
VOID
|
|
) const
|
|
{
|
|
return _dwSignature == CACHE_ENTRY_SIGNATURE;
|
|
}
|
|
|
|
protected:
|
|
|
|
virtual ~CACHE_ENTRY();
|
|
|
|
private:
|
|
|
|
DWORD _dwSignature;
|
|
LONG _cRefs;
|
|
BOOL _fFlushed;
|
|
LONG _cTTL;
|
|
LONG _cConfiguredTTL;
|
|
BOOL _fCached;
|
|
CSmallSpinLock _lock;
|
|
OBJECT_CACHE * _pObjectCache;
|
|
CDirMonitorEntry * _pDirmonInvalidator;
|
|
};
|
|
|
|
class CACHE_ENTRY_HASH : public CTypedHashTable< CACHE_ENTRY_HASH,
|
|
CACHE_ENTRY,
|
|
CACHE_KEY * >
|
|
{
|
|
public:
|
|
|
|
CACHE_ENTRY_HASH() : CTypedHashTable< CACHE_ENTRY_HASH,
|
|
CACHE_ENTRY,
|
|
CACHE_KEY * >
|
|
( "CACHE_ENTRY_HASH" )
|
|
{
|
|
}
|
|
|
|
static CACHE_KEY *
|
|
ExtractKey(
|
|
const CACHE_ENTRY * pCacheEntry
|
|
)
|
|
{
|
|
return pCacheEntry->QueryCacheKey();
|
|
}
|
|
|
|
static DWORD
|
|
CalcKeyHash(
|
|
const CACHE_KEY * pCacheKey
|
|
)
|
|
{
|
|
return pCacheKey->QueryKeyHash();
|
|
}
|
|
|
|
static bool
|
|
EqualKeys(
|
|
const CACHE_KEY * pCacheKey1,
|
|
const CACHE_KEY * pCacheKey2
|
|
)
|
|
{
|
|
return pCacheKey1->QueryIsEqual( pCacheKey2 ) ? true : false;
|
|
}
|
|
|
|
static void
|
|
AddRefRecord(
|
|
CACHE_ENTRY * pCacheEntry,
|
|
int nIncr
|
|
);
|
|
};
|
|
|
|
struct CACHE_HINT_CONFIG
|
|
{
|
|
DWORD cmsecTTL;
|
|
DWORD cmsecScavengeTime;
|
|
DWORD cmsecActivityWindow;
|
|
};
|
|
|
|
class CACHE_HINT_MANAGER;
|
|
|
|
//
|
|
// All caches derive from this abstract class
|
|
//
|
|
|
|
#define OBJECT_CACHE_SIGNATURE 'SCBO'
|
|
#define OBJECT_CACHE_SIGNATURE_FREE 'xcbo'
|
|
|
|
class OBJECT_CACHE
|
|
{
|
|
public:
|
|
|
|
dllexp OBJECT_CACHE();
|
|
|
|
dllexp virtual ~OBJECT_CACHE();
|
|
|
|
dllexp
|
|
HRESULT
|
|
SetCacheConfiguration(
|
|
DWORD cmsecScavenge,
|
|
DWORD cmsecTTL,
|
|
DWORD dwSupportedInvalidation,
|
|
CACHE_HINT_CONFIG * pCacheHintConfig
|
|
);
|
|
|
|
dllexp
|
|
HRESULT
|
|
FindCacheEntry(
|
|
CACHE_KEY * pCacheKey,
|
|
CACHE_ENTRY ** ppCacheEntry,
|
|
BOOL * pfShouldCache = NULL
|
|
);
|
|
|
|
dllexp
|
|
HRESULT
|
|
FlushCacheEntry(
|
|
CACHE_KEY * pCacheKey
|
|
);
|
|
|
|
dllexp
|
|
HRESULT
|
|
AddCacheEntry(
|
|
CACHE_ENTRY * pCacheEntry
|
|
);
|
|
|
|
dllexp
|
|
HRESULT
|
|
AddDirmonInvalidator(
|
|
DIRMON_CONFIG * pDirmonConfig,
|
|
CDirMonitorEntry ** ppDME
|
|
);
|
|
|
|
VOID
|
|
FlushByTTL(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DoDirmonInvalidationFlush(
|
|
WCHAR * pszPath
|
|
);
|
|
|
|
VOID
|
|
DoMetadataInvalidationFlush(
|
|
WCHAR * pszMetapath
|
|
);
|
|
|
|
VOID
|
|
Clear(
|
|
VOID
|
|
)
|
|
{
|
|
_hashTable.Clear();
|
|
}
|
|
|
|
BOOL
|
|
QuerySupportsDirmonSpecific(
|
|
VOID
|
|
)
|
|
{
|
|
return !!( _dwSupportedInvalidation & CACHE_INVALIDATION_DIRMON_SPECIFIC );
|
|
}
|
|
|
|
BOOL
|
|
QuerySupportsDirmonFlush(
|
|
VOID
|
|
)
|
|
{
|
|
return !!( _dwSupportedInvalidation & CACHE_INVALIDATION_DIRMON_FLUSH );
|
|
}
|
|
|
|
BOOL
|
|
QuerySupportsMetadataFlush(
|
|
VOID
|
|
)
|
|
{
|
|
return !!( _dwSupportedInvalidation & CACHE_INVALIDATION_METADATA );
|
|
}
|
|
|
|
VOID
|
|
DoReferenceTrace(
|
|
CACHE_ENTRY * pCacheEntry,
|
|
DWORD cRefs
|
|
)
|
|
{
|
|
if ( _pTraceLog != NULL )
|
|
{
|
|
WriteRefTraceLog( _pTraceLog, cRefs, pCacheEntry );
|
|
}
|
|
}
|
|
|
|
virtual
|
|
WCHAR *
|
|
QueryName(
|
|
VOID
|
|
) const = 0;
|
|
|
|
virtual
|
|
VOID
|
|
DoDirmonInvalidationSpecific(
|
|
WCHAR * pszPath
|
|
)
|
|
{
|
|
}
|
|
|
|
static
|
|
VOID
|
|
WINAPI
|
|
ScavengerCallback(
|
|
PVOID pObjectCache,
|
|
BOOLEAN TimerOrWaitFired
|
|
);
|
|
|
|
static
|
|
LK_PREDICATE
|
|
CacheFlushByTTL(
|
|
CACHE_ENTRY * pCacheEntry,
|
|
VOID * pvState
|
|
);
|
|
|
|
static
|
|
LK_PREDICATE
|
|
CacheFlushByDirmon(
|
|
CACHE_ENTRY * pCacheEntry,
|
|
VOID * pvState
|
|
);
|
|
|
|
static
|
|
LK_PREDICATE
|
|
CacheFlushByMetadata(
|
|
CACHE_ENTRY * pCacheEntry,
|
|
VOID * pvState
|
|
);
|
|
|
|
BOOL
|
|
CheckSignature(
|
|
VOID
|
|
) const
|
|
{
|
|
return _dwSignature == OBJECT_CACHE_SIGNATURE;
|
|
}
|
|
|
|
BOOL
|
|
SupportsInvalidation(
|
|
DWORD dwInvalidationType
|
|
)
|
|
{
|
|
return !!( dwInvalidationType & _dwSupportedInvalidation );
|
|
}
|
|
|
|
DWORD
|
|
QueryConfiguredTTL(
|
|
VOID
|
|
)
|
|
{
|
|
return ( _cmsecTTL / _cmsecScavengeTime ) + 1;
|
|
}
|
|
|
|
VOID
|
|
IncHits(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedIncrement( (LPLONG) &_cCacheHits );
|
|
InterlockedIncrement( (LPLONG) &_cPerfCacheHits );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryHits(
|
|
VOID
|
|
)
|
|
{
|
|
return InterlockedExchange( (LPLONG) &_cPerfCacheHits, 0 );
|
|
}
|
|
|
|
VOID
|
|
IncMisses(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedIncrement( (LPLONG) &_cCacheMisses );
|
|
InterlockedIncrement( (LPLONG) &_cPerfCacheMisses );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryMisses(
|
|
VOID
|
|
)
|
|
{
|
|
return InterlockedExchange( (LPLONG) &_cPerfCacheMisses, 0 );
|
|
}
|
|
|
|
VOID
|
|
IncFlushes(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedIncrement( (LPLONG) &_cCacheFlushes );
|
|
InterlockedIncrement( (LPLONG) &_cPerfCacheFlushes );
|
|
InterlockedIncrement( (LPLONG) &_cActiveFlushedEntries );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryFlushes(
|
|
VOID
|
|
)
|
|
{
|
|
return InterlockedExchange( (LPLONG) &_cPerfCacheFlushes, 0 );
|
|
}
|
|
|
|
VOID
|
|
DecActiveFlushedEntries(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedDecrement( (LPLONG) &_cActiveFlushedEntries );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryActiveFlushedEntries(
|
|
VOID
|
|
)
|
|
{
|
|
return _cActiveFlushedEntries;
|
|
}
|
|
|
|
VOID
|
|
IncFlushCalls(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedIncrement( (LPLONG) &_cFlushCalls );
|
|
InterlockedIncrement( (LPLONG) &_cPerfFlushCalls );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryFlushCalls(
|
|
VOID
|
|
)
|
|
{
|
|
return InterlockedExchange( (LPLONG) &_cPerfFlushCalls, 0 );
|
|
}
|
|
|
|
VOID
|
|
IncEntriesCached(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedIncrement( (LPLONG) &_cEntriesCached );
|
|
InterlockedIncrement( (LPLONG) &_cTotalEntriesCached );
|
|
InterlockedIncrement( (LPLONG) &_cPerfTotalEntriesCached );
|
|
}
|
|
|
|
VOID
|
|
DecEntriesCached(
|
|
VOID
|
|
)
|
|
{
|
|
InterlockedDecrement( (LPLONG) &_cEntriesCached );
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryCurrentEntryCount(
|
|
VOID
|
|
) const
|
|
{
|
|
return _cEntriesCached;
|
|
}
|
|
|
|
DWORD
|
|
PerfQueryTotalEntriesCached(
|
|
VOID
|
|
) const
|
|
{
|
|
return InterlockedExchange( (LPLONG) &_cTotalEntriesCached, 0 );
|
|
}
|
|
|
|
private:
|
|
|
|
DWORD _dwSignature;
|
|
CACHE_ENTRY_HASH _hashTable;
|
|
LIST_ENTRY _listEntry;
|
|
HANDLE _hTimer;
|
|
DWORD _cmsecScavengeTime;
|
|
DWORD _cmsecTTL;
|
|
DWORD _dwSupportedInvalidation;
|
|
|
|
//
|
|
// Some stats
|
|
//
|
|
|
|
DWORD _cCacheHits;
|
|
DWORD _cCacheMisses;
|
|
DWORD _cCacheFlushes;
|
|
DWORD _cActiveFlushedEntries;
|
|
DWORD _cFlushCalls;
|
|
DWORD _cEntriesCached;
|
|
DWORD _cTotalEntriesCached;
|
|
|
|
//
|
|
// Perfmon helper stats (when debugging, ignore these values)
|
|
//
|
|
|
|
DWORD _cPerfCacheHits;
|
|
DWORD _cPerfCacheMisses;
|
|
DWORD _cPerfCacheFlushes;
|
|
DWORD _cPerfFlushCalls;
|
|
DWORD _cPerfTotalEntriesCached;
|
|
|
|
//
|
|
// Cache hint manager (if needed)
|
|
//
|
|
|
|
CACHE_HINT_MANAGER * _pHintManager;
|
|
|
|
//
|
|
// Ref tracing for all
|
|
//
|
|
|
|
PTRACE_LOG _pTraceLog;
|
|
|
|
static LIST_ENTRY sm_CacheListHead;
|
|
};
|
|
|
|
#endif
|