Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1243 lines
29 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. --*/
  4. #include "precomp.h"
  5. #include <wbemcomn.h>
  6. #include "hiecache.h"
  7. #include <creposit.h>
  8. #include <malloc.h>
  9. #include <corex.h>
  10. extern bool g_bShuttingDown;
  11. long CHierarchyCache::s_nCaches = 0;
  12. long CClassRecord::s_nRecords = 0;
  13. //
  14. //
  15. // CClassRecord::CClassRecord
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. CClassRecord::CClassRecord(LPCWSTR wszClassName, LPCWSTR wszHash)
  19. : m_wszClassName(NULL), m_pClassDef(NULL), m_pParent(NULL),
  20. m_eIsKeyed(e_KeynessUnknown), m_bTreeComplete(false),
  21. m_bChildrenComplete(false),
  22. m_lLastChildInvalidationIndex(-1), m_pMoreRecentlyUsed(NULL),
  23. m_pLessRecentlyUsed(NULL), m_lRef(0), m_nStatus(0), m_bSystemClass(false)
  24. {
  25. size_t dwLen = wcslen(wszClassName)+1;
  26. m_wszClassName = new WCHAR[dwLen];
  27. if (m_wszClassName == NULL)
  28. throw CX_MemoryException();
  29. StringCchCopyW(m_wszClassName, dwLen, wszClassName);
  30. StringCchCopyW(m_wszHash, MAX_HASH_LEN+1, wszHash);
  31. m_dwLastUsed = GetTickCount();
  32. s_nRecords++;
  33. }
  34. CClassRecord::~CClassRecord()
  35. {
  36. delete [] m_wszClassName;
  37. if(m_pClassDef)
  38. {
  39. if(m_pClassDef->Release() != 0)
  40. {
  41. s_nRecords++;
  42. s_nRecords--;
  43. }
  44. }
  45. s_nRecords--;
  46. }
  47. HRESULT CClassRecord::EnsureChild(CClassRecord* pChild)
  48. {
  49. for(int i = 0; i < m_apChildren.GetSize(); i++)
  50. {
  51. if(m_apChildren[i] == pChild)
  52. return WBEM_S_FALSE;
  53. }
  54. if(m_apChildren.Add(pChild) < 0)
  55. return WBEM_E_OUT_OF_MEMORY;
  56. return WBEM_S_NO_ERROR;
  57. }
  58. HRESULT CClassRecord::RemoveChild(CClassRecord* pChild)
  59. {
  60. for(int i = 0; i < m_apChildren.GetSize(); i++)
  61. {
  62. if(m_apChildren[i] == pChild)
  63. {
  64. m_apChildren.RemoveAt(i);
  65. return WBEM_S_NO_ERROR;
  66. }
  67. }
  68. return WBEM_E_NOT_FOUND;
  69. }
  70. //
  71. //
  72. // CHierarchyCache::CHierarchyCache
  73. //
  74. /////////////////////////////////////////////////////////////////////
  75. CHierarchyCache::CHierarchyCache(CForestCache* pForest)
  76. : m_pForest(pForest), m_lNextInvalidationIndex(0), m_lRef(0),
  77. m_hresError(S_OK)
  78. {
  79. s_nCaches++;
  80. }
  81. CHierarchyCache::~CHierarchyCache()
  82. {
  83. Clear();
  84. s_nCaches--;
  85. }
  86. void CHierarchyCache::Clear()
  87. {
  88. CInCritSec ics(m_pForest->GetLock());
  89. TIterator it = m_map.begin();
  90. while(it != m_map.end())
  91. {
  92. CClassRecord* pRecord = it->second;
  93. m_pForest->RemoveRecord(pRecord);
  94. it = m_map.erase(it);
  95. pRecord->Release();
  96. }
  97. }
  98. void CHierarchyCache::SetError(HRESULT hresError)
  99. {
  100. m_hresError = hresError;
  101. }
  102. HRESULT CHierarchyCache::GetError()
  103. {
  104. return m_hresError;
  105. }
  106. bool CHierarchyCache::MakeKey(LPCWSTR wszClassName, LPWSTR wszKey)
  107. {
  108. // wbem_wcsupr(wszKey, wszClassName);
  109. return A51Hash(wszClassName, wszKey);
  110. }
  111. INTERNAL CClassRecord* CHierarchyCache::FindClass(LPCWSTR wszClassName)
  112. {
  113. CInCritSec ics(m_pForest->GetLock());
  114. LPWSTR wszKey = (WCHAR*)TempAlloc((MAX_HASH_LEN+2) * sizeof(WCHAR));
  115. if (wszKey == NULL)
  116. return NULL;
  117. CTempFreeMe tfm(wszKey, (MAX_HASH_LEN+2) * sizeof(WCHAR));
  118. if (!MakeKey(wszClassName, wszKey))
  119. return 0;
  120. return FindClassByKey(wszKey);
  121. }
  122. INTERNAL CClassRecord* CHierarchyCache::FindClassByKey(LPCWSTR wszKey)
  123. {
  124. TIterator it = m_map.find(wszKey);
  125. if(it == m_map.end())
  126. return NULL;
  127. return it->second;
  128. }
  129. INTERNAL CClassRecord* CHierarchyCache::EnsureClass(LPCWSTR wszClassName)
  130. {
  131. CInCritSec ics(m_pForest->GetLock());
  132. LPWSTR wszKey = (WCHAR*)TempAlloc((MAX_HASH_LEN+2) * sizeof(WCHAR));
  133. if (wszKey == NULL)
  134. return NULL;
  135. CTempFreeMe tfm(wszKey, (MAX_HASH_LEN+2) * sizeof(WCHAR));
  136. if (!MakeKey(wszClassName, wszKey))
  137. return 0;
  138. TIterator it = m_map.find(wszKey);
  139. if(it == m_map.end())
  140. {
  141. //
  142. // Create a new record with the name
  143. //
  144. try
  145. {
  146. CClassRecord* pRecord = new CClassRecord(wszClassName, wszKey);
  147. if(pRecord == NULL)
  148. return NULL;
  149. pRecord->AddRef(); // one for the map
  150. m_map[pRecord->m_wszHash] = pRecord;
  151. return pRecord;
  152. }
  153. catch (CX_MemoryException)
  154. {
  155. return NULL;
  156. }
  157. }
  158. else
  159. {
  160. return it->second;
  161. }
  162. }
  163. HRESULT CHierarchyCache::AssertClass(_IWmiObject* pClass, LPCWSTR wszClassName,
  164. bool bClone, __int64 nTime, bool bSystemClass)
  165. {
  166. CInCritSec ics(m_pForest->GetLock());
  167. HRESULT hres;
  168. m_pForest->MarkAsserted(this, wszClassName);
  169. //
  170. // If no record is given, find one
  171. //
  172. CClassRecord* pRecord = NULL;
  173. if(wszClassName == NULL)
  174. {
  175. VARIANT v;
  176. VariantInit(&v);
  177. CClearMe cm(&v);
  178. hres = pClass->Get(L"__CLASS", 0, &v, NULL, NULL);
  179. if(FAILED(hres) || V_VT(&v) != VT_BSTR)
  180. return WBEM_E_INVALID_CLASS;
  181. pRecord = EnsureClass(V_BSTR(&v));
  182. }
  183. else
  184. pRecord = EnsureClass(wszClassName);
  185. if(pRecord == NULL)
  186. return WBEM_E_OUT_OF_MEMORY;
  187. //
  188. // Figure out the parent
  189. //
  190. VARIANT v;
  191. VariantInit(&v);
  192. hres = pClass->Get(L"__SUPERCLASS", 0, &v, NULL, NULL);
  193. CClearMe cm(&v);
  194. if(SUCCEEDED(hres))
  195. {
  196. if(V_VT(&v) == VT_BSTR)
  197. pRecord->m_pParent = EnsureClass(V_BSTR(&v));
  198. else
  199. pRecord->m_pParent = EnsureClass(L"");
  200. if(pRecord->m_pParent)
  201. pRecord->m_pParent->EnsureChild(pRecord);
  202. }
  203. else
  204. {
  205. return hres;
  206. }
  207. //
  208. // Check if the class is keyed
  209. //
  210. unsigned __int64 i64Flags = 0;
  211. hres = pClass->QueryObjectFlags(0, WMIOBJECT_GETOBJECT_LOFLAG_KEYED,
  212. &i64Flags);
  213. if(FAILED(hres))
  214. return hres;
  215. if(i64Flags)
  216. {
  217. pRecord->m_eIsKeyed = e_Keyed;
  218. }
  219. else
  220. {
  221. pRecord->m_eIsKeyed = e_NotKeyed;
  222. }
  223. //
  224. // Expell whatever definition is there from the cache
  225. //
  226. m_pForest->RemoveRecord(pRecord);
  227. //
  228. // Figure out how much space this object will take
  229. //
  230. DWORD dwSize;
  231. hres = pClass->GetObjectMemory(NULL, 0, &dwSize);
  232. if(hres != WBEM_E_BUFFER_TOO_SMALL)
  233. {
  234. if(SUCCEEDED(hres))
  235. return WBEM_E_CRITICAL_ERROR;
  236. else
  237. return hres;
  238. }
  239. //
  240. // Good. Make room and add to cache
  241. //
  242. if(m_pForest->MakeRoom(dwSize))
  243. {
  244. if(bClone)
  245. {
  246. IWbemClassObject* pObj = NULL;
  247. hres = pClass->Clone(&pObj);
  248. if(FAILED(hres))
  249. return hres;
  250. if(pObj)
  251. {
  252. pObj->QueryInterface(IID__IWmiObject,
  253. (void**)&pRecord->m_pClassDef);
  254. pObj->Release();
  255. }
  256. }
  257. else
  258. { pRecord->m_pClassDef = pClass;
  259. pClass->AddRef();
  260. }
  261. if(nTime)
  262. {
  263. pRecord->m_bRead = true;
  264. pRecord->m_nClassDefCachedTime = nTime;
  265. }
  266. else
  267. {
  268. pRecord->m_bRead = false;
  269. pRecord->m_nClassDefCachedTime = g_nCurrentTime++;
  270. }
  271. pRecord->m_dwClassDefSize = dwSize;
  272. pRecord->m_bSystemClass = bSystemClass;
  273. //
  274. // It is most recently used, of course
  275. //
  276. m_pForest->Add(pRecord);
  277. }
  278. return WBEM_S_NO_ERROR;
  279. }
  280. HRESULT CHierarchyCache::InvalidateClass(LPCWSTR wszClassName)
  281. {
  282. CInCritSec ics(m_pForest->GetLock());
  283. HRESULT hres;
  284. //
  285. // Find the record if not given
  286. //
  287. CClassRecord* pRecord = NULL;
  288. pRecord = FindClass(wszClassName);
  289. if(pRecord == NULL)
  290. {
  291. //
  292. // The record is not there --- there is nothing to invalidate. This
  293. // is based on the assumption that if a class record is in the
  294. // cache, then so are all its parents, which is true at the moment
  295. // because in order to construct a class we need to retrieve its
  296. // parents first.
  297. //
  298. return WBEM_S_FALSE;
  299. }
  300. pRecord->AddRef();
  301. CTemplateReleaseMe<CClassRecord> rm1(pRecord);
  302. LONGLONG lThisInvalidationIndex = m_lNextInvalidationIndex++;
  303. hres = InvalidateClassInternal(pRecord);
  304. //
  305. // Clear complete bits in all our parents, since this invalidation
  306. // means that no current enumeration of children can be trusted. At the same
  307. // time untie ourselves from the parent!
  308. //
  309. if(pRecord->m_pParent)
  310. {
  311. pRecord->m_pParent->m_bChildrenComplete = false;
  312. pRecord->m_pParent->m_bTreeComplete = false;
  313. pRecord->m_pParent->m_lLastChildInvalidationIndex =
  314. lThisInvalidationIndex;
  315. pRecord->m_pParent->RemoveChild(pRecord);
  316. CClassRecord* pCurrent = pRecord->m_pParent->m_pParent;
  317. while(pCurrent)
  318. {
  319. pCurrent->m_bTreeComplete = false;
  320. pCurrent = pCurrent->m_pParent;
  321. }
  322. }
  323. return S_OK;
  324. }
  325. HRESULT CHierarchyCache::InvalidateClassInternal(CClassRecord* pRecord)
  326. {
  327. //
  328. // Untie from the usage chain
  329. //
  330. //
  331. // Remove all its children from the cache
  332. //
  333. for(int i = 0; i < pRecord->m_apChildren.GetSize(); i++)
  334. {
  335. InvalidateClassInternal(pRecord->m_apChildren[i]);
  336. }
  337. pRecord->m_apChildren.RemoveAll();
  338. //
  339. // Count ourselves out of the total memory
  340. //
  341. m_pForest->RemoveRecord(pRecord);
  342. //
  343. // Remove ourselves from the cache
  344. //
  345. m_map.erase(pRecord->m_wszHash);
  346. pRecord->Release();
  347. return S_OK;
  348. }
  349. HRESULT CHierarchyCache::DoneWithChildren(LPCWSTR wszClassName, bool bRecursive,
  350. LONGLONG lStartIndex, CClassRecord* pRecord)
  351. {
  352. CInCritSec ics(m_pForest->GetLock());
  353. HRESULT hres;
  354. //
  355. // Find the record if not given
  356. //
  357. if(pRecord == NULL)
  358. {
  359. pRecord = FindClass(wszClassName);
  360. if(pRecord == NULL)
  361. {
  362. // Big time invalidation must have occurred
  363. return WBEM_S_FALSE;
  364. }
  365. }
  366. return DoneWithChildrenByRecord(pRecord, bRecursive, lStartIndex);
  367. }
  368. HRESULT CHierarchyCache::DoneWithChildrenByHash(LPCWSTR wszHash,
  369. bool bRecursive, LONGLONG lStartIndex)
  370. {
  371. CInCritSec ics(m_pForest->GetLock());
  372. HRESULT hres;
  373. //
  374. // Find the record if not given
  375. //
  376. CClassRecord* pRecord = FindClassByKey(wszHash);
  377. if(pRecord == NULL)
  378. {
  379. // Big time invalidation must have occurred
  380. return WBEM_S_FALSE;
  381. }
  382. return DoneWithChildrenByRecord(pRecord, bRecursive, lStartIndex);
  383. }
  384. HRESULT CHierarchyCache::DoneWithChildrenByRecord(CClassRecord* pRecord,
  385. bool bRecursive, LONGLONG lStartIndex)
  386. {
  387. //
  388. // Check if any child invalidations occurred in this node since we started
  389. //
  390. if(lStartIndex < pRecord->m_lLastChildInvalidationIndex)
  391. return WBEM_S_FALSE;
  392. else
  393. pRecord->m_bChildrenComplete = true;
  394. if(bRecursive)
  395. {
  396. //
  397. // We have completed a recursive enumeration --- descend the
  398. // hierarchy and mark as complete all the children that have not been
  399. // modified since the start
  400. //
  401. bool bAllValid = true;
  402. for(int i = 0; i < pRecord->m_apChildren.GetSize(); i++)
  403. {
  404. CClassRecord* pChildRecord = pRecord->m_apChildren[i];
  405. HRESULT hres = DoneWithChildren(pChildRecord->m_wszClassName, true,
  406. lStartIndex, pChildRecord);
  407. if(hres != S_OK)
  408. bAllValid = false;
  409. }
  410. if(bAllValid)
  411. {
  412. //
  413. // There were no invalidations anywhere in the tree, which makes
  414. // this record tree-complete
  415. //
  416. pRecord->m_bTreeComplete = true;
  417. return WBEM_S_NO_ERROR;
  418. }
  419. else
  420. return S_FALSE;
  421. }
  422. else
  423. return WBEM_S_NO_ERROR;
  424. }
  425. RELEASE_ME _IWmiObject* CHierarchyCache::GetClassDef(LPCWSTR wszClassName,
  426. bool bClone, __int64* pnTime,
  427. bool* pbRead)
  428. {
  429. CInCritSec ics(m_pForest->GetLock());
  430. CClassRecord* pRecord = FindClass(wszClassName);
  431. if(pRecord == NULL)
  432. return NULL;
  433. if(pnTime)
  434. *pnTime = pRecord->m_nClassDefCachedTime;
  435. if(pbRead)
  436. *pbRead = pRecord->m_bRead;
  437. return GetClassDefFromRecord(pRecord, bClone);
  438. }
  439. RELEASE_ME _IWmiObject* CHierarchyCache::GetClassDefByHash(LPCWSTR wszHash,
  440. bool bClone, __int64* pnTime,
  441. bool* pbRead, bool *pbSystemClass)
  442. {
  443. CInCritSec ics(m_pForest->GetLock());
  444. CClassRecord* pRecord = FindClassByKey(wszHash);
  445. if(pRecord == NULL)
  446. return NULL;
  447. if(pbRead)
  448. *pbRead = pRecord->m_bRead;
  449. if(pnTime)
  450. *pnTime = pRecord->m_nClassDefCachedTime;
  451. if (pbSystemClass)
  452. *pbSystemClass = pRecord->m_bSystemClass;
  453. return GetClassDefFromRecord(pRecord, bClone);
  454. }
  455. // assumes: in m_cs
  456. RELEASE_ME _IWmiObject* CHierarchyCache::GetClassDefFromRecord(
  457. CClassRecord* pRecord,
  458. bool bClone)
  459. {
  460. //
  461. // Accessing m_pClassDef, so we have to lock the forest
  462. //
  463. CInCritSec ics(m_pForest->GetLock());
  464. if(pRecord->m_pClassDef)
  465. {
  466. m_pForest->MakeMostRecentlyUsed(pRecord);
  467. if(bClone)
  468. {
  469. IWbemClassObject* pObj = NULL;
  470. if(FAILED(pRecord->m_pClassDef->Clone(&pObj)))
  471. return NULL;
  472. else
  473. {
  474. _IWmiObject* pRes = NULL;
  475. pObj->QueryInterface(IID__IWmiObject, (void**)&pRes);
  476. pObj->Release();
  477. return pRes;
  478. }
  479. }
  480. else
  481. {
  482. pRecord->m_pClassDef->AddRef();
  483. return pRecord->m_pClassDef;
  484. }
  485. }
  486. else
  487. return NULL;
  488. }
  489. HRESULT CHierarchyCache::EnumChildren(LPCWSTR wszClassName, bool bRecursive,
  490. CWStringArray& awsChildren)
  491. {
  492. CInCritSec ics(m_pForest->GetLock());
  493. //
  494. // Get the record
  495. //
  496. CClassRecord* pRecord = FindClass(wszClassName);
  497. if(pRecord == NULL)
  498. return WBEM_S_FALSE;
  499. //
  500. // Check if it is complete for this type of enumeration
  501. //
  502. if(!pRecord->m_bChildrenComplete)
  503. return WBEM_S_FALSE;
  504. if(bRecursive && !pRecord->m_bTreeComplete)
  505. return WBEM_S_FALSE;
  506. return EnumChildrenInternal(pRecord, bRecursive, awsChildren);
  507. }
  508. HRESULT CHierarchyCache::EnumChildrenInternal(CClassRecord* pRecord,
  509. bool bRecursive,
  510. CWStringArray& awsChildren)
  511. {
  512. for(int i = 0; i < pRecord->m_apChildren.GetSize(); i++)
  513. {
  514. CClassRecord* pChildRecord = pRecord->m_apChildren[i];
  515. if(awsChildren.Add(pChildRecord->m_wszClassName) < 0)
  516. return WBEM_E_OUT_OF_MEMORY;
  517. if(bRecursive)
  518. {
  519. HRESULT hres = EnumChildrenInternal(pChildRecord, bRecursive,
  520. awsChildren);
  521. if(FAILED(hres))
  522. return hres;
  523. }
  524. }
  525. return WBEM_S_NO_ERROR;
  526. }
  527. HRESULT CHierarchyCache::EnumChildKeysByKey(LPCWSTR wszClassKey,
  528. CWStringArray& awsChildKeys)
  529. {
  530. CInCritSec ics(m_pForest->GetLock());
  531. //
  532. // Get the record
  533. //
  534. CClassRecord* pRecord = FindClassByKey(wszClassKey);
  535. if(pRecord == NULL)
  536. return WBEM_S_FALSE;
  537. //
  538. // Check if it is complete for this type of enumeration
  539. //
  540. if(!pRecord->m_bChildrenComplete)
  541. return WBEM_S_FALSE;
  542. for(int i = 0; i < pRecord->m_apChildren.GetSize(); i++)
  543. {
  544. CClassRecord* pChildRecord = pRecord->m_apChildren[i];
  545. if(awsChildKeys.Add(pChildRecord->m_wszHash) < 0)
  546. return WBEM_E_OUT_OF_MEMORY;
  547. }
  548. return WBEM_S_NO_ERROR;
  549. }
  550. HRESULT CHierarchyCache::GetKeyRoot(LPCWSTR wszClassName,
  551. TEMPFREE_ME LPWSTR* pwszKeyRoot)
  552. {
  553. CInCritSec ics(m_pForest->GetLock());
  554. CClassRecord* pRecord = FindClass(wszClassName);
  555. if(pRecord == NULL)
  556. return WBEM_E_NOT_FOUND;
  557. return GetKeyRootByRecord(pRecord, pwszKeyRoot);
  558. }
  559. // assumes: in cs
  560. HRESULT CHierarchyCache::GetKeyRootByRecord(CClassRecord* pRecord,
  561. TEMPFREE_ME LPWSTR* pwszKeyRoot)
  562. {
  563. *pwszKeyRoot = NULL;
  564. if(pRecord->m_eIsKeyed == e_NotKeyed)
  565. return WBEM_E_CANNOT_BE_ABSTRACT;
  566. //
  567. // Go up until an unkeyed record is found. Keep the previous in pPrev
  568. //
  569. CClassRecord* pPrev = pRecord;
  570. while(pRecord && pRecord->m_eIsKeyed == e_Keyed)
  571. {
  572. pPrev = pRecord;
  573. pRecord = pRecord->m_pParent;
  574. }
  575. if(pRecord && pRecord->m_eIsKeyed == e_NotKeyed)
  576. {
  577. //
  578. // Found unkeyed parent --- pPrev is the root
  579. //
  580. LPCWSTR wszKeyRoot = pPrev->m_wszClassName;
  581. DWORD dwLen = wcslen(wszKeyRoot)+1;
  582. *pwszKeyRoot = (WCHAR*)TempAlloc(dwLen * sizeof(WCHAR));
  583. if (*pwszKeyRoot == NULL)
  584. return WBEM_E_OUT_OF_MEMORY;
  585. StringCchCopyW(*pwszKeyRoot, dwLen, wszKeyRoot);
  586. return S_OK;
  587. }
  588. else
  589. {
  590. //
  591. // No unkeyed parents --- since "" is known to be unkeyed, we had have
  592. // hit a gap in the cache
  593. //
  594. return WBEM_E_NOT_FOUND;
  595. }
  596. }
  597. HRESULT CHierarchyCache::GetKeyRootByKey(LPCWSTR wszKey,
  598. TEMPFREE_ME LPWSTR* pwszKeyRoot)
  599. {
  600. CInCritSec ics(m_pForest->GetLock());
  601. CClassRecord* pRecord = FindClassByKey(wszKey);
  602. if(pRecord == NULL)
  603. return WBEM_E_NOT_FOUND;
  604. return GetKeyRootByRecord(pRecord, pwszKeyRoot);
  605. }
  606. DELETE_ME LPWSTR CHierarchyCache::GetParent(LPCWSTR wszClassName)
  607. {
  608. CInCritSec ics(m_pForest->GetLock());
  609. CClassRecord* pRecord = FindClass(wszClassName);
  610. if(pRecord == NULL)
  611. return NULL;
  612. if(pRecord->m_pParent)
  613. {
  614. LPCWSTR wszParent = pRecord->m_pParent->m_wszClassName;
  615. size_t dwLen = wcslen(wszParent)+1;
  616. LPWSTR wszCopy = new WCHAR[dwLen];
  617. if (wszCopy == NULL)
  618. return NULL;
  619. StringCchCopyW(wszCopy, dwLen, wszParent);
  620. return wszCopy;
  621. }
  622. else
  623. return NULL;
  624. }
  625. //
  626. //
  627. // CForestCache
  628. //
  629. //////////////////////////////////////////////////////////////////////
  630. HRESULT CForestCache::Initialize()
  631. {
  632. CInCritSec ics(&m_cs);
  633. if (m_bInit)
  634. return S_OK;
  635. //
  636. // Read the size limits from the registry
  637. //
  638. HKEY hKey;
  639. long lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  640. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  641. 0, KEY_READ | KEY_WRITE, &hKey);
  642. if(lRes)
  643. return lRes;
  644. CRegCloseMe cm(hKey);
  645. DWORD dwLen = sizeof(DWORD);
  646. DWORD dwMaxSize;
  647. lRes = RegQueryValueExW(hKey, L"Max Class Cache Size", NULL, NULL,
  648. (LPBYTE)&dwMaxSize, &dwLen);
  649. //
  650. // If not there, set to default and write the default into the registry
  651. //
  652. if(lRes != ERROR_SUCCESS)
  653. {
  654. dwMaxSize = 5000000;
  655. lRes = RegSetValueExW(hKey, L"Max Class Cache Size", 0, REG_DWORD,
  656. (LPBYTE)&dwMaxSize, sizeof(DWORD));
  657. }
  658. //
  659. // Read the maximum useful age of an item
  660. //
  661. dwLen = sizeof(DWORD);
  662. DWORD dwMaxAge;
  663. lRes = RegQueryValueExW(hKey, L"Max Class Cache Item Age (ms)", NULL, NULL,
  664. (LPBYTE)&dwMaxAge, &dwLen);
  665. //
  666. // If not there, set to default and write the default into the registry
  667. //
  668. if(lRes != ERROR_SUCCESS)
  669. {
  670. dwMaxAge = 10000;
  671. lRes = RegSetValueExW(hKey, L"Max Class Cache Item Age (ms)", 0,
  672. REG_DWORD, (LPBYTE)&dwMaxAge, sizeof(DWORD));
  673. }
  674. //
  675. // Apply
  676. //
  677. SetMaxMemory(dwMaxSize, dwMaxAge);
  678. //
  679. // Create a timer queue for flushing
  680. //
  681. //m_hTimerQueue = CreateTimerQueue();
  682. //m_hCompletionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  683. m_bInit = TRUE;
  684. return WBEM_S_NO_ERROR;
  685. }
  686. bool CForestCache::MakeRoom(DWORD dwSize)
  687. {
  688. CInCritSec ics(&m_cs);
  689. if (!m_bInit)
  690. return false;
  691. if(dwSize > m_dwMaxMemory)
  692. return false; // no hope!
  693. //
  694. // Remove records until satisfied. Also, remove all records older than the
  695. // maximum age
  696. //
  697. DWORD dwNow = GetTickCount();
  698. while(m_pLeastRecentlyUsed &&
  699. (m_dwTotalMemory + dwSize > m_dwMaxMemory ||
  700. dwNow - m_pLeastRecentlyUsed->m_dwLastUsed > m_dwMaxAgeMs)
  701. )
  702. {
  703. RemoveRecord(m_pLeastRecentlyUsed);
  704. }
  705. return true;
  706. }
  707. bool CForestCache::Flush()
  708. {
  709. CInCritSec ics(&m_cs);
  710. if (!m_bInit)
  711. return false;
  712. while(m_pLeastRecentlyUsed)
  713. {
  714. RemoveRecord(m_pLeastRecentlyUsed);
  715. }
  716. return true;
  717. }
  718. //
  719. //
  720. // Test Only Function NOT IN REGULAR CODE
  721. //
  722. ///////////////////////////////////////////////////////////////
  723. #ifdef DBG
  724. bool CForestCache::Test()
  725. {
  726. if(m_pMostRecentlyUsed == NULL)
  727. {
  728. if(m_pLeastRecentlyUsed)
  729. DebugBreak();
  730. return true;
  731. }
  732. if(m_pMostRecentlyUsed->m_pMoreRecentlyUsed)
  733. DebugBreak();
  734. CClassRecord* pOne = m_pMostRecentlyUsed;
  735. CClassRecord* pTwo = m_pMostRecentlyUsed->m_pLessRecentlyUsed;
  736. while(pOne && pOne != pTwo)
  737. {
  738. if(pOne->m_pLessRecentlyUsed && pOne->m_pLessRecentlyUsed->m_pMoreRecentlyUsed != pOne)
  739. DebugBreak();
  740. if(pOne->m_pClassDef == NULL)
  741. DebugBreak();
  742. if(pOne->m_pLessRecentlyUsed == NULL && pOne != m_pLeastRecentlyUsed)
  743. DebugBreak();
  744. pOne = pOne->m_pLessRecentlyUsed;
  745. if(pTwo)
  746. pTwo = pTwo->m_pLessRecentlyUsed;
  747. if(pTwo)
  748. pTwo = pTwo->m_pLessRecentlyUsed;
  749. }
  750. if(pOne)
  751. DebugBreak();
  752. return true;
  753. }
  754. #endif
  755. void CForestCache::MakeMostRecentlyUsed(CClassRecord* pRecord)
  756. {
  757. CInCritSec ics(&m_cs);
  758. //Test();
  759. Untie(pRecord);
  760. pRecord->m_pMoreRecentlyUsed = NULL;
  761. pRecord->m_pLessRecentlyUsed = m_pMostRecentlyUsed;
  762. if(m_pMostRecentlyUsed)
  763. m_pMostRecentlyUsed->m_pMoreRecentlyUsed = pRecord;
  764. m_pMostRecentlyUsed = pRecord;
  765. if(m_pLeastRecentlyUsed == NULL)
  766. m_pLeastRecentlyUsed = pRecord;
  767. pRecord->m_dwLastUsed = GetTickCount();
  768. pRecord->m_nStatus = 4;
  769. //Test();
  770. //
  771. // Schedule a timer to clean up, if not already there
  772. //
  773. if(m_hCurrentTimer == NULL)
  774. {
  775. CreateTimerQueueTimer(&m_hCurrentTimer, NULL,
  776. (WAITORTIMERCALLBACK)&staticTimerCallback, this, m_dwMaxAgeMs,
  777. m_dwMaxAgeMs, WT_EXECUTEINTIMERTHREAD);
  778. }
  779. }
  780. void CForestCache::staticTimerCallback(void* pParam, BOOLEAN)
  781. {
  782. #ifdef DBG
  783. if (pParam != &g_Glob.m_ForestCache)
  784. {
  785. char pBuff[128];
  786. StringCchPrintfA(pBuff,128, "_RTLP_GENERIC_TIMER::Context == %p != %p\n",pParam,&g_Glob.m_ForestCache);
  787. OutputDebugStringA(pBuff);
  788. DebugBreak();
  789. }
  790. #endif
  791. g_Glob.m_ForestCache.TimerCallback();
  792. }
  793. void CForestCache::TimerCallback()
  794. {
  795. CInCritSec ics(&m_cs);
  796. // g_Glob.GetForestCache()->m_hCurrentTimer can be NULL at this point
  797. // if there is the CForestCache::Deinitialize function being executed
  798. // but we will delete the timer in that function instead of deleteing it below
  799. if (!m_bInit)
  800. return;
  801. //
  802. // Clean up what's stale
  803. //
  804. MakeRoom(0);
  805. //
  806. // See if we have any more reasons to live
  807. //
  808. if(m_pMostRecentlyUsed == NULL)
  809. {
  810. HANDLE hCurrentTimer;
  811. if (hCurrentTimer = InterlockedCompareExchangePointer(&m_hCurrentTimer,0,m_hCurrentTimer))
  812. {
  813. DeleteTimerQueueTimer( NULL, hCurrentTimer, NULL);
  814. }
  815. }
  816. }
  817. void CForestCache::Add(CClassRecord* pRecord)
  818. {
  819. CInCritSec ics(&m_cs);
  820. if (!m_bInit)
  821. return;
  822. MakeMostRecentlyUsed(pRecord);
  823. m_dwTotalMemory += pRecord->m_dwClassDefSize;
  824. pRecord->m_nStatus = 3;
  825. }
  826. void CForestCache::RemoveRecord(CClassRecord* pRecord)
  827. {
  828. CInCritSec ics(&m_cs);
  829. if (!m_bInit)
  830. return;
  831. if(pRecord->m_pClassDef == NULL)
  832. return;
  833. Untie(pRecord);
  834. m_dwTotalMemory -= pRecord->m_dwClassDefSize;
  835. pRecord->m_pClassDef->Release();
  836. pRecord->m_pClassDef = NULL;
  837. pRecord->m_nStatus = 2;
  838. }
  839. //
  840. //
  841. // helper function, always in m_cs
  842. //
  843. ///////////////////////////////////////////////////////
  844. void CForestCache::Untie(CClassRecord* pRecord)
  845. {
  846. CClassRecord* pPrev = pRecord->m_pLessRecentlyUsed;
  847. CClassRecord* pNext = pRecord->m_pMoreRecentlyUsed;
  848. if(pPrev)
  849. pPrev->m_pMoreRecentlyUsed = pNext;
  850. if(pNext)
  851. pNext->m_pLessRecentlyUsed = pPrev;
  852. if(m_pLeastRecentlyUsed == pRecord)
  853. m_pLeastRecentlyUsed = m_pLeastRecentlyUsed->m_pMoreRecentlyUsed;
  854. if(m_pMostRecentlyUsed == pRecord)
  855. m_pMostRecentlyUsed = m_pMostRecentlyUsed->m_pLessRecentlyUsed;
  856. pRecord->m_pMoreRecentlyUsed = pRecord->m_pLessRecentlyUsed = NULL;
  857. }
  858. void CForestCache::SetMaxMemory(DWORD dwMaxMemory, DWORD dwMaxAgeMs)
  859. {
  860. m_dwMaxMemory = dwMaxMemory;
  861. m_dwMaxAgeMs = dwMaxAgeMs;
  862. //
  863. // Make room for 0 bytes --- has the effect of clearing all the records
  864. // above the limit
  865. //
  866. MakeRoom(0);
  867. }
  868. CHierarchyCache* CForestCache::GetNamespaceCache(WString & wszNamespace)
  869. {
  870. CInCritSec ics(&m_cs);
  871. if (!m_bInit)
  872. return NULL;
  873. //
  874. // See if you can find one
  875. //
  876. TIterator it = m_map.find(wszNamespace);
  877. if(it != m_map.end())
  878. {
  879. it->second->AddRef();
  880. return it->second;
  881. }
  882. else
  883. {
  884. //
  885. // Not there --- create one
  886. //
  887. CHierarchyCache* pCache = new CHierarchyCache(this);
  888. if(pCache == NULL)
  889. return NULL;
  890. try
  891. {
  892. pCache->AddRef(); // this refcount is for the cache
  893. m_map[wszNamespace] = pCache;
  894. pCache->AddRef(); // this refcount is for the customers
  895. }
  896. catch (CX_MemoryException)
  897. {
  898. delete pCache; // despite the AddRef
  899. pCache = NULL;
  900. }
  901. return pCache;
  902. }
  903. }
  904. void CForestCache::ReleaseNamespaceCache(WString & wszNamespace,
  905. CHierarchyCache* pCache)
  906. {
  907. CInCritSec ics(&m_cs);
  908. //
  909. // this is a cleanup function, we always want this to be called
  910. //
  911. //if (!m_bInit)
  912. // return;
  913. //
  914. // Find it in the map
  915. //
  916. TIterator it = m_map.find(wszNamespace);
  917. if (it != m_map.end() && (it->second == pCache))
  918. {
  919. //
  920. // Last ref-count --- remove
  921. //
  922. if( 1 == pCache->Release())
  923. {
  924. m_map.erase(it);
  925. pCache->Release(); // this is the last one
  926. }
  927. }
  928. else
  929. {
  930. pCache->Release();
  931. }
  932. }
  933. void CForestCache::BeginTransaction()
  934. {
  935. m_bAssertedInTransaction = false;
  936. }
  937. bool CForestCache::MarkAsserted(CHierarchyCache* pCache, LPCWSTR wszClassName)
  938. {
  939. m_bAssertedInTransaction = true;
  940. return true;
  941. }
  942. void CForestCache::CommitTransaction()
  943. {
  944. m_bAssertedInTransaction = false;
  945. }
  946. void CForestCache::AbortTransaction()
  947. {
  948. if(m_bAssertedInTransaction)
  949. Clear();
  950. m_bAssertedInTransaction = false;
  951. }
  952. void CForestCache::Clear()
  953. {
  954. CInCritSec ics(&m_cs);
  955. if (!m_bInit)
  956. return;
  957. Flush();
  958. TIterator it = m_map.begin();
  959. while(it != m_map.end())
  960. {
  961. it->second->Clear();
  962. it++;
  963. }
  964. }
  965. HRESULT
  966. CForestCache::Deinitialize()
  967. {
  968. HANDLE hCurrentTimer;
  969. if (hCurrentTimer = InterlockedCompareExchangePointer(&m_hCurrentTimer,0,m_hCurrentTimer))
  970. {
  971. DeleteTimerQueueTimer( NULL, hCurrentTimer, NULL);
  972. }
  973. CInCritSec ics(&m_cs);
  974. if (!m_bInit)
  975. return S_OK;
  976. TIterator it = m_map.begin();
  977. while(it != m_map.end())
  978. {
  979. it->second->Clear();
  980. it->second->Release();
  981. it->second = NULL;
  982. it++;
  983. };
  984. m_map.erase(m_map.begin(),m_map.end());
  985. m_bInit = FALSE;
  986. return S_OK;
  987. }
  988. CForestCache::~CForestCache()
  989. {
  990. }