|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: lru.cpp
//
// Contents: LRU cache implementation
//
// History: 24-Dec-97 kirtd Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
//+---------------------------------------------------------------------------
//
// Member: CLruEntry::CLruEntry, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CLruEntry::CLruEntry ( IN PCLRUCACHE pCache, IN PCRYPT_DATA_BLOB pIdentifier, IN LPVOID pvData, OUT BOOL& rfResult ) { rfResult = TRUE;
m_cRefs = 1; m_pPrevEntry = NULL; m_pNextEntry = NULL; m_Usage = 0;
m_pCache = pCache; m_pvData = pvData; m_pBucket = pCache->BucketFromIdentifier( pIdentifier );
if ( pCache->Flags() & LRU_CACHE_NO_COPY_IDENTIFIER ) { m_Identifier = *pIdentifier; } else { m_Identifier.cbData = pIdentifier->cbData; m_Identifier.pbData = new BYTE [ pIdentifier->cbData ]; if ( m_Identifier.pbData != NULL ) { memcpy( m_Identifier.pbData, pIdentifier->pbData, pIdentifier->cbData ); } else { rfResult = FALSE; SetLastError( (DWORD) E_OUTOFMEMORY ); return; } }
assert( m_pBucket != NULL ); assert( m_Identifier.pbData != NULL ); }
//+---------------------------------------------------------------------------
//
// Member: CLruEntry::~CLruEntry, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CLruEntry::~CLruEntry () { m_pCache->FreeEntryData( m_pvData );
if ( !( m_pCache->Flags() & LRU_CACHE_NO_COPY_IDENTIFIER ) ) { delete m_Identifier.pbData; } }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::CLruCache, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CLruCache::CLruCache ( IN PLRU_CACHE_CONFIG pConfig, OUT BOOL& rfResult ) { rfResult = TRUE;
m_Config.dwFlags = LRU_CACHE_NO_SERIALIZE; m_cEntries = 0; m_aBucket = new LRU_CACHE_BUCKET [ pConfig->cBuckets ]; if ( m_aBucket == NULL ) { rfResult = FALSE; SetLastError( (DWORD) E_OUTOFMEMORY ); return; }
memset( m_aBucket, 0, sizeof( LRU_CACHE_BUCKET ) * pConfig->cBuckets );
if ( !( pConfig->dwFlags & LRU_CACHE_NO_SERIALIZE ) ) { if (! Pki_InitializeCriticalSection( &m_Lock )) { rfResult = FALSE; return; } }
m_Config = *pConfig; m_UsageClock = 0; m_cLruDisabled = 0; }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::~CLruCache, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CLruCache::~CLruCache () { if ( m_cEntries > 0 ) { PurgeAllEntries( 0, NULL ); }
if ( !( m_Config.dwFlags & LRU_CACHE_NO_SERIALIZE ) ) { DeleteCriticalSection( &m_Lock ); }
delete m_aBucket; }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::EnableLruOfEntries, public
//
// Synopsis: enable LRU of entries and purge anything over the watermark
//
//----------------------------------------------------------------------------
VOID CLruCache::EnableLruOfEntries (IN OPTIONAL LPVOID pvLruRemovalContext) { LockCache();
assert( m_cLruDisabled > 0 );
if ( m_cLruDisabled == 0 ) { return; }
m_cLruDisabled -= 1;
if ( m_cLruDisabled == 0 ) { while ( m_cEntries > m_Config.MaxEntries ) { PurgeLeastRecentlyUsed( pvLruRemovalContext ); } }
UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::DisableLruOfEntries, public
//
// Synopsis: disable LRU of entries
//
//----------------------------------------------------------------------------
VOID CLruCache::DisableLruOfEntries () { LockCache();
m_cLruDisabled += 1;
UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::InsertEntry, public
//
// Synopsis: insert an entry into the cache
//
//----------------------------------------------------------------------------
VOID CLruCache::InsertEntry ( IN PCLRUENTRY pEntry, IN OPTIONAL LPVOID pvLruRemovalContext ) { assert( pEntry->PrevPointer() == NULL ); assert( pEntry->NextPointer() == NULL );
pEntry->AddRef();
LockCache();
if ( ( m_cEntries == m_Config.MaxEntries ) && ( m_Config.MaxEntries != 0 ) && ( m_cLruDisabled == 0 ) ) { PurgeLeastRecentlyUsed( pvLruRemovalContext ); }
assert( ( m_cEntries < m_Config.MaxEntries ) || ( m_Config.MaxEntries == 0 ) || ( m_cLruDisabled > 0 ) );
pEntry->SetNextPointer( pEntry->Bucket()->pList );
if ( pEntry->Bucket()->pList != NULL ) { pEntry->Bucket()->pList->SetPrevPointer( pEntry ); }
pEntry->Bucket()->pList = pEntry;
m_cEntries += 1;
TouchEntryNoLock( pEntry, 0 );
UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::RemoveEntry, public
//
// Synopsis: remove an entry from the cache
//
//----------------------------------------------------------------------------
VOID CLruCache::RemoveEntry ( IN PCLRUENTRY pEntry, IN DWORD dwFlags, IN OPTIONAL LPVOID pvRemovalContext ) { LockCache();
RemoveEntryFromBucket( pEntry->Bucket(), pEntry, dwFlags, pvRemovalContext );
UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::TouchEntry, public
//
// Synopsis: touch the entry
//
//----------------------------------------------------------------------------
VOID CLruCache::TouchEntry (IN PCLRUENTRY pEntry, IN DWORD dwFlags) { LockCache();
TouchEntryNoLock( pEntry, dwFlags );
UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::FindEntry, public
//
// Synopsis: find the entry matching the given identifier
//
//----------------------------------------------------------------------------
PCLRUENTRY CLruCache::FindEntry (IN PCRYPT_DATA_BLOB pIdentifier, IN BOOL fTouchEntry) { PLRU_CACHE_BUCKET pBucket;
pBucket = BucketFromIdentifier( pIdentifier );
assert( pBucket != NULL );
return( FindNextMatchingEntryInBucket( pBucket, NULL, pIdentifier, fTouchEntry ) ); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::NextMatchingEntry, public
//
// Synopsis: find the next matching entry to pPrevEntry
//
//----------------------------------------------------------------------------
PCLRUENTRY CLruCache::NextMatchingEntry (IN PCLRUENTRY pPrevEntry, IN BOOL fTouchEntry) { PCLRUENTRY pNextEntry;
pNextEntry = FindNextMatchingEntryInBucket( NULL, pPrevEntry, NULL, fTouchEntry );
pPrevEntry->Release();
return( pNextEntry ); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::WalkEntries, public
//
// Synopsis: walk the entries
//
//----------------------------------------------------------------------------
VOID CLruCache::WalkEntries (IN PFN_WALK_ENTRIES pfnWalk, IN LPVOID pvParameter) { DWORD cCount; PCLRUENTRY pEntry; PCLRUENTRY pNextEntry;
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ ) { pEntry = m_aBucket[ cCount ].pList;
while ( pEntry != NULL ) { pNextEntry = pEntry->NextPointer();
if ( ( *pfnWalk )( pvParameter, pEntry ) == FALSE ) { return; }
pEntry = pNextEntry; } } }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::RemoveEntryFromBucket, public
//
// Synopsis: remove entry from bucket
//
//----------------------------------------------------------------------------
VOID CLruCache::RemoveEntryFromBucket ( IN PLRU_CACHE_BUCKET pBucket, IN PCLRUENTRY pEntry, IN DWORD dwFlags, IN OPTIONAL LPVOID pvRemovalContext ) { if ( pEntry->PrevPointer() != NULL ) { pEntry->PrevPointer()->SetNextPointer( pEntry->NextPointer() ); } else { assert( pBucket->pList == pEntry );
pBucket->pList = pEntry->NextPointer(); }
if ( pEntry->NextPointer() != NULL ) { pEntry->NextPointer()->SetPrevPointer( pEntry->PrevPointer() ); }
pEntry->SetPrevPointer( NULL ); pEntry->SetNextPointer( NULL );
m_cEntries -= 1;
if ( ( m_Config.pfnOnRemoval != NULL ) && !( dwFlags & LRU_SUPPRESS_REMOVAL_NOTIFICATION ) ) { ( *m_Config.pfnOnRemoval )( pEntry->Data(), pvRemovalContext ); }
pEntry->Release(); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::FindNextMatchingEntryInBucket, public
//
// Synopsis: find the next matching entry in the given bucket. If pCurrent
// is non NULL then start from there, the bucket is not needed and
// pIdentifier is ignored. If pCurrent is NULL then pIdentifier
// and the bucket must both be non NULL
//
//----------------------------------------------------------------------------
PCLRUENTRY CLruCache::FindNextMatchingEntryInBucket ( IN PLRU_CACHE_BUCKET pBucket, IN PCLRUENTRY pCurrent, IN PCRYPT_DATA_BLOB pIdentifier, IN BOOL fTouchEntry ) { LockCache();
if ( pCurrent == NULL ) { pCurrent = pBucket->pList; } else { pIdentifier = pCurrent->Identifier(); pCurrent = pCurrent->NextPointer(); }
while ( pCurrent != NULL ) { if ( ( pIdentifier->cbData == pCurrent->Identifier()->cbData ) && ( memcmp( pIdentifier->pbData, pCurrent->Identifier()->pbData, pIdentifier->cbData ) == 0 ) ) { break; }
pCurrent = pCurrent->NextPointer(); }
if ( pCurrent != NULL ) { pCurrent->AddRef();
if ( fTouchEntry == TRUE ) { TouchEntryNoLock( pCurrent, 0 ); } }
UnlockCache();
return( pCurrent ); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::PurgeLeastRecentlyUsed, public
//
// Synopsis: find and remove the least recently used entry
//
//----------------------------------------------------------------------------
VOID CLruCache::PurgeLeastRecentlyUsed (IN OPTIONAL LPVOID pvLruRemovalContext) { DWORD cCount; PLRU_CACHE_BUCKET pBucket; PCLRUENTRY pEntry; PCLRUENTRY pLRU;
assert( m_cEntries > 0 );
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ ) { if ( m_aBucket[cCount].pList != NULL ) { break; } }
pBucket = &m_aBucket[cCount]; cCount += 1; for ( ; cCount < m_Config.cBuckets; cCount++ ) { if ( ( m_aBucket[cCount].pList != NULL ) && ( m_aBucket[cCount].Usage < pBucket->Usage ) ) { pBucket = &m_aBucket[cCount]; } }
assert( pBucket != NULL ); assert( pBucket->pList != NULL );
pLRU = pBucket->pList; pEntry = pLRU->NextPointer();
while ( pEntry != NULL ) { if ( pEntry->Usage() < pLRU->Usage() ) { pLRU = pEntry; }
pEntry = pEntry->NextPointer(); }
RemoveEntryFromBucket( pBucket, pLRU, 0, pvLruRemovalContext ); }
//+---------------------------------------------------------------------------
//
// Member: CLruCache::PurgeAllEntries, public
//
// Synopsis: remove all entries from the cache
//
//----------------------------------------------------------------------------
VOID CLruCache::PurgeAllEntries ( IN DWORD dwFlags, IN OPTIONAL LPVOID pvRemovalContext ) { DWORD cCount;
for ( cCount = 0; cCount < m_Config.cBuckets; cCount++ ) { while ( m_aBucket[cCount].pList != NULL ) { RemoveEntryFromBucket( &m_aBucket[cCount], m_aBucket[cCount].pList, dwFlags, pvRemovalContext ); } }
assert( m_cEntries == 0 ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptCreateLruCache
//
// Synopsis: create an LRU cache area
//
//----------------------------------------------------------------------------
BOOL WINAPI I_CryptCreateLruCache ( IN PLRU_CACHE_CONFIG pConfig, OUT HLRUCACHE* phCache ) { BOOL fResult = FALSE; PCLRUCACHE pCache;
pCache = new CLruCache( pConfig, fResult ); if ( pCache == NULL ) { SetLastError( (DWORD) E_OUTOFMEMORY ); return( FALSE ); }
if ( fResult == FALSE ) { delete pCache; return( FALSE ); }
*phCache = (HLRUCACHE)pCache; return( TRUE ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptFlushLruCache
//
// Synopsis: flush the cache
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptFlushLruCache ( IN HLRUCACHE hCache, IN OPTIONAL DWORD dwFlags, IN OPTIONAL LPVOID pvRemovalContext ) { ( (PCLRUCACHE)hCache )->LockCache();
( (PCLRUCACHE)hCache )->PurgeAllEntries( dwFlags, pvRemovalContext );
( (PCLRUCACHE)hCache )->UnlockCache(); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptFreeLruCache
//
// Synopsis: free the LRU cache area
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptFreeLruCache ( IN HLRUCACHE hCache, IN DWORD dwFlags, IN OPTIONAL LPVOID pvRemovalContext ) { if ( hCache == NULL ) { return; }
if ( dwFlags != 0 ) { ( (PCLRUCACHE)hCache )->PurgeAllEntries( dwFlags, pvRemovalContext ); }
delete (PCLRUCACHE)hCache; }
//+---------------------------------------------------------------------------
//
// Function: I_CryptCreateLruEntry
//
// Synopsis: create an LRU entry
//
//----------------------------------------------------------------------------
BOOL WINAPI I_CryptCreateLruEntry ( IN HLRUCACHE hCache, IN PCRYPT_DATA_BLOB pIdentifier, IN LPVOID pvData, OUT HLRUENTRY* phEntry ) { BOOL fResult = FALSE; PCLRUENTRY pEntry;
pEntry = new CLruEntry( (PCLRUCACHE)hCache, pIdentifier, pvData, fResult );
if ( pEntry == NULL ) { SetLastError( (DWORD) E_OUTOFMEMORY ); return( FALSE ); }
if ( fResult == FALSE ) { delete pEntry; return( FALSE ); }
*phEntry = (HLRUENTRY)pEntry; return( TRUE ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptGetLruEntryIdentifier
//
// Synopsis: return the identifier for the entry
//
//----------------------------------------------------------------------------
PCRYPT_DATA_BLOB WINAPI I_CryptGetLruEntryIdentifier ( IN HLRUENTRY hEntry ) { return( ( (PCLRUENTRY)hEntry )->Identifier() ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptGetLruEntryData
//
// Synopsis: get the data associated with the entry
//
//----------------------------------------------------------------------------
LPVOID WINAPI I_CryptGetLruEntryData ( IN HLRUENTRY hEntry ) { return( ( (PCLRUENTRY)hEntry )->Data() ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptAddRefLruEntry
//
// Synopsis: add a reference to the entry
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptAddRefLruEntry ( IN HLRUENTRY hEntry ) { ( (PCLRUENTRY)hEntry )->AddRef(); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptReleaseLruEntry
//
// Synopsis: remove a reference from the entry
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptReleaseLruEntry ( IN HLRUENTRY hEntry ) { ( (PCLRUENTRY)hEntry )->Release(); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptInsertLruEntry
//
// Synopsis: insert the entry into its associated cache
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptInsertLruEntry ( IN HLRUENTRY hEntry, IN OPTIONAL LPVOID pvLruRemovalContext ) { PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->InsertEntry( pEntry, pvLruRemovalContext ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptRemoveLruEntry
//
// Synopsis: remove the entry from its associated cache
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptRemoveLruEntry ( IN HLRUENTRY hEntry, IN DWORD dwFlags, IN LPVOID pvLruRemovalContext ) { PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->RemoveEntry( pEntry, dwFlags, pvLruRemovalContext ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptTouchLruEntry
//
// Synopsis: touch the entry
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptTouchLruEntry ( IN HLRUENTRY hEntry, IN DWORD dwFlags ) { PCLRUENTRY pEntry = (PCLRUENTRY)hEntry;
pEntry->Cache()->TouchEntry( pEntry, dwFlags ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptFindLruEntry
//
// Synopsis: find the entry with the given identifier
//
//----------------------------------------------------------------------------
HLRUENTRY WINAPI I_CryptFindLruEntry ( IN HLRUCACHE hCache, IN PCRYPT_DATA_BLOB pIdentifier ) { PCLRUCACHE pCache = (PCLRUCACHE)hCache;
return( pCache->FindEntry( pIdentifier, FALSE ) ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptFindLruEntryData
//
// Synopsis: find the entry with the given identifier
//
//----------------------------------------------------------------------------
LPVOID WINAPI I_CryptFindLruEntryData ( IN HLRUCACHE hCache, IN PCRYPT_DATA_BLOB pIdentifier, OUT HLRUENTRY* phEntry ) { PCLRUCACHE pCache = (PCLRUCACHE)hCache; PCLRUENTRY pEntry;
pEntry = pCache->FindEntry( pIdentifier, TRUE ); *phEntry = (HLRUENTRY)pEntry;
if ( pEntry != NULL ) { return( pEntry->Data() ); }
return( NULL ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptEnumMatchingLruEntries
//
// Synopsis: get the next matching entry
//
//----------------------------------------------------------------------------
HLRUENTRY WINAPI I_CryptEnumMatchingLruEntries ( IN HLRUENTRY hPrevEntry ) { PCLRUCACHE pCache = ( (PCLRUENTRY)hPrevEntry )->Cache(); PCLRUENTRY pNextEntry;
pNextEntry = pCache->NextMatchingEntry( (PCLRUENTRY)hPrevEntry, FALSE );
return( (HLRUENTRY)pNextEntry ); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptEnableLruOfEntries
//
// Synopsis: enable LRU of entries
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptEnableLruOfEntries ( IN HLRUCACHE hCache, IN OPTIONAL LPVOID pvLruRemovalContext ) { ( (PCLRUCACHE)hCache )->EnableLruOfEntries( pvLruRemovalContext); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptDisableLruOfEntries
//
// Synopsis: disable LRU of entries
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptDisableLruOfEntries ( IN HLRUCACHE hCache ) { ( (PCLRUCACHE)hCache )->DisableLruOfEntries(); }
//+---------------------------------------------------------------------------
//
// Function: I_CryptWalkAllLruCacheEntries
//
// Synopsis: walk the LRU cache entries
//
//----------------------------------------------------------------------------
VOID WINAPI I_CryptWalkAllLruCacheEntries ( IN HLRUCACHE hCache, IN PFN_WALK_ENTRIES pfnWalk, IN LPVOID pvParameter ) { ( (PCLRUCACHE)hCache )->WalkEntries( pfnWalk, pvParameter ); }
|