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.

1299 lines
30 KiB

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