Source code of Windows XP (NT5)
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.

936 lines
16 KiB

  1. /*++
  2. cacheimp.h -
  3. This file contains all the template function definitions required
  4. to make the cache manager work.
  5. --*/
  6. template < class Data,
  7. class Key,
  8. class Constructor,
  9. BOOL fAtomic
  10. >
  11. void
  12. Cache< Data, Key, Constructor, fAtomic >::Schedule() {
  13. /*++
  14. Routine Description :
  15. This function runs through all the items in the Cache
  16. bumping TTL's. If there are any items ready to go
  17. then we dump them from the Cache.
  18. Arguments :
  19. None.
  20. Return Value :
  21. Nothing
  22. --*/
  23. if( !m_fValid )
  24. return ;
  25. m_Lock.ShareLock() ;
  26. DWORD cExpungable = 0 ;
  27. BOOL fExpunge = m_ExpireList.Expire( cExpungable ) ;
  28. m_Lock.ShareUnlock() ;
  29. if( fExpunge ) {
  30. Expunge() ;
  31. }
  32. }
  33. template < class Data,
  34. class Key,
  35. class Constructor,
  36. BOOL fAtomic
  37. >
  38. BOOL
  39. Cache<Data, Key, Constructor, fAtomic>::RemoveEntry(
  40. CacheState* pEntry
  41. ) {
  42. /*++
  43. Routine Description :
  44. This function removes an entry from the Cache.
  45. We call our hash table to delete the item.
  46. the CacheState destructor automagically removes
  47. the item from our linked lists.
  48. CALLER MUST HOLD APPROPRIATE LOCKS!
  49. Arguments :
  50. pEntry - item to be removed from cache
  51. Return Value :
  52. TRUE if successfully removed !
  53. --*/
  54. CACHEENTRY *pCacheEntry = (CACHEENTRY*)pEntry ;
  55. return m_Lookup.DeleteData( pCacheEntry->GetKey(), pCacheEntry ) ;
  56. }
  57. template < class Data,
  58. class Key,
  59. class Constructor,
  60. BOOL fAtomic
  61. >
  62. BOOL
  63. Cache<Data, Key, Constructor, fAtomic>::QueryRemoveEntry(
  64. CacheState* pEntry ) {
  65. /*++
  66. Routine Description :
  67. This function is called from CacheList object to
  68. determine whether we want to remove an item from the Cache.
  69. This function is used to implement the ExpungeSpecific
  70. function available to clients.
  71. CALLER MUST HOLD APPROPRIATE LOCKS!
  72. Arguments :
  73. pEntry - item we want to determine whether it should remain !
  74. Return Value :
  75. TRUE if successfully removed !
  76. --*/
  77. CACHEENTRY *pCacheEntry = (CACHEENTRY*) pEntry ;
  78. if( m_pCallbackObject ) {
  79. return m_pCallbackObject->fRemoveCacheItem( *pCacheEntry->m_pData ) ;
  80. }
  81. return FALSE ;
  82. }
  83. template < class Data,
  84. class Key,
  85. class Constructor,
  86. BOOL fAtomic
  87. >
  88. BOOL
  89. Cache<Data, Key, Constructor, fAtomic>::ExpungeInternal(
  90. const CACHEENTRY* pProtected,
  91. BOOL fDoCheap,
  92. Key* key,
  93. CACHEENTRY* pData
  94. ) {
  95. /*++
  96. Routine Description :
  97. This function is called when we want to force some thing
  98. out of the cache. The caller can provide a key
  99. to force a particular item out of the cache.
  100. CALLER MUST HOLD APPROPRIATE LOCKS!
  101. Arguments :
  102. pProtected - an Element we want to make sure is not removed !
  103. key - Pointer to the key identifying the item to be removed
  104. pData - pointer to the CACHEENTRY object containing the data
  105. and key we wish to remove.
  106. Return Value :
  107. TRUE something is successfully removed from the cache.
  108. --*/
  109. if( key != 0 ) {
  110. return m_Lookup.DeleteData( *key, pData ) ;
  111. }
  112. return m_ExpireList.Expunge( this, fDoCheap, pProtected ) ;
  113. }
  114. #ifdef DEBUG
  115. template < class Data,
  116. class Key,
  117. class Constructor,
  118. BOOL fAtomic
  119. >
  120. long Cache<Data, Key, Constructor, fAtomic>::s_cCreated = 0 ;
  121. #endif
  122. template < class Data,
  123. class Key,
  124. class Constructor,
  125. BOOL fAtomic
  126. >
  127. Cache<Data, Key, Constructor, fAtomic>::Cache( ) : m_fValid( FALSE ) {
  128. /*++
  129. Routine Description :
  130. This function initializes our member variables.
  131. Arguments :
  132. cMax - maximum number of elements the cache should hold
  133. Return Value :
  134. Nothing
  135. --*/
  136. #ifdef DEBUG
  137. InterlockedIncrement( &s_cCreated ) ;
  138. #endif
  139. AddToSchedule() ;
  140. }
  141. template < class Data,
  142. class Key,
  143. class Constructor,
  144. BOOL fAtomic
  145. >
  146. Cache<Data, Key, Constructor, fAtomic>::~Cache( ) {
  147. /*++
  148. Routine Description :
  149. This function destroys a Cache object !
  150. Arguments :
  151. None
  152. Return Value :
  153. Nothing
  154. --*/
  155. RemoveFromSchedule() ;
  156. //
  157. // Member and Base class destruction follows !!
  158. //
  159. #ifdef DEBUG
  160. InterlockedDecrement( &s_cCreated ) ;
  161. #endif
  162. }
  163. template < class Data,
  164. class Key,
  165. class Constructor,
  166. BOOL fAtomic
  167. >
  168. BOOL
  169. Cache<Data, Key, Constructor, fAtomic>::Init(
  170. DWORD (*pfnHash)( const Key& ),
  171. DWORD dwLifetimeSeconds,
  172. DWORD cMaxInstances,
  173. PSTOPHINT_FN pfnStopHint
  174. ) {
  175. /*++
  176. Routine Description :
  177. This function initializes the cache so that it is ready
  178. to take entries.
  179. Arguments :
  180. pfnHash - function to be used to compute hash values on keys
  181. dwLifetimeSeconds - The number of seconds objects should live in the Cache
  182. pfnStopHint - function to be used to send stop hints during
  183. long spins so shutdown's don't time out.
  184. Return Value :
  185. TRUE if successfull
  186. --*/
  187. m_ExpireList.m_cMax = long(cMaxInstances) ;
  188. m_ExpireList.m_pfnStopHint = pfnStopHint;
  189. m_TTL = 1 + (dwLifetimeSeconds / CScheduleThread::dwNotificationSeconds) ;
  190. return m_fValid = m_Lookup.Init( 100, 100, pfnHash ) ;
  191. }
  192. template < class Data,
  193. class Key,
  194. class Constructor,
  195. BOOL fAtomic
  196. >
  197. BOOL
  198. Cache<Data, Key, Constructor, fAtomic>::Expunge(
  199. Key* key,
  200. CACHEENTRY* pData
  201. ) {
  202. /*++
  203. Routine Description :
  204. This function is called when we want to force some thing
  205. out of the cache. The caller can provide a key
  206. to force a particular item out of the cache.
  207. WE WILL GRAB THE NECESSARY LOCKS !
  208. Arguments :
  209. pfnHash - function to be used to compute hash values on keys
  210. Return Value :
  211. TRUE if successfull
  212. --*/
  213. _ASSERT( m_fValid ) ;
  214. m_Lock.ExclusiveLock() ;
  215. BOOL fReturn = ExpungeInternal( 0, FALSE, key, pData ) ;
  216. m_Lock.ExclusiveUnlock() ;
  217. return fReturn ;
  218. }
  219. template < class Data,
  220. class Key,
  221. class Constructor,
  222. BOOL fAtomic
  223. >
  224. BOOL
  225. Cache<Data, Key, Constructor, fAtomic>::ExpungeSpecific(
  226. CALLBACKOBJ* pCallbackObject,
  227. BOOL fForced
  228. ) {
  229. /*++
  230. Routine Description :
  231. This function is called when we want to force some thing
  232. out of the cache. The caller can provide a key
  233. to force a particular item out of the cache.
  234. WE WILL GRAB THE NECESSARY LOCKS !
  235. Arguments :
  236. pfn - callback function used to determine what to remove
  237. from the Cache.
  238. fForced - if TRUE then we will remove from the Cache no matter
  239. what, even if other threads are using the object !
  240. Return Value :
  241. TRUE if successfull
  242. --*/
  243. m_Lock.ExclusiveLock() ;
  244. m_pCallbackObject = pCallbackObject ;
  245. BOOL fReturn = m_ExpireList.ExpungeSpecific( this, fForced ) ;
  246. m_Lock.ExclusiveUnlock() ;
  247. return fReturn ;
  248. }
  249. template < class Data,
  250. class Key,
  251. class Constructor,
  252. BOOL fAtomic
  253. >
  254. BOOL
  255. Cache<Data, Key, Constructor, fAtomic>::FindOrCreateInternal(
  256. DWORD dwHash,
  257. Key& key,
  258. Constructor& constructor,
  259. CRefPtr< Data >& pDataOut
  260. ) {
  261. /*++
  262. Routine Description :
  263. This function is called when we want something out
  264. of the Cache. We will either find the object or create it.
  265. WE WILL GRAB THE NECESSARY LOCKS !
  266. Arguments :
  267. key - The unique key used to find the item in the Cache.
  268. constructor - An object to pass to the Data's constructor and Init
  269. functions.
  270. pDataOut - Smart pointer which receives the result
  271. Return Value :
  272. TRUE if successfull
  273. --*/
  274. BOOL fReturn = FALSE ;
  275. pDataOut = 0 ;
  276. if( !m_fValid ) {
  277. SetLastError( 0 ) ;
  278. return FALSE ;
  279. } else {
  280. m_Lock.ShareLock() ;
  281. //
  282. // See if we can find an Entry in the cache for the item we want.
  283. //
  284. CACHEENTRY *pEntry = m_Lookup.SearchKeyHash( dwHash, key ) ;
  285. if( pEntry ) {
  286. pDataOut = pEntry->m_pData ;
  287. fReturn = TRUE ;
  288. m_ExpireList.LiveLonger( pEntry, (m_TTL/2)+1 ) ;
  289. }
  290. m_Lock.ShareUnlock() ;
  291. if( pDataOut == 0 ) {
  292. m_Lock.ExclusiveLock() ;
  293. //
  294. // Check that the Item we want in the Cache didn't make it
  295. // into the Cache in the brief moment we switched from a shared
  296. // to an exclusive lock.
  297. //
  298. pEntry = m_Lookup.SearchKeyHash( dwHash, key ) ;
  299. if( pEntry != 0 ) {
  300. //
  301. // It's in the cache - return the cached object !
  302. //
  303. pDataOut = pEntry->m_pData ;
  304. fReturn = TRUE ;
  305. m_ExpireList.LiveLonger( pEntry, (m_TTL/2)+1 ) ;
  306. m_Lock.ExclusiveUnlock() ;
  307. } else {
  308. //
  309. // We're going to have to create one of the elements that goes
  310. // in the cache. Let's do that now !
  311. //
  312. const CACHEENTRY *pCacheEntry = 0 ;
  313. BOOL fOverFlow = FALSE ;
  314. Data *pData = 0 ;
  315. //
  316. // We Add another brace here because we want to explicitly manage
  317. // the lifetime of tempCacheEntry
  318. //
  319. {
  320. //
  321. // tempCacheEntry will be copied by the FHash template into
  322. // another CACHEENTRY object when it does its insertion.
  323. //
  324. CACHEENTRY tempCacheEntry( m_TTL ) ;
  325. //
  326. // The constructor of the Data object is expected to initialize
  327. // only the 'key' data of the Data object so that the data can be
  328. // found in the Cache.
  329. //
  330. tempCacheEntry.m_pData = pData = new Data( key, constructor ) ;
  331. if( tempCacheEntry.m_pData ) {
  332. pCacheEntry = m_Lookup.InsertDataHash( dwHash, tempCacheEntry ) ;
  333. if( pCacheEntry ) {
  334. if( m_ExpireList.Append( pCacheEntry ) ) {
  335. if( !ExpungeInternal( pCacheEntry, TRUE ) ) {
  336. m_ExpireList.ForceExpunge( this, pCacheEntry ) ;
  337. }
  338. }
  339. pDataOut = pCacheEntry->m_pData ;
  340. pDataOut->ExclusiveLock() ;
  341. } else {
  342. //
  343. // The Insertion failed !
  344. // Falling through correctly handles this error case !
  345. //
  346. }
  347. }
  348. //
  349. // Delete tempCacheEntry's reference to the Data object.
  350. // if an error occurred inserting into hash tables etc...
  351. // this will automatically destroy the data object.
  352. //
  353. tempCacheEntry.m_pData = 0 ;
  354. }
  355. //
  356. // Release the cache's lock. We do this now - the constructor
  357. // for the 'Data' object should do minimal work. We will not call
  358. // the init function for the Data object, with the 'cache' locks
  359. // relingquished. This lets others use the cache while expensive
  360. // construction operations continue.
  361. //
  362. m_Lock.ExclusiveUnlock() ;
  363. //
  364. // Complete the initialization of the new Data item if it exists !
  365. //
  366. if( pDataOut != 0 ) {
  367. BOOL fSuccess = pDataOut->Init( constructor ) ;
  368. pDataOut->ExclusiveUnlock() ;
  369. if( fSuccess ) {
  370. fReturn = TRUE ;
  371. } else {
  372. pDataOut = 0 ;
  373. //
  374. // Need to Expire the entry we just placed in the Cache !
  375. //
  376. // NOTE : Expunge() manages its own locks !!!
  377. //
  378. Expunge( &key ) ;
  379. }
  380. }
  381. }
  382. }
  383. }
  384. return fReturn ;
  385. }
  386. template < class Data,
  387. class Key,
  388. class Constructor,
  389. BOOL fAtomic
  390. >
  391. inline BOOL
  392. Cache<Data, Key, Constructor, fAtomic>::FindOrCreate(
  393. Key& key,
  394. Constructor& constructor,
  395. CRefPtr< Data >& pDataOut ) {
  396. /*++
  397. Routine Description :
  398. This function is called when we want something out
  399. of the Cache. We will either find the object or create it.
  400. WE WILL GRAB THE NECESSARY LOCKS !
  401. Arguments :
  402. key - The unique key used to find the item in the Cache.
  403. constructor - An object to pass to the Data's constructor and Init
  404. functions.
  405. pDataOut - Smart pointer which receives the result
  406. Return Value :
  407. TRUE if successfull
  408. --*/
  409. DWORD dw = m_pfnHash( key ) ;
  410. return FindOrCreateInternal( dw,
  411. key,
  412. constructor,
  413. pDataOut
  414. ) ;
  415. }
  416. template < class Data,
  417. class Key,
  418. class Constructor,
  419. BOOL fAtomic
  420. >
  421. MultiCache< Data, Key, Constructor, fAtomic >::MultiCache() :
  422. m_fValid( FALSE ),
  423. m_pCaches( 0 ) ,
  424. m_cSubCaches( 0 ),
  425. m_pfnHash( 0 ) {
  426. /*++
  427. Routine Description :
  428. This function initializes the MultiCache's data structures
  429. Arguments :
  430. None.
  431. Return Value :
  432. Nothing
  433. --*/
  434. }
  435. template < class Data,
  436. class Key,
  437. class Constructor,
  438. BOOL fAtomic
  439. >
  440. MultiCache< Data, Key, Constructor, fAtomic >::~MultiCache() {
  441. /*++
  442. Routine Description :
  443. This function destroys all of our data structures - release
  444. all of our subcaches !
  445. Arguments :
  446. None.
  447. Return Value :
  448. Nothing
  449. --*/
  450. if( m_pCaches ) {
  451. delete[] m_pCaches ;
  452. }
  453. }
  454. template < class Data,
  455. class Key,
  456. class Constructor,
  457. BOOL fAtomic
  458. >
  459. BOOL
  460. MultiCache< Data, Key, Constructor, fAtomic >::Init(
  461. DWORD (*pfnHash)( const Key & ),
  462. DWORD dwLifetimeSeconds,
  463. DWORD cSubCaches,
  464. DWORD cMaxElements,
  465. PSTOPHINT_FN pfnStopHint) {
  466. /*++
  467. Routine Description :
  468. This function initializes the MultiCache - we use
  469. multiple independent Caches to split the work
  470. of caching all the data.
  471. Arguments :
  472. None.
  473. Return Value :
  474. Nothing
  475. --*/
  476. //
  477. // Check that we're in the right state for this !
  478. //
  479. _ASSERT( !m_fValid ) ;
  480. _ASSERT( m_pCaches == 0 ) ;
  481. //
  482. // Validate our arguments !!!
  483. //
  484. _ASSERT( pfnHash != 0 ) ;
  485. _ASSERT( dwLifetimeSeconds != 0 ) ;
  486. _ASSERT( cSubCaches != 0 ) ;
  487. _ASSERT( cMaxElements != 0 ) ;
  488. m_pfnHash = pfnHash ;
  489. m_cSubCaches = cSubCaches ;
  490. //
  491. // Allocate the necessary subcaches !
  492. //
  493. m_pCaches = new CACHEINSTANCE[m_cSubCaches] ;
  494. if( !m_pCaches ) {
  495. return FALSE ;
  496. } else {
  497. for( DWORD i=0; i<cSubCaches; i++ ) {
  498. if( !m_pCaches[i].Init( m_pfnHash, dwLifetimeSeconds, (cMaxElements / cSubCaches) + 1, pfnStopHint ) ) {
  499. delete m_pCaches ;
  500. return FALSE ;
  501. }
  502. }
  503. }
  504. m_fValid = TRUE ;
  505. return TRUE ;
  506. }
  507. template < class Data,
  508. class Key,
  509. class Constructor,
  510. BOOL fAtomic
  511. >
  512. DWORD
  513. MultiCache< Data, Key, Constructor, fAtomic >::ChooseInstance(
  514. DWORD dwHash
  515. ) {
  516. /*++
  517. Routine Description :
  518. Given a Key figure out which of our subinstances we wish to use.
  519. Arguments :
  520. None.
  521. Return Value :
  522. Nothing
  523. --*/
  524. //
  525. // Check that we're in the right state for this !
  526. //
  527. _ASSERT( m_fValid ) ;
  528. _ASSERT( m_pCaches != 0 ) ;
  529. //
  530. // Validate our arguments !!!
  531. //
  532. _ASSERT( m_pfnHash != 0 ) ;
  533. _ASSERT( m_cSubCaches != 0 ) ;
  534. //DWORD dwHash = m_pfnHash( k ) ;
  535. //
  536. // Constants below stolen from C-runtime rand() function !
  537. //
  538. dwHash = (((dwHash * 214013) +2531011) >> 8) % m_cSubCaches ;
  539. return dwHash ;
  540. }
  541. template < class Data,
  542. class Key,
  543. class Constructor,
  544. BOOL fAtomic
  545. >
  546. BOOL
  547. MultiCache< Data, Key, Constructor, fAtomic >::Expunge(
  548. Key* pk,
  549. CACHEENTRY* pData
  550. ) {
  551. /*++
  552. Routine Description :
  553. Either force a specified element out of the cache,
  554. or force out all those that are ready to go !
  555. Arguments :
  556. None.
  557. Return Value :
  558. Nothing
  559. --*/
  560. if( pk != 0 ) {
  561. DWORD dw = m_pfnHash( *pk ) ;
  562. CACHEINSTANCE* pInstance = &m_pCacges[ChooseInstance( dw )] ;
  563. return pInstance->Expunge( pk, pData ) ;
  564. } else {
  565. BOOL fReturn = TRUE ;
  566. for( DWORD i=0; i<m_cSubCaches; i++ ) {
  567. fReturn &= m_pCaches[i].Expunge() ;
  568. }
  569. }
  570. return fReturn ;
  571. }
  572. template < class Data,
  573. class Key,
  574. class Constructor,
  575. BOOL fAtomic
  576. >
  577. BOOL
  578. MultiCache< Data, Key, Constructor, fAtomic >::ExpungeSpecific(
  579. CALLBACKOBJ* pCallbackObject,
  580. BOOL fForced
  581. ) {
  582. /*++
  583. Routine Description :
  584. Either force a specified element out of the cache,
  585. or force out all those that are ready to go !
  586. Arguments :
  587. None.
  588. Return Value :
  589. Nothing
  590. --*/
  591. BOOL fReturn = TRUE ;
  592. for( DWORD i=0; i<m_cSubCaches; i++ ) {
  593. fReturn &= m_pCaches[i].ExpungeSpecific( pCallbackObject, fForced ) ;
  594. }
  595. return fReturn ;
  596. }
  597. template < class Data,
  598. class Key,
  599. class Constructor,
  600. BOOL fAtomic
  601. >
  602. BOOL
  603. MultiCache< Data, Key, Constructor, fAtomic >::FindOrCreate(
  604. Key& key,
  605. Constructor& constructor,
  606. CRefPtr< Data >& pDataOut
  607. ) {
  608. /*++
  609. Routine Description :
  610. Arguments :
  611. None.
  612. Return Value :
  613. Nothing
  614. --*/
  615. DWORD dw = m_pfnHash( key ) ;
  616. CACHEINSTANCE* pInstance = &m_pCaches[ChooseInstance(dw)] ;
  617. return pInstance->FindOrCreateInternal( dw, key, constructor, pDataOut ) ;
  618. }
  619. template < class Data,
  620. class Key,
  621. class Constructor,
  622. BOOL fAtomic
  623. >
  624. BOOL
  625. MultiCache< Data, Key, Constructor, fAtomic >::FindOrCreate(
  626. Key& key,
  627. DWORD dw,
  628. Constructor& constructor,
  629. CRefPtr< Data >& pDataOut
  630. ) {
  631. /*++
  632. Routine Description :
  633. Arguments :
  634. None.
  635. Return Value :
  636. Nothing
  637. --*/
  638. _ASSERT( dw == m_pfnHash( key ) ) ;
  639. CACHEINSTANCE* pInstance = &m_pCaches[ChooseInstance(dw)] ;
  640. return pInstance->FindOrCreateInternal( dw, key, constructor, pDataOut ) ;
  641. }