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.

1129 lines
22 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. usercache.cxx
  5. Abstract:
  6. Implements the common code shared by all the caches
  7. (file, meta, uri, token, ul-cached-response, etc)
  8. Author:
  9. Bilal Alam (balam) 11-Nov-2000
  10. Environment:
  11. Win32 - User Mode
  12. Project:
  13. ULW3.DLL
  14. --*/
  15. #include "precomp.hxx"
  16. #include "usercache.hxx"
  17. #include "cachehint.hxx"
  18. //static
  19. void
  20. CACHE_ENTRY_HASH::AddRefRecord(
  21. CACHE_ENTRY * pCacheEntry,
  22. int nIncr
  23. )
  24. /*++
  25. Routine Description:
  26. Dereference and possibly delete the cache entry. Note the destructor
  27. for the cache entry is private. Only this code should ever delete
  28. the cache entry
  29. Arguments:
  30. None
  31. Return Value:
  32. None
  33. --*/
  34. {
  35. DBG_ASSERT( pCacheEntry->CheckSignature() );
  36. if ( nIncr == +1 )
  37. {
  38. pCacheEntry->ReferenceCacheEntry();
  39. }
  40. else if ( nIncr == -1 )
  41. {
  42. pCacheEntry->SetFlushed();
  43. pCacheEntry->QueryCache()->IncFlushes();
  44. pCacheEntry->QueryCache()->DecEntriesCached();
  45. pCacheEntry->DereferenceCacheEntry();
  46. }
  47. else
  48. {
  49. DBG_ASSERT( FALSE );
  50. }
  51. }
  52. //
  53. // CACHE_ENTRY definitions
  54. //
  55. CACHE_ENTRY::CACHE_ENTRY(
  56. OBJECT_CACHE * pObjectCache,
  57. DWORD cTTLOverride
  58. )
  59. {
  60. _cRefs = 1;
  61. _fFlushed = FALSE;
  62. _fCached = FALSE;
  63. if ( cTTLOverride != 0 )
  64. {
  65. _cConfiguredTTL = cTTLOverride;
  66. }
  67. else
  68. {
  69. _cConfiguredTTL = pObjectCache->QueryConfiguredTTL();
  70. }
  71. _cTTL = _cConfiguredTTL;
  72. _pObjectCache = pObjectCache;
  73. _pDirmonInvalidator = NULL;
  74. _dwSignature = CACHE_ENTRY_SIGNATURE;
  75. }
  76. CACHE_ENTRY::~CACHE_ENTRY(
  77. VOID
  78. )
  79. {
  80. DBG_ASSERT( _cRefs == 0 );
  81. if ( _pDirmonInvalidator != NULL )
  82. {
  83. _pDirmonInvalidator->Release();
  84. _pDirmonInvalidator = NULL;
  85. }
  86. if ( _fFlushed )
  87. {
  88. DBG_ASSERT( QueryCache() != NULL );
  89. QueryCache()->DecActiveFlushedEntries();
  90. }
  91. _dwSignature = CACHE_ENTRY_SIGNATURE_FREE;
  92. }
  93. VOID
  94. CACHE_ENTRY::ReferenceCacheEntry(
  95. VOID
  96. )
  97. /*++
  98. Routine Description:
  99. Reference the given entry (duh)
  100. Arguments:
  101. None
  102. Return Value:
  103. None
  104. --*/
  105. {
  106. LONG cRefs;
  107. cRefs = InterlockedIncrement( &_cRefs );
  108. DBG_ASSERT( QueryCache() != NULL );
  109. QueryCache()->DoReferenceTrace( this, cRefs );
  110. }
  111. VOID
  112. CACHE_ENTRY::DereferenceCacheEntry(
  113. VOID
  114. )
  115. /*++
  116. Routine Description:
  117. Dereference and possibly delete the cache entry. Note the destructor
  118. for the cache entry is private. Only this code should ever delete
  119. the cache entry
  120. Arguments:
  121. None
  122. Return Value:
  123. None
  124. --*/
  125. {
  126. LONG cRefs;
  127. OBJECT_CACHE * pObjectCache = QueryCache();
  128. DBG_ASSERT( pObjectCache != NULL );
  129. cRefs = InterlockedDecrement( &_cRefs );
  130. pObjectCache->DoReferenceTrace( this, cRefs );
  131. if ( cRefs == 0 )
  132. {
  133. delete this;
  134. }
  135. }
  136. HRESULT
  137. CACHE_ENTRY::AddDirmonInvalidator(
  138. DIRMON_CONFIG * pDirmonConfig
  139. )
  140. /*++
  141. Routine Description:
  142. Setup dirmon invalidation for this cache entry
  143. Arguments:
  144. pDirmonConfig - path/token for use in monitoring directory
  145. Return Value:
  146. HRESULT
  147. --*/
  148. {
  149. CDirMonitorEntry * pDME = NULL;
  150. HRESULT hr;
  151. hr = QueryCache()->AddDirmonInvalidator( pDirmonConfig, &pDME );
  152. if ( FAILED( hr ) )
  153. {
  154. return hr;
  155. }
  156. DBG_ASSERT( pDME != NULL );
  157. //
  158. // Cleanup any old dir monitor entry
  159. //
  160. if ( _pDirmonInvalidator != NULL )
  161. {
  162. _pDirmonInvalidator->Release();
  163. }
  164. _pDirmonInvalidator = pDME;
  165. return NO_ERROR;
  166. }
  167. BOOL
  168. CACHE_ENTRY::Checkout(
  169. CACHE_USER *
  170. )
  171. /*++
  172. Routine Description:
  173. Checkout a cache entry
  174. Arguments:
  175. None
  176. Return Value:
  177. TRUE if the checkout was successful, else FALSE
  178. --*/
  179. {
  180. ReferenceCacheEntry();
  181. if ( QueryIsFlushed() )
  182. {
  183. DereferenceCacheEntry();
  184. QueryCache()->IncMisses();
  185. return FALSE;
  186. }
  187. else
  188. {
  189. InterlockedExchange( &_cTTL, _cConfiguredTTL );
  190. QueryCache()->IncHits();
  191. return TRUE;
  192. }
  193. }
  194. BOOL
  195. CACHE_ENTRY::QueryIsOkToFlushTTL(
  196. VOID
  197. )
  198. /*++
  199. Routine Description:
  200. Called when the cache scavenger is invoked. This routine returns whether
  201. it is OK to flush this entry due to TTL
  202. Arguments:
  203. None
  204. Return Value:
  205. TRUE if it is OK to flush by TTL, else FALSE
  206. --*/
  207. {
  208. //
  209. // Only do the TTL thing if the hash table holds the only reference to
  210. // the cache entry. We can be loose with this check as this is just an
  211. // optimization to prevent overzealous flushing
  212. //
  213. if ( _cRefs > 1 )
  214. {
  215. return FALSE;
  216. }
  217. if ( InterlockedDecrement( &_cTTL ) == 0 )
  218. {
  219. //
  220. // TTL has expired. However, we let the cache entry override this
  221. // expiry it wants to. Check that now
  222. //
  223. //
  224. // Entry be gone!
  225. //
  226. return TRUE;
  227. }
  228. else
  229. {
  230. return FALSE;
  231. }
  232. }
  233. BOOL
  234. CACHE_ENTRY::QueryIsOkToFlushMetadata(
  235. WCHAR * pszMetaPath,
  236. DWORD cchMetaPath
  237. )
  238. /*++
  239. Routine Description:
  240. Called whem metadata has changed. This routine returns whether the
  241. current cache entry should be flushed
  242. Arguments:
  243. pszMetaPath - Metabase path which changed
  244. cchMetaPath - Size of metabase path
  245. Return Value:
  246. TRUE if we should flush
  247. --*/
  248. {
  249. BOOL fRet;
  250. DBG_ASSERT( pszMetaPath != NULL );
  251. DBG_ASSERT( cchMetaPath != 0 );
  252. if ( pszMetaPath[ cchMetaPath - 1 ] == L'/' )
  253. {
  254. cchMetaPath--;
  255. }
  256. DBG_ASSERT( QueryCache()->QuerySupportsMetadataFlush() );
  257. if ( QueryMetadataPath() == NULL )
  258. {
  259. fRet = TRUE;
  260. }
  261. else if ( QueryMetadataPath()->QueryCCH() < cchMetaPath )
  262. {
  263. fRet = FALSE;
  264. }
  265. else if ( _wcsnicmp( QueryMetadataPath()->QueryStr(),
  266. pszMetaPath,
  267. cchMetaPath ) == 0 )
  268. {
  269. fRet = TRUE;
  270. }
  271. else
  272. {
  273. fRet = FALSE;
  274. }
  275. return fRet;
  276. }
  277. //
  278. // OBJECT_CACHE definitions
  279. //
  280. OBJECT_CACHE::OBJECT_CACHE(
  281. VOID
  282. )
  283. /*++
  284. Routine Description:
  285. Create an object cache. Obviously all the app-specific goo will be
  286. initialized in the derived class
  287. Arguments:
  288. None
  289. Return Value:
  290. None
  291. --*/
  292. {
  293. _hTimer = NULL;
  294. _pHintManager = NULL;
  295. _cmsecScavengeTime = 0;
  296. _cmsecTTL = 0;
  297. _dwSupportedInvalidation = 0;
  298. _cCacheHits = 0;
  299. _cCacheMisses = 0;
  300. _cCacheFlushes = 0;
  301. _cActiveFlushedEntries = 0;
  302. _cFlushCalls = 0;
  303. _cEntriesCached = 0;
  304. _cTotalEntriesCached = 0;
  305. _cPerfCacheHits = 0;
  306. _cPerfCacheMisses = 0;
  307. _cPerfCacheFlushes = 0;
  308. _cPerfFlushCalls = 0;
  309. _cPerfTotalEntriesCached = 0;
  310. #if DBG
  311. _pTraceLog = CreateRefTraceLog( 2000, 0 );
  312. #else
  313. _pTraceLog = NULL;
  314. #endif
  315. InitializeListHead( &_listEntry );
  316. _dwSignature = OBJECT_CACHE_SIGNATURE;
  317. }
  318. VOID
  319. OBJECT_CACHE::UnregisterScavenger(
  320. VOID
  321. )
  322. {
  323. if ( _hTimer != NULL )
  324. {
  325. DeleteTimerQueueTimer( NULL,
  326. _hTimer,
  327. INVALID_HANDLE_VALUE );
  328. _hTimer = NULL;
  329. }
  330. }
  331. OBJECT_CACHE::~OBJECT_CACHE(
  332. VOID
  333. )
  334. {
  335. _dwSignature = OBJECT_CACHE_SIGNATURE_FREE;
  336. UnregisterScavenger();
  337. if ( _pHintManager != NULL )
  338. {
  339. delete _pHintManager;
  340. _pHintManager = NULL;
  341. }
  342. if ( _pTraceLog != NULL )
  343. {
  344. DestroyRefTraceLog( _pTraceLog );
  345. _pTraceLog = NULL;
  346. }
  347. }
  348. VOID
  349. OBJECT_CACHE::CleanupCacheEntryListItems(
  350. LIST_ENTRY * pListHead
  351. )
  352. {
  353. CACHE_ENTRY * pCacheEntry;
  354. //
  355. // Free cache entry list items
  356. //
  357. while ( !IsListEmpty( pListHead ) )
  358. {
  359. pCacheEntry = CONTAINING_RECORD( pListHead->Flink,
  360. CACHE_ENTRY,
  361. _listEntry );
  362. RemoveEntryList( &pCacheEntry->_listEntry );
  363. pCacheEntry->_listEntry.Flink = NULL;
  364. pCacheEntry->DereferenceCacheEntry();
  365. }
  366. }
  367. //static
  368. VOID
  369. WINAPI
  370. OBJECT_CACHE::ScavengerCallback(
  371. PVOID pParam,
  372. BOOLEAN
  373. )
  374. {
  375. OBJECT_CACHE * pObjectCache;
  376. LIST_ENTRY listHead;
  377. pObjectCache = (OBJECT_CACHE*) pParam;
  378. DBG_ASSERT( pObjectCache != NULL );
  379. DBG_ASSERT( pObjectCache->CheckSignature() );
  380. InitializeListHead( &listHead);
  381. pObjectCache->FlushByTTL( &listHead );
  382. //
  383. // Remove all cache entries in the cache entry list
  384. //
  385. pObjectCache->CleanupCacheEntryListItems( &listHead );
  386. }
  387. //static
  388. LK_PREDICATE
  389. OBJECT_CACHE::CacheFlushByRegChange(
  390. CACHE_ENTRY * pCacheEntry,
  391. VOID * pvState
  392. )
  393. /*++
  394. Routine Description:
  395. Determine whether given entry should be deleted due to TTL change.
  396. Arguments:
  397. pCacheEntry - Cache entry to check
  398. pvState - Pointer to cache
  399. Return Value:
  400. LKP_PERFORM - do the delete,
  401. LKP_NO_ACTION - do nothing
  402. --*/
  403. {
  404. LIST_ENTRY * pListHead = static_cast<LIST_ENTRY *>( pvState );
  405. DBG_ASSERT( pCacheEntry != NULL );
  406. DBG_ASSERT( pCacheEntry->CheckSignature() );
  407. pCacheEntry->ReferenceCacheEntry();
  408. InsertHeadList(
  409. pListHead,
  410. &pCacheEntry->_listEntry );
  411. return LKP_PERFORM;
  412. }
  413. //static
  414. LK_PREDICATE
  415. OBJECT_CACHE::CacheFlushByTTL(
  416. CACHE_ENTRY * pCacheEntry,
  417. VOID * pvState
  418. )
  419. /*++
  420. Routine Description:
  421. Determine whether given entry should be deleted due to TTL
  422. Arguments:
  423. pCacheEntry - Cache entry to check
  424. pvState - Pointer to cache
  425. Return Value:
  426. LKP_PERFORM - do the delete,
  427. LKP_NO_ACTION - do nothing
  428. --*/
  429. {
  430. LIST_ENTRY * pListHead = static_cast<LIST_ENTRY *>( pvState );
  431. DBG_ASSERT( pCacheEntry != NULL );
  432. DBG_ASSERT( pCacheEntry->CheckSignature() );
  433. if ( pCacheEntry->QueryIsOkToFlushTTL() )
  434. {
  435. pCacheEntry->ReferenceCacheEntry();
  436. InsertHeadList(
  437. pListHead,
  438. &pCacheEntry->_listEntry );
  439. return LKP_PERFORM;
  440. }
  441. else
  442. {
  443. return LKP_NO_ACTION;
  444. }
  445. }
  446. //static
  447. LK_PREDICATE
  448. OBJECT_CACHE::CacheFlushByDirmon(
  449. CACHE_ENTRY * pCacheEntry,
  450. VOID * pvState
  451. )
  452. /*++
  453. Routine Description:
  454. Determine whether given entry should be deleted due to dir mon
  455. Arguments:
  456. pCacheEntry - Cache entry to check
  457. pvState - STRU of path which changed
  458. Return Value:
  459. LKP_PERFORM - do the delete,
  460. LKP_NO_ACTION - do nothing
  461. --*/
  462. {
  463. STRU * pstrPath = (STRU*) pvState;
  464. OBJECT_CACHE * pCache;
  465. DBG_ASSERT( pCacheEntry != NULL );
  466. DBG_ASSERT( pCacheEntry->CheckSignature() );
  467. pCache = pCacheEntry->QueryCache();
  468. DBG_ASSERT( pCache->CheckSignature() );
  469. if ( pCacheEntry->QueryIsOkToFlushDirmon( pstrPath->QueryStr(),
  470. pstrPath->QueryCCH() ) )
  471. {
  472. return LKP_PERFORM;
  473. }
  474. else
  475. {
  476. return LKP_NO_ACTION;
  477. }
  478. }
  479. //static
  480. LK_PREDICATE
  481. OBJECT_CACHE::CacheFlushByMetadata(
  482. CACHE_ENTRY * pCacheEntry,
  483. VOID * pvState
  484. )
  485. /*++
  486. Routine Description:
  487. Determine whether given entry should be deleted due to metadata change
  488. Arguments:
  489. pCacheEntry - Cache entry to check
  490. pvState - STRU with metapath which changed
  491. Return Value:
  492. LKP_PERFORM - do the delete,
  493. LKP_NO_ACTION - do nothing
  494. --*/
  495. {
  496. STRU * pstrPath = (STRU*) pvState;
  497. OBJECT_CACHE * pCache;
  498. DBG_ASSERT( pCacheEntry != NULL );
  499. DBG_ASSERT( pCacheEntry->CheckSignature() );
  500. pCache = pCacheEntry->QueryCache();
  501. DBG_ASSERT( pCache->CheckSignature() );
  502. if ( pCacheEntry->QueryIsOkToFlushMetadata( pstrPath->QueryStr(),
  503. pstrPath->QueryCCH() ) )
  504. {
  505. return LKP_PERFORM;
  506. }
  507. else
  508. {
  509. return LKP_NO_ACTION;
  510. }
  511. }
  512. VOID
  513. OBJECT_CACHE::FlushByRegChange(
  514. LIST_ENTRY * pListHead
  515. )
  516. /*++
  517. Routine Description:
  518. Flush any inactive cache entries who have outlived their TTL
  519. Arguments:
  520. pListHead - Head of the cache entry list to be deleted
  521. Return Value:
  522. None
  523. --*/
  524. {
  525. IncFlushCalls();
  526. //
  527. // Iterate the hash table, deleting expired itmes
  528. //
  529. _hashTable.DeleteIf( CacheFlushByRegChange, pListHead );
  530. }
  531. VOID
  532. OBJECT_CACHE::FlushByTTL(
  533. LIST_ENTRY * pListHead
  534. )
  535. /*++
  536. Routine Description:
  537. Flush any inactive cache entries who have outlived their TTL
  538. Arguments:
  539. pListHead - Head of the cache entry list to be deleted
  540. Return Value:
  541. None
  542. --*/
  543. {
  544. IncFlushCalls();
  545. //
  546. // Iterate the hash table, deleting expired itmes
  547. //
  548. _hashTable.DeleteIf( CacheFlushByTTL, pListHead );
  549. }
  550. VOID
  551. OBJECT_CACHE::DoDirmonInvalidationFlush(
  552. WCHAR * pszPath
  553. )
  554. /*++
  555. Routine Description:
  556. Flush all appropriate entries due to dirmon change notification
  557. Arguments:
  558. pszPath - Path that changed
  559. Return Value:
  560. None
  561. --*/
  562. {
  563. STACK_STRU( strPath, 256 );
  564. IncFlushCalls();
  565. if ( SUCCEEDED( strPath.Copy( pszPath ) ) )
  566. {
  567. _hashTable.DeleteIf( CacheFlushByDirmon, (VOID*) &strPath );
  568. }
  569. }
  570. VOID
  571. OBJECT_CACHE::DoMetadataInvalidationFlush(
  572. WCHAR * pszMetaPath
  573. )
  574. /*++
  575. Routine Description:
  576. Flush all appropriate entries due to metadata change notification
  577. Arguments:
  578. pszMetaPath - Metabase path which changed
  579. Return Value:
  580. None
  581. --*/
  582. {
  583. STACK_STRU( strPath, 256 );
  584. IncFlushCalls();
  585. if ( SUCCEEDED( strPath.Copy( pszMetaPath ) ) )
  586. {
  587. _hashTable.DeleteIf( CacheFlushByMetadata, (VOID*) &strPath );
  588. }
  589. }
  590. HRESULT
  591. OBJECT_CACHE::SetCacheConfiguration(
  592. DWORD cmsecScavengeTime,
  593. DWORD cmsecTTL,
  594. DWORD dwSupportedInvalidation,
  595. CACHE_HINT_CONFIG * pCacheHintConfig
  596. )
  597. /*++
  598. Routine Description:
  599. Do the general cache initialization here
  600. Arguments:
  601. cmsecScavengeTime - How often should a scavenger be run for this cache
  602. (should be no larger than the TTL expected for
  603. entries in this cache)
  604. cmsecTTL - TTL for entries in this cache
  605. dwSupportedInvalidation - How can the cache be invalidated?
  606. pCacheHintConfig - Cache hint configuration (NULL for no cache hints)
  607. Return Value:
  608. HRESULT
  609. --*/
  610. {
  611. BOOL fRet;
  612. HRESULT hr;
  613. DBG_ASSERT( cmsecTTL >= cmsecScavengeTime );
  614. //
  615. // Create a timer which fires every cmsecScavengeTime
  616. //
  617. _cmsecScavengeTime = cmsecScavengeTime;
  618. fRet = CreateTimerQueueTimer( &_hTimer,
  619. NULL,
  620. OBJECT_CACHE::ScavengerCallback,
  621. this,
  622. _cmsecScavengeTime,
  623. _cmsecScavengeTime,
  624. WT_EXECUTELONGFUNCTION );
  625. if ( !fRet )
  626. {
  627. return HRESULT_FROM_WIN32( GetLastError() );
  628. }
  629. _cmsecTTL = cmsecTTL;
  630. _dwSupportedInvalidation = dwSupportedInvalidation;
  631. //
  632. // Should we setup a cache hint table
  633. //
  634. if ( pCacheHintConfig != NULL )
  635. {
  636. _pHintManager = new CACHE_HINT_MANAGER;
  637. if ( _pHintManager == NULL )
  638. {
  639. hr = HRESULT_FROM_WIN32( GetLastError() );
  640. DeleteTimerQueueTimer( NULL,
  641. _hTimer,
  642. INVALID_HANDLE_VALUE );
  643. _hTimer = NULL;
  644. return hr;
  645. }
  646. hr = _pHintManager->Initialize( pCacheHintConfig );
  647. if ( FAILED( hr ) )
  648. {
  649. delete _pHintManager;
  650. _pHintManager = NULL;
  651. DeleteTimerQueueTimer( NULL,
  652. _hTimer,
  653. INVALID_HANDLE_VALUE );
  654. _hTimer = NULL;
  655. return hr;
  656. }
  657. }
  658. return NO_ERROR;
  659. }
  660. HRESULT
  661. OBJECT_CACHE::FindCacheEntry(
  662. CACHE_KEY * pCacheKey,
  663. CACHE_ENTRY ** ppCacheEntry,
  664. BOOL * pfShouldCache
  665. )
  666. /*++
  667. Routine Description:
  668. Lookup key in cache
  669. Arguments:
  670. pCacheKey - Cache key to lookup
  671. ppCacheEntry - Points to cache entry on success
  672. pfShouldCache - Provides a hint if possible on whether we should cache
  673. (can be NULL indicating no hint is needed)
  674. Return Value:
  675. HRESULT
  676. --*/
  677. {
  678. LK_RETCODE lkrc;
  679. HRESULT hr;
  680. CACHE_ENTRY * pCacheEntry = NULL;
  681. if ( ppCacheEntry == NULL ||
  682. pCacheKey == NULL )
  683. {
  684. DBG_ASSERT( FALSE );
  685. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  686. }
  687. *ppCacheEntry = NULL;
  688. //
  689. // First do a lookup
  690. //
  691. lkrc = _hashTable.FindKey( pCacheKey, &pCacheEntry );
  692. if ( lkrc == LK_SUCCESS )
  693. {
  694. //
  695. // If this entry has been flushed, then it really isn't a hit
  696. //
  697. if ( pCacheEntry->QueryIsFlushed() )
  698. {
  699. pCacheEntry->DereferenceCacheEntry();
  700. }
  701. else
  702. {
  703. IncHits();
  704. DBG_ASSERT( pCacheEntry != NULL );
  705. *ppCacheEntry = pCacheEntry;
  706. return NO_ERROR;
  707. }
  708. }
  709. IncMisses();
  710. //
  711. // Is a hint requested?
  712. //
  713. if ( pfShouldCache != NULL )
  714. {
  715. *pfShouldCache = TRUE;
  716. if ( _pHintManager != NULL )
  717. {
  718. hr = _pHintManager->ShouldCacheEntry( pCacheKey,
  719. pfShouldCache );
  720. //
  721. // Ignore error
  722. //
  723. }
  724. }
  725. return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  726. }
  727. HRESULT
  728. OBJECT_CACHE::FlushCacheEntry(
  729. CACHE_KEY * pCacheKey
  730. )
  731. /*++
  732. Routine Description:
  733. Flush given cache key
  734. Arguments:
  735. pCacheKey - Key to flush
  736. Return Value:
  737. HRESULT
  738. --*/
  739. {
  740. LK_RETCODE lkrc;
  741. CACHE_ENTRY * pCacheEntry;
  742. if ( pCacheKey == NULL )
  743. {
  744. DBG_ASSERT( FALSE );
  745. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  746. }
  747. //
  748. // First do a lookup
  749. //
  750. lkrc = _hashTable.FindKey( pCacheKey, &pCacheEntry );
  751. if ( lkrc == LK_SUCCESS )
  752. {
  753. DBG_ASSERT( pCacheEntry != NULL );
  754. if ( !pCacheEntry->QueryIsFlushed() )
  755. {
  756. _hashTable.DeleteRecord( pCacheEntry );
  757. }
  758. pCacheEntry->DereferenceCacheEntry();
  759. }
  760. return NO_ERROR;
  761. }
  762. HRESULT
  763. OBJECT_CACHE::AddCacheEntry(
  764. CACHE_ENTRY * pCacheEntry
  765. )
  766. /*++
  767. Routine Description:
  768. Lookup key in cache
  769. Arguments:
  770. pCacheEntry - Points to cache entry on success
  771. Return Value:
  772. HRESULT
  773. --*/
  774. {
  775. LK_RETCODE lkrc;
  776. if ( pCacheEntry == NULL )
  777. {
  778. DBG_ASSERT( FALSE );
  779. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  780. }
  781. DBG_ASSERT( pCacheEntry->QueryCached() == FALSE );
  782. //
  783. // Now try to insert into hash table
  784. //
  785. pCacheEntry->SetCached( TRUE );
  786. //
  787. // Replace a stale entry, if present
  788. //
  789. lkrc = _hashTable.InsertRecord( pCacheEntry, TRUE );
  790. if ( lkrc == LK_SUCCESS )
  791. {
  792. IncEntriesCached();
  793. }
  794. else
  795. {
  796. pCacheEntry->SetCached( FALSE );
  797. }
  798. return NO_ERROR;
  799. }
  800. HRESULT
  801. OBJECT_CACHE::AddDirmonInvalidator(
  802. DIRMON_CONFIG * pDirmonConfig,
  803. CDirMonitorEntry ** ppDME
  804. )
  805. /*++
  806. Routine Description:
  807. Add dirmon invalidator for this cache
  808. Arguments:
  809. pDirmonConfig - Configuration of dir monitor
  810. ppDME - filled with dir monitor entry to be attached to cache entry
  811. Return Value:
  812. HRESULT
  813. --*/
  814. {
  815. HRESULT hr = NO_ERROR;
  816. if ( !QuerySupportsDirmonSpecific() &&
  817. !QuerySupportsDirmonFlush() )
  818. {
  819. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  820. }
  821. //
  822. // Start monitoring
  823. //
  824. DBG_ASSERT( g_pCacheManager != NULL );
  825. hr = g_pCacheManager->MonitorDirectory( pDirmonConfig,
  826. ppDME );
  827. if ( FAILED( hr ) )
  828. {
  829. return hr;
  830. }
  831. DBG_ASSERT( *ppDME != NULL );
  832. return NO_ERROR;
  833. }