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.

1660 lines
47 KiB

  1. /*-----------------------------------------------------------------------------
  2. Microsoft Denali
  3. Microsoft Confidential
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Template Cache Manager
  6. File: CacheMgr.cpp
  7. Owner: DGottner
  8. Template cache manager implementation
  9. -----------------------------------------------------------------------------*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "perfdata.h"
  13. #include "memchk.h"
  14. CTemplateCacheManager g_TemplateCache;
  15. CIncFileMap g_IncFileMap;
  16. LONG g_nFlushThreads = 0;
  17. BOOL CTemplateCacheManager::m_fFailedToInitPersistCache = FALSE;
  18. char CTemplateCacheManager::m_szPersistCacheDir[MAX_PATH];
  19. /*===================================================================
  20. ZapTemplate
  21. Decrement the ref. count of a template to remove it from cache.
  22. If the template is global.asa, that's all we do because application
  23. manager has the last reference. Otherwise, we Release the template
  24. by calling CTemplate::End() to also free references to it from the
  25. debugger.
  26. Parameters: pTemplate - template pointer to Release() from cache
  27. Returns: new ref. count
  28. ===================================================================*/
  29. static inline
  30. ULONG ZapTemplate(CTemplate *pTemplate)
  31. {
  32. if (! pTemplate->FGlobalAsa())
  33. return pTemplate->End();
  34. else
  35. return pTemplate->Release();
  36. }
  37. /* ****************************************************************************
  38. CCacheManager member functions
  39. */
  40. /*===================================================================
  41. CTemplateCacheManager::CTemplateCacheManager
  42. Parameters: N/A
  43. Returns: N/A
  44. ===================================================================*/
  45. CTemplateCacheManager::CTemplateCacheManager()
  46. {
  47. m_pHashTemplates = NULL;
  48. m_szPersistCacheDir[0] = '\0';
  49. m_fFailedToInitPersistCache = FALSE;
  50. }
  51. /*===================================================================
  52. CTemplateCacheManager::~CTemplateCacheManager
  53. Parameters: N/A
  54. Returns: N/A
  55. ===================================================================*/
  56. CTemplateCacheManager::~CTemplateCacheManager()
  57. {
  58. }
  59. /*===================================================================
  60. CTemplateCacheManager::Init
  61. Init the template cache manager - phase 1 - that which can be done
  62. with just default values in Glob.
  63. Parameters: None
  64. Returns: Completion Status
  65. ===================================================================*/
  66. HRESULT CTemplateCacheManager::Init()
  67. {
  68. HRESULT hrInit;
  69. ErrInitCriticalSection(&m_csUpdate, hrInit);
  70. if (FAILED(hrInit))
  71. return(hrInit);
  72. // allocate the initial CTemplateHashTable
  73. m_pHashTemplates = new CTemplateHashTable;
  74. return S_OK;
  75. }
  76. /* ****************************************************************************
  77. CTemplateCacheManager member functions
  78. */
  79. /*===================================================================
  80. CTemplateCacheManager::UnInit
  81. Parameters: N/A
  82. Returns: Completion status
  83. ===================================================================*/
  84. HRESULT CTemplateCacheManager::UnInit()
  85. {
  86. if (m_pHashTemplates) {
  87. while (! m_pHashTemplates->FMemoryTemplatesIsEmpty()) {
  88. CTemplate *pTemplate = static_cast<CTemplate *>(m_pHashTemplates->MemoryTemplatesBegin());
  89. m_pHashTemplates->RemoveTemplate(pTemplate);
  90. ZapTemplate(pTemplate);
  91. }
  92. while (! m_pHashTemplates->FPersistTemplatesIsEmpty()) {
  93. CTemplate *pTemplate = static_cast<CTemplate *>(m_pHashTemplates->PersistTemplatesBegin());
  94. m_pHashTemplates->RemoveTemplate(pTemplate);
  95. ZapTemplate(pTemplate);
  96. }
  97. }
  98. delete m_pHashTemplates;
  99. m_pHashTemplates = NULL;
  100. #ifndef PERF_DISABLE
  101. g_PerfData.Zero_MEMORYTEMPLCACHE();
  102. g_PerfData.Zero_TEMPLCACHE();
  103. #endif
  104. DeleteCriticalSection(&m_csUpdate);
  105. // give any flush threads a chance to finish. This is necessary
  106. // to prevent an AV by LKRHash.
  107. DWORD maxSecondsToWait = 60;
  108. while (maxSecondsToWait-- && g_nFlushThreads) {
  109. Sleep(1000);
  110. }
  111. return S_OK;
  112. }
  113. /*===================================================================
  114. CTemplateCacheManager::FindCached
  115. Get a template from the cache only
  116. Parameters:
  117. szFile - file to find in the cache
  118. ppTemplate - [out] template object found
  119. Returns:
  120. HRESULT (S_OK if found, S_FALSE if noe found)
  121. ===================================================================*/
  122. HRESULT CTemplateCacheManager::FindCached(const TCHAR *szFile, DWORD dwInstanceID, CTemplate **ppTemplate)
  123. {
  124. Assert(IsNormalized(szFile));
  125. if (!ppTemplate)
  126. return E_POINTER;
  127. LockTemplateCache();
  128. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), ppTemplate);
  129. if (*ppTemplate)
  130. {
  131. if (!(*ppTemplate)->m_fReadyForUse)
  132. *ppTemplate = NULL; // not ready - as if nor found
  133. else
  134. (*ppTemplate)->AddRef(); // addref inside critical section
  135. }
  136. UnLockTemplateCache();
  137. return *ppTemplate? S_OK : S_FALSE;
  138. }
  139. /*===================================================================
  140. CTemplateCacheManager::Load
  141. Get a template from the cache, or load it into cache
  142. Parameters:
  143. szFile - file to load into the cache
  144. Returns: N/A
  145. ===================================================================*/
  146. HRESULT CTemplateCacheManager::Load(BOOL fRunGlobalAsp, const TCHAR *szFile, DWORD dwInstanceID, CHitObj *pHitObj, CTemplate **ppTemplate, BOOL *pfTemplateInCache)
  147. {
  148. HRESULT hr = S_OK; // return value
  149. HRESULT (CTemplate::*pmAction)(CHitObj *); // do we need to compile a new template or deliver an existing one?
  150. Assert(IsNormalized(szFile));
  151. BOOL fLocked = FALSE;
  152. // If this is the GLOBAL.ASA we can pick up
  153. // template directly from the application
  154. if (fRunGlobalAsp && pHitObj->PAppln()->PGlobalTemplate())
  155. {
  156. *ppTemplate = pHitObj->PAppln()->PGlobalTemplate();
  157. }
  158. // see if we already have looked up the template on the I/O thread...
  159. else if (!fRunGlobalAsp && pHitObj->GetTemplate())
  160. {
  161. *ppTemplate = pHitObj->GetTemplate();
  162. pHitObj->SetTemplate(NULL);
  163. }
  164. else
  165. // Otherwise we have to look for it in the cache
  166. {
  167. LockTemplateCache();
  168. fLocked = TRUE;
  169. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), ppTemplate);
  170. }
  171. if (*ppTemplate != NULL)
  172. {
  173. // Template found in cache -> use it
  174. (*ppTemplate)->AddRef();
  175. *pfTemplateInCache = TRUE;
  176. if (fLocked) // Global.Asa from App - no lock
  177. UnLockTemplateCache();
  178. pmAction = CTemplate::Deliver;
  179. }
  180. else
  181. {
  182. *pfTemplateInCache = FALSE;
  183. Assert(fLocked); // only could get here if not found in the hash table
  184. UnLockTemplateCache();
  185. // Create and init new template outside of crirical section
  186. CTemplate *pNewTemplate = new CTemplate;
  187. if (!pNewTemplate)
  188. hr = E_OUTOFMEMORY;
  189. if (SUCCEEDED(hr))
  190. hr = pNewTemplate->Init(pHitObj, !!fRunGlobalAsp, CTemplateKey(szFile, dwInstanceID));
  191. if (SUCCEEDED(hr))
  192. {
  193. LockTemplateCache();
  194. // Try to find if inserted by another thread
  195. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), ppTemplate);
  196. if (*ppTemplate != NULL)
  197. {
  198. // Template found in cache -> use it
  199. (*ppTemplate)->AddRef();
  200. UnLockTemplateCache();
  201. pmAction = CTemplate::Deliver;
  202. }
  203. else
  204. {
  205. // since we are creating a new template, call FlushCache to make
  206. // sure that no script engines are cached with this name
  207. g_ScriptManager.FlushCache(szFile);
  208. // Insert the newly created template
  209. *ppTemplate = pNewTemplate;
  210. pNewTemplate = NULL; // not to be deleted later
  211. m_pHashTemplates->InsertTemplate(*ppTemplate);
  212. (*ppTemplate)->AddRef();
  213. if (Glob(dwScriptFileCacheSize) == 0) {
  214. // This is special case when a valid template
  215. // does not get added to the cache
  216. // Don't attach such templates to debugger
  217. (*ppTemplate)->m_fDontAttach = TRUE;
  218. }
  219. UnLockTemplateCache();
  220. pmAction = CTemplate::Compile;
  221. }
  222. }
  223. // cleanup new template if created but unused
  224. if (pNewTemplate)
  225. pNewTemplate->Release();
  226. }
  227. if (FAILED(hr))
  228. return hr;
  229. // init succeeded: compile or deliver the template, as required
  230. hr = ((*ppTemplate)->*pmAction)(pHitObj);
  231. if (pmAction == CTemplate::Compile && (*ppTemplate)->m_fDontCache)
  232. {
  233. /* We were compiling and the compiler alerted us not to cache the failed template.
  234. Typically, this occurs when compile failure was caused by something other than
  235. bad template syntax (permissions failure, bad include file reference, etc.).
  236. We need to roll back to where the template did not exist.
  237. */
  238. // de-cache and release the template
  239. // NOTE we don't nullify template ptr, because we want ExecuteRequest to do the final release
  240. LockTemplateCache();
  241. if (m_pHashTemplates->RemoveTemplate(*ppTemplate) == LK_SUCCESS)
  242. ZapTemplate(*ppTemplate);
  243. UnLockTemplateCache();
  244. (*ppTemplate)->Release();
  245. *ppTemplate = NULL;
  246. }
  247. LockTemplateCache();
  248. // Remove old scripts from cache
  249. while (!m_pHashTemplates->FMemoryTemplatesIsEmpty()
  250. && (m_pHashTemplates->InMemoryTemplates() > Glob(dwScriptFileCacheSize))) {
  251. Assert (!m_pHashTemplates->FMemoryTemplatesIsEmpty());
  252. CTemplate *pOldTemplate = static_cast<CTemplate *>(m_pHashTemplates->MemoryTemplatesEnd());
  253. m_pHashTemplates->RemoveTemplate(pOldTemplate, TRUE);
  254. // flush the corresponding script engines. But only if the template
  255. // is valid.
  256. if (pOldTemplate->FIsValid()) {
  257. g_ScriptManager.FlushCache(pOldTemplate->GetSourceFileName());
  258. }
  259. // Only Zap the template if it is not persisted. The result of the above
  260. // call to RemoveTemplate is that the template may have been moved from the
  261. // memory cache to the persist cache. In which case, the template is still
  262. // effectively cached.
  263. if (pOldTemplate->FIsPersisted() == FALSE) {
  264. ZapTemplate(pOldTemplate);
  265. }
  266. }
  267. UnLockTemplateCache();
  268. // Store a pointer to the template with the application
  269. // if we haven't already done so
  270. if (SUCCEEDED(hr) && fRunGlobalAsp && pHitObj->PAppln()->PGlobalTemplate() == NULL)
  271. pHitObj->PAppln()->SetGlobalTemplate(*ppTemplate);
  272. // If we are shutting down, don't request change notification
  273. if (!IsShutDownInProgress())
  274. {
  275. // If running on NT, and we just compiled the template
  276. // register all the directories used by this template
  277. // for change notification
  278. if (FIsWinNT() && pmAction == CTemplate::Compile && SUCCEEDED(hr)) {
  279. if (!RegisterTemplateForChangeNotification(*ppTemplate, pHitObj->PAppln())) {
  280. LockTemplateCache();
  281. if (m_pHashTemplates->RemoveTemplate(*ppTemplate) == LK_SUCCESS)
  282. ZapTemplate(*ppTemplate);
  283. UnLockTemplateCache();
  284. }
  285. }
  286. // If running on NT, this is a new application, and the template is a global.asa
  287. // register this application for file change notifications
  288. if (FIsWinNT() && SUCCEEDED(hr) && (*ppTemplate)->m_fGlobalAsa && pHitObj->FStartApplication())
  289. {
  290. RegisterApplicationForChangeNotification(*ppTemplate, pHitObj->PAppln());
  291. }
  292. }
  293. return hr;
  294. }
  295. /*===================================================================
  296. CTemplateCacheManager::Flush
  297. Parameters:
  298. szFile - the file to remove from cache
  299. Returns:
  300. None
  301. ===================================================================*/
  302. void CTemplateCacheManager::Flush(const TCHAR *szFile, DWORD dwInstanceID)
  303. {
  304. LockTemplateAndIncFileCaches();
  305. Assert (IsNormalized(szFile));
  306. CTemplate *pTemplate;
  307. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), &pTemplate);
  308. while (pTemplate != NULL)
  309. {
  310. #ifndef PERF_DISABLE
  311. g_PerfData.Incr_TEMPLFLUSHES();
  312. #endif
  313. m_pHashTemplates->RemoveTemplate(pTemplate);
  314. // Make sure anyone using this template can tell it is obsolete
  315. pTemplate->Zombify();
  316. // Don't flush engines if this is a global.asa file
  317. // We'll need the engines to run Application_OnEnd
  318. // The application will flush the engine from the cache
  319. // when it unints
  320. if (!FIsGlobalAsa(szFile))
  321. {
  322. g_ScriptManager.FlushCache(szFile);
  323. }
  324. ZapTemplate(pTemplate);
  325. // If wildcard was specified in Flush for Instance ID, there may be
  326. // more templates to remove.
  327. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), &pTemplate);
  328. }
  329. UnLockTemplateAndIncFileCaches();
  330. }
  331. /*===================================================================
  332. CTemplateCacheManager::FlushAll
  333. Completely empties the template cache
  334. Parameters:
  335. None
  336. Returns:
  337. None
  338. ===================================================================*/
  339. void CTemplateCacheManager::FlushAll(VOID)
  340. {
  341. LockTemplateAndIncFileCaches();
  342. CTemplateHashTable *pNewTable = NULL;
  343. HANDLE hnd;
  344. // note that all of the following logic works on the premise that any
  345. // error causes the code to fall into the old mechanism of flushing
  346. // the hash table in place...
  347. // allocate a new table
  348. if (!(pNewTable = new CTemplateHashTable));
  349. // Create a thread to clean up the old table
  350. else if (!(hnd = CreateThread(NULL, 0, CTemplateCacheManager::FlushHashTableThread, m_pHashTemplates, 0, NULL)));
  351. else {
  352. // all the above was successful, so note that the new table is the
  353. // current table in the cache, cleanup and exit.
  354. DBGPRINTF((DBG_CONTEXT, "[CTemplateCacheManager] Flushing entire cache on another thread.\n"));
  355. InterlockedIncrement(&g_nFlushThreads);
  356. m_pHashTemplates = pNewTable;
  357. CloseHandle(hnd);
  358. UnLockTemplateAndIncFileCaches();
  359. return;
  360. }
  361. // delete the new table if something above failed.
  362. if (pNewTable)
  363. delete pNewTable;
  364. DBGPRINTF((DBG_CONTEXT, "[CTemplateCacheManager] Flushing entire cache in place\n"));
  365. FlushHashTable(m_pHashTemplates);
  366. UnLockTemplateAndIncFileCaches();
  367. return;
  368. }
  369. /*===================================================================
  370. CTemplateCacheManager::FlushHashTableThread
  371. Thread spun up by CTemplateCacheMgr::FlushAll() to flush all
  372. templates in the cache but not while under the critical section
  373. on the notification thread. Prevents unwanted contention on the
  374. cache.
  375. Parameters:
  376. None
  377. Returns:
  378. None
  379. ===================================================================*/
  380. DWORD CTemplateCacheManager::FlushHashTableThread(VOID *pArg)
  381. {
  382. CTemplateHashTable *pTable = (CTemplateHashTable *)pArg;
  383. Assert(pTable);
  384. FlushHashTable(pTable);
  385. delete pTable;
  386. InterlockedDecrement(&g_nFlushThreads);
  387. return S_OK;
  388. }
  389. /*===================================================================
  390. CTemplateCacheManager::FlushHashTable
  391. Does the actual work of flushing the templates.
  392. This routine may or may not be under the global cache manager
  393. crit sec. It will if the flush is happening on the notification
  394. thread. It won't be if it's happening on the FlushHashTableThread.
  395. Parameters:
  396. None
  397. Returns:
  398. None
  399. ===================================================================*/
  400. void CTemplateCacheManager::FlushHashTable(CTemplateHashTable *pTable)
  401. {
  402. // Delete templates from the cache until there are no more
  403. while (!pTable->FMemoryTemplatesIsEmpty()) {
  404. CTemplate *pTemplate = static_cast<CTemplate *>(pTable->MemoryTemplatesEnd());
  405. // Remove the template from its various data structures
  406. pTable->RemoveTemplate(pTemplate);
  407. // Make sure anyone using this template can tell it is obsolete
  408. pTemplate->Zombify();
  409. // Flush the engine for this template from the script engine cache
  410. // (use hash key, in case template was previously a zombie.)
  411. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  412. ZapTemplate(pTemplate);
  413. }
  414. // Delete templates from the cache until there are no more
  415. while (!pTable->FPersistTemplatesIsEmpty()) {
  416. CTemplate *pTemplate = static_cast<CTemplate *>(pTable->PersistTemplatesEnd());
  417. // Remove the template from its various data structures
  418. pTable->RemoveTemplate(pTemplate);
  419. // Make sure anyone using this template can tell it is obsolete
  420. pTemplate->Zombify();
  421. // Flush the engine for this template from the script engine cache
  422. // (use hash key, in case template was previously a zombie.)
  423. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  424. ZapTemplate(pTemplate);
  425. }
  426. }
  427. /*===================================================================
  428. CTemplateCacheManager::FlushFiles
  429. Empties template cache of files that match a prefix
  430. Parameters:
  431. None
  432. Returns:
  433. None
  434. ===================================================================*/
  435. void CTemplateCacheManager::FlushFiles(const TCHAR *szFilePrefix)
  436. {
  437. LockTemplateAndIncFileCaches();
  438. BOOL fDoingMemoryTemplates = TRUE;
  439. // Delete templates from the cache until there are no more
  440. CDblLink *pLink = m_pHashTemplates->MemoryTemplatesBegin();
  441. while (! (fDoingMemoryTemplates
  442. ? m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink)
  443. : m_pHashTemplates->FPersistTemplatesDblLinkAtEnd(pLink))) {
  444. CDblLink *pNextLink = pLink->PNext();
  445. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  446. if (_tcsncmp(pTemplate->ExtractHashKey()->szPathTranslated, szFilePrefix, _tcslen(szFilePrefix)) == 0) {
  447. #if UNICODE
  448. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %S\n", pTemplate->ExtractHashKey()->szPathTranslated));
  449. #else
  450. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %s\n", pTemplate->ExtractHashKey()->szPathTranslated));
  451. #endif
  452. // Remove the template from its various data structures
  453. m_pHashTemplates->RemoveTemplate(pTemplate);
  454. // Make sure anyone using this template can tell it is obsolete
  455. pTemplate->Zombify();
  456. // Flush the engine for this template from the script engine cache
  457. // (use hash key, in case template was previously a zombie.)
  458. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  459. ZapTemplate(pTemplate);
  460. #ifndef PERF_DISABLE
  461. g_PerfData.Incr_TEMPLFLUSHES();
  462. #endif
  463. }
  464. pLink = pNextLink;
  465. if (fDoingMemoryTemplates && m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink)) {
  466. fDoingMemoryTemplates = FALSE;
  467. pLink = m_pHashTemplates->PersistTemplatesBegin();
  468. }
  469. }
  470. UnLockTemplateAndIncFileCaches();
  471. }
  472. /*===================================================================
  473. CTemplateCacheManager::AddApplicationToDebuggerUI
  474. Loop through the template cache, and create doc nodes for
  475. all templates that belong to the application
  476. Parameters:
  477. pAppln - pointer to application to attach to.
  478. Returns: N/A
  479. ===================================================================*/
  480. void CTemplateCacheManager::AddApplicationToDebuggerUI(CAppln *pAppln)
  481. {
  482. CDblLink *pLink;
  483. for (pLink = m_pHashTemplates->MemoryTemplatesBegin(); !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink); pLink = pLink->PNext())
  484. {
  485. // Bug 92070:
  486. // Determine if the template is a member of pAppln by comparing
  487. // the virtual path of the template to the application's virtual
  488. // path (previously compared physical paths) Since a template
  489. // can have multiple virtual paths, only the first instance wins.
  490. // Thus the template will only appear in the application that first
  491. // loaded it.
  492. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  493. if (_tcscmp(pAppln->GetApplnPath(SOURCEPATHTYPE_VIRTUAL), pTemplate->GetApplnPath(SOURCEPATHTYPE_VIRTUAL)) == 0)
  494. pTemplate->AttachTo(pAppln);
  495. }
  496. }
  497. /*===================================================================
  498. CTemplateCacheManager::RemoveApplicationFromDebuggerUI
  499. Loop through the template cache, and remove doc nodes for
  500. all templates that belong to the application
  501. Parameters:
  502. pAppln - pointer to application to detach from
  503. if pAppln is NULL, detach from ALL applications
  504. Returns: N/A
  505. ===================================================================*/
  506. void CTemplateCacheManager::RemoveApplicationFromDebuggerUI(CAppln *pAppln)
  507. {
  508. CDblLink *pLink;
  509. for (pLink = m_pHashTemplates->MemoryTemplatesBegin();
  510. !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink);
  511. pLink = pLink->PNext())
  512. {
  513. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  514. if (pAppln != NULL)
  515. pTemplate->DetachFrom(pAppln);
  516. else
  517. pTemplate->Detach();
  518. }
  519. }
  520. /*===================================================================
  521. void CTemplateCacheManager::RegisterTemplateForChangeNotification
  522. Request to watch template directories for file changes
  523. Parameters:
  524. A pointer to the template
  525. Returns:
  526. BOOL True if successfully registered for change notification
  527. ===================================================================*/
  528. BOOL CTemplateCacheManager::RegisterTemplateForChangeNotification(CTemplate *pTemplate, CAppln *pApplication)
  529. {
  530. STACK_BUFFER( tempPath, MAX_PATH );
  531. // Doesnt happen on Win95
  532. if (!FIsWinNT()) {
  533. return FALSE;
  534. }
  535. for (DWORD i = 0; i < pTemplate->m_cFilemaps; i++) {
  536. // Check if this directory is already registered for change notification
  537. // Pick out the directory portion of the path
  538. TCHAR *szEndOfPath = _tcsrchr(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, _T('\\'));
  539. size_t cch = DIFF(szEndOfPath - pTemplate->m_rgpFilemaps[i]->m_szPathTranslated)+1;
  540. if (tempPath.Resize((cch * sizeof(TCHAR)) + sizeof(TCHAR)) == FALSE) {
  541. // if failure to resize, continue registering...
  542. continue;
  543. }
  544. TCHAR *szPath = (TCHAR *) tempPath.QueryPtr();
  545. _tcsncpy(szPath, pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, cch);
  546. szPath[cch] = 0;
  547. // if the template is within the application's physical path, then it is
  548. // already being monitored.
  549. CASPDirMonitorEntry *pDME = NULL;
  550. if (pDME = pApplication->FPathMonitored(szPath)) {
  551. pDME->AddRef();
  552. pTemplate->m_rgpFilemaps[i]->m_pDME= pDME;
  553. continue;
  554. }
  555. if (RegisterASPDirMonitorEntry(szPath, &pDME)) {
  556. Assert(pDME);
  557. pTemplate->m_rgpFilemaps[i]->m_pDME= pDME;
  558. }
  559. else {
  560. // the current file failed to register. Release all previous DMEs
  561. // and return FALSE...
  562. if (i > 0) {
  563. while (--i) {
  564. pTemplate->m_rgpFilemaps[i]->m_pDME->Release();
  565. pTemplate->m_rgpFilemaps[i]->m_pDME = NULL;
  566. }
  567. }
  568. return FALSE;
  569. }
  570. }
  571. return TRUE;
  572. }
  573. /*===================================================================
  574. void CTemplateCacheManager::RegisterApplicationForChangeNotification
  575. Request to watch template directories for file changes
  576. Parameters:
  577. A pointer to the template
  578. Returns:
  579. BOOL True if successfully registered for change notification
  580. ===================================================================*/
  581. BOOL CTemplateCacheManager::RegisterApplicationForChangeNotification(CTemplate *pTemplate, CAppln *pApplication)
  582. {
  583. STACK_BUFFER( tempPath, MAX_PATH );
  584. // Doesnt happen on Win95
  585. if (!FIsWinNT())
  586. {
  587. return FALSE;
  588. }
  589. // Start with 1 to skip GLOBAL.ASA that is always added
  590. // in hitobj.cpp when new application gets created
  591. for (DWORD i = 1; i < pTemplate->m_cFilemaps; i++)
  592. {
  593. // Add to list of file-application mappings
  594. g_FileAppMap.AddFileApplication(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, pApplication);
  595. // Check if this directory is already registered for change notification
  596. // Pick out the directory portion of the path
  597. TCHAR *szEndOfPath = _tcsrchr(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, _T('\\'));
  598. size_t cch = DIFF(szEndOfPath - pTemplate->m_rgpFilemaps[i]->m_szPathTranslated) + 1;
  599. if (tempPath.Resize((cch*sizeof(TCHAR)) + sizeof(TCHAR)) == FALSE) {
  600. // if failure, continue registering anyway...
  601. continue;
  602. }
  603. TCHAR *szPath = (TCHAR *) tempPath.QueryPtr();
  604. _tcsncpy(szPath, pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, cch);
  605. szPath[cch] = 0;
  606. // if the template is within the application's physical path, then it is
  607. // already being monitored.
  608. if (pApplication->FPathMonitored(szPath)) {
  609. continue;
  610. }
  611. // Register directory for monitoring
  612. CASPDirMonitorEntry *pDME = NULL;
  613. if (RegisterASPDirMonitorEntry(szPath, &pDME))
  614. {
  615. Assert(pDME);
  616. pApplication->AddDirMonitorEntry(pDME);
  617. }
  618. }
  619. return TRUE;
  620. }
  621. /*===================================================================
  622. BOOL CTemplateCacheManager::ShutdownCacheChangeNotification
  623. Turn off change notification for changes to files in the cache
  624. Parameters:
  625. None
  626. Returns:
  627. Nothing
  628. ===================================================================*/
  629. BOOL CTemplateCacheManager::ShutdownCacheChangeNotification()
  630. {
  631. BOOL fDoingMemoryTemplates = TRUE;
  632. // Doesnt happen on Win95
  633. if (!FIsWinNT())
  634. {
  635. return FALSE;
  636. }
  637. LockTemplateCache();
  638. CTemplate *pTemplate = static_cast<CTemplate *>(m_pHashTemplates->MemoryTemplatesBegin());
  639. while (fDoingMemoryTemplates
  640. ? !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pTemplate)
  641. : !m_pHashTemplates->FPersistTemplatesDblLinkAtEnd(pTemplate)) {
  642. if(pTemplate->m_rgpFilemaps)
  643. {
  644. for(UINT i = 0; i < pTemplate->m_cFilemaps; i++)
  645. {
  646. // Give up our ref count on the directory monitor entry
  647. if (pTemplate->m_rgpFilemaps[i]->m_pDME)
  648. {
  649. pTemplate->m_rgpFilemaps[i]->m_pDME->Release();
  650. pTemplate->m_rgpFilemaps[i]->m_pDME = NULL;
  651. }
  652. }
  653. }
  654. pTemplate = static_cast<CTemplate *>(pTemplate->PNext());
  655. if (fDoingMemoryTemplates && m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pTemplate)) {
  656. fDoingMemoryTemplates = FALSE;
  657. pTemplate = static_cast<CTemplate *>(m_pHashTemplates->PersistTemplatesBegin());
  658. }
  659. }
  660. UnLockTemplateCache();
  661. return TRUE;
  662. }
  663. /* ****************************************************************************
  664. CIncFileMap member functions
  665. */
  666. /*===================================================================
  667. CIncFileMap::CIncFileMap
  668. Parameters: N/A
  669. Returns: N/A
  670. ===================================================================*/
  671. CIncFileMap::CIncFileMap()
  672. {
  673. }
  674. /*===================================================================
  675. CIncFileMap::~CIncFileMap
  676. Parameters: N/A
  677. Returns: N/A
  678. ===================================================================*/
  679. CIncFileMap::~CIncFileMap()
  680. {
  681. }
  682. /*===================================================================
  683. CIncFileMap::Init
  684. Parameters: None
  685. Returns: Completion Status
  686. ===================================================================*/
  687. HRESULT CIncFileMap::Init()
  688. {
  689. HRESULT hr;
  690. ErrInitCriticalSection(&m_csUpdate, hr);
  691. if (FAILED(hr))
  692. return(hr);
  693. return m_mpszIncFile.Init(CINCFILEBUCKETS);
  694. }
  695. /*===================================================================
  696. CIncFileMap::GetIncFile
  697. Get an inc-file from the cache, first storing it into cache if it is not yet there.
  698. Parameters:
  699. szIncFile - file name
  700. ppIncFile - ptr-to-ptr to inc-file (out-parameter)
  701. Returns: HRESULT
  702. ===================================================================*/
  703. HRESULT CIncFileMap::GetIncFile(const TCHAR *szFile, CIncFile **ppIncFile)
  704. {
  705. HRESULT hrInit = S_OK; // return value
  706. LockIncFileCache();
  707. Assert(IsNormalized(szFile));
  708. *ppIncFile = static_cast<CIncFile *>(m_mpszIncFile.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR)));
  709. // if we have a cached inc-file at this stage, it must be "reliable," so we use it.
  710. // else, if we have no cached inc-file, create a new one.
  711. if (*ppIncFile == NULL)
  712. {
  713. if ((*ppIncFile = new CIncFile) == NULL)
  714. {
  715. UnLockIncFileCache();
  716. return E_OUTOFMEMORY;
  717. }
  718. if (SUCCEEDED(hrInit = (*ppIncFile)->Init(szFile)))
  719. {
  720. // The hash table will hold a reference to the inc file
  721. (*ppIncFile)->AddRef();
  722. m_mpszIncFile.AddElem(*ppIncFile);
  723. }
  724. else
  725. *ppIncFile = NULL;
  726. }
  727. if (SUCCEEDED(hrInit))
  728. {
  729. // The caller will hold a reference to the inc file
  730. (*ppIncFile)->AddRef();
  731. }
  732. UnLockIncFileCache();
  733. return hrInit;
  734. }
  735. /*===================================================================
  736. CIncFileMap::UnInit
  737. Parameters: N/A
  738. Returns: Completion status
  739. ===================================================================*/
  740. HRESULT CIncFileMap::UnInit()
  741. {
  742. CIncFile *pNukeIncFile = static_cast<CIncFile *>(m_mpszIncFile.Head());
  743. while (pNukeIncFile != NULL)
  744. {
  745. CIncFile *pNext = static_cast<CIncFile *>(pNukeIncFile->m_pNext);
  746. pNukeIncFile->OnIncFileDecache();
  747. pNukeIncFile->Release();
  748. pNukeIncFile = pNext;
  749. }
  750. DeleteCriticalSection(&m_csUpdate);
  751. return m_mpszIncFile.UnInit();
  752. }
  753. /*===================================================================
  754. CIncFileMap::Flush
  755. Parameters:
  756. szFile - the file to remove from cache
  757. Returns:
  758. None
  759. ===================================================================*/
  760. void CIncFileMap::Flush(const TCHAR *szFile)
  761. {
  762. LockTemplateAndIncFileCaches();
  763. Assert(IsNormalized(szFile));
  764. CIncFile *pIncFile = static_cast<CIncFile *>(m_mpszIncFile.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR)));
  765. if (pIncFile != NULL)
  766. {
  767. if (pIncFile->FlushTemplates())
  768. {
  769. // Remove from hash table
  770. m_mpszIncFile.DeleteElem(szFile, _tcslen(szFile)*sizeof(TCHAR));
  771. // The hash table gave up its reference
  772. // to the incfile
  773. pIncFile->OnIncFileDecache();
  774. pIncFile->Release();
  775. }
  776. }
  777. UnLockTemplateAndIncFileCaches();
  778. }
  779. /*===================================================================
  780. CIncFileMap::FlushFiles
  781. Parameters:
  782. szFile - the file prefix to search for in cache
  783. Returns:
  784. None
  785. ===================================================================*/
  786. void CIncFileMap::FlushFiles(const TCHAR *szFilePrefix)
  787. {
  788. LockTemplateAndIncFileCaches();
  789. Assert(IsNormalized(szFilePrefix));
  790. CIncFile *pIncFile = static_cast<CIncFile *>(m_mpszIncFile.Head());
  791. while (pIncFile != NULL)
  792. {
  793. CIncFile *pNextFile = static_cast<CIncFile *>(pIncFile->m_pNext);
  794. int cchFilePrefix = _tcslen(szFilePrefix);
  795. if (pIncFile->m_cbKey >= (cchFilePrefix*(int)sizeof(TCHAR)) &&
  796. _tcsncmp(reinterpret_cast<TCHAR *>(pIncFile->m_pKey), szFilePrefix, cchFilePrefix) == 0)
  797. {
  798. #if UNICODE
  799. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %S\n", pIncFile->m_pKey));
  800. #else
  801. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %s\n", pIncFile->m_pKey));
  802. #endif
  803. if (pIncFile->FlushTemplates())
  804. {
  805. // Remove from hash table
  806. m_mpszIncFile.DeleteElem(pIncFile->m_pKey, pIncFile->m_cbKey);
  807. // The hash table gave up its reference
  808. // to the incfile
  809. pIncFile->OnIncFileDecache();
  810. pIncFile->Release();
  811. }
  812. }
  813. pIncFile = pNextFile;
  814. }
  815. UnLockTemplateAndIncFileCaches();
  816. }
  817. /* ****************************************************************************
  818. Non-class support functions
  819. */
  820. /*===================================================================
  821. FFileChangedSinceCached
  822. Has the file changed since it was cached?
  823. Parameters:
  824. szFile - file name
  825. ftPrevWriteTime - the file's "previous write time"
  826. (its last-write-time value when the file was cached)
  827. Returns:
  828. TRUE or FALSE
  829. ===================================================================*/
  830. BOOL FFileChangedSinceCached(const TCHAR *szFile, FILETIME& ftPrevWriteTime)
  831. {
  832. WIN32_FILE_ATTRIBUTE_DATA fad; // win32 file attributes data structure
  833. BOOL fRet = FALSE; // return value
  834. // This fn doesnt exist on Win95. On Win95 we do no caching anyway, so we dont care.
  835. if (!FIsWinNT())
  836. return(TRUE);
  837. if (FAILED(AspGetFileAttributes(szFile, &fad)))
  838. {
  839. // assume file was changed if get file attributes failed
  840. fRet = TRUE;
  841. }
  842. if( 0 != CompareFileTime( &ftPrevWriteTime, &(fad.ftLastWriteTime) ) )
  843. {
  844. // file was changed if file times differ
  845. fRet = TRUE;
  846. }
  847. return fRet;
  848. }
  849. /*===================================================================
  850. CTemplateCacheManager::CTemplateHashTable::TrimPersistCache
  851. Parameters:
  852. dwTrimCount - the number of templates to trim from the cache
  853. Returns:
  854. TRUE - if dwTrimCount was actually trimmed
  855. FALSE - if exited before dwTrimCount was met
  856. ===================================================================*/
  857. BOOL CTemplateCacheManager::CTemplateHashTable::TrimPersistCache(DWORD dwTrimCount)
  858. {
  859. // enter a while loop to trim until the count is reached
  860. while(dwTrimCount--) {
  861. // if there isn't anything else to trim, we're done. Return FALSE
  862. // to indicate that dwTrimCount was not met.
  863. if (m_dwPersistedTemplates == 0) {
  864. return(FALSE);
  865. }
  866. else {
  867. CTemplate *pTemplate;
  868. // get the oldest template from the list
  869. pTemplate = static_cast<CTemplate *>(PersistTemplatesEnd());
  870. // remove the template.
  871. RemoveTemplate(pTemplate);
  872. ZapTemplate(pTemplate);
  873. }
  874. }
  875. // return TRUE to indicate that the TrimCount was met.
  876. return(TRUE);
  877. }
  878. /*===================================================================
  879. CTemplateCacheManager::CTemplateHashTable::ScavengePersistCache
  880. Parameters:
  881. <NONE>
  882. Returns:
  883. VOID
  884. ===================================================================*/
  885. VOID CTemplateCacheManager::CTemplateHashTable::ScavengePersistCache()
  886. {
  887. CTemplate *pTemplate;
  888. CTemplate *pTemplateNext;
  889. // enter a for loop to look at all persisted templates to see if
  890. // any memory can be freed. It's memory can be freed only if the
  891. // ref count is 1 (the sole ref count is for the cache). Also note
  892. // that the list is re-ordered to move templates to the head of the
  893. // list that can't have their memory freed at this time because of
  894. // the ref count.
  895. for (pTemplate = static_cast<CTemplate *>(PersistTemplatesBegin());
  896. (pTemplate != static_cast<CTemplate *>(&m_listPersistTemplates)) && (pTemplate->m_pbStart != NULL);
  897. pTemplate = pTemplateNext) {
  898. pTemplateNext = static_cast<CTemplate *>(pTemplate->PNext());
  899. // this check should be safe. The only risk is that we miss a release
  900. // of the template from 2 to 1, in which case will miss it this time
  901. // but get it the next time through. AddRef from 1 to 2 is impossible
  902. // to interrupt because it couldn't be on this list when it gets AddRef'd
  903. // from 1 to 2 and moving it from this list is protected by the template
  904. // cache lock which we should be under.
  905. if (pTemplate->m_cRefs == 1) {
  906. // remove the memory
  907. CTemplate::LargeFree(pTemplate->m_pbStart);
  908. pTemplate->m_pbStart = NULL;
  909. }
  910. else {
  911. // if some is still using it, move the template to the head of the
  912. // list so that we'll check again later.
  913. pTemplate->PrependTo(m_listPersistTemplates);
  914. }
  915. }
  916. }
  917. /*===================================================================
  918. GetAggregatedTemplCounter()
  919. Returns the Template Perf Counter. To do this, initializes a private
  920. copy of the perfmainblock and aggregates the stats into it.
  921. ===================================================================*/
  922. static DWORD GetAggregatedTemplCounter()
  923. {
  924. CPerfMainBlock perfSharedBlk;
  925. DWORD pdwCounters[C_PERF_PROC_COUNTERS];
  926. BOOL bInited = FALSE;
  927. memset(pdwCounters, 0, sizeof(pdwCounters));
  928. if (!(bInited = (perfSharedBlk.Init() == S_OK)));
  929. else {
  930. perfSharedBlk.GetStats(pdwCounters);
  931. }
  932. if (bInited)
  933. perfSharedBlk.UnInit();
  934. return(pdwCounters[ID_TEMPLCACHE]);
  935. }
  936. /*===================================================================
  937. CTemplateCacheManager::InitPersistCache
  938. Parameters:
  939. [none]
  940. Returns:
  941. BOOL to indicate if the init was successful
  942. ===================================================================*/
  943. BOOL CTemplateCacheManager::InitPersistCache()
  944. {
  945. HANDLE hImpersonationToken = NULL;
  946. BOOL fRevertedToSelf = FALSE;
  947. HANDLE hThread;
  948. hThread = GetCurrentThread();
  949. if (OpenThreadToken( hThread,
  950. TOKEN_READ | TOKEN_IMPERSONATE,
  951. TRUE,
  952. &hImpersonationToken )) {
  953. RevertToSelf();
  954. fRevertedToSelf = TRUE;
  955. }
  956. // get the PersistCacheDir from the globals table
  957. strcpy(m_szPersistCacheDir,Glob(pszPersistTemplateDir));
  958. // Check to see if the directory exists...
  959. DWORD dirAttribs = GetFileAttributesA(m_szPersistCacheDir);
  960. if ((dirAttribs == 0xffffffff)
  961. || !(dirAttribs & FILE_ATTRIBUTE_DIRECTORY)) {
  962. MSG_Error(IDS_CACHE_DIR_MISSING);
  963. m_fFailedToInitPersistCache = TRUE;
  964. }
  965. else {
  966. // append the trailing slash to the directory name
  967. strcat(m_szPersistCacheDir,"\\");
  968. // next, cleanup the temp directory.
  969. // since asp.dll can execute in many process simultaneously, we'll
  970. // check the perf counter to see if there are any templates
  971. // cached anywhere on the system.
  972. if (GetAggregatedTemplCounter() == 0) {
  973. CHAR DirectoryWildcard[MAX_PATH];
  974. WIN32_FIND_DATAA win32FindData;
  975. strcpy(DirectoryWildcard, m_szPersistCacheDir);
  976. strcat(DirectoryWildcard, "ASP*.TMP");
  977. // use FindFirstFile to begin the enumeration of all files in the
  978. // temp directory.
  979. HANDLE hDirectory = FindFirstFileA( DirectoryWildcard, &win32FindData );
  980. if ( hDirectory != INVALID_HANDLE_VALUE ) {
  981. BOOL success = TRUE;
  982. while ( success ) {
  983. char fileName[MAX_PATH];
  984. // FindFirst/FindNext returns just the filename. Build up
  985. // the entire path and then call DeleteFile. We'll ignore
  986. // errors as there isn't much we could do with the error
  987. // except fail the cache init.
  988. strcpy( fileName, m_szPersistCacheDir );
  989. strcat( fileName, win32FindData.cFileName );
  990. DeleteFileA( fileName );
  991. success = FindNextFileA( hDirectory, &win32FindData );
  992. }
  993. FindClose( hDirectory );
  994. }
  995. else {
  996. GetLastError();
  997. }
  998. }
  999. }
  1000. if (fRevertedToSelf) {
  1001. SetThreadToken(&hThread, hImpersonationToken);
  1002. }
  1003. return(!m_fFailedToInitPersistCache);
  1004. }
  1005. /*===================================================================
  1006. CTemplateCacheManager::CTemplateHashTable::CanPersistTemplate
  1007. Parameters:
  1008. pTemplate - The template to test for persistability
  1009. Returns:
  1010. BOOL to indicate if template can be persisted.
  1011. ===================================================================*/
  1012. BOOL CTemplateCacheManager::CTemplateHashTable::CanPersistTemplate(CTemplate *pTemplate)
  1013. {
  1014. // if MaxFiles is zero, then the persist cache is disabled
  1015. if (Glob(dwPersistTemplateMaxFiles) == 0) {
  1016. return(FALSE);
  1017. }
  1018. // can't persist if the persist cache failed to init
  1019. if (m_fFailedToInitPersistCache == TRUE) {
  1020. return(FALSE);
  1021. }
  1022. // can't persist templates that are marked as debuggable. The
  1023. // script engines need access to the memory.
  1024. if (pTemplate->FDebuggable()) {
  1025. return(FALSE);
  1026. }
  1027. // at this point, we're going to return true. The next part of the code
  1028. // trims the cache as necessary.
  1029. if (m_dwPersistedTemplates >= Glob(dwPersistTemplateMaxFiles)) {
  1030. TrimPersistCache(m_dwPersistedTemplates - Glob(dwPersistTemplateMaxFiles) + 1);
  1031. }
  1032. return(TRUE);
  1033. }
  1034. /*===================================================================
  1035. CTemplateCacheManager::CTemplateHashTable::InsertTemplate
  1036. Parameters:
  1037. pTemplate - Template to insert into the memory cache
  1038. Returns:
  1039. LK_RETCODE indicating the success of the insertion
  1040. ===================================================================*/
  1041. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::InsertTemplate(CTemplate *pTemplate)
  1042. {
  1043. LK_RETCODE rcode = InsertRecord(pTemplate, true);
  1044. if (rcode == LK_SUCCESS) {
  1045. #ifndef PERF_DISABLE
  1046. g_PerfData.Incr_MEMORYTEMPLCACHE();
  1047. g_PerfData.Incr_TEMPLCACHE();
  1048. #endif
  1049. m_dwInMemoryTemplates++;
  1050. pTemplate->PrependTo(m_listMemoryTemplates);
  1051. pTemplate->SetHashTablePtr(this);
  1052. }
  1053. ScavengePersistCache();
  1054. return rcode;
  1055. }
  1056. /*===================================================================
  1057. CTemplateCacheManager::CTemplateHashTable::RemoveTemplate
  1058. Parameters:
  1059. pTemplate - Template to remove from cache
  1060. fPersist - indicate if memory template is a candidate for persist
  1061. Returns:
  1062. LK_RETCODE indicating the success of the removal
  1063. ===================================================================*/
  1064. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::RemoveTemplate(CTemplate *pTemplate, BOOL fPersist)
  1065. {
  1066. LK_RETCODE rcode = LK_SUCCESS;
  1067. #if DBG_PERSTEMPL
  1068. DBGPRINTF((DBG_CONTEXT,
  1069. "RemoveTemplate entered.\n\tTemplate = %s.\n\tfPersist = %d.\n\tFIsPersisted = %d\n",
  1070. pTemplate->GetSourceFileName(),
  1071. fPersist,
  1072. pTemplate->FIsPersisted()));
  1073. #endif
  1074. // if the template isn't in the cache, or if the template isn't on this
  1075. // particular hash table, then just bail. Nothing to
  1076. // do here. It may not be on this particular hash table because the entire
  1077. // table may have been torn off the global cache manager and scheduled for
  1078. // cleanup on the flush thread. In this case, we're checking the wrong
  1079. // table. The flush thread will eventually clean this one up.
  1080. if (pTemplate->FIsEmpty() || (pTemplate->GetHashTablePtr() != this)) {
  1081. return LK_NO_SUCH_KEY;
  1082. }
  1083. // no matter what, this template is going to be unlinked from it's
  1084. // current CDblLink
  1085. pTemplate->UnLink();
  1086. // update the appropriate counter
  1087. if (pTemplate->FIsPersisted() == FALSE) {
  1088. // decrement the number of InMemoryTemplates...
  1089. #ifndef PERF_DISABLE
  1090. g_PerfData.Decr_MEMORYTEMPLCACHE();
  1091. #endif
  1092. m_dwInMemoryTemplates--;
  1093. }
  1094. else {
  1095. m_dwPersistedTemplates--;
  1096. }
  1097. // if asked to be persisted, see if it's a candidate to be persisted.
  1098. if (fPersist && CanPersistTemplate(pTemplate)) {
  1099. // so persist it.
  1100. if (pTemplate->PersistData(m_szPersistCacheDir) != S_OK) {
  1101. // a failure will result in the record being deleted.
  1102. #ifndef PERF_DISABLE
  1103. g_PerfData.Decr_TEMPLCACHE();
  1104. #endif
  1105. rcode = DeleteRecord(pTemplate);
  1106. }
  1107. else {
  1108. // if successfully persisted, then add to the list of
  1109. // persisted templates
  1110. pTemplate->PrependTo(m_listPersistTemplates);
  1111. m_dwPersistedTemplates++;
  1112. }
  1113. }
  1114. else {
  1115. #ifndef PERF_DISABLE
  1116. g_PerfData.Decr_TEMPLCACHE();
  1117. #endif
  1118. // if not asked to persist, then delete the record.
  1119. rcode = DeleteRecord(pTemplate);
  1120. }
  1121. ScavengePersistCache();
  1122. return rcode;
  1123. }
  1124. /*===================================================================
  1125. CTemplateCacheManager::CTemplateHashTable::FindTemplate
  1126. Parameters:
  1127. rTemplate - the key for the template being looked up
  1128. Returns:
  1129. LK_RETCODE indicating the success of the look up
  1130. ===================================================================*/
  1131. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::FindTemplate(const CTemplateKey &rTemplateKey, CTemplate **ppTemplate)
  1132. {
  1133. #if DBG_PERSTEMPL
  1134. DBGPRINTF((DBG_CONTEXT,
  1135. "FindTemplate entered\n\tLooking for %s\n",
  1136. rTemplateKey.szPathTranslated));
  1137. #endif
  1138. #ifndef PERF_DISABLE
  1139. g_PerfData.Incr_MEMORYTEMPLCACHETRYS();
  1140. g_PerfData.Incr_TEMPLCACHETRYS();
  1141. #endif
  1142. LK_RETCODE rcode = FindKey(&rTemplateKey, ppTemplate);
  1143. // see if we found it.
  1144. if (rcode == LK_SUCCESS) {
  1145. #if DBG_PERSTEMPL
  1146. DBGPRINTF((DBG_CONTEXT,
  1147. "Template found\n\tfPersisted = %d\n",
  1148. (*ppTemplate)->FIsPersisted()));
  1149. #endif
  1150. #ifndef PERF_DISABLE
  1151. g_PerfData.Incr_TEMPLCACHEHITS();
  1152. #endif
  1153. // found it. Is it persisted?
  1154. if ((*ppTemplate)->FIsPersisted()) {
  1155. // It is persisted. Unlink it from the persisted list.
  1156. (*ppTemplate)->UnLink();
  1157. m_dwPersistedTemplates--;
  1158. // unpersist it
  1159. if ((*ppTemplate)->UnPersistData() != S_OK) {
  1160. // error occurred
  1161. // get the template out of the cache
  1162. DeleteRecord(*ppTemplate);
  1163. // release the reference that the cache had on the template
  1164. (*ppTemplate)->Release();
  1165. // NULL out *ppTemplate so that the caller doesn't think they
  1166. // got a valid template
  1167. *ppTemplate = NULL;
  1168. #ifndef PERF_DISABLE
  1169. g_PerfData.Decr_TEMPLCACHE();
  1170. #endif
  1171. // return NO_SUCH_KEY so that a new template will be built
  1172. return(LK_NO_SUCH_KEY);
  1173. }
  1174. // bump the number of in memory templates
  1175. #ifndef PERF_DISABLE
  1176. g_PerfData.Incr_MEMORYTEMPLCACHE();
  1177. #endif
  1178. m_dwInMemoryTemplates++;
  1179. }
  1180. else {
  1181. #ifndef PERF_DISABLE
  1182. g_PerfData.Incr_MEMORYTEMPLCACHEHITS();
  1183. #endif
  1184. }
  1185. // add it to, or move it to the top of, the memory templates
  1186. (*ppTemplate)->PrependTo(m_listMemoryTemplates);
  1187. }
  1188. ScavengePersistCache();
  1189. return rcode;
  1190. }