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.

1365 lines
26 KiB

  1. /*++
  2. CacheMTX.h
  3. This file provides the definition of the all the template
  4. functions required by cachemt.h
  5. --*/
  6. #ifndef _CACHEMTX_H_
  7. #define _CACHEMTX_H_
  8. //
  9. // This member function removes entries from the cache -
  10. // we remove them from the hash table which leads to destruction !
  11. //
  12. template< class Data,
  13. class Key,
  14. class Constructor
  15. >
  16. void
  17. CacheImp<Data, Key, Constructor>::RemoveEntry(
  18. CacheState* pCacheState
  19. ) {
  20. /*++
  21. Routine Description :
  22. Remove a CacheState object from the hash table
  23. Arguments :
  24. pCacheState - The CacheState derived object about to be destroyed
  25. Return Value :
  26. TRUE if removed !
  27. --*/
  28. TENTRY* pEntry = (TENTRY*)pCacheState ;
  29. Key k;
  30. pEntry->GetKey(k);
  31. m_Lookup.DeleteData( k, pEntry ) ;
  32. }
  33. template< class Data,
  34. class Key,
  35. class Constructor
  36. >
  37. BOOL
  38. CacheImp<Data, Key, Constructor>::QueryRemoveEntry(
  39. CacheState* pState
  40. ) {
  41. /*++
  42. Routine Description :
  43. Determine whether we want to remove an entry from cache - do
  44. so by calling a user provided object stored in a member variable - m_pCurrent
  45. Arguments :
  46. pCacheState - The CacheState object we're curious about
  47. Return Value :
  48. TRUE if removed !
  49. --*/
  50. _ASSERT( m_pCurrent != 0 ) ;
  51. TENTRY* pEntry = (TENTRY*)pState ;
  52. if( m_pCurrent )
  53. return m_pCurrent->fRemoveCacheItem( *pEntry->m_pData ) ;
  54. return TRUE ;
  55. }
  56. template< class Data,
  57. class Key,
  58. class Constructor
  59. >
  60. CacheImp<Data, Key, Constructor>::CacheImp() :
  61. m_dwSignature( DWORD('hcaC') ) ,
  62. m_pCurrent( 0 ) {
  63. /*++
  64. Routine Description :
  65. Construct a CacheImp object - Init() must be called before any use
  66. Arguments :
  67. None
  68. Return Value :
  69. None
  70. --*/
  71. }
  72. template< class Data,
  73. class Key,
  74. class Constructor
  75. >
  76. BOOL
  77. CacheImp<Data, Key, Constructor>::FindOrCreate(
  78. FORC_ARG& args,
  79. FORC_RES& result
  80. ) {
  81. /*++
  82. Routine Description :
  83. Either find an object in the cache or create a new one !
  84. Arguments :
  85. args - a structure containing all of the things
  86. we need,
  87. m_dwHash - the hash of the key
  88. m_key - the actual key of the item we're looking for
  89. m_constructor - the object which would create
  90. a new item into the cace !
  91. result -
  92. a smartptr to the resulting object !
  93. Return Value :
  94. We always return TRUE, indicating that the caller
  95. can marshall the results back to the end-user at any time.
  96. --*/
  97. //
  98. // Check that our state is good !
  99. //
  100. _ASSERT( m_ExpireList.IsValid() ) ;
  101. _ASSERT( args.m_dwHash == ComputeHash( args.m_key ) ) ;
  102. //
  103. // Check to see whether the item is already in the cache !
  104. //
  105. TENTRY *pEntry = m_Lookup.SearchKeyHash( args.m_dwHash,
  106. args.m_key
  107. ) ;
  108. //
  109. // Entry is already present - move it to the back !
  110. //
  111. if( pEntry ) {
  112. //
  113. // Update the entry's last access time !
  114. //
  115. pEntry->Stamp() ;
  116. //
  117. // Recently touched, so send to the back of the expire list !
  118. //
  119. m_ExpireList.MoveToBack( pEntry ) ;
  120. result = pEntry->m_pData ;
  121. } else {
  122. //
  123. // NOTE : TENTRY's constructor will stamp the time fields as required !
  124. //
  125. Data* pData = args.m_constructor.Create( args.m_key ) ;
  126. if( pData &&
  127. pData->Init( constructor ) ) {
  128. TENTRY* pEntry = new TENTRY( pData ) ;
  129. //
  130. // Error paths will destroy this unless we set it to NULL !
  131. //
  132. pData = 0 ;
  133. //
  134. // If we managed to construct everything !
  135. //
  136. if( pEntry ) {
  137. TENTRY* pCacheEntry = m_Lookup.InsertDataHash( args.m_dwHash, *pEntry ) ;
  138. if( pCacheEntry ) {
  139. //
  140. // Error paths will destroy this unless we set it to NULL !
  141. //
  142. pEntry = 0 ;
  143. //
  144. // Add to the expiration list -
  145. //
  146. if( m_ExpireList.Append( pCacheEntry ) ) {
  147. //
  148. // The expiration list is at max capacity - should remove something !
  149. //
  150. EXP_ARG args( 0, 0 ) ;
  151. DWORD count ;
  152. Expunge( args, count ) ;
  153. }
  154. result = pCacheEntry->m_pData ;
  155. }
  156. }
  157. if( pEntry ) {
  158. delete pEntry ;
  159. }
  160. }
  161. if( pData ) {
  162. delete pData ;
  163. }
  164. }
  165. //
  166. // Check that our state is good !
  167. //
  168. _ASSERT( m_ExpireList.IsValid() ) ;
  169. return TRUE ;
  170. }
  171. template< class Data,
  172. class Key,
  173. class Constructor
  174. >
  175. BOOL
  176. CacheImp<Data, Key, Constructor>::Expunge(
  177. EXP_ARG& args,
  178. DWORD& countExpunged
  179. ) {
  180. /*++
  181. Routine Description :
  182. Find an object in the cache and remove it!
  183. Arguments :
  184. args - a structure containing all of the things
  185. we need,
  186. m_pkey - pointer to the key of the item to be removed
  187. m_pData - pointer to the Cache element holding the item.
  188. countExpunged -
  189. how many objects removed from the cache - should be 1 if
  190. the specified item is found.
  191. Return Value :
  192. We always return TRUE, indicating that the caller
  193. can marshall the results back to the end-user at any time.
  194. --*/
  195. //
  196. // Check that our state is good !
  197. //
  198. _ASSERT( m_ExpireList.IsValid() ) ;
  199. countExpunged = 0 ;
  200. if( args.m_pkey ) {
  201. TENTRY* pRemoved = m_Lookup.DeleteData( *args.m_pkey, args.m_pData ) ;
  202. if( pRemoved ) {
  203. m_ExpireList.Remove( pRemoved ) ;
  204. countExpunged = 1;
  205. delete pRemoved ;
  206. //
  207. // Check that our state is good !
  208. //
  209. _ASSERT( m_ExpireList.IsValid() ) ;
  210. return TRUE ;
  211. }
  212. }
  213. m_ExpireList.Expunge( this, 0, countExpunged, TRUE ) ;
  214. //
  215. // Check that our state is good !
  216. //
  217. _ASSERT( m_ExpireList.IsValid() ) ;
  218. return TRUE ;
  219. }
  220. template< class Data,
  221. class Key,
  222. class Constructor
  223. >
  224. BOOL
  225. CacheImp<Data, Key, Constructor>::ExpungeSpecific(
  226. EXP_SPECIFIC_ARG& args,
  227. DWORD& countExpunged
  228. ) {
  229. /*++
  230. Routine Description :
  231. Select a set of items in the cache for removal !
  232. Arguments :
  233. args - a structure containing all of the things
  234. we need,
  235. m_pCacheCallback - an object to be called to select the items
  236. to be removed from the cache.
  237. countExpunged -
  238. how many objects removed from the cache - should be 1 if
  239. the specified item is found.
  240. Return Value :
  241. We always return TRUE, indicating that the caller
  242. can marshall the results back to the end-user at any time.
  243. --*/
  244. //
  245. // Check that our state is good !
  246. //
  247. _ASSERT( m_ExpireList.IsValid() ) ;
  248. countExpunged = 0 ;
  249. m_pCurrent = args.m_pCacheCallback ;
  250. m_ExpireList.ExpungeSpecific( this, args.m_fForced, countExpunged ) ;
  251. m_pCurrent = 0 ;
  252. //
  253. // Check that our state is good !
  254. //
  255. _ASSERT( m_ExpireList.IsValid() ) ;
  256. return TRUE ;
  257. }
  258. template< class Data,
  259. class Key,
  260. class Constructor
  261. >
  262. BOOL
  263. CacheImp<Data, Key, Constructor>::Expire(
  264. DWORD& countExpunged
  265. ) {
  266. /*++
  267. Routine Description :
  268. Remove the old items from the cache !
  269. Arguments :
  270. countExpunged -
  271. how many objects removed from the cache - should be 1 if
  272. the specified item is found.
  273. Return Value :
  274. We always return TRUE, indicating that the caller
  275. can marshall the results back to the end-user at any time.
  276. --*/
  277. //
  278. // Check that our state is good !
  279. //
  280. _ASSERT( m_ExpireList.IsValid() ) ;
  281. countExpunged = 0 ;
  282. FILETIME filetimeNow ;
  283. GetSystemTimeAsFileTime( &filetimeNow ) ;
  284. ULARGE_INTEGER ulNow ;
  285. ulNow.LowPart = filetimeNow.dwLowDateTime ;
  286. ulNow.HighPart = filetimeNow.dwHighDateTime ;
  287. ulNow.QuadPart -= m_qwExpire.QuadPart ;
  288. filetimeNow.dwLowDateTime = ulNow.LowPart ;
  289. filetimeNow.dwHighDateTime = ulNow.HighPart ;
  290. m_ExpireList.Expunge(
  291. this,
  292. &filetimeNow,
  293. countExpunged,
  294. FALSE
  295. ) ;
  296. //
  297. // Check that our state is good !
  298. //
  299. _ASSERT( m_ExpireList.IsValid() ) ;
  300. return TRUE ;
  301. }
  302. //
  303. // The following set of functions are for synchronous use
  304. // such as Initialization and Termination of the Cache.
  305. //
  306. //
  307. // Initialization function - take pointer to function
  308. // which should be used to compute hash values on Key's
  309. // Also takes the number of seconds objects should live in
  310. // the cache !
  311. //
  312. template< class Data,
  313. class Key,
  314. class Constructor
  315. >
  316. BOOL
  317. CacheImp<Data, Key, Constructor>::Init(
  318. DWORD (*pfnHash)( const Key& ),
  319. DWORD dwLifetimeSeconds,
  320. DWORD cMaxInstances,
  321. PSTOPHINT_FN pfnStopHint
  322. ) {
  323. /*++
  324. Routine Description :
  325. Initialize the cache !
  326. Arguments :
  327. pfnHash - The function which can compute the hash value of a key
  328. dwLifetimeSeconds - The oldest we should let items get within the cache
  329. cMaxInstances - The maximum number of items we should allow in the cache !
  330. Return Value :
  331. We return TRUE if the cache successfully initializes.
  332. --*/
  333. m_qwExpire.QuadPart = DWORDLONG(dwLifetimeSeconds) * DWORDLONG( 10000000 ) ;
  334. return m_Lookup.Init(
  335. &TENTRY::m_pBucket,
  336. 100,
  337. 100,
  338. pfnHash
  339. ) ;
  340. }
  341. template< class Data,
  342. class Key,
  343. class Constructor
  344. >
  345. DWORD
  346. CacheImp<Data, Key, Constructor>::ComputeHash(
  347. Key& key
  348. ) {
  349. return m_Lookup.ComputeHash( key ) ;
  350. }
  351. //
  352. // Default constructor
  353. //
  354. template< class Data,
  355. class Key,
  356. class Constructor
  357. >
  358. TAsyncCache< Data, Key, Constructor >::TAsyncCache() :
  359. m_Service( m_Implementation ),
  360. m_dwSignature( DWORD('CysA' ) ) {
  361. }
  362. //
  363. // Find an Item in the Cache or Create an Item to be held in the Cache !
  364. //
  365. template< class Data,
  366. class Key,
  367. class Constructor
  368. >
  369. BOOL
  370. TAsyncCache< Data, Key, Constructor >::FindOrCreate(
  371. CStateStackInterface& allocator,
  372. DWORD dwHash,
  373. Key& key,
  374. Constructor& constructor,
  375. COMP_OBJ* pComplete ) {
  376. /*++
  377. Routine Description :
  378. Marshall all the arguments for Finding and Creating Cache Items to
  379. the implementation class !
  380. Arguments :
  381. key - The key of the item we want to find in the cache
  382. constructor - The object which can create an item if needed
  383. pComplete - the object which is notified if we manage
  384. to pend the call
  385. Return Value :
  386. TRUE if the operation is pending
  387. FALSE otherwise !
  388. --*/
  389. _ASSERT( !FOnMyStack( pComplete ) ) ;
  390. _ASSERT( !FOnMyStack( &constructor ) ) ;
  391. _ASSERT( !FOnMyStack( &key ) ) ;
  392. _ASSERT( dwHash == m_Implementation.ComputeHash( key ) ) ;
  393. if( m_fGood ) {
  394. IMP::FORC_ARG args( dwHash, key, constructor ) ;
  395. CACHE_CREATE_CALL* pcall = new( allocator )
  396. CACHE_CREATE_CALL(
  397. allocator,
  398. &IMP::FindOrCreate,
  399. args,
  400. pComplete
  401. ) ;
  402. if( pcall ) {
  403. m_Service.QueueRequest( pcall ) ;
  404. return TRUE ;
  405. }
  406. }
  407. return FALSE ;
  408. }
  409. //
  410. // Remove an Item from the cache !
  411. //
  412. //
  413. // Function which can be used to remove items from the Cache
  414. //
  415. template< class Data,
  416. class Key,
  417. class Constructor
  418. >
  419. BOOL
  420. TAsyncCache< Data, Key, Constructor >::Expunge(
  421. CStateStackInterface& allocator,
  422. EXP_COMP_OBJ* pComplete,
  423. Key* key,
  424. IMP::TENTRY* pData
  425. ) {
  426. /*++
  427. Routine Description :
  428. Marshall all the arguments for removing an item from the cache !
  429. Arguments :
  430. pComplete - the object which is notified if we manage
  431. to pend the call
  432. key - the key of the item to be removed from the cache
  433. pData - for internal use only !
  434. Return Value :
  435. TRUE if the operation is pending
  436. FALSE otherwise !
  437. --*/
  438. if( m_fGood ) {
  439. IMP::EXP_ARG args( key, pData ) ;
  440. EXPUNGE_CALL* pcall = new( allocator )
  441. EXPUNGE_CALL(
  442. allocator,
  443. &IMP::Expunge,
  444. args,
  445. pComplete
  446. ) ;
  447. if( pcall ) {
  448. m_Service.QueueRequest( pcall ) ;
  449. return TRUE ;
  450. }
  451. }
  452. return FALSE ;
  453. }
  454. //
  455. // Function which can be passed a function pointer to determine
  456. // exactly what items are to be removed from the Cache.
  457. // if fForced == TRUE then items are removed from the Cache
  458. // no matter what.
  459. //
  460. template< class Data,
  461. class Key,
  462. class Constructor
  463. >
  464. BOOL
  465. TAsyncCache< Data, Key, Constructor >::ExpungeSpecific(
  466. CStateStackInterface& allocator,
  467. EXP_COMP_OBJ* pComplete,
  468. class CacheCallback< Data >* pSelector,
  469. BOOL fForced,
  470. TEntry<Data,Key>* pProtected
  471. ) {
  472. /*++
  473. Routine Description :
  474. Marshall all the arguments for removing a set of items
  475. form the cache
  476. Arguments :
  477. pComplete - the object which is notified if we manage
  478. to pend the call
  479. pSelector - the object which will select what is to be removed
  480. from the cache !
  481. fForced - if TRUE kick items out of the cache even if there
  482. are external references !
  483. Return Value :
  484. TRUE if the operation is pending
  485. FALSE otherwise !
  486. --*/
  487. if( m_fGood ) {
  488. IMP::EXP_SPECIFIC_ARG args( pSelector,
  489. pProtected,
  490. fForced
  491. ) ;
  492. EXPUNGE_SPECIFIC* pcall = new( allocator )
  493. EXPUNGE_SPECIFIC(
  494. allocator,
  495. &IMP::ExpungeSpecific,
  496. args,
  497. pComplete
  498. ) ;
  499. if( pcall ) {
  500. m_Service.QueueRequest( pcall ) ;
  501. return TRUE ;
  502. }
  503. }
  504. return FALSE ;
  505. }
  506. //
  507. // Expire old stuff in the cache - everything older than
  508. // dwLifetimeSeconds (specified at Init() time
  509. // which is NOT in use should be kicked out.
  510. //
  511. template< class Data,
  512. class Key,
  513. class Constructor
  514. >
  515. BOOL
  516. TAsyncCache< Data, Key, Constructor >::Expire(
  517. CStateStackInterface& allocator,
  518. EXP_COMP_OBJ* pComplete
  519. ) {
  520. /*++
  521. Routine Description :
  522. Marshall all the arguments for expiring all the old items
  523. in the cache
  524. Arguments :
  525. pComplete - the object which is notified if we manage
  526. to pend the call
  527. Return Value :
  528. TRUE if the operation is pending
  529. FALSE otherwise !
  530. --*/
  531. if( m_fGood ) {
  532. EXPIRE_CALL* pcall = new( allocator )
  533. EXPIRE_CALL(
  534. allocator,
  535. &IMP::Expire,
  536. pComplete
  537. ) ;
  538. if( pcall ) {
  539. m_Service.QueueRequest( pcall ) ;
  540. return TRUE ;
  541. }
  542. }
  543. return FALSE ;
  544. }
  545. //
  546. // Initialization function - take pointer to function
  547. // which should be used to compute hash values on Key's
  548. // Also takes the number of seconds objects should live in
  549. // the cache !
  550. //
  551. template< class Data,
  552. class Key,
  553. class Constructor
  554. >
  555. BOOL
  556. TAsyncCache< Data, Key, Constructor >::Init(
  557. DWORD (*pfnHash)( const Key& ),
  558. DWORD dwLifetimeSeconds,
  559. DWORD cMaxInstances,
  560. PSTOPHINT_FN pfnStopHint
  561. ) {
  562. /*++
  563. Routine Description :
  564. Initialize the cache
  565. Arguments :
  566. pfnHash - the function used to compute hash values for keys
  567. dwLifetimeSeconds - How long something should stay in the cache
  568. in units of seconds.
  569. cMaxInstances - the maximum number of items in the cache
  570. Return Value :
  571. TRUE if successfull
  572. FALSE otherwise !
  573. --*/
  574. m_fGood = m_Implementation.Init( pfnHash,
  575. dwLifetimeSeconds,
  576. cMaxInstances,
  577. pfnStopHint
  578. ) ;
  579. return m_fGood ;
  580. }
  581. template< class Data,
  582. class Key,
  583. class Constructor
  584. >
  585. TMultiAsyncCache< Data, Key, Constructor >::TMultiAsyncCache() :
  586. m_dwSignature( DWORD( 'tluM' ) ),
  587. m_cSubCaches( 0 ),
  588. m_pfnHash( 0 ),
  589. m_pCaches( 0 ) {
  590. /*++
  591. Routine Description :
  592. Construct a MultiAsyncCache - Init() must be called
  593. before we can be used
  594. Arguments :
  595. None
  596. Return Value :
  597. None
  598. --*/
  599. }
  600. template< class Data,
  601. class Key,
  602. class Constructor
  603. >
  604. TMultiAsyncCache< Data, Key, Constructor >::~TMultiAsyncCache() {
  605. if( m_pCaches != 0 )
  606. delete[] m_pCaches ;
  607. }
  608. template< class Data,
  609. class Key,
  610. class Constructor
  611. >
  612. DWORD
  613. TMultiAsyncCache< Data, Key, Constructor >::ChooseInstance(
  614. DWORD dwHash
  615. ) {
  616. /*++
  617. Routine Description :
  618. given the hash value of a key - figure out where it should
  619. be stored.
  620. Arguments :
  621. dwHash - Computed hash value of a key
  622. Return Value :
  623. index into m_pCaches
  624. --*/
  625. _ASSERT( m_pCaches != 0 ) ;
  626. _ASSERT( m_cSubCaches != 0 ) ;
  627. dwHash = (((dwHash * 214013) +2531011) >> 8) % m_cSubCaches ;
  628. return dwHash ;
  629. }
  630. template< class Data,
  631. class Key,
  632. class Constructor
  633. >
  634. BOOL
  635. TMultiAsyncCache< Data, Key, Constructor >::Init(
  636. DWORD cCaches,
  637. DWORD (*pfnHash)( const Key& ),
  638. DWORD dwLifetimeSeconds,
  639. DWORD cMaxInstances,
  640. PSTOPHINT_FN pfnStopHint
  641. ) {
  642. /*++
  643. Routine Description :
  644. Initialize the MultiWay Cache - Allocate several
  645. subcaches to route requests too.
  646. Arguments :
  647. cCaches - Number of SubCaches to use !
  648. pfnHash - Hash Function for cache elements
  649. dwLifetimeSeconds - How long things can stay in the cache !
  650. cMaxInstances - Maximum number of elements in the cache !
  651. pfnStopHint - function to call during shutdown !
  652. Return Value :
  653. TRUE if successfull - FALSE otherwise.
  654. --*/
  655. _ASSERT( cCaches != 0 ) ;
  656. _ASSERT( pfnHash != 0 ) ;
  657. _ASSERT( dwLifetimeSeconds > 0 ) ;
  658. _ASSERT( cMaxInstances > cCaches ) ;
  659. m_cSubCaches = cCaches ;
  660. m_pfnHash = pfnHash ;
  661. m_pCaches = new ASYNCCACHEINSTANCE[m_cSubCaches ] ;
  662. if( !m_pCaches )
  663. return FALSE ;
  664. else {
  665. for( DWORD i=0; i<m_cSubCaches; i++ ) {
  666. if( !m_pCaches[i].Init(
  667. pfnHash,
  668. dwLifetimeSeconds,
  669. cMaxInstances / cCaches,
  670. pfnStopHint
  671. ) ) {
  672. delete m_pCaches ;
  673. return FALSE ;
  674. }
  675. }
  676. }
  677. return TRUE ;
  678. }
  679. template< class Data,
  680. class Key,
  681. class Constructor
  682. >
  683. BOOL
  684. TMultiAsyncCache< Data, Key, Constructor >::FindOrCreate(
  685. CStateStackInterface& allocator,
  686. DWORD dwHash,
  687. Key& key,
  688. Constructor& constructor,
  689. COMP_OBJ* pComplete
  690. ) {
  691. /*++
  692. Routine Description :
  693. Find an Element within the Cache - and if its not present,
  694. create it !
  695. Arguments :
  696. dwHash - the hash of the key
  697. key - the key of the item in the cache
  698. constructor - the object which will create the
  699. data item if required.
  700. pComplete - the object which gets the completion notification !
  701. Return Value :
  702. TRUE if successfull - FALSE otherwise.
  703. --*/
  704. _ASSERT( !FOnMyStack( pComplete ) ) ;
  705. _ASSERT( !FOnMyStack( &constructor ) ) ;
  706. _ASSERT( !FOnMyStack( &key ) ) ;
  707. _ASSERT( m_cSubCaches != 0 ) ;
  708. _ASSERT( m_pCaches != 0 ) ;
  709. _ASSERT( dwHash == m_pfnHash( key ) ) ;
  710. ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ;
  711. return pInstance->FindOrCreate(
  712. allocator,
  713. dwHash,
  714. key,
  715. constructor,
  716. pComplete
  717. ) ;
  718. }
  719. template< class Data,
  720. class Key,
  721. class Constructor
  722. >
  723. BOOL
  724. TMultiAsyncCache< Data, Key, Constructor >::FindOrCreate(
  725. CStateStackInterface& allocator,
  726. Key& key,
  727. Constructor& constructor,
  728. COMP_OBJ* pComplete
  729. ) {
  730. /*++
  731. Routine Description :
  732. Find an Element within the Cache - and if its not present,
  733. create it !
  734. Arguments :
  735. dwHash - the hash of the key
  736. key - the key of the item in the cache
  737. constructor - the object which will create the
  738. data item if required.
  739. pComplete - the object which gets the completion notification !
  740. Return Value :
  741. TRUE if successfull - FALSE otherwise.
  742. --*/
  743. _ASSERT( m_cSubCaches != 0 ) ;
  744. _ASSERT( m_pCaches != 0 ) ;
  745. _ASSERT( m_pfnHash != 0 ) ;
  746. _ASSERT( !FOnMyStack( pComplete ) ) ;
  747. _ASSERT( !FOnMyStack( &constructor ) ) ;
  748. _ASSERT( !FOnMyStack( &key ) ) ;
  749. DWORD dwHash = m_pfnHash( key ) ;
  750. ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ;
  751. return pInstance->FindOrCreate(
  752. allocator,
  753. dwHash,
  754. key,
  755. constructor,
  756. pComplete
  757. ) ;
  758. }
  759. template< class Data,
  760. class Key,
  761. class Constructor
  762. >
  763. BOOL
  764. TMultiAsyncCache< Data, Key, Constructor >::Expunge(
  765. CStateStackInterface& allocator,
  766. EXP_COMP_OBJ* pComplete,
  767. Key* key
  768. ) {
  769. /*++
  770. Routine Description :
  771. Remove a particular item from the cache - this will cause
  772. the cache to loose its reference to the item.
  773. Arguments :
  774. pComplete - the object to be notified once the target object
  775. is removed
  776. key - key of the item to be removed - if NULL remove a
  777. single random element.
  778. pData - Not for External Customers - points to internal
  779. Cache data structures when we want to ensure we
  780. are removing exactly what we want to remove !
  781. Return Value :
  782. TRUE if successfull, FALSE otherwise !
  783. --*/
  784. _ASSERT( !FOnMyStack( pComplete ) ) ;
  785. _ASSERT( !FOnMyStack( key ) ) ;
  786. //
  787. // If they gave us a key we can select an Instance !
  788. //
  789. ASYNCCACHEINSTANCE* pInstance = &m_pCaches[0] ;
  790. if( key != 0 ) {
  791. DWORD dwHash = m_pfnHash( *key ) ;
  792. ASYNCCACHEINSTANCE* pInstance = &m_pCaches[ ChooseInstance( dwHash ) ] ;
  793. }
  794. return pInstance->Expunge(
  795. allocator,
  796. pComplete,
  797. key,
  798. 0
  799. ) ;
  800. }
  801. template< class AsyncCache >
  802. class ExpungeWrapper : public AsyncCache::EXP_COMP_OBJ {
  803. //
  804. // This class exists to help spread Expunge calls accross
  805. // all the individual classes
  806. //
  807. //
  808. private :
  809. //
  810. // The first cache instance
  811. //
  812. AsyncCache* m_pCurrent ;
  813. //
  814. // Points beyond the last cache instance
  815. //
  816. AsyncCache* m_pLast ;
  817. //
  818. // The user provided Expunge Selector !
  819. //
  820. CacheCallback< AsyncCache::CACHEDATA >* m_pSelector ;
  821. //
  822. // Does the user want items forced from the cache !
  823. //
  824. BOOL m_fForced ;
  825. //
  826. // Object to notify when we have completed removing objects !
  827. //
  828. AsyncCache::EXP_COMP_OBJ* m_pComplete ;
  829. //
  830. // Total number of items removed from the cache !
  831. //
  832. DWORD m_dwTotal ;
  833. //
  834. // The stack used to allocate child objects !
  835. //
  836. CStateStackInterface& m_Stack ;
  837. public :
  838. ExpungeWrapper(
  839. CStateStackInterface& stack,
  840. AsyncCache* pFirst,
  841. AsyncCache* pLast,
  842. AsyncCache::EXP_COMP_OBJ* pComplete,
  843. CacheCallback< AsyncCache::CACHEDATA >* pSelector,
  844. BOOL fForced
  845. ) :
  846. m_Stack( stack ),
  847. m_pCurrent( pFirst ),
  848. m_pLast( pLast ),
  849. m_pComplete( pComplete ),
  850. m_pSelector( pSelector ),
  851. m_fForced( fForced ),
  852. m_dwTotal( 0 ) {
  853. }
  854. //
  855. // The function which handles error completions !
  856. //
  857. void
  858. ErrorComplete( DWORD dw ) {
  859. AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ;
  860. delete this ;
  861. if( pTemp != 0 )
  862. pTemp->ErrorComplete( dw ) ;
  863. }
  864. //
  865. // The function which handles regular completions !
  866. //
  867. void
  868. Complete( DWORD& dw ) {
  869. //
  870. // Add up the total number of items Expunged !
  871. //
  872. m_dwTotal += dw ;
  873. //
  874. // If necessary - Do the Expunge in the next portion
  875. // of the cache !
  876. //
  877. if( ++m_pCurrent < m_pLast ) {
  878. if( !m_pCurrent->ExpungeSpecific(
  879. m_Stack,
  880. this,
  881. m_pSelector,
  882. m_fForced
  883. ) ) {
  884. ErrorComplete( 0 ) ;
  885. }
  886. } else {
  887. //
  888. // Destroy ourselves before giving the client
  889. // a chance to run !!
  890. //
  891. AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ;
  892. DWORD dwTemp = m_dwTotal ;
  893. delete this ;
  894. //
  895. // Let the end user know how many items were removed !
  896. //
  897. if( pTemp != 0 )
  898. pTemp->Complete( dwTemp ) ;
  899. }
  900. }
  901. } ;
  902. template< class Data,
  903. class Key,
  904. class Constructor
  905. >
  906. BOOL
  907. TMultiAsyncCache< Data, Key, Constructor >::ExpungeSpecific(
  908. CStateStackInterface& allocator,
  909. EXP_COMP_OBJ* pComplete,
  910. class CacheCallback< Data >* pSelector,
  911. BOOL fForced
  912. ) {
  913. /*++
  914. Routine Description :
  915. Remove many items from the cache, meeting some specified
  916. criteria !
  917. We have to wrap the users completion object with our own,
  918. as we will notify the end user when all the other
  919. notifications are completed.
  920. Arguments :
  921. pComplete - the object to be notified once the target object
  922. is removed
  923. key - key of the item to be removed - if NULL remove a
  924. single random element.
  925. pData - Not for External Customers - points to internal
  926. Cache data structures when we want to ensure we
  927. are removing exactly what we want to remove !
  928. Return Value :
  929. TRUE if successfull, FALSE otherwise !
  930. --*/
  931. _ASSERT( !FOnMyStack( pComplete ) ) ;
  932. _ASSERT( !FOnMyStack( pSelector ) ) ;
  933. typedef ExpungeWrapper< ASYNCCACHEINSTANCE > WRAPPER ;
  934. WRAPPER* pwrapper = new( allocator )
  935. WRAPPER(
  936. allocator,
  937. &m_pCaches[0],
  938. &m_pCaches[m_cSubCaches],
  939. pComplete,
  940. pSelector,
  941. fForced
  942. ) ;
  943. if( pwrapper ) {
  944. if( m_pCaches[0].ExpungeSpecific( allocator,
  945. pwrapper,
  946. pSelector,
  947. fForced
  948. ) ) {
  949. return TRUE ;
  950. }
  951. delete pwrapper ;
  952. }
  953. return FALSE ;
  954. }
  955. template< class AsyncCache >
  956. class ExpireWrapper : public AsyncCache::EXP_COMP_OBJ {
  957. private :
  958. //
  959. // First Cache we execute on !
  960. //
  961. AsyncCache* m_pCurrent ;
  962. //
  963. // One beyond the last cache we execute on !
  964. //
  965. AsyncCache* m_pLast ;
  966. //
  967. // Total number of objects expired !
  968. //
  969. DWORD m_dwTotal ;
  970. //
  971. // Client's completion object !
  972. //
  973. AsyncCache::EXP_COMP_OBJ* m_pComplete ;
  974. //
  975. // The stack used to allocate child objects !
  976. //
  977. CStateStackInterface& m_Stack ;
  978. public :
  979. ExpireWrapper( CStateStackInterface& stack,
  980. AsyncCache* pFirst,
  981. AsyncCache* pLast,
  982. AsyncCache::EXP_COMP_OBJ* pComplete
  983. ) :
  984. m_Stack( stack ),
  985. m_pCurrent( pFirst ),
  986. m_pLast( pLast ),
  987. m_pComplete( pComplete ),
  988. m_dwTotal( 0 ) {
  989. }
  990. //
  991. // The function which handles error completions !
  992. //
  993. void
  994. ErrorComplete( DWORD dw ) {
  995. AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ;
  996. delete this ;
  997. if( pTemp != 0 )
  998. pTemp->ErrorComplete( dw ) ;
  999. }
  1000. //
  1001. // The function which handles regular completions !
  1002. //
  1003. void
  1004. Complete( DWORD& dw ) {
  1005. //
  1006. // Add up the total number of items Expunged !
  1007. //
  1008. m_dwTotal += dw ;
  1009. //
  1010. // If necessary - Do the Expunge in the next portion
  1011. // of the cache !
  1012. //
  1013. if( ++m_pCurrent < m_pLast ) {
  1014. if( !m_pCurrent->Expire(m_Stack, this ) ) {
  1015. ErrorComplete( 0 ) ;
  1016. }
  1017. } else {
  1018. //
  1019. // Destroy ourselves before giving the client
  1020. // a chance to run !!
  1021. //
  1022. AsyncCache::EXP_COMP_OBJ* pTemp = m_pComplete ;
  1023. DWORD dwTemp = m_dwTotal ;
  1024. delete this ;
  1025. //
  1026. // Let the end user know how many items were removed !
  1027. //
  1028. if( pTemp != 0 )
  1029. pTemp->Complete( dwTemp ) ;
  1030. }
  1031. }
  1032. } ;
  1033. template< class Data,
  1034. class Key,
  1035. class Constructor
  1036. >
  1037. BOOL
  1038. TMultiAsyncCache< Data, Key, Constructor >::Expire(
  1039. CStateStackInterface& allocator,
  1040. EXP_COMP_OBJ* pComplete
  1041. ) {
  1042. /*++
  1043. Routine Description :
  1044. Remove many items from the cache, meeting some specified
  1045. criteria !
  1046. We have to wrap the users completion object with our own,
  1047. as we will notify the end user when all the other
  1048. notifications are completed.
  1049. Arguments :
  1050. pComplete - the object to be notified once the target object
  1051. is removed
  1052. key - key of the item to be removed - if NULL remove a
  1053. single random element.
  1054. pData - Not for External Customers - points to internal
  1055. Cache data structures when we want to ensure we
  1056. are removing exactly what we want to remove !
  1057. Return Value :
  1058. TRUE if successfull, FALSE otherwise !
  1059. --*/
  1060. _ASSERT( !FOnMyStack( pComplete ) ) ;
  1061. typedef ExpireWrapper< ASYNCCACHEINSTANCE > WRAPPER ;
  1062. WRAPPER* pwrapper = new( allocator )
  1063. WRAPPER( allocator,
  1064. &m_pCaches[0],
  1065. &m_pCaches[m_cSubCaches ] ,
  1066. pComplete
  1067. ) ;
  1068. if( pwrapper ) {
  1069. if( m_pCaches[0].Expire( allocator, pwrapper ) ) {
  1070. return TRUE ;
  1071. }
  1072. delete pwrapper ;
  1073. }
  1074. return FALSE ;
  1075. }
  1076. #endif // _CACHEMTX_H_