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.

1538 lines
36 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1998 **/
  4. /**********************************************************************/
  5. /*
  6. tsunami.cxx
  7. This module contains most of the public Tsunami Cache routines.
  8. FILE HISTORY:
  9. MCourage 09-Dec-1997 Created
  10. */
  11. #include <tsunami.hxx>
  12. #include <inetinfo.h>
  13. #include <issched.hxx>
  14. #include "inetreg.h"
  15. #include "globals.hxx"
  16. #include "tsunamip.hxx"
  17. #include <inetsvcs.h>
  18. #include "metacach.hxx"
  19. #include "filecach.hxx"
  20. #include "blobcach.hxx"
  21. #include "atq.h"
  22. #include "tracelog.h"
  23. #include <lkrhash.h>
  24. #include "filehash.hxx"
  25. #include "blobhash.hxx"
  26. #include "tlcach.h"
  27. #include "etagmb.h"
  28. BOOL g_fCacheSecDesc = TRUE;
  29. //
  30. // from TsInit.cxx
  31. //
  32. HANDLE g_hQuit = NULL;
  33. HANDLE g_hNewItem = NULL;
  34. BOOL g_fW3OnlyNoAuth = FALSE;
  35. BOOL TsNoDirOpenSupport = FALSE;
  36. #if TSUNAMI_REF_DEBUG
  37. PTRACE_LOG RefTraceLog;
  38. #endif // TSUNAMI_REF_DEBUG
  39. //
  40. // The TTL to scavenge the cache and the id of the scheduled work item of the
  41. // next scheduled scavenge
  42. //
  43. DWORD g_cmsecObjectCacheTTL = (INETA_DEF_OBJECT_CACHE_TTL * 1000);
  44. DWORD g_dwObjectCacheCookie = 0;
  45. # define MIN_CACHE_SCAVENGE_TIME (5*1000) // 5 seconds
  46. //
  47. // Disables Tsunami Caching
  48. //
  49. BOOL DisableTsunamiCaching = FALSE;
  50. //
  51. // Allows us to mask the invalid flags
  52. //
  53. DWORD TsValidCreateFileOptions = TS_IIS_VALID_FLAGS;
  54. //
  55. // from globals.cxx
  56. //
  57. CONFIGURATION Configuration;
  58. BOOL g_fDisableCaching = FALSE;
  59. //
  60. // Initialization and cleanup
  61. //
  62. BOOL
  63. Tsunami_Initialize(
  64. VOID
  65. )
  66. /*++
  67. Routine Description:
  68. Sets up all the core caches. Call this before using any
  69. cache routines.
  70. Arguments:
  71. None.
  72. Return Values:
  73. TRUE on success
  74. --*/
  75. {
  76. HRESULT hr;
  77. HKEY hKey;
  78. DWORD dwType;
  79. DWORD nBytes;
  80. DWORD dwValue;
  81. DWORD dwMaxFile;
  82. DWORD err;
  83. #if TSUNAMI_REF_DEBUG
  84. RefTraceLog = CreateRefTraceLog(
  85. 256, // LogSize
  86. 0 // ExtraBytesInHeader
  87. );
  88. #endif // TSUNAMI_REF_DEBUG
  89. //
  90. // Initialize global events
  91. //
  92. g_hQuit = IIS_CREATE_EVENT(
  93. "g_hQuit",
  94. &g_hQuit,
  95. TRUE,
  96. FALSE
  97. );
  98. g_hNewItem = IIS_CREATE_EVENT(
  99. "g_hNewItem",
  100. &g_hNewItem,
  101. FALSE,
  102. FALSE
  103. );
  104. if ( (g_hQuit == NULL) || (g_hNewItem == NULL) ) {
  105. goto Failure;
  106. }
  107. //
  108. // Set defaults
  109. //
  110. MEMORYSTATUS ms;
  111. ms.dwLength = sizeof(MEMORYSTATUS);
  112. GlobalMemoryStatus( &ms );
  113. //
  114. // default is 1K files per 32MB of physical memory after the 1st 8MB,
  115. // minimum INETA_MIN_DEF_FILE_HANDLE
  116. //
  117. if ( ms.dwTotalPhys > 8 * 1024 * 1024 )
  118. {
  119. dwMaxFile = (DWORD)(ms.dwTotalPhys - 8 * 1024 * 1024) / ( 32 * 1024 );
  120. if ( dwMaxFile < INETA_MIN_DEF_FILE_HANDLE )
  121. {
  122. dwMaxFile = INETA_MIN_DEF_FILE_HANDLE;
  123. }
  124. }
  125. else
  126. {
  127. dwMaxFile = INETA_MIN_DEF_FILE_HANDLE;
  128. }
  129. //
  130. // If this is not a NTS, disable tsunami caching by default
  131. //
  132. if ( !TsIsNtServer() ) {
  133. DisableTsunamiCaching = TRUE;
  134. }
  135. //
  136. // Read the registry key to see whether tsunami caching is enabled
  137. //
  138. err = RegOpenKeyEx(
  139. HKEY_LOCAL_MACHINE,
  140. INETA_PARAMETERS_KEY,
  141. 0,
  142. KEY_READ,
  143. &hKey
  144. );
  145. if ( err == ERROR_SUCCESS ) {
  146. nBytes = sizeof(dwValue);
  147. err = RegQueryValueEx(
  148. hKey,
  149. INETA_DISABLE_TSUNAMI_CACHING,
  150. NULL,
  151. &dwType,
  152. (LPBYTE)&dwValue,
  153. &nBytes
  154. );
  155. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  156. DisableTsunamiCaching = (BOOL)dwValue;
  157. }
  158. //
  159. // How big do files have to be before we stop caching them
  160. //
  161. err = RegQueryValueEx(
  162. hKey,
  163. INETA_MAX_CACHED_FILE_SIZE,
  164. NULL,
  165. &dwType,
  166. (LPBYTE)&dwValue,
  167. &nBytes
  168. );
  169. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  170. g_dwFileCacheByteThreshold = dwValue;
  171. } else {
  172. g_dwFileCacheByteThreshold = INETA_DEF_MAX_CACHED_FILE_SIZE;
  173. }
  174. //
  175. // How big is the memory cache in megabytes
  176. //
  177. err = RegQueryValueEx(
  178. hKey,
  179. INETA_MEM_CACHE_SIZE,
  180. NULL,
  181. &dwType,
  182. (LPBYTE)&dwValue,
  183. &nBytes
  184. );
  185. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  186. //
  187. // set the size in megabytes
  188. //
  189. g_dwMemCacheSize = dwValue * (1024 * 1024);
  190. } else {
  191. g_dwMemCacheSize = INETA_DEF_MEM_CACHE_SIZE;
  192. }
  193. //
  194. // Do we use the sequential read flag to read files?
  195. //
  196. err = RegQueryValueEx(
  197. hKey,
  198. INETA_ENABLE_SEQUENTIAL_READ,
  199. NULL,
  200. &dwType,
  201. (LPBYTE)&dwValue,
  202. &nBytes
  203. );
  204. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  205. g_bEnableSequentialRead = dwValue ? 1 : 0;
  206. } else {
  207. g_bEnableSequentialRead = INETA_DEF_ENABLE_SEQUENTIAL_READ;
  208. }
  209. if ( g_fW3OnlyNoAuth )
  210. {
  211. //
  212. // TODO: investigate is security descriptor caching
  213. // can be used in the non-SYSTEM account case.
  214. //
  215. g_fCacheSecDesc = FALSE;
  216. }
  217. else
  218. {
  219. //
  220. // read the enable cache sec desc flag
  221. //
  222. nBytes = sizeof(dwValue);
  223. err = RegQueryValueEx(
  224. hKey,
  225. INETA_CACHE_USE_ACCESS_CHECK,
  226. NULL,
  227. &dwType,
  228. (LPBYTE)&dwValue,
  229. &nBytes
  230. );
  231. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  232. g_fCacheSecDesc = !!dwValue;
  233. }
  234. else {
  235. g_fCacheSecDesc = INETA_DEF_CACHE_USE_ACCESS_CHECK;
  236. }
  237. }
  238. //
  239. // Read the maximum # of files in cache
  240. //
  241. nBytes = sizeof(dwValue);
  242. if ( RegQueryValueEx(
  243. hKey,
  244. INETA_MAX_OPEN_FILE,
  245. NULL,
  246. &dwType,
  247. (LPBYTE) &dwValue,
  248. &nBytes
  249. ) == ERROR_SUCCESS && dwType == REG_DWORD )
  250. {
  251. dwMaxFile = dwValue;
  252. }
  253. RegCloseKey( hKey );
  254. }
  255. //
  256. // if tsunami caching is disabled, set the flags accordingly
  257. //
  258. if ( DisableTsunamiCaching ) {
  259. g_fDisableCaching = TRUE;
  260. TsValidCreateFileOptions = TS_PWS_VALID_FLAGS;
  261. g_fCacheSecDesc = FALSE;
  262. }
  263. //
  264. // Initialize the ETag Metabase Change Number
  265. //
  266. hr = ETagChangeNumber::Create();
  267. if ( FAILED(hr) ) {
  268. goto Failure;
  269. }
  270. //
  271. // Initialize the directory change manager
  272. //
  273. if ( !DcmInitialize( ) ) {
  274. goto Failure;
  275. }
  276. //
  277. // Initialize the tsunami cache manager
  278. //
  279. if ( !FileCache_Initialize( dwMaxFile )) {
  280. goto Failure;
  281. }
  282. if ( !MetaCache_Initialize() ) {
  283. goto Failure;
  284. }
  285. if ( !BlobCache_Initialize() ) {
  286. goto Failure;
  287. }
  288. return( TRUE );
  289. Failure:
  290. IIS_PRINTF( ( buff, "Tsunami_Initialize() Failed. Error = %d\n",
  291. GetLastError()));
  292. if ( g_hQuit )
  293. {
  294. CloseHandle( g_hQuit );
  295. g_hQuit = NULL;
  296. }
  297. if ( g_hNewItem )
  298. {
  299. CloseHandle( g_hNewItem );
  300. g_hNewItem = NULL;
  301. }
  302. return FALSE;
  303. } // Tsunami_Initialize
  304. VOID
  305. Tsunami_Terminate(
  306. VOID
  307. )
  308. /*++
  309. Routine Description:
  310. Cleans up all the core caches.
  311. Arguments:
  312. None.
  313. Return Values:
  314. None.
  315. --*/
  316. {
  317. DWORD dwResult;
  318. if ( !SetEvent( g_hQuit ) ) {
  319. IIS_PRINTF((buff,
  320. "No Quit event posted for Tsunami. No Cleanup\n"));
  321. return;
  322. }
  323. //
  324. // Flush all items from the cache
  325. //
  326. TsCacheFlush( 0 );
  327. //
  328. // Synchronize with our thread so we don't leave here before the
  329. // thread has finished cleaning up
  330. //
  331. CloseHandle( g_hQuit );
  332. CloseHandle( g_hNewItem );
  333. BlobCache_Terminate();
  334. MetaCache_Terminate();
  335. FileCache_Terminate();
  336. DcmTerminate();
  337. ETagChangeNumber::Destroy();
  338. #if TSUNAMI_REF_DEBUG
  339. if( RefTraceLog != NULL ) {
  340. DestroyRefTraceLog( RefTraceLog );
  341. RefTraceLog = NULL;
  342. }
  343. #endif // TSUNAMI_REF_DEBUG
  344. } // Tsunami_Terminate
  345. //
  346. // Scavenger routines
  347. //
  348. BOOL
  349. FileFlushFilterTTL(
  350. TS_OPEN_FILE_INFO * pFileInfo,
  351. PVOID pv
  352. )
  353. {
  354. if (pFileInfo->GetIORefCount()) {
  355. //
  356. // Try not to time out entries which are in use for I/O.
  357. //
  358. return FALSE;
  359. }
  360. if (pFileInfo->GetTTL() == 0) {
  361. pFileInfo->TraceCheckpointEx(TS_MAGIC_TIMEOUT, 0, 0);
  362. return TRUE;
  363. } else {
  364. if (pFileInfo->IsInitialized()) {
  365. pFileInfo->DecrementTTL();
  366. }
  367. return FALSE;
  368. }
  369. }
  370. BOOL
  371. BlobFlushFilterTTL(
  372. PBLOB_HEADER pBlob,
  373. PVOID pv
  374. )
  375. {
  376. if (pBlob->TTL == 0) {
  377. pBlob->TraceCheckpointEx(TS_MAGIC_TIMEOUT, 0, 0);
  378. return TRUE;
  379. } else {
  380. pBlob->TTL--;
  381. return FALSE;
  382. }
  383. }
  384. VOID
  385. WINAPI
  386. CacheScavenger(
  387. VOID * pContext
  388. )
  389. {
  390. FilteredFlushFileCache(FileFlushFilterTTL, NULL);
  391. FilteredFlushBlobCache(BlobFlushFilterTTL, NULL);
  392. }
  393. BOOL
  394. InitializeCacheScavenger(
  395. VOID
  396. )
  397. /*++
  398. Routine Description:
  399. This function kicks off the scheduled tsunami object cache scavenger
  400. Arguments:
  401. None.
  402. Return Values:
  403. TRUE on success
  404. --*/
  405. {
  406. HKEY hkey;
  407. //
  408. // Schedule a scavenger to close all of the objects that haven't been
  409. // referenced in the last ttl
  410. //
  411. if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  412. INETA_PARAMETERS_KEY,
  413. 0,
  414. KEY_READ,
  415. &hkey ))
  416. {
  417. DWORD dwType;
  418. DWORD nBytes;
  419. DWORD dwValue;
  420. nBytes = sizeof(dwValue);
  421. if ( RegQueryValueEx(
  422. hkey,
  423. INETA_OBJECT_CACHE_TTL,
  424. NULL,
  425. &dwType,
  426. (LPBYTE) &dwValue,
  427. &nBytes
  428. ) == ERROR_SUCCESS && dwType == REG_DWORD )
  429. {
  430. g_cmsecObjectCacheTTL = dwValue;
  431. } else {
  432. g_cmsecObjectCacheTTL = 0;
  433. }
  434. //
  435. // Don't schedule anything if the scavenger should be disabled
  436. //
  437. if ( g_cmsecObjectCacheTTL == 0xffffffff )
  438. {
  439. RegCloseKey( hkey );
  440. return TRUE;
  441. }
  442. //
  443. // The registry setting is in seconds, convert to milliseconds
  444. //
  445. g_cmsecObjectCacheTTL *= 1000;
  446. //
  447. // Supply the default if no value was specified
  448. //
  449. if ( !g_cmsecObjectCacheTTL )
  450. {
  451. g_cmsecObjectCacheTTL = INETA_DEF_OBJECT_CACHE_TTL * 1000;
  452. }
  453. RegCloseKey( hkey );
  454. }
  455. //
  456. // Require a minimum of thirty seconds
  457. //
  458. g_cmsecObjectCacheTTL = max( g_cmsecObjectCacheTTL,
  459. MIN_CACHE_SCAVENGE_TIME );
  460. g_dwObjectCacheCookie = ScheduleWorkItem(
  461. CacheScavenger,
  462. NULL,
  463. g_cmsecObjectCacheTTL,
  464. TRUE ); // Periodic
  465. if ( !g_dwObjectCacheCookie )
  466. {
  467. return FALSE;
  468. }
  469. return TRUE;
  470. }
  471. VOID
  472. TerminateCacheScavenger(
  473. VOID
  474. )
  475. /*++
  476. Routine Description:
  477. Stops the cache scavenger
  478. Arguments:
  479. None.
  480. Return Values:
  481. None.
  482. --*/
  483. {
  484. if ( g_dwObjectCacheCookie )
  485. {
  486. RemoveWorkItem( g_dwObjectCacheCookie );
  487. g_dwObjectCacheCookie = 0;
  488. }
  489. }
  490. //
  491. // Blob memory management
  492. //
  493. BOOL
  494. TsAllocate(
  495. IN const TSVC_CACHE &TSvcCache,
  496. IN ULONG cbSize,
  497. IN OUT PVOID * ppvNewBlock
  498. )
  499. {
  500. return( TsAllocateEx( TSvcCache,
  501. cbSize,
  502. ppvNewBlock,
  503. NULL ) );
  504. }
  505. BOOL
  506. TsAllocateEx(
  507. IN const TSVC_CACHE &TSvcCache,
  508. IN ULONG cbSize,
  509. IN OUT PVOID * ppvNewBlock,
  510. OPTIONAL PUSER_FREE_ROUTINE pfnFreeRoutine
  511. )
  512. /*++
  513. Routine Description:
  514. This function allocates a memory block for the calling server.
  515. The returned block is suitable for use as a parameter to
  516. TsCacheDirectoryBlob(). Blocks allocated by this function
  517. must either be cached or freed with TsFree(). Freeing of
  518. cached blocks will be handled by the cache manager.
  519. Anything allocated with this routine MUST be derived from
  520. BLOB_HEADER!
  521. Arguments:
  522. TSvcCache - An initialized TSVC_CACHE structure.
  523. cbSize - Number of bytes to allocate. (Must be strictly
  524. greater than zero.)
  525. ppvNewBlock - Address of a pointer to store the new block's
  526. address in.
  527. pfnFreeRoutine - pointer to a routine that will be called to
  528. clean up the block when it is decached.
  529. Return Value:
  530. TRUE - The allocation succeeded, and *ppvNewBlock points to
  531. at least cbSize accessable bytes.
  532. FALSE - The allocation failed.
  533. --*/
  534. {
  535. CBlobKey * pBlobKey;
  536. PBLOB_HEADER pbhNewBlock;
  537. DBG_ASSERT( cbSize > 0 );
  538. DBG_ASSERT( ppvNewBlock != NULL );
  539. //
  540. // allocate the blob and the key while we're at it.
  541. //
  542. pBlobKey = (CBlobKey *) ALLOC(cbSize + sizeof(CBlobKey));
  543. if ( pBlobKey != NULL )
  544. {
  545. //
  546. // If the allocation succeeded, we return a pointer to
  547. // the new structure which is directly preceded by it's key.
  548. //
  549. pbhNewBlock = (PBLOB_HEADER) (pBlobKey + 1);
  550. *ppvNewBlock = ( PVOID )( pbhNewBlock );
  551. //
  552. // Set up the BLOB_HEADER: Normal flags and stored allocation
  553. // size.
  554. //
  555. pbhNewBlock->Signature = TS_BLOB_SIGNATURE;
  556. pbhNewBlock->pBlobKey = pBlobKey;
  557. pbhNewBlock->IsCached = FALSE;
  558. pbhNewBlock->pfnFreeRoutine = pfnFreeRoutine;
  559. pbhNewBlock->lRefCount = 0;
  560. pbhNewBlock->TTL = 1;
  561. pbhNewBlock->pSecDesc = NULL;
  562. pbhNewBlock->hLastSuccessAccessToken = INVALID_HANDLE_VALUE;
  563. pBlobKey->m_pszPathName = NULL;
  564. pBlobKey->m_cbPathName = 0;
  565. pBlobKey->m_dwService = TSvcCache.GetServiceId();
  566. pBlobKey->m_dwInstance = TSvcCache.GetInstanceId();
  567. pBlobKey->m_dwDemux = 0;
  568. pbhNewBlock->TraceCheckpointEx(TS_MAGIC_ALLOCATE, (PVOID) (ULONG_PTR) cbSize, pfnFreeRoutine);
  569. }
  570. else
  571. {
  572. //
  573. // The allocation failed, and we need to return NULL
  574. //
  575. *ppvNewBlock = NULL;
  576. return FALSE;
  577. }
  578. return TRUE;
  579. }
  580. BOOL
  581. TsFree(
  582. IN const TSVC_CACHE &TSvcCache,
  583. IN PVOID pvOldBlock
  584. )
  585. /*++
  586. Routine Description:
  587. This function frees a memory block allocated with TsAllocate().
  588. Blocks that are currently cached cannot be freed with this
  589. function.
  590. Arguments:
  591. TSvcCache - An initialized TSVC_CACHE structure.
  592. pvOldBlock - The address of the block to free. (Must be
  593. non-NULL.)
  594. Return Value:
  595. TRUE - The block was freed. The pointer pvOldBlock is no longer
  596. valid.
  597. FALSE - The block was not freed. Possible reasons include:
  598. - pvOldBlock does not point to a block allocated with
  599. TsAllocate().
  600. - pvOldBlock points to a block that has been cached
  601. with CacheDirectoryBlob().
  602. - pServiceInfo does not point to a valid SERVICE_INFO
  603. structure.
  604. --*/
  605. {
  606. BOOL bSuccess;
  607. PBLOB_HEADER pbhOldBlock;
  608. CBlobKey * pRealOldBlock;
  609. DBG_ASSERT( pvOldBlock != NULL );
  610. //
  611. // Adjust the input pointer to refer to the BLOB_HEADER.
  612. //
  613. pbhOldBlock = (( PBLOB_HEADER )pvOldBlock );
  614. DBG_ASSERT( TS_BLOB_SIGNATURE == pbhOldBlock->Signature );
  615. //
  616. // Track memory corruption in free builds.
  617. //
  618. if ( TS_BLOB_SIGNATURE != pbhOldBlock->Signature ) {
  619. SetLastError( ERROR_INVALID_PARAMETER );
  620. return FALSE;
  621. }
  622. //
  623. // If the Blob is currently in the cache, we can't free it.
  624. // Check for this in the Blob's flags, and fail if it
  625. // occurs.
  626. //
  627. if ( pbhOldBlock->IsCached )
  628. {
  629. DBGPRINTF(( DBG_CONTEXT,
  630. "A service (%d) has attempted to TsFree a BLOB that it put in the cache.",
  631. TSvcCache.GetServiceId() ));
  632. BREAKPOINT();
  633. bSuccess = FALSE;
  634. }
  635. else
  636. {
  637. pbhOldBlock->Signature = TS_FREE_BLOB_SIGNATURE;
  638. if ( pbhOldBlock->pfnFreeRoutine )
  639. {
  640. bSuccess = pbhOldBlock->pfnFreeRoutine( pvOldBlock );
  641. }
  642. else
  643. {
  644. bSuccess = TRUE;
  645. }
  646. if ( bSuccess )
  647. {
  648. //
  649. // Free the memory used by the Blob.
  650. //
  651. pRealOldBlock = ((CBlobKey *) pvOldBlock) - 1;
  652. DBG_ASSERT( NULL == pRealOldBlock->m_pszPathName );
  653. pbhOldBlock->TraceCheckpointEx(TS_MAGIC_DELETE_NC,
  654. (PVOID) (ULONG_PTR) (pRealOldBlock->m_dwDemux),
  655. pbhOldBlock->pfnFreeRoutine);
  656. bSuccess = !!FREE( pRealOldBlock );
  657. /*
  658. DEC_COUNTER( TSvcCache.GetServiceId(),
  659. CurrentObjects );
  660. */
  661. }
  662. }
  663. return( bSuccess );
  664. } // TsFree
  665. //
  666. // Standard cache operations
  667. //
  668. BOOL
  669. TsCacheDirectoryBlob(
  670. IN const TSVC_CACHE &TSvcCache,
  671. IN PCSTR pszDirectoryName,
  672. IN ULONG cchDirectoryName,
  673. IN ULONG iDemultiplexor,
  674. IN PVOID pvBlob,
  675. IN BOOLEAN bKeepCheckedOut,
  676. IN PSECURITY_DESCRIPTOR pSecDesc
  677. )
  678. /*++
  679. Routine Description:
  680. This function associates the Blob given as input with the specified
  681. directory and demultiplexing number. Services should use this
  682. function to add a Blob to the cache.
  683. Callers must not cache the same Blob twice. Once a Blob is cached,
  684. its contents must not be modified, and it must not be freed or re-cached.
  685. Arguments:
  686. TSvcCache - An initialized TSVC_CACHE structure.
  687. pszDirectoryName - The name that will be used as a key in the cache.
  688. iDemultiplexor - Identifies the type of the object to be stored
  689. pvBlob - Pointer to the actual object to be stored
  690. bKeepCheckedOut - If TRUE, the caller can keep a reference to the cached object.
  691. pSecDesc - An optional SECURITY_DESCRIPTOR that goes along with the object
  692. Return Values:
  693. TRUE - The block successfully added to the cache
  694. FALSE - The block could not be added to the cache
  695. --*/
  696. {
  697. BOOL bSuccess;
  698. PBLOB_HEADER pBlob = (PBLOB_HEADER)pvBlob;
  699. DBG_ASSERT( TS_BLOB_SIGNATURE == pBlob->Signature );
  700. //
  701. // set up the key
  702. //
  703. CBlobKey * pbk = pBlob->pBlobKey;
  704. DBG_ASSERT( NULL != pbk );
  705. pbk->m_cbPathName = cchDirectoryName;
  706. pbk->m_pszPathName = (PCHAR) ALLOC(pbk->m_cbPathName + 1);
  707. if (NULL != pbk->m_pszPathName) {
  708. memcpy(pbk->m_pszPathName, pszDirectoryName, pbk->m_cbPathName + 1);
  709. } else {
  710. pbk->m_cbPathName = 0;
  711. pbk->m_pszPathName = NULL;
  712. return FALSE;
  713. }
  714. IISstrupr( (PUCHAR)pbk->m_pszPathName );
  715. pbk->m_dwService = TSvcCache.GetServiceId();
  716. pbk->m_dwInstance = TSvcCache.GetInstanceId();
  717. pbk->m_dwDemux = iDemultiplexor;
  718. //
  719. // try to cache
  720. //
  721. bSuccess = CacheBlob(pBlob);
  722. if (bSuccess && !bKeepCheckedOut) {
  723. CheckinBlob(pBlob);
  724. }
  725. if (!bSuccess) {
  726. FREE(pbk->m_pszPathName);
  727. pbk->m_pszPathName = NULL;
  728. pbk->m_cbPathName = 0;
  729. }
  730. return bSuccess;
  731. } // TsCacheDirectoryBlob
  732. BOOL
  733. TsDeCacheCachedBlob(
  734. PVOID pBlobPayload
  735. )
  736. /*++
  737. Description:
  738. This function removes a blob payload object from the cache
  739. Arguments:
  740. pCacheObject - Object to decache
  741. Return Values:
  742. TRUE on success
  743. --*/
  744. {
  745. DecacheBlob( (PBLOB_HEADER)pBlobPayload );
  746. return TRUE;
  747. }
  748. BOOL
  749. TsCheckOutCachedBlob(
  750. IN const TSVC_CACHE &TSvcCache,
  751. IN PCSTR pszDirectoryName,
  752. IN ULONG cchDirectoryName,
  753. IN ULONG iDemultiplexor,
  754. IN PVOID * ppvBlob,
  755. IN HANDLE ,
  756. IN BOOL ,
  757. IN PSECURITY_DESCRIPTOR* )
  758. /*++
  759. Routine Description:
  760. Searches the cache for a named cache entry. If the entry is found,
  761. it is checked out and returned to the caller.
  762. Arguments:
  763. TSvcCache - An initialized TSVC_CACHE structure.
  764. pszDirectoryName - The name used as a key in the cache.
  765. iDemultiplexor - Identifies the type of the object to be stored
  766. ppvBlob - If the entry is found, a pointer to it will be
  767. placed here.
  768. hAccessToken - Optional parameter used to determine if the
  769. caller is allowed to access the cached object.
  770. fMayCacheAccessToken - If this is TRUE, and the caller succesfully gains
  771. access to the cached object, the hAccessToken will
  772. be saved with the object in the cache.
  773. ppSecDesc - If this is non-NULL, the caller will be given a
  774. copy of the objects security descriptor.
  775. Return Values:
  776. None.
  777. --*/
  778. {
  779. CHAR achUpName[MAX_PATH+1];
  780. BOOL bSuccess;
  781. // People really do use this.
  782. // DBG_ASSERT( ppSecDesc == NULL );
  783. //
  784. // Make sure the path is upper case
  785. //
  786. IISstrncpy(achUpName, pszDirectoryName, MAX_PATH);
  787. achUpName[MAX_PATH] = 0;
  788. cchDirectoryName = min(cchDirectoryName, MAX_PATH);
  789. IISstrupr( reinterpret_cast<PUCHAR>(achUpName) );
  790. bSuccess = CheckoutBlob(achUpName,
  791. cchDirectoryName,
  792. TSvcCache.GetServiceId(),
  793. TSvcCache.GetInstanceId(),
  794. iDemultiplexor,
  795. (PBLOB_HEADER *) ppvBlob);
  796. if (bSuccess) {
  797. //
  798. // Security handled by the caller
  799. //
  800. ((PBLOB_HEADER)*ppvBlob)->TTL = 1;
  801. return TRUE;
  802. } else {
  803. return FALSE;
  804. }
  805. }
  806. BOOL
  807. TsCheckInCachedBlob(
  808. IN PVOID pvBlob
  809. )
  810. /*++
  811. Routine Description:
  812. When a client is done with a blob it must check it back into the cache.
  813. Arguments:
  814. pvBlob - The object to be checked in
  815. Return Values:
  816. TRUE for success
  817. --*/
  818. {
  819. CheckinBlob((PBLOB_HEADER) pvBlob);
  820. return( TRUE );
  821. } // TsCheckInCachedBlob
  822. BOOL
  823. TsCheckInOrFree(
  824. IN PVOID pvOldBlock
  825. )
  826. /*++
  827. Routine Description:
  828. This function checks in a cached memory block or
  829. frees a non-cached memory block allocated with TsAllocate().
  830. Arguments:
  831. pvOldBlock - The address of the block to free. (Must be
  832. non-NULL.)
  833. Return Value:
  834. TRUE - The block was freed. The pointer pvOldBlock is no longer
  835. valid.
  836. FALSE - The block was not freed. Possible reasons include:
  837. - pvOldBlock does not point to a block allocated with
  838. TsAllocate().
  839. --*/
  840. {
  841. PBLOB_HEADER pBlob = (PBLOB_HEADER) pvOldBlock;
  842. TSVC_CACHE dummy;
  843. if (pBlob->IsCached) {
  844. CheckinBlob(pBlob);
  845. } else {
  846. TsFree(dummy, (PVOID)pBlob);
  847. }
  848. return( TRUE );
  849. } // TsCheckInOrFree
  850. BOOL
  851. TsCacheFlushDemux(
  852. IN ULONG iDemux
  853. )
  854. /*++
  855. Routine Description:
  856. Flush all cache items whose demultiplexor matches that specified.
  857. Arguments:
  858. iDemux - Value of demux whose cache items are to be flushed.
  859. --*/
  860. {
  861. if (RESERVED_DEMUX_OPEN_FILE == iDemux) {
  862. FlushFileCache();
  863. } else {
  864. //
  865. // Only place where this function is called from is from odbc with
  866. // a demux of RESERVED_DEMUX_QUERY_CACHE. We do not need to worry
  867. // about other cases
  868. //
  869. FlushBlobCache();
  870. }
  871. return TRUE;
  872. } // TsCacheFlushDemux
  873. BOOL
  874. FlushFilterService(
  875. PBLOB_HEADER pBlob,
  876. PVOID pv
  877. )
  878. {
  879. DWORD dwServerMask = * (DWORD *)pv;
  880. return (pBlob->pBlobKey->m_dwService == dwServerMask);
  881. }
  882. BOOL
  883. TsCacheFlush(
  884. IN DWORD dwServerMask
  885. )
  886. /*++
  887. Routine Description:
  888. This function flushes the blob cache of all items for the specified service
  889. or for all services if dwServerMask is zero.
  890. --*/
  891. {
  892. if (dwServerMask) {
  893. FilteredFlushBlobCache(FlushFilterService, &dwServerMask);
  894. } else {
  895. FlushBlobCache();
  896. }
  897. return TRUE;
  898. } // TsCacheFlush
  899. BOOL
  900. FlushFilterUser(
  901. TS_OPEN_FILE_INFO *pOpenFile,
  902. PVOID pv
  903. )
  904. {
  905. HANDLE hUser = * (HANDLE *)pv;
  906. return (pOpenFile->QueryUser() == hUser);
  907. }
  908. BOOL
  909. TsCacheFlushUser(
  910. IN HANDLE hUserToken,
  911. IN BOOL fDefer
  912. )
  913. /*++
  914. Routine Description:
  915. This function flushes all file handles associated the passed user context
  916. Arguments:
  917. hUserToken - User token to flush from the cache
  918. fDefer - Build list but close handles later in worker thread (Not supported)
  919. --*/
  920. {
  921. FilteredFlushFileCache(FlushFilterUser, &hUserToken);
  922. return TRUE;
  923. } // TsCacheFlushUser
  924. typedef struct _FLUSH_URL_PARAM {
  925. PCSTR pszURL;
  926. DWORD cbURL;
  927. DWORD dwService;
  928. DWORD dwInstance;
  929. } FLUSH_URL_PARAM;
  930. BOOL
  931. FlushFilterURL(
  932. PBLOB_HEADER pBlob,
  933. PVOID pv
  934. )
  935. {
  936. DBG_ASSERT( pBlob );
  937. DBG_ASSERT( pBlob->pBlobKey );
  938. FLUSH_URL_PARAM * fup = (FLUSH_URL_PARAM *)pv;
  939. CBlobKey * pbk = pBlob->pBlobKey;
  940. BOOL bAtRoot;
  941. //
  942. // If we're flushing everything, then don't bother
  943. // with the string comparison
  944. //
  945. bAtRoot = (fup->cbURL == 1) && (fup->pszURL[0] == '/');
  946. //
  947. // If the service, instance, and URL prefixes match then we flush.
  948. //
  949. return ( (pbk->m_dwService == fup->dwService)
  950. && (pbk->m_dwInstance == fup->dwInstance)
  951. && (bAtRoot
  952. || ((pbk->m_cbPathName >= fup->cbURL)
  953. && (memcmp(pbk->m_pszPathName, fup->pszURL, fup->cbURL) == 0))) );
  954. }
  955. VOID
  956. TsFlushURL(
  957. IN const TSVC_CACHE &TSvcCache,
  958. IN PCSTR pszURL,
  959. IN DWORD dwURLLength,
  960. IN ULONG iDemultiplexor
  961. )
  962. /*++
  963. Routine Description:
  964. This routine takes as input a URL and removes from the cache all cached
  965. objects that have the input URL as their prefix. This is mostly called
  966. when we get a change notify for metadata.
  967. Arguments
  968. TSvcCache - Service cache
  969. pszURL - The URL prefix to be flushed.
  970. iDemultiplexor - The demultiplexor for the caller's entries.
  971. Returns
  972. Nothing
  973. --*/
  974. {
  975. FLUSH_URL_PARAM fuparam;
  976. STACK_STR( strUpName, MAX_PATH );
  977. //
  978. // It really only makes sense to flush the URI cache
  979. // with this function.
  980. //
  981. DBG_ASSERT( RESERVED_DEMUX_URI_INFO == iDemultiplexor );
  982. //
  983. // Make sure the path is upper case
  984. //
  985. strUpName.Copy( pszURL, dwURLLength );
  986. IISstrupr( (PUCHAR) strUpName.QueryStr() );
  987. fuparam.pszURL = strUpName.QueryStr();
  988. fuparam.cbURL = dwURLLength;
  989. fuparam.dwService = TSvcCache.GetServiceId();
  990. fuparam.dwInstance = TSvcCache.GetInstanceId();
  991. FilteredFlushURIBlobCache(FlushFilterURL, &fuparam);
  992. }
  993. BOOL
  994. TsExpireCachedBlob(
  995. IN const TSVC_CACHE &TSvcCache,
  996. IN PVOID pvBlob
  997. )
  998. {
  999. DecacheBlob((PBLOB_HEADER) pvBlob);
  1000. return TRUE;
  1001. } // TsExpireCachedBlob
  1002. //
  1003. // Misc cache management
  1004. //
  1005. BOOL
  1006. TsCacheQueryStatistics(
  1007. IN DWORD Level,
  1008. IN DWORD dwServerMask,
  1009. IN INETA_CACHE_STATISTICS * pCacheCtrs
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. This function returns the statistics for the global cache or for the
  1014. individual services
  1015. Arguments:
  1016. Level - Only valid value is 0
  1017. dwServerMask - Server mask to retrieve statistics for or 0 for the sum
  1018. of the services
  1019. pCacheCtrs - Receives the statistics for cache
  1020. Notes:
  1021. CacheBytesTotal and CacheBytesInUse are not kept on a per-server basis
  1022. so they are only returned when retrieving summary statistics.
  1023. Returns:
  1024. TRUE on success, FALSE on failure
  1025. --*/
  1026. {
  1027. if ( dwServerMask > LAST_PERF_CTR_SVC )
  1028. {
  1029. SetLastError( ERROR_INVALID_PARAMETER );
  1030. return FALSE;
  1031. }
  1032. if ( g_pFileCacheStats
  1033. && g_pURICacheStats
  1034. && g_pBlobCacheStats
  1035. && (dwServerMask == 0) ) {
  1036. pCacheCtrs->FilesCached = g_pFileCacheStats->GetFilesCached();
  1037. pCacheCtrs->TotalFilesCached = g_pFileCacheStats->GetTotalFilesCached();
  1038. pCacheCtrs->FileHits = g_pFileCacheStats->GetHits();
  1039. pCacheCtrs->FileMisses = g_pFileCacheStats->GetMisses();
  1040. pCacheCtrs->FileFlushes = g_pFileCacheStats->GetFlushes();
  1041. pCacheCtrs->FlushedEntries = g_pFileCacheStats->GetFlushedEntries();
  1042. pCacheCtrs->TotalFlushed = g_pFileCacheStats->GetTotalFlushed();
  1043. pCacheCtrs->URICached = g_pURICacheStats->GetBlobsCached();
  1044. pCacheCtrs->TotalURICached = g_pURICacheStats->GetTotalBlobsCached();
  1045. pCacheCtrs->URIHits = g_pURICacheStats->GetHits();
  1046. pCacheCtrs->URIMisses = g_pURICacheStats->GetMisses();
  1047. pCacheCtrs->URIFlushes = g_pURICacheStats->GetFlushes();
  1048. pCacheCtrs->TotalURIFlushed = g_pURICacheStats->GetTotalFlushed();
  1049. pCacheCtrs->BlobCached = g_pBlobCacheStats->GetBlobsCached();
  1050. pCacheCtrs->TotalBlobCached = g_pBlobCacheStats->GetTotalBlobsCached();
  1051. pCacheCtrs->BlobHits = g_pBlobCacheStats->GetHits();
  1052. pCacheCtrs->BlobMisses = g_pBlobCacheStats->GetMisses();
  1053. pCacheCtrs->BlobFlushes = g_pBlobCacheStats->GetFlushes();
  1054. pCacheCtrs->TotalBlobFlushed = g_pBlobCacheStats->GetTotalFlushed();
  1055. QueryMemoryCacheStatistics( pCacheCtrs, FALSE );
  1056. } else {
  1057. //
  1058. // Either we're reporting for a specific service
  1059. // or stats are not set up. Set all cache
  1060. // counters to zero.
  1061. //
  1062. pCacheCtrs->FilesCached = 0;
  1063. pCacheCtrs->TotalFilesCached = 0;
  1064. pCacheCtrs->FileHits = 0;
  1065. pCacheCtrs->FileMisses = 0;
  1066. pCacheCtrs->FileFlushes = 0;
  1067. pCacheCtrs->FlushedEntries = 0;
  1068. pCacheCtrs->TotalFlushed = 0;
  1069. pCacheCtrs->URICached = 0;
  1070. pCacheCtrs->TotalURICached = 0;
  1071. pCacheCtrs->URIHits = 0;
  1072. pCacheCtrs->URIMisses = 0;
  1073. pCacheCtrs->URIFlushes = 0;
  1074. pCacheCtrs->TotalURIFlushed = 0;
  1075. pCacheCtrs->BlobCached = 0;
  1076. pCacheCtrs->TotalBlobCached = 0;
  1077. pCacheCtrs->BlobHits = 0;
  1078. pCacheCtrs->BlobMisses = 0;
  1079. pCacheCtrs->BlobFlushes = 0;
  1080. pCacheCtrs->TotalBlobFlushed = 0;
  1081. QueryMemoryCacheStatistics( pCacheCtrs, TRUE );
  1082. }
  1083. return TRUE;
  1084. }
  1085. BOOL
  1086. TsCacheClearStatistics(
  1087. IN DWORD dwServerMask
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. Clears the the specified service's statistics
  1092. --*/
  1093. {
  1094. if ( dwServerMask > LAST_PERF_CTR_SVC )
  1095. {
  1096. SetLastError( ERROR_INVALID_PARAMETER );
  1097. return FALSE;
  1098. }
  1099. //
  1100. // Currently this function isn't supported
  1101. //
  1102. SetLastError( ERROR_NOT_SUPPORTED );
  1103. return FALSE;
  1104. } // TsCacheClearStatistics
  1105. const char * g_IISAuxCounterNames[] =
  1106. {
  1107. "Aac Open URI Files",
  1108. "Cac Calls to TsOpenURI()",
  1109. "Cac Calls to TsCloseURI()",
  1110. "Max Counters"
  1111. };
  1112. extern "C"
  1113. VOID
  1114. TsDumpCacheCounters( OUT CHAR * pchBuffer, IN OUT LPDWORD lpcbBuffer )
  1115. {
  1116. DWORD cb = 0;
  1117. *lpcbBuffer = cb;
  1118. return ;
  1119. } // TsDumpCacheCounters()
  1120. VOID
  1121. TsDumpHashTableStats( IN OUT CHAR * pchBuffer, IN OUT LPDWORD lpcbBuffer )
  1122. {
  1123. CLKRHashTableStats hts;
  1124. if (!g_pFileInfoTable) {
  1125. *lpcbBuffer = 0;
  1126. return;
  1127. }
  1128. hts = g_pFileInfoTable->GetStatistics();
  1129. *lpcbBuffer = sprintf( pchBuffer,
  1130. "<TABLE>"
  1131. "<TR><TD>Record Count</TD><TD>%d</TD></TR>"
  1132. "<TR><TD>Table Size</TD><TD>%d</TD></TR>"
  1133. "<TR><TD>Directory Size</TD><TD>%d</TD></TR>"
  1134. "<TR><TD>Longest Chain</TD><TD>%d</TD></TR>"
  1135. "<TR><TD>Empty Slots</TD><TD>%d</TD></TR>"
  1136. "<TR><TD>Split Factor</TD><TD>%f</TD></TR>"
  1137. "<TR><TD>Average Search Length</TD><TD>%f</TD></TR>"
  1138. "<TR><TD>Expected Search Length</TD><TD>%f</TD></TR>"
  1139. "<TR><TD>Average Unsuccessful Search Length</TD><TD>%f</TD></TR>"
  1140. "<TR><TD>Expected Unsuccessful Search Length</TD><TD>%f</TD></TR>"
  1141. "</TABLE>",
  1142. hts.RecordCount,
  1143. hts.TableSize,
  1144. hts.DirectorySize,
  1145. hts.LongestChain,
  1146. hts.EmptySlots,
  1147. hts.SplitFactor,
  1148. hts.AvgSearchLength,
  1149. hts.ExpSearchLength,
  1150. hts.AvgUSearchLength,
  1151. hts.ExpUSearchLength );
  1152. }
  1153. VOID
  1154. TsDumpCacheToHtml( OUT CHAR * pchBuffer, IN OUT LPDWORD lpcbBuffer )
  1155. {
  1156. LIST_ENTRY * pEntry;
  1157. DWORD cItemsOnBin = 0;
  1158. DWORD cTotalItems = 0;
  1159. DWORD i, c, cb;
  1160. DWORD cbTable;
  1161. cb = wsprintf( pchBuffer,
  1162. " <h4>File Hash Table Stats</h4> " );
  1163. TsDumpHashTableStats( pchBuffer + cb, &cbTable );
  1164. cb += cbTable;
  1165. cb += wsprintf( pchBuffer + cb,
  1166. " <h4>Some other stats</h4> ");
  1167. if (g_pFileCacheStats) {
  1168. g_pFileCacheStats->DumpToHtml(pchBuffer + cb, &cbTable);
  1169. cb += cbTable;
  1170. }
  1171. DumpMemoryCacheToHtml( pchBuffer + cb, &cbTable );
  1172. cb += cbTable;
  1173. *lpcbBuffer = cb;
  1174. return;
  1175. } // TsDumpCacheToHtml()
  1176. //
  1177. // tsunami.cxx
  1178. //