|
|
/*++
CacheMTX.h
This file provides the definition of the all the template functions required by cachemt.h
--*/
#ifndef _CACHEMTX_H_
#define _CACHEMTX_H_
//
// This member function removes entries from the cache -
// we remove them from the hash table which leads to destruction !
//
template< class Data, class Key, class Constructor > void CacheImp<Data, Key, Constructor>::RemoveEntry( CacheState* pCacheState ) { /*++
Routine Description :
Remove a CacheState object from the hash table
Arguments :
pCacheState - The CacheState derived object about to be destroyed
Return Value :
TRUE if removed !
--*/ TENTRY* pEntry = (TENTRY*)pCacheState ; Key k; pEntry->GetKey(k); m_Lookup.DeleteData( k, pEntry ) ; }
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::QueryRemoveEntry( CacheState* pState ) { /*++
Routine Description :
Determine whether we want to remove an entry from cache - do so by calling a user provided object stored in a member variable - m_pCurrent
Arguments :
pCacheState - The CacheState object we're curious about
Return Value :
TRUE if removed !
--*/ _ASSERT( m_pCurrent != 0 ) ;
TENTRY* pEntry = (TENTRY*)pState ; if( m_pCurrent ) return m_pCurrent->fRemoveCacheItem( *pEntry->m_pData ) ; return TRUE ; }
template< class Data, class Key, class Constructor > CacheImp<Data, Key, Constructor>::CacheImp() : m_dwSignature( DWORD('hcaC') ) , m_pCurrent( 0 ) { /*++
Routine Description :
Construct a CacheImp object - Init() must be called before any use
Arguments :
None
Return Value :
None
--*/
}
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::FindOrCreate( FORC_ARG& args, FORC_RES& result ) { /*++
Routine Description :
Either find an object in the cache or create a new one !
Arguments :
args - a structure containing all of the things we need, m_dwHash - the hash of the key m_key - the actual key of the item we're looking for m_constructor - the object which would create a new item into the cace !
result - a smartptr to the resulting object !
Return Value :
We always return TRUE, indicating that the caller can marshall the results back to the end-user at any time.
--*/
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
_ASSERT( args.m_dwHash == ComputeHash( args.m_key ) ) ;
//
// Check to see whether the item is already in the cache !
//
TENTRY *pEntry = m_Lookup.SearchKeyHash( args.m_dwHash, args.m_key ) ;
//
// Entry is already present - move it to the back !
//
if( pEntry ) { //
// Update the entry's last access time !
//
pEntry->Stamp() ; //
// Recently touched, so send to the back of the expire list !
//
m_ExpireList.MoveToBack( pEntry ) ; result = pEntry->m_pData ; } else { //
// NOTE : TENTRY's constructor will stamp the time fields as required !
//
Data* pData = args.m_constructor.Create( args.m_key ) ; if( pData && pData->Init( constructor ) ) {
TENTRY* pEntry = new TENTRY( pData ) ; //
// Error paths will destroy this unless we set it to NULL !
//
pData = 0 ;
//
// If we managed to construct everything !
//
if( pEntry ) { TENTRY* pCacheEntry = m_Lookup.InsertDataHash( args.m_dwHash, *pEntry ) ; if( pCacheEntry ) { //
// Error paths will destroy this unless we set it to NULL !
//
pEntry = 0 ; //
// Add to the expiration list -
//
if( m_ExpireList.Append( pCacheEntry ) ) { //
// The expiration list is at max capacity - should remove something !
//
EXP_ARG args( 0, 0 ) ; DWORD count ; Expunge( args, count ) ;
} result = pCacheEntry->m_pData ; } } if( pEntry ) { delete pEntry ; } } if( pData ) { delete pData ; } }
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
return TRUE ; }
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::Expunge( EXP_ARG& args, DWORD& countExpunged ) { /*++
Routine Description :
Find an object in the cache and remove it!
Arguments :
args - a structure containing all of the things we need, m_pkey - pointer to the key of the item to be removed m_pData - pointer to the Cache element holding the item. countExpunged - how many objects removed from the cache - should be 1 if the specified item is found. Return Value :
We always return TRUE, indicating that the caller can marshall the results back to the end-user at any time.
--*/
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
countExpunged = 0 ; if( args.m_pkey ) { TENTRY* pRemoved = m_Lookup.DeleteData( *args.m_pkey, args.m_pData ) ; if( pRemoved ) { m_ExpireList.Remove( pRemoved ) ; countExpunged = 1; delete pRemoved ; //
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ; return TRUE ; } } m_ExpireList.Expunge( this, 0, countExpunged, TRUE ) ;
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ; return TRUE ; }
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::ExpungeSpecific( EXP_SPECIFIC_ARG& args, DWORD& countExpunged ) { /*++
Routine Description :
Select a set of items in the cache for removal ! Arguments :
args - a structure containing all of the things we need, m_pCacheCallback - an object to be called to select the items to be removed from the cache. countExpunged - how many objects removed from the cache - should be 1 if the specified item is found. Return Value :
We always return TRUE, indicating that the caller can marshall the results back to the end-user at any time.
--*/
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
countExpunged = 0 ;
m_pCurrent = args.m_pCacheCallback ;
m_ExpireList.ExpungeSpecific( this, args.m_fForced, countExpunged ) ;
m_pCurrent = 0 ;
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
return TRUE ; }
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::Expire( DWORD& countExpunged ) { /*++
Routine Description :
Remove the old items from the cache !
Arguments :
countExpunged - how many objects removed from the cache - should be 1 if the specified item is found. Return Value :
We always return TRUE, indicating that the caller can marshall the results back to the end-user at any time.
--*/
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ;
countExpunged = 0 ;
FILETIME filetimeNow ; GetSystemTimeAsFileTime( &filetimeNow ) ;
ULARGE_INTEGER ulNow ; ulNow.LowPart = filetimeNow.dwLowDateTime ; ulNow.HighPart = filetimeNow.dwHighDateTime ;
ulNow.QuadPart -= m_qwExpire.QuadPart ;
filetimeNow.dwLowDateTime = ulNow.LowPart ; filetimeNow.dwHighDateTime = ulNow.HighPart ; m_ExpireList.Expunge( this, &filetimeNow, countExpunged, FALSE ) ;
//
// Check that our state is good !
//
_ASSERT( m_ExpireList.IsValid() ) ; return TRUE ; }
//
// The following set of functions are for synchronous use
// such as Initialization and Termination of the Cache.
//
//
// Initialization function - take pointer to function
// which should be used to compute hash values on Key's
// Also takes the number of seconds objects should live in
// the cache !
//
template< class Data, class Key, class Constructor > BOOL CacheImp<Data, Key, Constructor>::Init( DWORD (*pfnHash)( const Key& ), DWORD dwLifetimeSeconds, DWORD cMaxInstances, PSTOPHINT_FN pfnStopHint ) { /*++
Routine Description :
Initialize the cache !
Arguments :
pfnHash - The function which can compute the hash value of a key dwLifetimeSeconds - The oldest we should let items get within the cache cMaxInstances - The maximum number of items we should allow in the cache ! Return Value :
We return TRUE if the cache successfully initializes.
--*/
m_qwExpire.QuadPart = DWORDLONG(dwLifetimeSeconds) * DWORDLONG( 10000000 ) ;
return m_Lookup.Init( &TENTRY::m_pBucket, 100, 100, pfnHash ) ; }
template< class Data, class Key, class Constructor > DWORD CacheImp<Data, Key, Constructor>::ComputeHash( Key& key ) { return m_Lookup.ComputeHash( key ) ; }
//
// Default constructor
//
template< class Data, class Key, class Constructor > TAsyncCache< Data, Key, Constructor >::TAsyncCache() : m_Service( m_Implementation ), m_dwSignature( DWORD('CysA' ) ) { }
//
// Find an Item in the Cache or Create an Item to be held in the Cache !
//
template< class Data, class Key, class Constructor > BOOL TAsyncCache< Data, Key, Constructor >::FindOrCreate( CStateStackInterface& allocator, DWORD dwHash, Key& key, Constructor& constructor, COMP_OBJ* pComplete ) { /*++
Routine Description :
Marshall all the arguments for Finding and Creating Cache Items to the implementation class !
Arguments :
key - The key of the item we want to find in the cache constructor - The object which can create an item if needed pComplete - the object which is notified if we manage to pend the call
Return Value :
TRUE if the operation is pending FALSE otherwise !
--*/
_ASSERT( !FOnMyStack( pComplete ) ) ; _ASSERT( !FOnMyStack( &constructor ) ) ; _ASSERT( !FOnMyStack( &key ) ) ;
_ASSERT( dwHash == m_Implementation.ComputeHash( key ) ) ;
if( m_fGood ) { IMP::FORC_ARG args( dwHash, key, constructor ) ; CACHE_CREATE_CALL* pcall = new( allocator ) CACHE_CREATE_CALL( allocator, &IMP::FindOrCreate, args, pComplete ) ; if( pcall ) { m_Service.QueueRequest( pcall ) ; return TRUE ; } } return FALSE ; }
//
// Remove an Item from the cache !
//
//
// Function which can be used to remove items from the Cache
//
template< class Data, class Key, class Constructor > BOOL TAsyncCache< Data, Key, Constructor >::Expunge( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete, Key* key, IMP::TENTRY* pData ) { /*++
Routine Description :
Marshall all the arguments for removing an item from the cache !
Arguments :
pComplete - the object which is notified if we manage to pend the call key - the key of the item to be removed from the cache pData - for internal use only !
Return Value :
TRUE if the operation is pending FALSE otherwise !
--*/
if( m_fGood ) { IMP::EXP_ARG args( key, pData ) ; EXPUNGE_CALL* pcall = new( allocator ) EXPUNGE_CALL( allocator, &IMP::Expunge, args, pComplete ) ; if( pcall ) { m_Service.QueueRequest( pcall ) ; return TRUE ; } } return FALSE ; }
//
// Function which can be passed a function pointer to determine
// exactly what items are to be removed from the Cache.
// if fForced == TRUE then items are removed from the Cache
// no matter what.
//
template< class Data, class Key, class Constructor > BOOL TAsyncCache< Data, Key, Constructor >::ExpungeSpecific( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete, class CacheCallback< Data >* pSelector, BOOL fForced, TEntry<Data,Key>* pProtected ) { /*++
Routine Description :
Marshall all the arguments for removing a set of items form the cache
Arguments :
pComplete - the object which is notified if we manage to pend the call pSelector - the object which will select what is to be removed from the cache ! fForced - if TRUE kick items out of the cache even if there are external references ! Return Value :
TRUE if the operation is pending FALSE otherwise !
--*/
if( m_fGood ) { IMP::EXP_SPECIFIC_ARG args( pSelector, pProtected, fForced ) ; EXPUNGE_SPECIFIC* pcall = new( allocator ) EXPUNGE_SPECIFIC( allocator, &IMP::ExpungeSpecific, args, pComplete ) ; if( pcall ) { m_Service.QueueRequest( pcall ) ; return TRUE ; } } return FALSE ; }
//
// Expire old stuff in the cache - everything older than
// dwLifetimeSeconds (specified at Init() time
// which is NOT in use should be kicked out.
//
template< class Data, class Key, class Constructor > BOOL TAsyncCache< Data, Key, Constructor >::Expire( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete ) { /*++
Routine Description :
Marshall all the arguments for expiring all the old items in the cache
Arguments :
pComplete - the object which is notified if we manage to pend the call Return Value :
TRUE if the operation is pending FALSE otherwise !
--*/
if( m_fGood ) { EXPIRE_CALL* pcall = new( allocator ) EXPIRE_CALL( allocator, &IMP::Expire, pComplete ) ; if( pcall ) { m_Service.QueueRequest( pcall ) ; return TRUE ; } } return FALSE ; }
//
// Initialization function - take pointer to function
// which should be used to compute hash values on Key's
// Also takes the number of seconds objects should live in
// the cache !
//
template< class Data, class Key, class Constructor > BOOL TAsyncCache< Data, Key, Constructor >::Init( DWORD (*pfnHash)( const Key& ), DWORD dwLifetimeSeconds, DWORD cMaxInstances, PSTOPHINT_FN pfnStopHint ) { /*++
Routine Description : Initialize the cache
Arguments :
pfnHash - the function used to compute hash values for keys dwLifetimeSeconds - How long something should stay in the cache in units of seconds. cMaxInstances - the maximum number of items in the cache Return Value :
TRUE if successfull FALSE otherwise !
--*/
m_fGood = m_Implementation.Init( pfnHash, dwLifetimeSeconds, cMaxInstances, pfnStopHint ) ; return m_fGood ; }
template< class Data, class Key, class Constructor > TMultiAsyncCache< Data, Key, Constructor >::TMultiAsyncCache() : m_dwSignature( DWORD( 'tluM' ) ), m_cSubCaches( 0 ), m_pfnHash( 0 ), m_pCaches( 0 ) { /*++
Routine Description :
Construct a MultiAsyncCache - Init() must be called before we can be used
Arguments :
None
Return Value :
None
--*/
}
template< class Data, class Key, class Constructor > TMultiAsyncCache< Data, Key, Constructor >::~TMultiAsyncCache() {
if( m_pCaches != 0 ) delete[] m_pCaches ;
}
template< class Data, class Key, class Constructor > DWORD TMultiAsyncCache< Data, Key, Constructor >::ChooseInstance( DWORD dwHash ) { /*++
Routine Description :
given the hash value of a key - figure out where it should be stored.
Arguments :
dwHash - Computed hash value of a key
Return Value :
index into m_pCaches
--*/
_ASSERT( m_pCaches != 0 ) ; _ASSERT( m_cSubCaches != 0 ) ;
dwHash = (((dwHash * 214013) +2531011) >> 8) % m_cSubCaches ;
return dwHash ;
}
template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::Init( DWORD cCaches, DWORD (*pfnHash)( const Key& ), DWORD dwLifetimeSeconds, DWORD cMaxInstances, PSTOPHINT_FN pfnStopHint ) { /*++
Routine Description :
Initialize the MultiWay Cache - Allocate several subcaches to route requests too.
Arguments :
cCaches - Number of SubCaches to use ! pfnHash - Hash Function for cache elements dwLifetimeSeconds - How long things can stay in the cache ! cMaxInstances - Maximum number of elements in the cache ! pfnStopHint - function to call during shutdown !
Return Value :
TRUE if successfull - FALSE otherwise.
--*/
_ASSERT( cCaches != 0 ) ; _ASSERT( pfnHash != 0 ) ; _ASSERT( dwLifetimeSeconds > 0 ) ; _ASSERT( cMaxInstances > cCaches ) ;
m_cSubCaches = cCaches ; m_pfnHash = pfnHash ; m_pCaches = new ASYNCCACHEINSTANCE[m_cSubCaches ] ;
if( !m_pCaches ) return FALSE ; else { for( DWORD i=0; i<m_cSubCaches; i++ ) { if( !m_pCaches[i].Init( pfnHash, dwLifetimeSeconds, cMaxInstances / cCaches, pfnStopHint ) ) { delete m_pCaches ; return FALSE ; } } } return TRUE ; } template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::FindOrCreate( CStateStackInterface& allocator, DWORD dwHash, Key& key, Constructor& constructor, COMP_OBJ* pComplete ) { /*++
Routine Description :
Find an Element within the Cache - and if its not present, create it !
Arguments : dwHash - the hash of the key key - the key of the item in the cache constructor - the object which will create the data item if required. pComplete - the object which gets the completion notification !
Return Value :
TRUE if successfull - FALSE otherwise.
--*/
_ASSERT( !FOnMyStack( pComplete ) ) ; _ASSERT( !FOnMyStack( &constructor ) ) ; _ASSERT( !FOnMyStack( &key ) ) ;
_ASSERT( m_cSubCaches != 0 ) ; _ASSERT( m_pCaches != 0 ) ; _ASSERT( dwHash == m_pfnHash( key ) ) ;
ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ; return pInstance->FindOrCreate( allocator, dwHash, key, constructor, pComplete ) ; }
template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::FindOrCreate( CStateStackInterface& allocator, Key& key, Constructor& constructor, COMP_OBJ* pComplete ) { /*++
Routine Description :
Find an Element within the Cache - and if its not present, create it !
Arguments : dwHash - the hash of the key key - the key of the item in the cache constructor - the object which will create the data item if required. pComplete - the object which gets the completion notification !
Return Value :
TRUE if successfull - FALSE otherwise.
--*/
_ASSERT( m_cSubCaches != 0 ) ; _ASSERT( m_pCaches != 0 ) ; _ASSERT( m_pfnHash != 0 ) ;
_ASSERT( !FOnMyStack( pComplete ) ) ; _ASSERT( !FOnMyStack( &constructor ) ) ; _ASSERT( !FOnMyStack( &key ) ) ;
DWORD dwHash = m_pfnHash( key ) ;
ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ; return pInstance->FindOrCreate( allocator, dwHash, key, constructor, pComplete ) ; }
template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::Expunge( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete, Key* key ) { /*++
Routine Description :
Remove a particular item from the cache - this will cause the cache to loose its reference to the item.
Arguments :
pComplete - the object to be notified once the target object is removed key - key of the item to be removed - if NULL remove a single random element. pData - Not for External Customers - points to internal Cache data structures when we want to ensure we are removing exactly what we want to remove !
Return Value :
TRUE if successfull, FALSE otherwise !
--*/
_ASSERT( !FOnMyStack( pComplete ) ) ; _ASSERT( !FOnMyStack( key ) ) ;
//
// If they gave us a key we can select an Instance !
//
ASYNCCACHEINSTANCE* pInstance = &m_pCaches[0] ; if( key != 0 ) { DWORD dwHash = m_pfnHash( *key ) ; ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ; }
return pInstance->Expunge( allocator, pComplete, key, 0 ) ; }
template< class AsyncCache > class ExpungeWrapper : public AsyncCache::EXP_COMP_OBJ { //
// This class exists to help spread Expunge calls accross
// all the individual classes
//
//
private : //
// The first cache instance
//
AsyncCache* m_pCurrent ; //
// Points beyond the last cache instance
//
AsyncCache* m_pLast ; //
// The user provided Expunge Selector !
//
CacheCallback< AsyncCache::CACHEDATA >* m_pSelector ; //
// Does the user want items forced from the cache !
//
BOOL m_fForced ; //
// Object to notify when we have completed removing objects !
//
AsyncCache::EXP_COMP_OBJ* m_pComplete ; //
// Total number of items removed from the cache !
//
DWORD m_dwTotal ; //
// The stack used to allocate child objects !
//
CStateStackInterface& m_Stack ;
public : ExpungeWrapper( CStateStackInterface& stack, AsyncCache* pFirst, AsyncCache* pLast, AsyncCache::EXP_COMP_OBJ* pComplete, CacheCallback< AsyncCache::CACHEDATA >* pSelector, BOOL fForced ) : m_Stack( stack ), m_pCurrent( pFirst ), m_pLast( pLast ), m_pComplete( pComplete ), m_pSelector( pSelector ), m_fForced( fForced ), m_dwTotal( 0 ) { }
//
// The function which handles error completions !
//
void ErrorComplete( DWORD dw ) { AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ; delete this ; if( pTemp != 0 ) pTemp->ErrorComplete( dw ) ; }
//
// The function which handles regular completions !
//
void Complete( DWORD& dw ) { //
// Add up the total number of items Expunged !
//
m_dwTotal += dw ; //
// If necessary - Do the Expunge in the next portion
// of the cache !
//
if( ++m_pCurrent < m_pLast ) {
if( !m_pCurrent->ExpungeSpecific( m_Stack, this, m_pSelector, m_fForced ) ) { ErrorComplete( 0 ) ; } } else {
//
// Destroy ourselves before giving the client
// a chance to run !!
//
AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ; DWORD dwTemp = m_dwTotal ; delete this ;
//
// Let the end user know how many items were removed !
//
if( pTemp != 0 ) pTemp->Complete( dwTemp ) ; } } } ;
template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::ExpungeSpecific( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete, class CacheCallback< Data >* pSelector, BOOL fForced ) { /*++
Routine Description :
Remove many items from the cache, meeting some specified criteria ! We have to wrap the users completion object with our own, as we will notify the end user when all the other notifications are completed.
Arguments :
pComplete - the object to be notified once the target object is removed key - key of the item to be removed - if NULL remove a single random element. pData - Not for External Customers - points to internal Cache data structures when we want to ensure we are removing exactly what we want to remove !
Return Value :
TRUE if successfull, FALSE otherwise !
--*/
_ASSERT( !FOnMyStack( pComplete ) ) ; _ASSERT( !FOnMyStack( pSelector ) ) ;
typedef ExpungeWrapper< ASYNCCACHEINSTANCE > WRAPPER ;
WRAPPER* pwrapper = new( allocator ) WRAPPER( allocator, &m_pCaches[0], &m_pCaches[m_cSubCaches], pComplete, pSelector, fForced ) ;
if( pwrapper ) { if( m_pCaches[0].ExpungeSpecific( allocator, pwrapper, pSelector, fForced ) ) { return TRUE ; } delete pwrapper ; } return FALSE ; }
template< class AsyncCache > class ExpireWrapper : public AsyncCache::EXP_COMP_OBJ { private : //
// First Cache we execute on !
//
AsyncCache* m_pCurrent ; //
// One beyond the last cache we execute on !
//
AsyncCache* m_pLast ; //
// Total number of objects expired !
//
DWORD m_dwTotal ; //
// Client's completion object !
//
AsyncCache::EXP_COMP_OBJ* m_pComplete ; //
// The stack used to allocate child objects !
//
CStateStackInterface& m_Stack ;
public : ExpireWrapper( CStateStackInterface& stack, AsyncCache* pFirst, AsyncCache* pLast, AsyncCache::EXP_COMP_OBJ* pComplete ) : m_Stack( stack ), m_pCurrent( pFirst ), m_pLast( pLast ), m_pComplete( pComplete ), m_dwTotal( 0 ) { }
//
// The function which handles error completions !
//
void ErrorComplete( DWORD dw ) { AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ; delete this ; if( pTemp != 0 ) pTemp->ErrorComplete( dw ) ; }
//
// The function which handles regular completions !
//
void Complete( DWORD& dw ) { //
// Add up the total number of items Expunged !
//
m_dwTotal += dw ; //
// If necessary - Do the Expunge in the next portion
// of the cache !
//
if( ++m_pCurrent < m_pLast ) {
if( !m_pCurrent->Expire(m_Stack, this ) ) { ErrorComplete( 0 ) ; } } else {
//
// Destroy ourselves before giving the client
// a chance to run !!
//
AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ; DWORD dwTemp = m_dwTotal ; delete this ;
//
// Let the end user know how many items were removed !
//
if( pTemp != 0 ) pTemp->Complete( dwTemp ) ; } } } ;
template< class Data, class Key, class Constructor > BOOL TMultiAsyncCache< Data, Key, Constructor >::Expire( CStateStackInterface& allocator, EXP_COMP_OBJ* pComplete ) { /*++
Routine Description :
Remove many items from the cache, meeting some specified criteria ! We have to wrap the users completion object with our own, as we will notify the end user when all the other notifications are completed.
Arguments :
pComplete - the object to be notified once the target object is removed key - key of the item to be removed - if NULL remove a single random element. pData - Not for External Customers - points to internal Cache data structures when we want to ensure we are removing exactly what we want to remove !
Return Value :
TRUE if successfull, FALSE otherwise !
--*/
_ASSERT( !FOnMyStack( pComplete ) ) ;
typedef ExpireWrapper< ASYNCCACHEINSTANCE > WRAPPER ;
WRAPPER* pwrapper = new( allocator ) WRAPPER( allocator, &m_pCaches[0], &m_pCaches[m_cSubCaches ] , pComplete ) ;
if( pwrapper ) { if( m_pCaches[0].Expire( allocator, pwrapper ) ) { return TRUE ; } delete pwrapper ; } return FALSE ; }
#endif // _CACHEMTX_H_
|