/*++ Copyright (c) 1999 Microsoft Corporation Module Name : cachehint.cxx Abstract: Provides hint to caches about whether or not to cache an entry, based on usage patterns Author: Bilal Alam (balam) 11-Nov-2000 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" #include "cachehint.hxx" BOOL CACHE_HINT_ENTRY::QueryIsOkToCache( DWORD tickCountNow, DWORD cmsecActivityWindow ) /*++ Routine Description: Is it OK to cache entry, given recent activity Arguments: tickCountNow - Current tick count cmsecActivityWindow - Maximum window between access to cause caching Return Value: TRUE to cache, FALSE to not cache --*/ { DWORD lastUsageTime; DWORD timeBetweenUsage; lastUsageTime = InterlockedExchange( (LPLONG) &_cLastUsageTime, tickCountNow ); if ( lastUsageTime > tickCountNow ) { timeBetweenUsage = tickCountNow + ( UINT_MAX - lastUsageTime ); } else { timeBetweenUsage = tickCountNow - lastUsageTime; } if ( timeBetweenUsage < cmsecActivityWindow ) { return TRUE; } else { return FALSE; } } CACHE_HINT_MANAGER::CACHE_HINT_MANAGER() : _cConfiguredTTL( 0 ), _cmsecActivityWindow( 0 ), _hTimer( NULL ) { } CACHE_HINT_MANAGER::~CACHE_HINT_MANAGER() { if ( _hTimer ) { DeleteTimerQueueTimer( NULL, _hTimer, INVALID_HANDLE_VALUE ); _hTimer = NULL; } } //static VOID WINAPI CACHE_HINT_MANAGER::ScavengerCallback( PVOID pParam, BOOLEAN TimerOrWaitFired ) { CACHE_HINT_MANAGER * pHintManager; pHintManager = (CACHE_HINT_MANAGER*) pParam; pHintManager->FlushByTTL(); } //static LK_PREDICATE CACHE_HINT_MANAGER::HintFlushByTTL( CACHE_HINT_ENTRY * pHintEntry, VOID * pvState ) /*++ Routine Description: Determine whether given entry should be deleted due to TTL Arguments: pCacheEntry - Cache hint entry to check pvState - Unused Return Value: LKP_PERFORM - do the delete, LKP_NO_ACTION - do nothing --*/ { DBG_ASSERT( pHintEntry != NULL ); if ( pHintEntry->QueryIsOkToFlushTTL() ) { return LKP_PERFORM; } else { return LKP_NO_ACTION; } } VOID CACHE_HINT_MANAGER::FlushByTTL( VOID ) /*++ Routine Description: Flush hint entries which have expired Arguments: None Return Value: None --*/ { _hintTable.DeleteIf( HintFlushByTTL, NULL ); } HRESULT CACHE_HINT_MANAGER::Initialize( CACHE_HINT_CONFIG * pConfig ) /*++ Routine Description: Initialize cache hint table Arguments: pConfig - Cache hint config table Return Value: HRESULT --*/ { BOOL fRet; if ( pConfig == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } _cConfiguredTTL = pConfig->cmsecTTL / pConfig->cmsecScavengeTime + 1; _cmsecActivityWindow = pConfig->cmsecActivityWindow; fRet = CreateTimerQueueTimer( &_hTimer, NULL, CACHE_HINT_MANAGER::ScavengerCallback, this, pConfig->cmsecScavengeTime, pConfig->cmsecScavengeTime, WT_EXECUTELONGFUNCTION ); if ( !fRet ) { return HRESULT_FROM_WIN32( GetLastError() ); } return NO_ERROR; } HRESULT CACHE_HINT_MANAGER::ShouldCacheEntry( CACHE_KEY * pCacheEntryKey, BOOL * pfShouldCache ) /*++ Routine Description: Determine whether we the given entry should be cached Arguments: pCacheEntryKey - Entry key in question (must implement QueryHintKey()) pfShouldCache - Set to TRUE if we should cache Return Value: HRESULT --*/ { LK_RETCODE lkrc; CACHE_HINT_ENTRY * pHintEntry = NULL; DWORD tickCount; HRESULT hr; if ( pCacheEntryKey == NULL || pfShouldCache == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } *pfShouldCache = FALSE; DBG_ASSERT( pCacheEntryKey->QueryHintKey() != NULL ); lkrc = _hintTable.FindKey( pCacheEntryKey->QueryHintKey(), &pHintEntry ); if ( lkrc == LK_SUCCESS ) { DBG_ASSERT( pHintEntry != NULL ); tickCount = GetTickCount(); if ( pHintEntry->QueryIsOkToCache( tickCount, _cmsecActivityWindow ) ) { // // We can delete this hint entry now // _hintTable.DeleteRecord( pHintEntry ); *pfShouldCache = TRUE; } // // Release corresponding to the FindKey // pHintEntry->Release(); } else { pHintEntry = new CACHE_HINT_ENTRY( _cConfiguredTTL, GetTickCount() ); if ( pHintEntry == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } hr = pHintEntry->SetKey( pCacheEntryKey->QueryHintKey() ); if ( FAILED( hr ) ) { pHintEntry->Release(); return hr; } lkrc = _hintTable.InsertRecord( pHintEntry ); // // Release the extra reference // pHintEntry->Release(); } return NO_ERROR; }