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.

1217 lines
27 KiB

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