Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

814 lines
17 KiB

  1. /*++
  2. Cache2.h
  3. This header file defines an LRU0 cache template that
  4. can be used to hold arbitrary objects !
  5. Items in the Cache must have the following format :
  6. class DataItem {
  7. ICacheRefInterface* m_pCacheRefInterface ;
  8. } ;
  9. class Constructor {
  10. DATA*
  11. Create( KEY&, PERCACHEDATA& )
  12. void
  13. Release( DATA*, PERCACHEDATA* )
  14. void
  15. StaticRelease( DATA*, PERCACHEDATA* )
  16. }
  17. --*/
  18. #ifndef _CACHE2_H_
  19. #define _CACHE2_H_
  20. #include "randfail.h"
  21. #include "fdlhash.h"
  22. #include "lockq.h"
  23. #include "tfdlist.h"
  24. #include "rwnew.h"
  25. #include "refptr2.h"
  26. typedef CShareLockNH CACHELOCK ;
  27. class CAllocatorCache {
  28. /*++
  29. Class Description :
  30. This class provides a Memory Allocation cache - we work with
  31. an operator new provide below. We exist to provide some
  32. optimizations for allocations of the elements of the caches
  33. specified in this module.
  34. NOTE :
  35. We assume the caller provides all locking !
  36. --*/
  37. private :
  38. //
  39. // The structurure we use to keep our free list !
  40. //
  41. struct FreeSpace {
  42. struct FreeSpace* m_pNext ;
  43. } ;
  44. //
  45. // Size of each element - clients must not ask for something bigger !
  46. //
  47. DWORD m_cbSize ;
  48. //
  49. // Number of elements in our list at this moment !
  50. //
  51. DWORD m_cElements ;
  52. //
  53. // The maximum number of elements we should hold !
  54. //
  55. DWORD m_cMaxElements ;
  56. //
  57. // Top of the stack !
  58. //
  59. struct FreeSpace* m_pHead ;
  60. //
  61. // Make the following private - nobody is allowed to use these !
  62. //
  63. CAllocatorCache( CAllocatorCache& ) ;
  64. CAllocatorCache& operator=( CAllocatorCache& ) ;
  65. public :
  66. //
  67. // Initialize the Allocation Cache !
  68. //
  69. CAllocatorCache( DWORD cbSize,
  70. DWORD cMaxElements = 512
  71. ) ;
  72. //
  73. // Destroy the Allocation Cache - release extra memory back to system !
  74. //
  75. ~CAllocatorCache() ;
  76. //
  77. // Allocate a block of memory
  78. // returns NULL if Out of Memory !
  79. //
  80. void*
  81. Allocate( size_t cb ) ;
  82. //
  83. // Return some memory back to the system heap !
  84. //
  85. void
  86. Free( void* pv ) ;
  87. } ;
  88. class ICacheRefInterface : public CQElement {
  89. /*++
  90. Class Description :
  91. This class defines the interface for Cache References -
  92. the mechanism that allows multiple caches to reference
  93. a single data item.
  94. --*/
  95. protected :
  96. //
  97. // Add an item to the list of caches referencing
  98. // this cache item !
  99. //
  100. virtual BOOL
  101. AddCacheReference( class ICacheRefInterface*, void* pv, BOOL ) = 0 ;
  102. //
  103. // Remove an item from the list of caches referencing
  104. // this cache item !
  105. //
  106. virtual BOOL
  107. RemoveCacheReference( BOOL fQueue ) = 0 ;
  108. //
  109. // Remove all references to the cache item !
  110. //
  111. virtual BOOL
  112. RemoveAllReferences( ) = 0 ;
  113. } ;
  114. #include "cintrnl.h"
  115. // This callback function is used to issue a stop hint during a
  116. // long spin while shutting down so that the shutdown won't time
  117. // out.
  118. typedef void (*PSTOPHINT_FN)();
  119. extern CRITICAL_SECTION g_CacheShutdown ;
  120. //
  121. // Call these functions to initialize the Cache Library
  122. //
  123. extern BOOL __stdcall CacheLibraryInit() ;
  124. extern BOOL __stdcall CacheLibraryTerm() ;
  125. template < class Data,
  126. class Key
  127. >
  128. class CacheExpungeObject {
  129. public :
  130. //
  131. // This function is called to determine whether we should remove
  132. // the item from the cache.
  133. //
  134. // pKey - Pointer to the Key of the item in the cache
  135. // pData - Pointer to the data for the item in the cache
  136. // cOutstandingReferences - The number of times of outstanding check-outs on the item !
  137. // fMultipleReferenced - TRUE if there is more than one cache that contains
  138. // this item !
  139. //
  140. virtual
  141. BOOL
  142. fRemoveCacheItem( Key* pKey,
  143. Data* pData
  144. ) = 0 ;
  145. } ;
  146. template < class Data >
  147. class CacheCallback {
  148. public :
  149. virtual BOOL fRemoveCacheItem( Data& d ) {
  150. return FALSE ;
  151. }
  152. } ;
  153. class CacheStats : public CHashStats {
  154. public :
  155. enum COUNTER {
  156. ITEMS, // Number of items in the cache
  157. CLRU, // Number of items in the LRU List
  158. EXPIRED, // Number of items that have been expired !
  159. INSERTS, // Number of items inserted over time
  160. READHITS, // Number of times we've had a cache hit needing only readlocks during FindOrCreate()!
  161. SUCCESSSEARCH, // Number of times we've successfully searched for an item !
  162. FAILSEARCH, // Number of times we've failed to find an item !
  163. RESEARCH, // Number of times we've had to search a second time for an item
  164. WRITEHITS, // Number of times we've had a cache hit requiring a PartialLock()
  165. PARTIALCREATES, // Number of times we've created an item with only a PartialLock
  166. EXCLUSIVECREATES, // Number of times we've created an item with an Exclusive Lock !
  167. CEFAILS, // Number of times we've failed to allocate a CACHEENTRY structure
  168. CLIENTALLOCFAILS, // Number of times we've failed to allocate a Data object
  169. CLIENTINITFAILS, // Number of times a client object has failed to initialize !
  170. MAXCOUNTER // A Invalid Counter - all values smaller than this !
  171. } ;
  172. //
  173. // Array of longs to hold different values !
  174. //
  175. long m_cCounters[MAXCOUNTER] ;
  176. CacheStats() {
  177. ZeroMemory( m_cCounters, sizeof(m_cCounters) ) ;
  178. }
  179. } ;
  180. typedef CacheStats CACHESTATS ;
  181. inline void
  182. IncrementStat( CacheStats* p, CACHESTATS::COUNTER c ) {
  183. _ASSERT( c < CACHESTATS::MAXCOUNTER ) ;
  184. if( p != 0 ) {
  185. InterlockedIncrement( &p->m_cCounters[c] ) ;
  186. }
  187. }
  188. inline void
  189. AddStat( CacheStats*p, CACHESTATS::COUNTER c, long l ) {
  190. _ASSERT( c < CACHESTATS::MAXCOUNTER ) ;
  191. if( p != 0 ) {
  192. InterlockedExchangeAdd( &p->m_cCounters[c], l ) ;
  193. }
  194. }
  195. inline void
  196. DecrementStat( CacheStats* p, CACHESTATS::COUNTER c ) {
  197. _ASSERT( c < CACHESTATS::MAXCOUNTER ) ;
  198. if( p != 0 ) {
  199. InterlockedDecrement( &p->m_cCounters[c] ) ;
  200. }
  201. }
  202. template < class Data,
  203. class Key,
  204. class Constructor,
  205. class PerCacheData = LPVOID
  206. >
  207. class CacheEx : public CacheTable {
  208. public :
  209. //
  210. // For compare, hash functions etc.... we will use this type !
  211. //
  212. typedef Data DATA ;
  213. typedef Key KEY ;
  214. typedef Key* PKEY ;
  215. //
  216. // Hash Computation function
  217. //
  218. typedef DWORD (*PFNHASH)( PKEY ) ;
  219. //
  220. // Key Comparison function - to be provided by caller !
  221. //
  222. typedef int (*PKEYCOMPARE)(PKEY, PKEY) ;
  223. //
  224. // Callback objects for Expunge Operations !
  225. //
  226. typedef CacheCallback< DATA > CALLBACKOBJ ;
  227. //
  228. // Objects that the user can give to the cache to manage the removal of items !
  229. //
  230. typedef CacheExpungeObject< DATA, KEY > EXPUNGEOBJECT ;
  231. private :
  232. //
  233. // Define a 'CACHEENTRY' object which holds all the
  234. // necessary data for each object which is placed in the cache !
  235. //
  236. typedef CCacheItemKey< DATA, KEY, Constructor, PerCacheData > CACHEENTRY ;
  237. //
  238. // Define the helper class for Hash Tables
  239. //
  240. typedef TFDLHash< CACHEENTRY, PKEY, &CacheState::HashDLIST > HASHTABLE ;
  241. //
  242. // An iterator that lets us walk everything in the hash table !
  243. //
  244. typedef TFDLHashIterator< HASHTABLE > HASHITER ;
  245. //
  246. // Is the 'Cache' initialized and in a valid state !
  247. //
  248. BOOL m_fValid ;
  249. //
  250. // An object to collect statistics about cache operations !
  251. // This may be NULL !
  252. //
  253. class CacheStats* m_pStats ;
  254. //
  255. // A list of everything in the Cache, used for TTL processing
  256. //
  257. CLRUList m_ExpireList ;
  258. //
  259. // A hash table we use to find things within the Cache
  260. //
  261. HASHTABLE m_Lookup ;
  262. //
  263. // Pointer to a runtime-user provided function which is used
  264. // to determine what things should be removed from the Cache
  265. //
  266. // BOOL (* m_pfnExpungeSpecific )( Data & ) ;
  267. //
  268. // Pointer to a runtime-user provided object derived from CacheCallback< Data >
  269. // which lets the user invoke some function for each item in the Cache !
  270. //
  271. CALLBACKOBJ* m_pCallbackObject ;
  272. //
  273. // Reader writer lock which protects all these data structures !
  274. //
  275. CACHELOCK m_Lock ;
  276. //
  277. // The initial TTL we should assign to all newly cached objects !
  278. //
  279. DWORD m_TTL ;
  280. //
  281. // The cache used for creation/deletion of our CACHEENTRY objects !
  282. //
  283. CAllocatorCache m_Cache ;
  284. protected :
  285. //
  286. // Virtual function called by CScheduleThread's thread which
  287. // we use to bump TTL counters
  288. //
  289. void
  290. Schedule();
  291. //
  292. // Function which removes an Entry from the Cache !
  293. //
  294. BOOL
  295. RemoveEntry(
  296. CacheState* pEntry
  297. ) ;
  298. //
  299. // Virtual Function called by CacheList when we pass call
  300. // CacheList::ExpungeSpecific
  301. //
  302. BOOL
  303. QueryRemoveEntry(
  304. CacheState* pEntry
  305. ) ;
  306. //
  307. // Virtual Function part of CacheTable interface - used
  308. // by LRUList to do appropriate locking !
  309. //
  310. CACHELOCK&
  311. GetLock() {
  312. return m_Lock ;
  313. }
  314. public :
  315. //
  316. // This is the users extra data - we will provide it on calls
  317. // to constructor objects so that they can track some state sync'd
  318. // with the cache locks !
  319. //
  320. PerCacheData m_PerCacheData ;
  321. //
  322. // This function is used to return an item to the cache -
  323. // it will bump down a ref count for the number of clients
  324. // currently using the item !
  325. //
  326. static void
  327. CheckIn( DATA* ) ;
  328. //
  329. // This function is provided for cases when the client needs
  330. // to check-in an item from a Cache Callback function (i.e. Expunge)
  331. //
  332. //
  333. static void
  334. CheckInNoLocks( DATA* ) ;
  335. //
  336. // This function is used to add a client reference to an item in the cache !
  337. //
  338. static void
  339. CheckOut( DATA*,
  340. long cClientRefs = 1
  341. ) ;
  342. //
  343. // Constructor - cMax specifies the maximum number of entries
  344. // we should hold in the cache.
  345. //
  346. CacheEx( ) ;
  347. //
  348. // Destructor - remove ourselves from schedule list before continuing !
  349. //
  350. ~CacheEx() ;
  351. //
  352. // Initialization function - take pointer to function
  353. // which should be used to compute hash values on Key's
  354. // Also takes the number of seconds objects should live in
  355. // the cache !
  356. //
  357. BOOL
  358. Init(
  359. PFNHASH pfnHash,
  360. PKEYCOMPARE pKeyCompare,
  361. DWORD dwLifetimeSeconds,
  362. DWORD cMaxInstances,
  363. CACHESTATS* pStats,
  364. PSTOPHINT_FN pfnStopHint = NULL
  365. ) {
  366. /*++
  367. Routine Description :
  368. This function initializes the cache so that it is ready
  369. to take entries.
  370. Arguments :
  371. pfnHash - function to be used to compute hash values on keys
  372. dwLifetimeSeconds - The number of seconds objects should live in the Cache
  373. pfnStopHint - function to be used to send stop hints during
  374. long spins so shutdown's don't time out.
  375. Return Value :
  376. TRUE if successfull
  377. --*/
  378. m_pStats = pStats ;
  379. m_ExpireList.Init( cMaxInstances,
  380. dwLifetimeSeconds
  381. ) ;
  382. return m_fValid = m_Lookup.Init(
  383. 256,
  384. 128,
  385. 4,
  386. pfnHash,
  387. &CACHEENTRY::GetKey,
  388. pKeyCompare,
  389. 0,
  390. pStats
  391. ) ;
  392. }
  393. void
  394. Expire() {
  395. EnterCriticalSection( &g_CacheShutdown ) ;
  396. DWORD c = 0 ;
  397. m_ExpireList.Expire( this, &m_Cache, c, &m_PerCacheData ) ;
  398. LeaveCriticalSection( &g_CacheShutdown ) ;
  399. }
  400. //
  401. // Called to remove all items from the cache !
  402. //
  403. BOOL
  404. EmptyCache() ;
  405. BOOL
  406. ExpungeItems(
  407. EXPUNGEOBJECT* pExpunge
  408. ) ;
  409. //
  410. // Function which can be used to remove items from the Cache
  411. // If default args are used we pick an expired item in the Cache
  412. // to remove
  413. //
  414. BOOL
  415. ExpungeKey(
  416. DWORD dwHash,
  417. PKEY key
  418. ) ;
  419. //
  420. // Either find an item in the cache or Construct a new item
  421. // and place it in the Cache.
  422. // return the result through pDataOut no matter what !
  423. //
  424. //
  425. // INTERNAL API's - These are public for convenience - not intended
  426. // for Use outside of cachelib !!
  427. //
  428. //
  429. // Either find an item in the cache or Construct a new item
  430. // and place it in the Cache.
  431. // return the result !
  432. //
  433. //
  434. //
  435. BOOL
  436. FindOrCreateInternal(
  437. DWORD dwHash,
  438. KEY& key,
  439. Constructor& constructor,
  440. DATA* &pData,
  441. BOOL fEarlyCreate = FALSE /* Best Perf if this is FALSE - but required by some users !*/
  442. ) ;
  443. //
  444. // Find the item if it is in the cache !
  445. //
  446. DATA*
  447. FindInternal(
  448. DWORD dwHash,
  449. KEY& key
  450. ) ;
  451. //
  452. // Insert a new item into the cache -
  453. // We get to specify whether and what kind of reference
  454. // we will hold outside of the cache !
  455. //
  456. BOOL
  457. InsertInternal(
  458. DWORD dwHash,
  459. KEY& key,
  460. DATA* pData,
  461. long cClientRefs = 0
  462. ) ;
  463. #ifdef DEBUG
  464. static long s_cCreated ;
  465. #endif
  466. } ;
  467. template < class Data,
  468. class Key,
  469. class Constructor,
  470. class PerCacheData = LPVOID
  471. >
  472. class MultiCacheEx {
  473. public:
  474. typedef Data DATA ;
  475. typedef Key KEY ;
  476. typedef Key* PKEY ;
  477. //
  478. // Hash Computation function
  479. //
  480. typedef DWORD (*PFNHASH)( PKEY ) ;
  481. //
  482. // Key Comparison function - to be provided by caller !
  483. //
  484. typedef int (*PKEYCOMPARE)(PKEY, PKEY) ;
  485. //
  486. // Callback objects for Expunge Operations !
  487. //
  488. typedef CacheCallback< DATA > CALLBACKOBJ ;
  489. //
  490. // Objects that the user can give to the cache to manage the removal of items !
  491. //
  492. typedef CacheExpungeObject< DATA, KEY > EXPUNGEOBJECT ;
  493. private :
  494. //
  495. // Define a 'CACHEENTRY' object which holds all the
  496. // necessary data for each object which is placed in the cache !
  497. //
  498. typedef CCacheItemKey< DATA, KEY, Constructor, PerCacheData > CACHEENTRY ;
  499. //
  500. // Define the type for a single instance !
  501. //
  502. typedef CacheEx< Data, Key, Constructor, PerCacheData > CACHEINSTANCE ;
  503. //
  504. // Is the 'Cache' initialized and in a valid state !
  505. //
  506. BOOL m_fValid ;
  507. //
  508. // Pointer to the various Cache's we subdivide our work into
  509. //
  510. CACHEINSTANCE *m_pCaches ;
  511. //
  512. // Number of sub cache's we use to split up the work !
  513. //
  514. DWORD m_cSubCaches ;
  515. //
  516. // We use the hash function to choose which of our subcaches to work with !
  517. //
  518. typename CACHEINSTANCE::PFNHASH m_pfnHash ;
  519. //
  520. // Return the correct cache instance to hold the selected piece of data !
  521. //
  522. DWORD ChooseInstance( DWORD dwHash ) ;
  523. public :
  524. //
  525. // Constructor - cMax specifies the maximum number of entries
  526. // we should hold in the cache.
  527. //
  528. MultiCacheEx( ) ;
  529. //
  530. // Destructor - destroys are various sub cache's
  531. //
  532. ~MultiCacheEx() ;
  533. //
  534. // Initialization function - take pointer to function
  535. // which should be used to compute hash values on Key's
  536. // Also takes the number of seconds objects should live in
  537. // the cache !
  538. //
  539. BOOL
  540. Init(
  541. PFNHASH pfnHash,
  542. PKEYCOMPARE pfnCompare,
  543. DWORD dwLifetimeSeconds,
  544. DWORD cMaxElements,
  545. DWORD cSubCaches,
  546. CACHESTATS* pStats,
  547. PSTOPHINT_FN pfnStopHint = NULL
  548. ) ;
  549. //
  550. // Expire items in the cache !
  551. //
  552. void
  553. Expire() ;
  554. //
  555. // Called to remove all items from the cache !
  556. //
  557. BOOL
  558. EmptyCache() ;
  559. //
  560. // The user wants to remove a large set of items from the cache !
  561. //
  562. BOOL
  563. ExpungeItems(
  564. EXPUNGEOBJECT* pExpunge
  565. ) ;
  566. //
  567. // Function which can be used to remove items from the Cache
  568. // If default args are used we pick an expired item in the Cache
  569. // to remove
  570. //
  571. BOOL
  572. ExpungeKey(
  573. PKEY key
  574. ) ;
  575. //
  576. // Either find an item in the cache or Construct a new item
  577. // and place it in the Cache.
  578. // return the result through pDataOut no matter what !
  579. //
  580. Data*
  581. FindOrCreate(
  582. Key& key,
  583. Constructor& constructor,
  584. BOOL fEarlyCreate = FALSE
  585. ) ;
  586. //
  587. // Either find an item in the cache or Construct a new item
  588. // and place it in the Cache.
  589. // return the result through pDataOut no matter what !
  590. // NOTE : This is for use when the caller has a cheaper
  591. // way to compute the hash value then us - in debug we
  592. // need to assure that the caller correctly computes this !
  593. //
  594. Data*
  595. FindOrCreate(
  596. DWORD dwHash,
  597. Key& key,
  598. Constructor& constructor,
  599. BOOL fEarlyCreate = FALSE
  600. ) ;
  601. //
  602. // Find an item in the cache - hash of key is precomputed !
  603. //
  604. Data*
  605. Find( DWORD dwHash,
  606. KEY& key
  607. ) ;
  608. //
  609. // Find an item in the cache
  610. //
  611. Data*
  612. Find( KEY& key ) ;
  613. //
  614. // Insert a new item into the cache -
  615. // We get to specify whether and what kind of reference
  616. // we will hold outside of the cache !
  617. //
  618. BOOL
  619. Insert( DWORD dwHash,
  620. KEY& key,
  621. Data* pData,
  622. long cClientRefs = 0
  623. ) ;
  624. //
  625. // Insert a new item into the cache -
  626. // We get to specify whether and what kind of reference
  627. // we will hold outside of the cache !
  628. //
  629. BOOL
  630. Insert( KEY& key,
  631. Data* pData,
  632. long cClientRefs = 0
  633. ) ;
  634. //
  635. // This function is used to return an item to the cache -
  636. // it will bump down a ref count for the number of clients
  637. // currently using the item !
  638. //
  639. static void
  640. CheckIn( DATA* ) ;
  641. //
  642. // This function is provided for cases when the client needs
  643. // to check-in an item from a Cache Callback function (i.e. Expunge)
  644. //
  645. //
  646. static void
  647. CheckInNoLocks( DATA* ) ;
  648. //
  649. // This function is used to add a client reference to an item in the cache !
  650. //
  651. static void
  652. CheckOut( DATA*,
  653. long cClientRefs = 1
  654. ) ;
  655. } ;
  656. #include "cache2i.h"
  657. #endif // _CACHE2_H_