759 lines
16 KiB
C++
759 lines
16 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1998 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
tlcach.cxx
|
|
|
|
This module implements the private interface to the two-level cache. This
|
|
cache is used to either cache the contents of a file or to copy the
|
|
file and cache the handle to it
|
|
|
|
FILE HISTORY:
|
|
BAlam 10-31-1998 Created
|
|
*/
|
|
|
|
#include "TsunamiP.Hxx"
|
|
#pragma hdrstop
|
|
|
|
// #define LOCAL_ALLOC 1
|
|
#define PRIVATE_HEAP 1
|
|
// #define VIRTUAL_ALLOC 1
|
|
// #define LOOKASIDE 1
|
|
|
|
#include "issched.hxx"
|
|
#include "tlcach.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// Memory Cache size statistics
|
|
|
|
DWORDLONG g_cbMaxMemCacheSize;
|
|
DWORDLONG g_cbMemCacheSize;
|
|
DWORDLONG g_cbMaxMemCacheUsed;
|
|
DWORD g_cMemCacheElements;
|
|
DWORD g_cMaxMemCacheElementsUsed;
|
|
|
|
// Cache utility
|
|
|
|
CRITICAL_SECTION g_csMemCache;
|
|
DWORD g_dwMemCacheSizeCookie;
|
|
DWORD g_cmsecAdjustmentTime = DEFAULT_ADJUSTMENT_TIME;
|
|
CHAR g_achTempPath[ MAX_PATH + 1 ];
|
|
|
|
|
|
|
|
#if defined(LOCAL_ALLOC)
|
|
|
|
const char g_szTsunamiAllocator[] = "LocalAlloc";
|
|
|
|
#elif defined(PRIVATE_HEAP)
|
|
|
|
const char g_szTsunamiAllocator[] = "PrivateHeap";
|
|
|
|
HANDLE g_hMemCacheHeap = NULL;
|
|
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
|
|
const char g_szTsunamiAllocator[] = "VirtualAlloc";
|
|
|
|
#elif defined(LOOKASIDE)
|
|
|
|
const char g_szTsunamiAllocator[] = "LookAside";
|
|
|
|
enum {
|
|
ENORMOUS = 300,
|
|
MANY = 200,
|
|
LOTS = 100,
|
|
SOME = 50,
|
|
FEW = 20,
|
|
MINIMAL = 4,
|
|
|
|
KB = 1024,
|
|
};
|
|
|
|
ALLOC_CACHE_CONFIGURATION g_aacc[] = {
|
|
{ 1, SOME, 128},
|
|
{ 1, SOME, 256},
|
|
{ 1, SOME, 512},
|
|
{ 1, LOTS, 768},
|
|
{ 1, LOTS, 1 * KB},
|
|
{ 1, ENORMOUS, 2 * KB},
|
|
{ 1, ENORMOUS, 3 * KB},
|
|
{ 1, ENORMOUS, 4 * KB},
|
|
{ 1, MANY, 5 * KB},
|
|
{ 1, MANY, 6 * KB},
|
|
{ 1, MANY, 7 * KB},
|
|
{ 1, MANY, 8 * KB},
|
|
{ 1, LOTS, 9 * KB},
|
|
{ 1, LOTS, 10 * KB},
|
|
{ 1, LOTS, 11 * KB},
|
|
{ 1, LOTS, 12 * KB},
|
|
{ 1, LOTS, 14 * KB},
|
|
{ 1, SOME, 16 * KB},
|
|
{ 1, SOME, 20 * KB},
|
|
{ 1, SOME, 24 * KB},
|
|
{ 1, SOME, 28 * KB},
|
|
{ 1, SOME, 32 * KB},
|
|
{ 1, FEW, 36 * KB},
|
|
{ 1, FEW, 40 * KB},
|
|
{ 1, FEW, 44 * KB},
|
|
{ 1, FEW, 48 * KB},
|
|
{ 1, FEW, 56 * KB},
|
|
{ 1, MINIMAL, 64 * KB},
|
|
{ 1, MINIMAL, 80 * KB},
|
|
{ 1, MINIMAL, 96 * KB},
|
|
{ 1, MINIMAL, 128 * KB},
|
|
{ 1, MINIMAL, 160 * KB},
|
|
{ 1, MINIMAL, 192 * KB},
|
|
{ 1, MINIMAL, 256 * KB},
|
|
};
|
|
|
|
CLookAside* g_laMemCache = NULL;
|
|
|
|
// paacc must be sorted in increasing sizes, it is sorted right now from
|
|
// where it is called
|
|
|
|
CLookAside::CLookAside(
|
|
ALLOC_CACHE_CONFIGURATION* paacc,
|
|
SIZE_T caacc)
|
|
: m_dwSignature(SIGNATURE),
|
|
m_apach(NULL),
|
|
m_aacc(NULL),
|
|
m_cach(0),
|
|
m_nMinSize(0),
|
|
m_nMaxSize(0)
|
|
{
|
|
ALLOC_CACHE_HANDLER** apach = new ALLOC_CACHE_HANDLER* [caacc];
|
|
if (apach == NULL)
|
|
return;
|
|
|
|
ALLOC_CACHE_CONFIGURATION* paacc2 = new ALLOC_CACHE_CONFIGURATION [caacc];
|
|
if (paacc2 == NULL)
|
|
return;
|
|
|
|
for (SIZE_T i = 0; i < caacc; ++i)
|
|
{
|
|
ALLOC_CACHE_CONFIGURATION acc = paacc[i];
|
|
acc.cbSize -= HEAP_PREFIX + HEAP_SUFFIX + ACACHE_OVERHEAD;
|
|
paacc2[i] = acc;
|
|
|
|
if (i == 0)
|
|
m_nMinSize = acc.cbSize;
|
|
else if (i == caacc-1)
|
|
m_nMaxSize = acc.cbSize;
|
|
|
|
char szName[40];
|
|
sprintf(szName, "TsLookAside-%d", acc.cbSize);
|
|
|
|
apach[i] = new ALLOC_CACHE_HANDLER(szName, &acc);
|
|
bool fInOrder = (i == 0 || paacc2[i].cbSize > paacc2[i-1].cbSize);
|
|
|
|
if (!fInOrder)
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT, "CLookAside: config array out of order\n"));
|
|
}
|
|
|
|
if (apach[i] == NULL || !fInOrder)
|
|
{
|
|
for (SIZE_T j = i; j-- > 0; )
|
|
{
|
|
delete apach[j];
|
|
}
|
|
m_nMinSize = m_nMaxSize = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_apach = apach;
|
|
m_aacc = paacc2;
|
|
m_cach = caacc;
|
|
}
|
|
|
|
|
|
|
|
CLookAside::~CLookAside()
|
|
{
|
|
for (SIZE_T j = m_cach; j-- > 0; )
|
|
{
|
|
delete m_apach[j];
|
|
}
|
|
|
|
delete [] m_apach;
|
|
delete [] m_aacc;
|
|
|
|
m_dwSignature = SIGNATURE_X;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
CLookAside::_FindAllocator(
|
|
IN DWORD cbSize)
|
|
{
|
|
if (cbSize > m_nMaxSize)
|
|
return -1; // too big to cache
|
|
else if (cbSize <= m_nMinSize)
|
|
return 0;
|
|
|
|
int l = 0, h = m_cach-1;
|
|
|
|
do
|
|
{
|
|
DBG_ASSERT(m_aacc[l].cbSize < cbSize && cbSize <= m_aacc[h].cbSize);
|
|
|
|
unsigned m = (unsigned) (l + h) >> 1;
|
|
DBG_ASSERT(m > 0);
|
|
|
|
if (m_aacc[m-1].cbSize < cbSize && cbSize <= m_aacc[m].cbSize)
|
|
return m;
|
|
else if (m_aacc[m].cbSize < cbSize)
|
|
l = m+1;
|
|
else
|
|
h = m-1;
|
|
} while (l <= h);
|
|
|
|
DBG_ASSERT(FALSE);
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
LPVOID
|
|
CLookAside::Alloc(
|
|
IN DWORD cbSize)
|
|
{
|
|
LPVOID pv = NULL;
|
|
int iAllocator = _FindAllocator(cbSize);
|
|
|
|
if (iAllocator < 0)
|
|
{
|
|
pv = VirtualAlloc(NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
|
|
}
|
|
else
|
|
{
|
|
DBG_ASSERT(iAllocator < m_cach && cbSize <= m_aacc[iAllocator].cbSize);
|
|
pv = m_apach[iAllocator]->Alloc();
|
|
}
|
|
|
|
return pv;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CLookAside::Free(
|
|
IN LPVOID pv,
|
|
IN DWORD cbSize)
|
|
{
|
|
int iAllocator = _FindAllocator(cbSize);
|
|
|
|
if (iAllocator < 0)
|
|
{
|
|
VirtualFree(pv, 0, MEM_RELEASE);
|
|
}
|
|
else
|
|
{
|
|
DBG_ASSERT(iAllocator < m_cach && cbSize <= m_aacc[iAllocator].cbSize);
|
|
m_apach[iAllocator]->Free(pv);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#endif // LOCAL_ALLOC
|
|
|
|
//
|
|
// Defines
|
|
//
|
|
|
|
#define MemCacheLock() ( EnterCriticalSection( &g_csMemCache ) )
|
|
#define MemCacheUnlock() ( LeaveCriticalSection( &g_csMemCache ) )
|
|
|
|
//
|
|
// Private declarations
|
|
//
|
|
|
|
VOID
|
|
WINAPI
|
|
I_MemoryCacheSizeAdjustor(
|
|
PVOID pContext
|
|
);
|
|
|
|
//
|
|
// Global functions
|
|
//
|
|
|
|
DWORD
|
|
InitializeTwoLevelCache(
|
|
IN DWORDLONG cbMemoryCacheSize
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Initialize memory cache
|
|
|
|
Arguments:
|
|
|
|
cbMemoryCacheSize - Size of memory cache (in bytes).
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, else Win32 Error
|
|
|
|
--*/
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if (DisableTsunamiCaching)
|
|
return dwError;
|
|
|
|
INITIALIZE_CRITICAL_SECTION( &g_csMemCache );
|
|
|
|
if ( cbMemoryCacheSize == (DWORDLONG)-1 )
|
|
{
|
|
MEMORYSTATUSEX MemoryStatus;
|
|
MemoryStatus.dwLength = sizeof MemoryStatus;
|
|
|
|
//
|
|
// Get our own estimate of size of cache
|
|
//
|
|
|
|
GlobalMemoryStatusEx( &MemoryStatus );
|
|
|
|
g_cbMaxMemCacheSize = min( MemoryStatus.ullAvailPhys,
|
|
MemoryStatus.ullTotalVirtual ) / 2;
|
|
|
|
//
|
|
// Schedule a max cache size adjustor
|
|
//
|
|
|
|
g_dwMemCacheSizeCookie = ScheduleWorkItem( I_MemoryCacheSizeAdjustor,
|
|
NULL,
|
|
g_cmsecAdjustmentTime,
|
|
TRUE );
|
|
if ( !g_dwMemCacheSizeCookie )
|
|
{
|
|
dwError = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_cbMaxMemCacheSize = cbMemoryCacheSize;
|
|
}
|
|
|
|
if ( dwError == ERROR_SUCCESS )
|
|
{
|
|
#if defined(LOCAL_ALLOC)
|
|
// no initialization needed
|
|
#elif defined(PRIVATE_HEAP)
|
|
g_hMemCacheHeap = HeapCreate( 0, 0, 0 );
|
|
if (g_hMemCacheHeap == NULL)
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
// no initialization needed
|
|
#elif defined(LOOKASIDE)
|
|
g_laMemCache = new CLookAside(g_aacc,
|
|
sizeof(g_aacc)/sizeof(g_aacc[0]));
|
|
if (g_laMemCache == NULL)
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
#endif // LOCAL_ALLOC
|
|
}
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
TerminateTwoLevelCache();
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
ReadFileIntoMemoryCache(
|
|
IN HANDLE hFile,
|
|
IN DWORD cbFile,
|
|
OUT DWORD * pcbRequired,
|
|
OUT VOID ** ppvBuffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Read contents of file into a buffer
|
|
|
|
Arguments:
|
|
|
|
hFile - Handle to valid file
|
|
cbFile - Size of file ( ==> size of buffer )
|
|
pcbRequired - Filled in with number of bytes required to be removed from
|
|
cache to fit element
|
|
ppvBuffer - Filled in with pointer to buffer with file contents. Set
|
|
to NULL on failure
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, else Win32 Error
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet;
|
|
VOID * pvBuffer = NULL;
|
|
DWORD cbRead;
|
|
OVERLAPPED Overlapped;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
DBG_ASSERT( hFile && ( hFile != INVALID_HANDLE_VALUE ) );
|
|
DBG_ASSERT( pcbRequired != NULL );
|
|
DBG_ASSERT( ppvBuffer != NULL );
|
|
|
|
*pcbRequired = 0;
|
|
|
|
//
|
|
// First check whether there will be room in cache for the blob
|
|
//
|
|
|
|
MemCacheLock();
|
|
|
|
if ( ( g_cbMemCacheSize + cbFile ) > g_cbMaxMemCacheSize )
|
|
{
|
|
//
|
|
// Not enough room for cache
|
|
//
|
|
|
|
MemCacheUnlock();
|
|
*pcbRequired = DIFF(( g_cbMemCacheSize + cbFile ) - g_cbMaxMemCacheSize);
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Finished;
|
|
}
|
|
|
|
g_cbMemCacheSize += cbFile;
|
|
g_cbMaxMemCacheUsed = max( g_cbMaxMemCacheUsed, g_cbMemCacheSize );
|
|
g_cMemCacheElements++;
|
|
g_cMaxMemCacheElementsUsed = max( g_cMaxMemCacheElementsUsed, g_cMemCacheElements );
|
|
|
|
MemCacheUnlock();
|
|
|
|
*pcbRequired = 0;
|
|
|
|
//
|
|
// Allocate blob for file
|
|
//
|
|
|
|
#if defined(LOCAL_ALLOC)
|
|
pvBuffer = LocalAlloc( LMEM_FIXED, cbFile );
|
|
#elif defined(PRIVATE_HEAP)
|
|
DBG_ASSERT(g_hMemCacheHeap != NULL);
|
|
pvBuffer = HeapAlloc( g_hMemCacheHeap, 0, cbFile );
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
pvBuffer = VirtualAlloc(NULL, cbFile, MEM_COMMIT, PAGE_READWRITE);
|
|
#elif defined(LOOKASIDE)
|
|
pvBuffer = g_laMemCache->Alloc(cbFile);
|
|
#endif // LOCAL_ALLOC
|
|
|
|
if ( pvBuffer == NULL )
|
|
{
|
|
MemCacheLock();
|
|
|
|
g_cbMemCacheSize -= cbFile;
|
|
|
|
MemCacheUnlock();
|
|
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Finished;
|
|
}
|
|
|
|
//
|
|
// Read file into blob
|
|
//
|
|
|
|
Overlapped.Offset = 0;
|
|
Overlapped.OffsetHigh = 0;
|
|
Overlapped.hEvent = NULL;
|
|
|
|
bRet = ReadFile( hFile,
|
|
pvBuffer,
|
|
cbFile,
|
|
&cbRead,
|
|
&Overlapped );
|
|
|
|
if ( !bRet )
|
|
{
|
|
dwError = GetLastError();
|
|
if ( dwError != ERROR_IO_PENDING )
|
|
{
|
|
//
|
|
// Something bad happened
|
|
//
|
|
|
|
goto Finished;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reset the error lest we confuse ourselves later on cleanup
|
|
//
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Wait for async read to complete
|
|
//
|
|
|
|
bRet = GetOverlappedResult( hFile,
|
|
&Overlapped,
|
|
&cbRead,
|
|
TRUE );
|
|
if ( !bRet )
|
|
{
|
|
//
|
|
// Something bad happened
|
|
//
|
|
|
|
dwError = GetLastError();
|
|
|
|
goto Finished;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure that we read the number of bytes we expected to
|
|
//
|
|
|
|
if ( cbRead != cbFile )
|
|
{
|
|
dwError = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
Finished:
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
if ( pvBuffer != NULL )
|
|
{
|
|
#if defined(LOCAL_ALLOC)
|
|
LocalFree( pvBuffer );
|
|
#elif defined(PRIVATE_HEAP)
|
|
HeapFree( g_hMemCacheHeap, 0, pvBuffer );
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
VirtualFree( pvBuffer, 0, MEM_RELEASE );
|
|
#elif defined(LOOKASIDE)
|
|
g_laMemCache->Free(pvBuffer, cbFile);
|
|
#endif // LOCAL_ALLOC
|
|
|
|
pvBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
*ppvBuffer = pvBuffer;
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
ReleaseFromMemoryCache(
|
|
IN VOID * pvBuffer,
|
|
IN DWORD cbBuffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Release file content blob from cache
|
|
|
|
Arguments:
|
|
|
|
pvBuffer - Buffer to release
|
|
cbBuffer - Size of buffer
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful, else Win32 Error
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( pvBuffer );
|
|
#if defined(LOCAL_ALLOC)
|
|
LocalFree( pvBuffer );
|
|
#elif defined(PRIVATE_HEAP)
|
|
DBG_ASSERT(g_hMemCacheHeap != NULL);
|
|
|
|
HeapFree( g_hMemCacheHeap, 0, pvBuffer );
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
VirtualFree( pvBuffer, 0, MEM_RELEASE );
|
|
#elif defined(LOOKASIDE)
|
|
g_laMemCache->Free(pvBuffer, cbBuffer);
|
|
#endif // LOCAL_ALLOC
|
|
|
|
MemCacheLock();
|
|
|
|
g_cbMemCacheSize -= cbBuffer;
|
|
g_cMemCacheElements--;
|
|
|
|
MemCacheUnlock();
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
TerminateTwoLevelCache(
|
|
VOID
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Terminate the memory cache
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
ERROR_INVALID_DATA if still elements in cache
|
|
|
|
--*/
|
|
{
|
|
if (DisableTsunamiCaching)
|
|
return ERROR_SUCCESS;
|
|
|
|
#if defined(LOCAL_ALLOC)
|
|
// no cleanup
|
|
#elif defined(PRIVATE_HEAP)
|
|
if (g_hMemCacheHeap != NULL)
|
|
{
|
|
DBG_REQUIRE( HeapDestroy( g_hMemCacheHeap ) );
|
|
g_hMemCacheHeap = NULL;
|
|
}
|
|
#elif defined(VIRTUAL_ALLOC)
|
|
// no cleanup
|
|
#elif defined(LOOKASIDE)
|
|
delete g_laMemCache;
|
|
g_laMemCache = NULL;
|
|
#endif // LOCAL_ALLOC
|
|
|
|
if ( g_dwMemCacheSizeCookie != 0 )
|
|
{
|
|
RemoveWorkItem( g_dwMemCacheSizeCookie );
|
|
g_dwMemCacheSizeCookie = 0;
|
|
}
|
|
|
|
DeleteCriticalSection( &g_csMemCache );
|
|
|
|
return ( g_cbMemCacheSize ) ?
|
|
ERROR_INVALID_DATA : ERROR_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
I_MemoryCacheSizeAdjustor(
|
|
IN PVOID pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to adjust the maximum size of the memory cache
|
|
|
|
Arguments:
|
|
|
|
pContext - Context (set to NULL)
|
|
|
|
Return value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
MEMORYSTATUSEX MemoryStatus;
|
|
MemoryStatus.dwLength = sizeof MemoryStatus;
|
|
|
|
GlobalMemoryStatusEx( &MemoryStatus );
|
|
|
|
MemCacheLock();
|
|
|
|
g_cbMaxMemCacheSize = min( MemoryStatus.ullAvailPhys + g_cbMemCacheSize,
|
|
MemoryStatus.ullTotalVirtual ) / 2;
|
|
|
|
MemCacheUnlock();
|
|
}
|
|
|
|
DWORD
|
|
DumpMemoryCacheToHtml(
|
|
IN CHAR * pszBuffer,
|
|
IN OUT DWORD * pcbBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump memory cache stats to buffer
|
|
|
|
Arguments:
|
|
|
|
pszBuffer - buffer to fill
|
|
pcbBuffer - size of buffer
|
|
|
|
Return value:
|
|
|
|
ERROR_SUCCESS if successful, else Win32 Error
|
|
|
|
--*/
|
|
{
|
|
*pcbBuffer = wsprintf( pszBuffer,
|
|
"<table>"
|
|
"<tr><td>Current memory cache size</td><td align=right>%I64d</td></tr>"
|
|
"<tr><td>Current memory cache limit</td><td align=right>%I64d</td></tr>"
|
|
"<tr><td>Number of items in memory cache</td><td align=right>%d</td></tr>"
|
|
"<tr><td>Peak memory cache size</td><td align=right>%I64d</td></tr>"
|
|
"<tr><td>Peak memory cache element count</td><td align=right>%d</td></tr>"
|
|
"</table>",
|
|
g_cbMemCacheSize,
|
|
g_cbMaxMemCacheSize,
|
|
g_cMemCacheElements,
|
|
g_cbMaxMemCacheUsed,
|
|
g_cMaxMemCacheElementsUsed
|
|
);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
QueryMemoryCacheStatistics(
|
|
IN INETA_CACHE_STATISTICS * pCacheCtrs,
|
|
IN BOOL fClearAll
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query memory cache perfmon counters
|
|
|
|
Arguments:
|
|
|
|
pCacheCtrs - Relevant members of stat structure are filled in
|
|
fClearAll - Clear the counters
|
|
|
|
Return value:
|
|
|
|
ERROR_SUCCESS if successful, else Win32 Error
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( pCacheCtrs );
|
|
|
|
if ( fClearAll )
|
|
{
|
|
pCacheCtrs->CurrentFileCacheSize = 0;
|
|
pCacheCtrs->MaximumFileCacheSize = 0;
|
|
}
|
|
else
|
|
{
|
|
pCacheCtrs->CurrentFileCacheSize = g_cbMemCacheSize;
|
|
pCacheCtrs->MaximumFileCacheSize = g_cbMaxMemCacheUsed;
|
|
}
|
|
}
|