windows-nt/Source/XPSP1/NT/inetsrv/iis/staxinc/cachemtx.h
2020-09-26 16:20:57 +08:00

1366 lines
26 KiB
C++

/*++
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_