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.

1664 lines
48 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. // also create the services config object
  286. hr = (*ppTemplate)->CreateTransServiceConfig(pHitObj->PAppln()->QueryAppConfig()->fTrackerEnabled());
  287. }
  288. // If running on NT, this is a new application, and the template is a global.asa
  289. // register this application for file change notifications
  290. if (FIsWinNT() && SUCCEEDED(hr) && (*ppTemplate)->m_fGlobalAsa && pHitObj->FStartApplication())
  291. {
  292. RegisterApplicationForChangeNotification(*ppTemplate, pHitObj->PAppln());
  293. }
  294. }
  295. return hr;
  296. }
  297. /*===================================================================
  298. CTemplateCacheManager::Flush
  299. Parameters:
  300. szFile - the file to remove from cache
  301. Returns:
  302. None
  303. ===================================================================*/
  304. void CTemplateCacheManager::Flush(const TCHAR *szFile, DWORD dwInstanceID)
  305. {
  306. LockTemplateAndIncFileCaches();
  307. Assert (IsNormalized(szFile));
  308. CTemplate *pTemplate;
  309. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), &pTemplate);
  310. while (pTemplate != NULL)
  311. {
  312. #ifndef PERF_DISABLE
  313. g_PerfData.Incr_TEMPLFLUSHES();
  314. #endif
  315. m_pHashTemplates->RemoveTemplate(pTemplate);
  316. // Make sure anyone using this template can tell it is obsolete
  317. pTemplate->Zombify();
  318. // Don't flush engines if this is a global.asa file
  319. // We'll need the engines to run Application_OnEnd
  320. // The application will flush the engine from the cache
  321. // when it unints
  322. if (!FIsGlobalAsa(szFile))
  323. {
  324. g_ScriptManager.FlushCache(szFile);
  325. }
  326. ZapTemplate(pTemplate);
  327. // If wildcard was specified in Flush for Instance ID, there may be
  328. // more templates to remove.
  329. m_pHashTemplates->FindTemplate(CTemplateKey(szFile, dwInstanceID), &pTemplate);
  330. }
  331. UnLockTemplateAndIncFileCaches();
  332. }
  333. /*===================================================================
  334. CTemplateCacheManager::FlushAll
  335. Completely empties the template cache
  336. Parameters:
  337. None
  338. Returns:
  339. None
  340. ===================================================================*/
  341. void CTemplateCacheManager::FlushAll(VOID)
  342. {
  343. LockTemplateAndIncFileCaches();
  344. CTemplateHashTable *pNewTable = NULL;
  345. HANDLE hnd;
  346. // note that all of the following logic works on the premise that any
  347. // error causes the code to fall into the old mechanism of flushing
  348. // the hash table in place...
  349. // allocate a new table
  350. if (!(pNewTable = new CTemplateHashTable));
  351. // Create a thread to clean up the old table
  352. else if (!(hnd = CreateThread(NULL, 0, CTemplateCacheManager::FlushHashTableThread, m_pHashTemplates, 0, NULL)));
  353. else {
  354. // all the above was successful, so note that the new table is the
  355. // current table in the cache, cleanup and exit.
  356. DBGPRINTF((DBG_CONTEXT, "[CTemplateCacheManager] Flushing entire cache on another thread.\n"));
  357. InterlockedIncrement(&g_nFlushThreads);
  358. m_pHashTemplates = pNewTable;
  359. CloseHandle(hnd);
  360. UnLockTemplateAndIncFileCaches();
  361. return;
  362. }
  363. // delete the new table if something above failed.
  364. if (pNewTable)
  365. delete pNewTable;
  366. DBGPRINTF((DBG_CONTEXT, "[CTemplateCacheManager] Flushing entire cache in place\n"));
  367. FlushHashTable(m_pHashTemplates);
  368. UnLockTemplateAndIncFileCaches();
  369. return;
  370. }
  371. /*===================================================================
  372. CTemplateCacheManager::FlushHashTableThread
  373. Thread spun up by CTemplateCacheMgr::FlushAll() to flush all
  374. templates in the cache but not while under the critical section
  375. on the notification thread. Prevents unwanted contention on the
  376. cache.
  377. Parameters:
  378. None
  379. Returns:
  380. None
  381. ===================================================================*/
  382. DWORD CTemplateCacheManager::FlushHashTableThread(VOID *pArg)
  383. {
  384. CTemplateHashTable *pTable = (CTemplateHashTable *)pArg;
  385. Assert(pTable);
  386. FlushHashTable(pTable);
  387. delete pTable;
  388. InterlockedDecrement(&g_nFlushThreads);
  389. return S_OK;
  390. }
  391. /*===================================================================
  392. CTemplateCacheManager::FlushHashTable
  393. Does the actual work of flushing the templates.
  394. This routine may or may not be under the global cache manager
  395. crit sec. It will if the flush is happening on the notification
  396. thread. It won't be if it's happening on the FlushHashTableThread.
  397. Parameters:
  398. None
  399. Returns:
  400. None
  401. ===================================================================*/
  402. void CTemplateCacheManager::FlushHashTable(CTemplateHashTable *pTable)
  403. {
  404. // Delete templates from the cache until there are no more
  405. while (!pTable->FMemoryTemplatesIsEmpty()) {
  406. CTemplate *pTemplate = static_cast<CTemplate *>(pTable->MemoryTemplatesEnd());
  407. // Remove the template from its various data structures
  408. pTable->RemoveTemplate(pTemplate);
  409. // Make sure anyone using this template can tell it is obsolete
  410. pTemplate->Zombify();
  411. // Flush the engine for this template from the script engine cache
  412. // (use hash key, in case template was previously a zombie.)
  413. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  414. ZapTemplate(pTemplate);
  415. }
  416. // Delete templates from the cache until there are no more
  417. while (!pTable->FPersistTemplatesIsEmpty()) {
  418. CTemplate *pTemplate = static_cast<CTemplate *>(pTable->PersistTemplatesEnd());
  419. // Remove the template from its various data structures
  420. pTable->RemoveTemplate(pTemplate);
  421. // Make sure anyone using this template can tell it is obsolete
  422. pTemplate->Zombify();
  423. // Flush the engine for this template from the script engine cache
  424. // (use hash key, in case template was previously a zombie.)
  425. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  426. ZapTemplate(pTemplate);
  427. }
  428. }
  429. /*===================================================================
  430. CTemplateCacheManager::FlushFiles
  431. Empties template cache of files that match a prefix
  432. Parameters:
  433. None
  434. Returns:
  435. None
  436. ===================================================================*/
  437. void CTemplateCacheManager::FlushFiles(const TCHAR *szFilePrefix)
  438. {
  439. LockTemplateAndIncFileCaches();
  440. BOOL fDoingMemoryTemplates = TRUE;
  441. // Delete templates from the cache until there are no more
  442. CDblLink *pLink = m_pHashTemplates->MemoryTemplatesBegin();
  443. while (! (fDoingMemoryTemplates
  444. ? m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink)
  445. : m_pHashTemplates->FPersistTemplatesDblLinkAtEnd(pLink))) {
  446. CDblLink *pNextLink = pLink->PNext();
  447. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  448. if (_tcsncmp(pTemplate->ExtractHashKey()->szPathTranslated, szFilePrefix, _tcslen(szFilePrefix)) == 0) {
  449. #if UNICODE
  450. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %S\n", pTemplate->ExtractHashKey()->szPathTranslated));
  451. #else
  452. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %s\n", pTemplate->ExtractHashKey()->szPathTranslated));
  453. #endif
  454. // Remove the template from its various data structures
  455. m_pHashTemplates->RemoveTemplate(pTemplate);
  456. // Make sure anyone using this template can tell it is obsolete
  457. pTemplate->Zombify();
  458. // Flush the engine for this template from the script engine cache
  459. // (use hash key, in case template was previously a zombie.)
  460. g_ScriptManager.FlushCache(pTemplate->ExtractHashKey()->szPathTranslated);
  461. ZapTemplate(pTemplate);
  462. #ifndef PERF_DISABLE
  463. g_PerfData.Incr_TEMPLFLUSHES();
  464. #endif
  465. }
  466. pLink = pNextLink;
  467. if (fDoingMemoryTemplates && m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink)) {
  468. fDoingMemoryTemplates = FALSE;
  469. pLink = m_pHashTemplates->PersistTemplatesBegin();
  470. }
  471. }
  472. UnLockTemplateAndIncFileCaches();
  473. }
  474. /*===================================================================
  475. CTemplateCacheManager::AddApplicationToDebuggerUI
  476. Loop through the template cache, and create doc nodes for
  477. all templates that belong to the application
  478. Parameters:
  479. pAppln - pointer to application to attach to.
  480. Returns: N/A
  481. ===================================================================*/
  482. void CTemplateCacheManager::AddApplicationToDebuggerUI(CAppln *pAppln)
  483. {
  484. CDblLink *pLink;
  485. for (pLink = m_pHashTemplates->MemoryTemplatesBegin(); !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink); pLink = pLink->PNext())
  486. {
  487. // Bug 92070:
  488. // Determine if the template is a member of pAppln by comparing
  489. // the virtual path of the template to the application's virtual
  490. // path (previously compared physical paths) Since a template
  491. // can have multiple virtual paths, only the first instance wins.
  492. // Thus the template will only appear in the application that first
  493. // loaded it.
  494. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  495. if (_tcscmp(pAppln->GetApplnPath(SOURCEPATHTYPE_VIRTUAL), pTemplate->GetApplnPath(SOURCEPATHTYPE_VIRTUAL)) == 0)
  496. pTemplate->AttachTo(pAppln);
  497. }
  498. }
  499. /*===================================================================
  500. CTemplateCacheManager::RemoveApplicationFromDebuggerUI
  501. Loop through the template cache, and remove doc nodes for
  502. all templates that belong to the application
  503. Parameters:
  504. pAppln - pointer to application to detach from
  505. if pAppln is NULL, detach from ALL applications
  506. Returns: N/A
  507. ===================================================================*/
  508. void CTemplateCacheManager::RemoveApplicationFromDebuggerUI(CAppln *pAppln)
  509. {
  510. CDblLink *pLink;
  511. for (pLink = m_pHashTemplates->MemoryTemplatesBegin();
  512. !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pLink);
  513. pLink = pLink->PNext())
  514. {
  515. CTemplate *pTemplate = static_cast<CTemplate *>(pLink);
  516. if (pAppln != NULL)
  517. pTemplate->DetachFrom(pAppln);
  518. else
  519. pTemplate->Detach();
  520. }
  521. }
  522. /*===================================================================
  523. void CTemplateCacheManager::RegisterTemplateForChangeNotification
  524. Request to watch template directories for file changes
  525. Parameters:
  526. A pointer to the template
  527. Returns:
  528. BOOL True if successfully registered for change notification
  529. ===================================================================*/
  530. BOOL CTemplateCacheManager::RegisterTemplateForChangeNotification(CTemplate *pTemplate, CAppln *pApplication)
  531. {
  532. STACK_BUFFER( tempPath, MAX_PATH );
  533. // Doesnt happen on Win95
  534. if (!FIsWinNT()) {
  535. return FALSE;
  536. }
  537. for (DWORD i = 0; i < pTemplate->m_cFilemaps; i++) {
  538. // Check if this directory is already registered for change notification
  539. // Pick out the directory portion of the path
  540. TCHAR *szEndOfPath = _tcsrchr(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, _T('\\'));
  541. size_t cch = DIFF(szEndOfPath - pTemplate->m_rgpFilemaps[i]->m_szPathTranslated)+1;
  542. if (tempPath.Resize((cch * sizeof(TCHAR)) + sizeof(TCHAR)) == FALSE) {
  543. // if failure to resize, continue registering...
  544. continue;
  545. }
  546. TCHAR *szPath = (TCHAR *) tempPath.QueryPtr();
  547. _tcsncpy(szPath, pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, cch);
  548. szPath[cch] = 0;
  549. // if the template is within the application's physical path, then it is
  550. // already being monitored.
  551. CASPDirMonitorEntry *pDME = NULL;
  552. if (pDME = pApplication->FPathMonitored(szPath)) {
  553. pDME->AddRef();
  554. pTemplate->m_rgpFilemaps[i]->m_pDME= pDME;
  555. continue;
  556. }
  557. if (RegisterASPDirMonitorEntry(szPath, &pDME)) {
  558. Assert(pDME);
  559. pTemplate->m_rgpFilemaps[i]->m_pDME= pDME;
  560. }
  561. else {
  562. // the current file failed to register. Release all previous DMEs
  563. // and return FALSE...
  564. if (i > 0) {
  565. while (--i) {
  566. pTemplate->m_rgpFilemaps[i]->m_pDME->Release();
  567. pTemplate->m_rgpFilemaps[i]->m_pDME = NULL;
  568. }
  569. }
  570. return FALSE;
  571. }
  572. }
  573. return TRUE;
  574. }
  575. /*===================================================================
  576. void CTemplateCacheManager::RegisterApplicationForChangeNotification
  577. Request to watch template directories for file changes
  578. Parameters:
  579. A pointer to the template
  580. Returns:
  581. BOOL True if successfully registered for change notification
  582. ===================================================================*/
  583. BOOL CTemplateCacheManager::RegisterApplicationForChangeNotification(CTemplate *pTemplate, CAppln *pApplication)
  584. {
  585. STACK_BUFFER( tempPath, MAX_PATH );
  586. // Doesnt happen on Win95
  587. if (!FIsWinNT())
  588. {
  589. return FALSE;
  590. }
  591. // Start with 1 to skip GLOBAL.ASA that is always added
  592. // in hitobj.cpp when new application gets created
  593. for (DWORD i = 1; i < pTemplate->m_cFilemaps; i++)
  594. {
  595. // Add to list of file-application mappings
  596. g_FileAppMap.AddFileApplication(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, pApplication);
  597. // Check if this directory is already registered for change notification
  598. // Pick out the directory portion of the path
  599. TCHAR *szEndOfPath = _tcsrchr(pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, _T('\\'));
  600. size_t cch = DIFF(szEndOfPath - pTemplate->m_rgpFilemaps[i]->m_szPathTranslated) + 1;
  601. if (tempPath.Resize((cch*sizeof(TCHAR)) + sizeof(TCHAR)) == FALSE) {
  602. // if failure, continue registering anyway...
  603. continue;
  604. }
  605. TCHAR *szPath = (TCHAR *) tempPath.QueryPtr();
  606. _tcsncpy(szPath, pTemplate->m_rgpFilemaps[i]->m_szPathTranslated, cch);
  607. szPath[cch] = 0;
  608. // if the template is within the application's physical path, then it is
  609. // already being monitored.
  610. if (pApplication->FPathMonitored(szPath)) {
  611. continue;
  612. }
  613. // Register directory for monitoring
  614. CASPDirMonitorEntry *pDME = NULL;
  615. if (RegisterASPDirMonitorEntry(szPath, &pDME))
  616. {
  617. Assert(pDME);
  618. pApplication->AddDirMonitorEntry(pDME);
  619. }
  620. }
  621. return TRUE;
  622. }
  623. /*===================================================================
  624. BOOL CTemplateCacheManager::ShutdownCacheChangeNotification
  625. Turn off change notification for changes to files in the cache
  626. Parameters:
  627. None
  628. Returns:
  629. Nothing
  630. ===================================================================*/
  631. BOOL CTemplateCacheManager::ShutdownCacheChangeNotification()
  632. {
  633. BOOL fDoingMemoryTemplates = TRUE;
  634. // Doesnt happen on Win95
  635. if (!FIsWinNT())
  636. {
  637. return FALSE;
  638. }
  639. LockTemplateCache();
  640. CTemplate *pTemplate = static_cast<CTemplate *>(m_pHashTemplates->MemoryTemplatesBegin());
  641. while (fDoingMemoryTemplates
  642. ? !m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pTemplate)
  643. : !m_pHashTemplates->FPersistTemplatesDblLinkAtEnd(pTemplate)) {
  644. if(pTemplate->m_rgpFilemaps)
  645. {
  646. for(UINT i = 0; i < pTemplate->m_cFilemaps; i++)
  647. {
  648. // Give up our ref count on the directory monitor entry
  649. if (pTemplate->m_rgpFilemaps[i]->m_pDME)
  650. {
  651. pTemplate->m_rgpFilemaps[i]->m_pDME->Release();
  652. pTemplate->m_rgpFilemaps[i]->m_pDME = NULL;
  653. }
  654. }
  655. }
  656. pTemplate = static_cast<CTemplate *>(pTemplate->PNext());
  657. if (fDoingMemoryTemplates && m_pHashTemplates->FMemoryTemplatesDblLinkAtEnd(pTemplate)) {
  658. fDoingMemoryTemplates = FALSE;
  659. pTemplate = static_cast<CTemplate *>(m_pHashTemplates->PersistTemplatesBegin());
  660. }
  661. }
  662. UnLockTemplateCache();
  663. return TRUE;
  664. }
  665. /* ****************************************************************************
  666. CIncFileMap member functions
  667. */
  668. /*===================================================================
  669. CIncFileMap::CIncFileMap
  670. Parameters: N/A
  671. Returns: N/A
  672. ===================================================================*/
  673. CIncFileMap::CIncFileMap()
  674. {
  675. }
  676. /*===================================================================
  677. CIncFileMap::~CIncFileMap
  678. Parameters: N/A
  679. Returns: N/A
  680. ===================================================================*/
  681. CIncFileMap::~CIncFileMap()
  682. {
  683. }
  684. /*===================================================================
  685. CIncFileMap::Init
  686. Parameters: None
  687. Returns: Completion Status
  688. ===================================================================*/
  689. HRESULT CIncFileMap::Init()
  690. {
  691. HRESULT hr;
  692. ErrInitCriticalSection(&m_csUpdate, hr);
  693. if (FAILED(hr))
  694. return(hr);
  695. return m_mpszIncFile.Init(CINCFILEBUCKETS);
  696. }
  697. /*===================================================================
  698. CIncFileMap::GetIncFile
  699. Get an inc-file from the cache, first storing it into cache if it is not yet there.
  700. Parameters:
  701. szIncFile - file name
  702. ppIncFile - ptr-to-ptr to inc-file (out-parameter)
  703. Returns: HRESULT
  704. ===================================================================*/
  705. HRESULT CIncFileMap::GetIncFile(const TCHAR *szFile, CIncFile **ppIncFile)
  706. {
  707. HRESULT hrInit = S_OK; // return value
  708. LockIncFileCache();
  709. Assert(IsNormalized(szFile));
  710. *ppIncFile = static_cast<CIncFile *>(m_mpszIncFile.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR)));
  711. // if we have a cached inc-file at this stage, it must be "reliable," so we use it.
  712. // else, if we have no cached inc-file, create a new one.
  713. if (*ppIncFile == NULL)
  714. {
  715. if ((*ppIncFile = new CIncFile) == NULL)
  716. {
  717. UnLockIncFileCache();
  718. return E_OUTOFMEMORY;
  719. }
  720. if (SUCCEEDED(hrInit = (*ppIncFile)->Init(szFile)))
  721. {
  722. // The hash table will hold a reference to the inc file
  723. (*ppIncFile)->AddRef();
  724. m_mpszIncFile.AddElem(*ppIncFile);
  725. }
  726. else
  727. *ppIncFile = NULL;
  728. }
  729. if (SUCCEEDED(hrInit))
  730. {
  731. // The caller will hold a reference to the inc file
  732. (*ppIncFile)->AddRef();
  733. }
  734. UnLockIncFileCache();
  735. return hrInit;
  736. }
  737. /*===================================================================
  738. CIncFileMap::UnInit
  739. Parameters: N/A
  740. Returns: Completion status
  741. ===================================================================*/
  742. HRESULT CIncFileMap::UnInit()
  743. {
  744. CIncFile *pNukeIncFile = static_cast<CIncFile *>(m_mpszIncFile.Head());
  745. while (pNukeIncFile != NULL)
  746. {
  747. CIncFile *pNext = static_cast<CIncFile *>(pNukeIncFile->m_pNext);
  748. pNukeIncFile->OnIncFileDecache();
  749. pNukeIncFile->Release();
  750. pNukeIncFile = pNext;
  751. }
  752. DeleteCriticalSection(&m_csUpdate);
  753. return m_mpszIncFile.UnInit();
  754. }
  755. /*===================================================================
  756. CIncFileMap::Flush
  757. Parameters:
  758. szFile - the file to remove from cache
  759. Returns:
  760. None
  761. ===================================================================*/
  762. void CIncFileMap::Flush(const TCHAR *szFile)
  763. {
  764. LockTemplateAndIncFileCaches();
  765. Assert(IsNormalized(szFile));
  766. CIncFile *pIncFile = static_cast<CIncFile *>(m_mpszIncFile.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR)));
  767. if (pIncFile != NULL)
  768. {
  769. if (pIncFile->FlushTemplates())
  770. {
  771. // Remove from hash table
  772. m_mpszIncFile.DeleteElem(szFile, _tcslen(szFile)*sizeof(TCHAR));
  773. // The hash table gave up its reference
  774. // to the incfile
  775. pIncFile->OnIncFileDecache();
  776. pIncFile->Release();
  777. }
  778. }
  779. UnLockTemplateAndIncFileCaches();
  780. }
  781. /*===================================================================
  782. CIncFileMap::FlushFiles
  783. Parameters:
  784. szFile - the file prefix to search for in cache
  785. Returns:
  786. None
  787. ===================================================================*/
  788. void CIncFileMap::FlushFiles(const TCHAR *szFilePrefix)
  789. {
  790. LockTemplateAndIncFileCaches();
  791. Assert(IsNormalized(szFilePrefix));
  792. CIncFile *pIncFile = static_cast<CIncFile *>(m_mpszIncFile.Head());
  793. while (pIncFile != NULL)
  794. {
  795. CIncFile *pNextFile = static_cast<CIncFile *>(pIncFile->m_pNext);
  796. int cchFilePrefix = _tcslen(szFilePrefix);
  797. if (pIncFile->m_cbKey >= (cchFilePrefix*(int)sizeof(TCHAR)) &&
  798. _tcsncmp(reinterpret_cast<TCHAR *>(pIncFile->m_pKey), szFilePrefix, cchFilePrefix) == 0)
  799. {
  800. #if UNICODE
  801. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %S\n", pIncFile->m_pKey));
  802. #else
  803. DBGPRINTF((DBG_CONTEXT, "FlushFiles: flushing %s\n", pIncFile->m_pKey));
  804. #endif
  805. if (pIncFile->FlushTemplates())
  806. {
  807. // Remove from hash table
  808. m_mpszIncFile.DeleteElem(pIncFile->m_pKey, pIncFile->m_cbKey);
  809. // The hash table gave up its reference
  810. // to the incfile
  811. pIncFile->OnIncFileDecache();
  812. pIncFile->Release();
  813. }
  814. }
  815. pIncFile = pNextFile;
  816. }
  817. UnLockTemplateAndIncFileCaches();
  818. }
  819. /* ****************************************************************************
  820. Non-class support functions
  821. */
  822. /*===================================================================
  823. FFileChangedSinceCached
  824. Has the file changed since it was cached?
  825. Parameters:
  826. szFile - file name
  827. ftPrevWriteTime - the file's "previous write time"
  828. (its last-write-time value when the file was cached)
  829. Returns:
  830. TRUE or FALSE
  831. ===================================================================*/
  832. BOOL FFileChangedSinceCached(const TCHAR *szFile, FILETIME& ftPrevWriteTime)
  833. {
  834. WIN32_FILE_ATTRIBUTE_DATA fad; // win32 file attributes data structure
  835. BOOL fRet = FALSE; // return value
  836. // This fn doesnt exist on Win95. On Win95 we do no caching anyway, so we dont care.
  837. if (!FIsWinNT())
  838. return(TRUE);
  839. if (FAILED(AspGetFileAttributes(szFile, &fad)))
  840. {
  841. // assume file was changed if get file attributes failed
  842. fRet = TRUE;
  843. }
  844. if( 0 != CompareFileTime( &ftPrevWriteTime, &(fad.ftLastWriteTime) ) )
  845. {
  846. // file was changed if file times differ
  847. fRet = TRUE;
  848. }
  849. return fRet;
  850. }
  851. /*===================================================================
  852. CTemplateCacheManager::CTemplateHashTable::TrimPersistCache
  853. Parameters:
  854. dwTrimCount - the number of templates to trim from the cache
  855. Returns:
  856. TRUE - if dwTrimCount was actually trimmed
  857. FALSE - if exited before dwTrimCount was met
  858. ===================================================================*/
  859. BOOL CTemplateCacheManager::CTemplateHashTable::TrimPersistCache(DWORD dwTrimCount)
  860. {
  861. // enter a while loop to trim until the count is reached
  862. while(dwTrimCount--) {
  863. // if there isn't anything else to trim, we're done. Return FALSE
  864. // to indicate that dwTrimCount was not met.
  865. if (m_dwPersistedTemplates == 0) {
  866. return(FALSE);
  867. }
  868. else {
  869. CTemplate *pTemplate;
  870. // get the oldest template from the list
  871. pTemplate = static_cast<CTemplate *>(PersistTemplatesEnd());
  872. // remove the template.
  873. RemoveTemplate(pTemplate);
  874. ZapTemplate(pTemplate);
  875. }
  876. }
  877. // return TRUE to indicate that the TrimCount was met.
  878. return(TRUE);
  879. }
  880. /*===================================================================
  881. CTemplateCacheManager::CTemplateHashTable::ScavengePersistCache
  882. Parameters:
  883. <NONE>
  884. Returns:
  885. VOID
  886. ===================================================================*/
  887. VOID CTemplateCacheManager::CTemplateHashTable::ScavengePersistCache()
  888. {
  889. CTemplate *pTemplate;
  890. CTemplate *pTemplateNext;
  891. // enter a for loop to look at all persisted templates to see if
  892. // any memory can be freed. It's memory can be freed only if the
  893. // ref count is 1 (the sole ref count is for the cache). Also note
  894. // that the list is re-ordered to move templates to the head of the
  895. // list that can't have their memory freed at this time because of
  896. // the ref count.
  897. for (pTemplate = static_cast<CTemplate *>(PersistTemplatesBegin());
  898. (pTemplate != static_cast<CTemplate *>(&m_listPersistTemplates)) && (pTemplate->m_pbStart != NULL);
  899. pTemplate = pTemplateNext) {
  900. pTemplateNext = static_cast<CTemplate *>(pTemplate->PNext());
  901. // this check should be safe. The only risk is that we miss a release
  902. // of the template from 2 to 1, in which case will miss it this time
  903. // but get it the next time through. AddRef from 1 to 2 is impossible
  904. // to interrupt because it couldn't be on this list when it gets AddRef'd
  905. // from 1 to 2 and moving it from this list is protected by the template
  906. // cache lock which we should be under.
  907. if (pTemplate->m_cRefs == 1) {
  908. // remove the memory
  909. CTemplate::LargeFree(pTemplate->m_pbStart);
  910. pTemplate->m_pbStart = NULL;
  911. }
  912. else {
  913. // if some is still using it, move the template to the head of the
  914. // list so that we'll check again later.
  915. pTemplate->PrependTo(m_listPersistTemplates);
  916. }
  917. }
  918. }
  919. /*===================================================================
  920. GetAggregatedTemplCounter()
  921. Returns the Template Perf Counter. To do this, initializes a private
  922. copy of the perfmainblock and aggregates the stats into it.
  923. ===================================================================*/
  924. static DWORD GetAggregatedTemplCounter()
  925. {
  926. CPerfMainBlock perfSharedBlk;
  927. DWORD pdwCounters[C_PERF_PROC_COUNTERS];
  928. BOOL bInited = FALSE;
  929. memset(pdwCounters, 0, sizeof(pdwCounters));
  930. if (!(bInited = (perfSharedBlk.Init() == S_OK)));
  931. else {
  932. perfSharedBlk.GetStats(pdwCounters);
  933. }
  934. if (bInited)
  935. perfSharedBlk.UnInit();
  936. return(pdwCounters[ID_TEMPLCACHE]);
  937. }
  938. /*===================================================================
  939. CTemplateCacheManager::InitPersistCache
  940. Parameters:
  941. [none]
  942. Returns:
  943. BOOL to indicate if the init was successful
  944. ===================================================================*/
  945. BOOL CTemplateCacheManager::InitPersistCache()
  946. {
  947. HANDLE hImpersonationToken = NULL;
  948. BOOL fRevertedToSelf = FALSE;
  949. HANDLE hThread;
  950. hThread = GetCurrentThread();
  951. if (OpenThreadToken( hThread,
  952. TOKEN_READ | TOKEN_IMPERSONATE,
  953. TRUE,
  954. &hImpersonationToken )) {
  955. RevertToSelf();
  956. fRevertedToSelf = TRUE;
  957. }
  958. // get the PersistCacheDir from the globals table
  959. strcpy(m_szPersistCacheDir,Glob(pszPersistTemplateDir));
  960. // Check to see if the directory exists...
  961. DWORD dirAttribs = GetFileAttributesA(m_szPersistCacheDir);
  962. if ((dirAttribs == 0xffffffff)
  963. || !(dirAttribs & FILE_ATTRIBUTE_DIRECTORY)) {
  964. MSG_Error(IDS_CACHE_DIR_MISSING);
  965. m_fFailedToInitPersistCache = TRUE;
  966. }
  967. else {
  968. // append the trailing slash to the directory name
  969. strcat(m_szPersistCacheDir,"\\");
  970. // next, cleanup the temp directory.
  971. // since asp.dll can execute in many process simultaneously, we'll
  972. // check the perf counter to see if there are any templates
  973. // cached anywhere on the system.
  974. if (GetAggregatedTemplCounter() == 0) {
  975. CHAR DirectoryWildcard[MAX_PATH];
  976. WIN32_FIND_DATAA win32FindData;
  977. strcpy(DirectoryWildcard, m_szPersistCacheDir);
  978. strcat(DirectoryWildcard, "ASP*.TMP");
  979. // use FindFirstFile to begin the enumeration of all files in the
  980. // temp directory.
  981. HANDLE hDirectory = FindFirstFileA( DirectoryWildcard, &win32FindData );
  982. if ( hDirectory != INVALID_HANDLE_VALUE ) {
  983. BOOL success = TRUE;
  984. while ( success ) {
  985. char fileName[MAX_PATH];
  986. // FindFirst/FindNext returns just the filename. Build up
  987. // the entire path and then call DeleteFile. We'll ignore
  988. // errors as there isn't much we could do with the error
  989. // except fail the cache init.
  990. strcpy( fileName, m_szPersistCacheDir );
  991. strcat( fileName, win32FindData.cFileName );
  992. DeleteFileA( fileName );
  993. success = FindNextFileA( hDirectory, &win32FindData );
  994. }
  995. FindClose( hDirectory );
  996. }
  997. else {
  998. GetLastError();
  999. }
  1000. }
  1001. }
  1002. if (fRevertedToSelf) {
  1003. SetThreadToken(&hThread, hImpersonationToken);
  1004. }
  1005. return(!m_fFailedToInitPersistCache);
  1006. }
  1007. /*===================================================================
  1008. CTemplateCacheManager::CTemplateHashTable::CanPersistTemplate
  1009. Parameters:
  1010. pTemplate - The template to test for persistability
  1011. Returns:
  1012. BOOL to indicate if template can be persisted.
  1013. ===================================================================*/
  1014. BOOL CTemplateCacheManager::CTemplateHashTable::CanPersistTemplate(CTemplate *pTemplate)
  1015. {
  1016. // if MaxFiles is zero, then the persist cache is disabled
  1017. if (Glob(dwPersistTemplateMaxFiles) == 0) {
  1018. return(FALSE);
  1019. }
  1020. // can't persist if the persist cache failed to init
  1021. if (m_fFailedToInitPersistCache == TRUE) {
  1022. return(FALSE);
  1023. }
  1024. // can't persist templates that are marked as debuggable. The
  1025. // script engines need access to the memory.
  1026. if (pTemplate->FDebuggable()) {
  1027. return(FALSE);
  1028. }
  1029. // at this point, we're going to return true. The next part of the code
  1030. // trims the cache as necessary.
  1031. if (m_dwPersistedTemplates >= Glob(dwPersistTemplateMaxFiles)) {
  1032. TrimPersistCache(m_dwPersistedTemplates - Glob(dwPersistTemplateMaxFiles) + 1);
  1033. }
  1034. return(TRUE);
  1035. }
  1036. /*===================================================================
  1037. CTemplateCacheManager::CTemplateHashTable::InsertTemplate
  1038. Parameters:
  1039. pTemplate - Template to insert into the memory cache
  1040. Returns:
  1041. LK_RETCODE indicating the success of the insertion
  1042. ===================================================================*/
  1043. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::InsertTemplate(CTemplate *pTemplate)
  1044. {
  1045. LK_RETCODE rcode = InsertRecord(pTemplate, true);
  1046. if (rcode == LK_SUCCESS) {
  1047. #ifndef PERF_DISABLE
  1048. g_PerfData.Incr_MEMORYTEMPLCACHE();
  1049. g_PerfData.Incr_TEMPLCACHE();
  1050. #endif
  1051. m_dwInMemoryTemplates++;
  1052. pTemplate->PrependTo(m_listMemoryTemplates);
  1053. pTemplate->SetHashTablePtr(this);
  1054. }
  1055. ScavengePersistCache();
  1056. return rcode;
  1057. }
  1058. /*===================================================================
  1059. CTemplateCacheManager::CTemplateHashTable::RemoveTemplate
  1060. Parameters:
  1061. pTemplate - Template to remove from cache
  1062. fPersist - indicate if memory template is a candidate for persist
  1063. Returns:
  1064. LK_RETCODE indicating the success of the removal
  1065. ===================================================================*/
  1066. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::RemoveTemplate(CTemplate *pTemplate, BOOL fPersist)
  1067. {
  1068. LK_RETCODE rcode = LK_SUCCESS;
  1069. #if DBG_PERSTEMPL
  1070. DBGPRINTF((DBG_CONTEXT,
  1071. "RemoveTemplate entered.\n\tTemplate = %s.\n\tfPersist = %d.\n\tFIsPersisted = %d\n",
  1072. pTemplate->GetSourceFileName(),
  1073. fPersist,
  1074. pTemplate->FIsPersisted()));
  1075. #endif
  1076. // if the template isn't in the cache, or if the template isn't on this
  1077. // particular hash table, then just bail. Nothing to
  1078. // do here. It may not be on this particular hash table because the entire
  1079. // table may have been torn off the global cache manager and scheduled for
  1080. // cleanup on the flush thread. In this case, we're checking the wrong
  1081. // table. The flush thread will eventually clean this one up.
  1082. if (pTemplate->FIsEmpty() || (pTemplate->GetHashTablePtr() != this)) {
  1083. return LK_NO_SUCH_KEY;
  1084. }
  1085. // no matter what, this template is going to be unlinked from it's
  1086. // current CDblLink
  1087. pTemplate->UnLink();
  1088. // update the appropriate counter
  1089. if (pTemplate->FIsPersisted() == FALSE) {
  1090. // decrement the number of InMemoryTemplates...
  1091. #ifndef PERF_DISABLE
  1092. g_PerfData.Decr_MEMORYTEMPLCACHE();
  1093. #endif
  1094. m_dwInMemoryTemplates--;
  1095. }
  1096. else {
  1097. m_dwPersistedTemplates--;
  1098. }
  1099. // if asked to be persisted, see if it's a candidate to be persisted.
  1100. if (fPersist && CanPersistTemplate(pTemplate)) {
  1101. // so persist it.
  1102. if (pTemplate->PersistData(m_szPersistCacheDir) != S_OK) {
  1103. // a failure will result in the record being deleted.
  1104. #ifndef PERF_DISABLE
  1105. g_PerfData.Decr_TEMPLCACHE();
  1106. #endif
  1107. rcode = DeleteRecord(pTemplate);
  1108. }
  1109. else {
  1110. // if successfully persisted, then add to the list of
  1111. // persisted templates
  1112. pTemplate->PrependTo(m_listPersistTemplates);
  1113. m_dwPersistedTemplates++;
  1114. }
  1115. }
  1116. else {
  1117. #ifndef PERF_DISABLE
  1118. g_PerfData.Decr_TEMPLCACHE();
  1119. #endif
  1120. // if not asked to persist, then delete the record.
  1121. rcode = DeleteRecord(pTemplate);
  1122. }
  1123. ScavengePersistCache();
  1124. return rcode;
  1125. }
  1126. /*===================================================================
  1127. CTemplateCacheManager::CTemplateHashTable::FindTemplate
  1128. Parameters:
  1129. rTemplate - the key for the template being looked up
  1130. Returns:
  1131. LK_RETCODE indicating the success of the look up
  1132. ===================================================================*/
  1133. LK_RETCODE CTemplateCacheManager::CTemplateHashTable::FindTemplate(const CTemplateKey &rTemplateKey, CTemplate **ppTemplate)
  1134. {
  1135. #if DBG_PERSTEMPL
  1136. DBGPRINTF((DBG_CONTEXT,
  1137. "FindTemplate entered\n\tLooking for %s\n",
  1138. rTemplateKey.szPathTranslated));
  1139. #endif
  1140. #ifndef PERF_DISABLE
  1141. g_PerfData.Incr_MEMORYTEMPLCACHETRYS();
  1142. g_PerfData.Incr_TEMPLCACHETRYS();
  1143. #endif
  1144. LK_RETCODE rcode = FindKey(&rTemplateKey, ppTemplate);
  1145. // see if we found it.
  1146. if (rcode == LK_SUCCESS) {
  1147. #if DBG_PERSTEMPL
  1148. DBGPRINTF((DBG_CONTEXT,
  1149. "Template found\n\tfPersisted = %d\n",
  1150. (*ppTemplate)->FIsPersisted()));
  1151. #endif
  1152. #ifndef PERF_DISABLE
  1153. g_PerfData.Incr_TEMPLCACHEHITS();
  1154. #endif
  1155. // found it. Is it persisted?
  1156. if ((*ppTemplate)->FIsPersisted()) {
  1157. // It is persisted. Unlink it from the persisted list.
  1158. (*ppTemplate)->UnLink();
  1159. m_dwPersistedTemplates--;
  1160. // unpersist it
  1161. if ((*ppTemplate)->UnPersistData() != S_OK) {
  1162. // error occurred
  1163. // get the template out of the cache
  1164. DeleteRecord(*ppTemplate);
  1165. // release the reference that the cache had on the template
  1166. (*ppTemplate)->Release();
  1167. // NULL out *ppTemplate so that the caller doesn't think they
  1168. // got a valid template
  1169. *ppTemplate = NULL;
  1170. #ifndef PERF_DISABLE
  1171. g_PerfData.Decr_TEMPLCACHE();
  1172. #endif
  1173. // return NO_SUCH_KEY so that a new template will be built
  1174. return(LK_NO_SUCH_KEY);
  1175. }
  1176. // bump the number of in memory templates
  1177. #ifndef PERF_DISABLE
  1178. g_PerfData.Incr_MEMORYTEMPLCACHE();
  1179. #endif
  1180. m_dwInMemoryTemplates++;
  1181. }
  1182. else {
  1183. #ifndef PERF_DISABLE
  1184. g_PerfData.Incr_MEMORYTEMPLCACHEHITS();
  1185. #endif
  1186. }
  1187. // add it to, or move it to the top of, the memory templates
  1188. (*ppTemplate)->PrependTo(m_listMemoryTemplates);
  1189. }
  1190. ScavengePersistCache();
  1191. return rcode;
  1192. }