/*++ Cache.h This file defines some templates which implement a generic cache manager. In order to use the Cache manager, your class must have the following : // // SampleClass derives from CRefCount as smart pointers // 'CRefPtr' are used to manage the life time of cached // objects. // class SampleClass : public CRefCount { // // Cached class has a constructor which takes two // arguments, the Key used to find the Data in the Cache // and the 'Constructor' (which is a type specified in // the cache template) which contains whatever // initialization data that needs to be passed. // // The Cached class should do minimal work within the // constructor. The FindOrCreate() function will also // call an innitialization class which finishes initialization // of the object. // SampleClass( Key& k, Constructor &constructor ) ; // // If the Cached class does not do all of its initialization // in its Constructor, then The ExclusiveLock() function must // guarantee that no clients can use the object untill the // lock is released. // // If the Cached class is completely initialized after the // constructor is called then this can be a no-op function. // ExclusiveLock() ; // // After this is called clients may use the object. // ExclusiveUnlock() ; // // The Init() function is called by FindOrCreate() // after the contructor has been invoked. This function // must complete any initialization required. // // Member functions are called by FindOrCreate() in this order : // // SampleClass() // Constructor is called // ExclusiveLock() // Init() // ExclusiveUnlock() // // All Cache Client code must be able to deal with objects // returned from the cache which failed initialization for // whatever reason. // BOOL Init( Constructor& constructor ) ; // // This function must return a reference to the // Key value stored within the data. // Key& GetKey() ; // // Must return non-zero if the provided Key matches // the one stored in the data . // int MatchKey( Key& ) ; } ; --*/ #ifndef _CACHE_H_ #define _CACHE_H_ #ifndef _ASSERT #define _ASSERT(x) if(!(x)) DebugBreak() ; else #endif // This callback function is used to issue a stop hint during a // long spin while shutting down so that the shutdown won't time // out. typedef void (*PSTOPHINT_FN)(); // // cacheint.h includes all the necessary helper classes // etc... that make the general cache engine work ! // // #include "cacheint.h" // // Utility class for those which wish to have pools of locks for // their objects ! // class CLockPool { private : // // Array of locks to share amongst Xover data structures // _CACHELOCK m_locks[256] ; // // // long m_lockIndex ; public : _CACHELOCK* AllocateLock() { return &m_locks[ DWORD(InterlockedIncrement( &m_lockIndex )) % 256 ] ; } } ; // // CacheCallback class - clients can pass an object derived from // this into the Cache for functions which require some kind of user // callback processing ! // template < class Data > class CacheCallback { public : virtual BOOL fRemoveCacheItem( Data& d ) { return FALSE ; } } ; // // Call these functions to initialize the Cache Library // extern BOOL __stdcall CacheLibraryInit() ; extern BOOL __stdcall CacheLibraryTerm() ; template < class Data, class Key, class Constructor, BOOL fAtomic = TRUE > class Cache : public CScheduleThread, CacheTable { private : // // Define a 'CACHEENTRY' object which holds all the // necessary data for each object which is placed in the cache ! // typedef CacheEntry< Data, Key, fAtomic > CACHEENTRY ; // // Define callback objects for Expunge Operations. // typedef CacheCallback< Data > CALLBACKOBJ; // // Is the 'Cache' initialized and in a valid state ! // BOOL m_fValid ; // // A list of everything in the Cache, used for TTL processing // CacheList m_ExpireList ; // // A hash table we use to find things within the Cache // TFHash< CACHEENTRY, Key > m_Lookup ; // // Pointer to a runtime-user provided function which is used // to determine what things should be removed from the Cache // BOOL (* m_pfnExpungeSpecific )( Data & ) ; // // Pointer to a runtime-user provided object derived from CacheCallback< Data > // which lets the user invoke some function for each item in the Cache ! // CALLBACKOBJ* m_pCallbackObject ; // // Reader writer lock which protects all these data structures ! // _CACHELOCK m_Lock ; // // The initial TTL we should assign to all newly cached objects ! // DWORD m_TTL ; protected : // // Virtual function called by CScheduleThread's thread which // we use to bump TTL counters // void Schedule(); // // Function which removes an Entry from the Cache ! // BOOL RemoveEntry( CacheState* pEntry ) ; // // Virtual Function called by CacheList when we pass call // CacheList::ExpungeSpecific // BOOL QueryRemoveEntry( CacheState* pEntry ) ; // // Function which can remove a specific item from the Cache // or walk the Cache deleting all the expired items. // // BOOL ExpungeInternal( const CACHEENTRY* pProtected = 0, BOOL fDoCheap = FALSE, Key* key=0, CACHEENTRY* pData = 0 ) ; public : // // INTERNAL API's - These are public for convenience - not intended // for Use outside of cachelib !! // // // Either find an item in the cache or Construct a new item // and place it in the Cache. // return the result through pDataOut no matter what ! // BOOL FindOrCreateInternal( DWORD dwHash, Key& key, Constructor& constructor, CRefPtr< Data >& pDataOut ) ; // // Constructor - cMax specifies the maximum number of entries // we should hold in the cache. // Cache( ) ; // // Destructor - remove ourselves from schedule list before continuing ! // ~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 ! // BOOL Init( DWORD (*pfnHash)( const Key& ), DWORD dwLifetimeSeconds, DWORD cMaxInstances, PSTOPHINT_FN pfnStopHint = NULL ) ; // // Function which can be used to remove items from the Cache // If default args are used we pick an expired item in the Cache // to remove // BOOL Expunge( Key* key = 0, CACHEENTRY* pData = 0 ) ; // // 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. // BOOL ExpungeSpecific( CALLBACKOBJ* pCallback, BOOL fForced ) ; // // Either find an item in the cache or Construct a new item // and place it in the Cache. // return the result through pDataOut no matter what ! // BOOL FindOrCreate( Key& key, Constructor& constructor, CRefPtr< Data >& pDataOut ) ; #ifdef DEBUG static long s_cCreated ; #endif } ; template < class Data, class Key, class Constructor, BOOL fAtomic = TRUE > class MultiCache { private : // // Define a 'CACHEENTRY' object which holds all the // necessary data for each object which is placed in the cache ! // typedef CacheEntry< Data, Key, fAtomic > CACHEENTRY ; // // Define callback objects for Expunge Operations. // typedef CacheCallback< Data > CALLBACKOBJ; // // Define the type for a single instance ! // typedef Cache< Data, Key, Constructor, fAtomic > CACHEINSTANCE ; // // Is the 'Cache' initialized and in a valid state ! // BOOL m_fValid ; // // Pointer to the various Cache's we subdivide our work into // CACHEINSTANCE *m_pCaches ; // // Number of sub cache's we use to split up the work ! // DWORD m_cSubCaches ; // // We use the hash function to choose which of our subcaches to work with ! // DWORD (*m_pfnHash)( const Key& ) ; // // Return the correct cache instance to hold the selected piece of data ! // //DWORD ChooseInstance( Key& k ) ; DWORD ChooseInstance( DWORD dwHash ) ; public : // // Constructor - cMax specifies the maximum number of entries // we should hold in the cache. // MultiCache( ) ; // // Destructor - destroys are various sub cache's // ~MultiCache() ; // // 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 ! // BOOL Init( DWORD (*pfnHash)( const Key& ), DWORD dwLifetimeSeconds, DWORD cSubCaches, DWORD cMaxElements, PSTOPHINT_FN pfnStopHint = NULL ) ; // // Function which can be used to remove items from the Cache // If default args are used we pick an expired item in the Cache // to remove // BOOL Expunge( Key* key = 0, CACHEENTRY* pData = 0 ) ; // // 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. // BOOL ExpungeSpecific( CALLBACKOBJ* pCallback, BOOL fForced ) ; // // Either find an item in the cache or Construct a new item // and place it in the Cache. // return the result through pDataOut no matter what ! // BOOL FindOrCreate( Key& key, Constructor& constructor, CRefPtr< Data >& pDataOut ) ; // // Either find an item in the cache or Construct a new item // and place it in the Cache. // return the result through pDataOut no matter what ! // NOTE : This is for use when the caller has a cheaper // way to compute the hash value then us - in debug we // need to assure that the caller correctly computes this ! // BOOL FindOrCreate( Key& key, DWORD dwHash, Constructor& constructor, CRefPtr< Data >& pDataOut ) ; } ; #include "cacheimp.h" #endif // _CACHE_H_