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.

688 lines
17 KiB

  1. //******************************************************************************
  2. //
  3. // AGGREG.CPP
  4. //
  5. // Copyright (C) 1996-1999 Microsoft Corporation
  6. //
  7. //******************************************************************************
  8. #include "precomp.h"
  9. #include "ess.h"
  10. #include "aggreg.h"
  11. IWbemClassObject* CEventAggregator::mstatic_pClass = NULL;
  12. CEventAggregator::CEventAggregator(CEssNamespace* pNamespace,
  13. CAbstractEventSink* pDest)
  14. : COwnedEventSink(pDest), m_aProperties(NULL), m_pNamespace(pNamespace),
  15. m_lNumProperties(0), m_pHavingTree(NULL)
  16. {
  17. }
  18. CEventAggregator::~CEventAggregator()
  19. {
  20. delete [] m_aProperties;
  21. delete m_pHavingTree;
  22. }
  23. HRESULT CEventAggregator::SetQueryExpression(CContextMetaData* pMeta,
  24. QL_LEVEL_1_RPN_EXPRESSION* pExpr)
  25. {
  26. HRESULT hres = WBEM_S_NO_ERROR;
  27. // Check that, if aggregation is required, tolerance is specified
  28. // ==============================================================
  29. if(!pExpr->bAggregated)
  30. {
  31. return WBEM_E_CRITICAL_ERROR; // internal error
  32. }
  33. if(pExpr->bAggregated && pExpr->AggregationTolerance.m_bExact)
  34. {
  35. ERRORTRACE((LOG_ESS, "Event aggregation query specified GROUP BY, but "
  36. "not GROUP WITHIN. This query is invalid and will not be acted "
  37. "upon\n"));
  38. return WBEM_E_MISSING_GROUP_WITHIN;
  39. }
  40. m_fTolerance = pExpr->AggregationTolerance.m_fTolerance;
  41. if(m_fTolerance < 0)
  42. return WBEM_E_INVALID_PARAMETER;
  43. // Check that all properties are valid
  44. // ===================================
  45. if(pExpr->bAggregateAll)
  46. {
  47. ERRORTRACE((LOG_ESS, "Aggregating based on all properties of an event "
  48. "is not supported\n"));
  49. return WBEM_E_MISSING_AGGREGATION_LIST;
  50. }
  51. // Get the class
  52. // =============
  53. _IWmiObject* pClass = NULL;
  54. pMeta->GetClass(pExpr->bsClassName, &pClass);
  55. if(pClass == NULL)
  56. {
  57. return WBEM_E_INVALID_CLASS;
  58. }
  59. CReleaseMe rm1(pClass);
  60. // Allocate the array to hold property names
  61. // =========================================
  62. delete [] m_aProperties;
  63. m_lNumProperties = pExpr->nNumAggregatedProperties;
  64. m_aProperties = new CPropertyName[m_lNumProperties];
  65. if(m_aProperties == NULL)
  66. return WBEM_E_OUT_OF_MEMORY;
  67. int i;
  68. for(i = 0; i < pExpr->nNumAggregatedProperties; i++)
  69. {
  70. CPropertyName& PropName = pExpr->pAggregatedPropertyNames[i];
  71. // Check existence
  72. // ===============
  73. CIMTYPE ct;
  74. if(FAILED(pClass->Get((LPWSTR)PropName.GetStringAt(0), 0, NULL,
  75. &ct, NULL)))
  76. {
  77. ERRORTRACE((LOG_ESS, "Invalid aggregation property %S --- not a "
  78. "member of class %S\n", (LPWSTR)PropName.GetStringAt(0),
  79. pExpr->bsClassName));
  80. return WBEM_E_INVALID_PROPERTY;
  81. }
  82. if(PropName.GetNumElements() > 1 && ct != CIM_OBJECT)
  83. {
  84. return WBEM_E_PROPERTY_NOT_AN_OBJECT;
  85. }
  86. if(PropName.GetNumElements() == 1 && ct == CIM_OBJECT)
  87. {
  88. return WBEM_E_AGGREGATING_BY_OBJECT;
  89. }
  90. m_aProperties[i] = PropName;
  91. }
  92. // Initialize post-evaluator with the data from the HAVING clause
  93. // ==============================================================
  94. QL_LEVEL_1_RPN_EXPRESSION* pHavingExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
  95. if(pHavingExpr == NULL)
  96. return WBEM_E_OUT_OF_MEMORY;
  97. pHavingExpr->SetClassName(L"__AggregateEvent");
  98. for(i = 0; i < pExpr->nNumHavingTokens; i++)
  99. {
  100. pHavingExpr->AddToken(pExpr->pArrayOfHavingTokens[i]);
  101. }
  102. delete m_pHavingTree;
  103. m_pHavingTree = new CEvalTree;
  104. if(m_pHavingTree == NULL)
  105. return WBEM_E_OUT_OF_MEMORY;
  106. hres = m_pHavingTree->CreateFromQuery(pMeta, pHavingExpr, 0, 0x7FFFFFFF);
  107. delete pHavingExpr;
  108. return hres;
  109. }
  110. HRESULT CEventAggregator::Initialize(IWbemServices* pNamespace)
  111. {
  112. return pNamespace->GetObject(L"__AggregateEvent", 0, GetCurrentEssContext(),
  113. &mstatic_pClass, NULL);
  114. }
  115. HRESULT CEventAggregator::Shutdown()
  116. {
  117. if(mstatic_pClass)
  118. mstatic_pClass->Release();
  119. mstatic_pClass = NULL;
  120. return WBEM_S_NO_ERROR;
  121. }
  122. HRESULT CEventAggregator::Indicate(long lNumEvents, IWbemEvent** apEvents,
  123. CEventContext* pContext)
  124. {
  125. HRESULT hresGlobal = S_OK;
  126. //
  127. // Note: we are going to lose the event's security context, but that is OK,
  128. // since the security check has already been done.
  129. //
  130. for(long i = 0; i < lNumEvents; i++)
  131. {
  132. HRESULT hres = Process(apEvents[i]);
  133. if(FAILED(hres))
  134. hresGlobal = hres;
  135. }
  136. return hresGlobal;
  137. }
  138. HRESULT CEventAggregator::Process(IWbemEvent* pEvent)
  139. {
  140. // Compute the event's aggregation vector
  141. // ======================================
  142. CVarVector* pvv = _new CVarVector;
  143. if(pvv == NULL)
  144. return WBEM_E_OUT_OF_MEMORY;
  145. HRESULT hres = ComputeAggregationVector(pEvent, *pvv);
  146. if(FAILED(hres))
  147. {
  148. delete pvv;
  149. return hres;
  150. }
  151. // Add event to the right bucket, creating one if needed.
  152. // THIS CALL ACQUIRES pvv!!!
  153. // ======================================================
  154. CBucket* pCreatedBucket = NULL;
  155. hres = AddEventToBucket(pEvent, pvv, &pCreatedBucket);
  156. if(FAILED(hres))
  157. {
  158. return hres;
  159. }
  160. if(pCreatedBucket)
  161. {
  162. // Create a timer instruction to empty this bucket
  163. // ===============================================
  164. CBucketInstruction* pInst =
  165. _new CBucketInstruction(this, pCreatedBucket, m_fTolerance);
  166. if(pInst == NULL)
  167. return WBEM_E_OUT_OF_MEMORY;
  168. pInst->AddRef();
  169. hres = m_pNamespace->GetTimerGenerator().Set(pInst,
  170. CWbemTime::GetZero());
  171. pInst->Release();
  172. if(FAILED(hres))
  173. {
  174. ERRORTRACE((LOG_ESS, "Failed to schedule aggregation instruction %p"
  175. "\n", pInst));
  176. return hres;
  177. }
  178. }
  179. return S_OK;
  180. }
  181. HRESULT CEventAggregator::AddEventToBucket(IWbemEvent* pEvent,
  182. ACQUIRE CVarVector* pvv, CBucket** ppCreatedBucket)
  183. {
  184. // Search for a matching bucket
  185. // ============================
  186. CInCritSec ics(&m_cs);
  187. BOOL bFound = FALSE;
  188. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  189. {
  190. CBucket* pBucket = m_apBuckets[i];
  191. if(pBucket->CompareTo(*pvv))
  192. {
  193. HRESULT hres = pBucket->AddEvent(pEvent);
  194. delete pvv;
  195. *ppCreatedBucket = NULL;
  196. return hres;
  197. }
  198. }
  199. // Need a _new bucket
  200. // ==================
  201. CBucket* pBucket = _new CBucket(pEvent, pvv); // takes over pvv
  202. if(pBucket == NULL)
  203. {
  204. delete pvv;
  205. return WBEM_E_OUT_OF_MEMORY;
  206. }
  207. if(m_apBuckets.Add(pBucket) < 0)
  208. {
  209. delete pBucket;
  210. return WBEM_E_OUT_OF_MEMORY;
  211. }
  212. *ppCreatedBucket = pBucket;
  213. return S_OK;
  214. }
  215. HRESULT CEventAggregator::ComputeAggregationVector(
  216. IN IWbemEvent* pEvent,
  217. OUT CVarVector& vv)
  218. {
  219. HRESULT hres;
  220. IWbemPropertySource* pPropSource = NULL;
  221. if(FAILED(pEvent->QueryInterface(IID_IWbemPropertySource,
  222. (void**)&pPropSource)))
  223. {
  224. return E_NOINTERFACE;
  225. }
  226. CReleaseMe rm1(pPropSource);
  227. // Go through all the properties and add their values to the array
  228. // ===============================================================
  229. for(int i = 0; i < m_lNumProperties; i++)
  230. {
  231. CPropertyName& PropName = m_aProperties[i];
  232. // Get the value
  233. // =============
  234. VARIANT v;
  235. VariantInit(&v);
  236. hres = pPropSource->GetPropertyValue(&PropName, 0, NULL, &v);
  237. if(FAILED(hres))
  238. return hres;
  239. // Add it to the array
  240. // ===================
  241. CVar* pVar = _new CVar;
  242. if(pVar == NULL)
  243. return WBEM_E_OUT_OF_MEMORY;
  244. pVar->SetVariant(&v);
  245. VariantClear(&v);
  246. if(vv.Add(pVar) < 0) // ACQUIRES pVar
  247. {
  248. delete pVar;
  249. return WBEM_E_OUT_OF_MEMORY;
  250. }
  251. }
  252. return WBEM_S_NO_ERROR;
  253. }
  254. HRESULT CEventAggregator::PostponeDispatchFirstBucket()
  255. {
  256. HRESULT hres;
  257. //
  258. // Construct the aggregate event while locked
  259. //
  260. IWbemEvent* pAggEvent = NULL;
  261. {
  262. CInCritSec ics(&m_cs);
  263. if(m_apBuckets.GetSize() == 0)
  264. return WBEM_S_FALSE;
  265. hres = m_apBuckets[0]->MakeAggregateEvent(&pAggEvent);
  266. if(FAILED(hres))
  267. return hres;
  268. m_apBuckets.RemoveAt(0);
  269. }
  270. CReleaseMe rm1(pAggEvent);
  271. return FireEvent(pAggEvent, false);
  272. }
  273. HRESULT CEventAggregator::DispatchBucket(CBucket* pBucket)
  274. {
  275. // Search for the bucket
  276. // =====================
  277. IWbemEvent* pAggEvent = NULL;
  278. {
  279. CInCritSec ics(&m_cs);
  280. BOOL bFound = FALSE;
  281. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  282. {
  283. if(m_apBuckets[i] == pBucket)
  284. {
  285. // Found it. Construct its event
  286. // =============================
  287. HRESULT hres = pBucket->MakeAggregateEvent(&pAggEvent);
  288. if(FAILED(hres))
  289. {
  290. ERRORTRACE((LOG_ESS, "Could not create an aggregate event: "
  291. "%X\n", hres));
  292. return hres;
  293. }
  294. // Delete the bucket
  295. // =================
  296. m_apBuckets.RemoveAt(i);
  297. break;
  298. }
  299. }
  300. }
  301. if(pAggEvent == NULL)
  302. {
  303. // No bucket!
  304. // ==========
  305. return WBEM_E_CRITICAL_ERROR; // internal error
  306. }
  307. CReleaseMe rm1(pAggEvent);
  308. //
  309. // We can fire this event directly on this thread, as it is ours
  310. //
  311. return FireEvent(pAggEvent, true);
  312. }
  313. HRESULT CEventAggregator::FireEvent(IWbemClassObject* pAggEvent,
  314. bool bRightNow)
  315. {
  316. // Constructed aggregate. Decorate it
  317. // ==================================
  318. m_pNamespace->DecorateObject(pAggEvent);
  319. // Check HAVING query
  320. // ==================
  321. BOOL bResult;
  322. CSortedArray aTrues;
  323. IWbemObjectAccess* pAccess;
  324. pAggEvent->QueryInterface(IID_IWbemObjectAccess, (void**)&pAccess);
  325. if(FAILED(m_pHavingTree->Evaluate(pAccess, aTrues)))
  326. {
  327. bResult = FALSE;
  328. }
  329. else
  330. {
  331. bResult = (aTrues.Size() > 0);
  332. }
  333. pAccess->Release();
  334. if(bResult)
  335. {
  336. // Get destination pointer, protecting from Deactivation
  337. // =====================================================
  338. CAbstractEventSink* pDest = NULL;
  339. {
  340. CInCritSec ics(&m_cs);
  341. pDest = m_pOwner;
  342. if(pDest)
  343. pDest->AddRef();
  344. }
  345. if(pDest)
  346. {
  347. if(bRightNow)
  348. pDest->Indicate(1, &pAggEvent, NULL);
  349. else
  350. PostponeIndicate(pDest, pAggEvent);
  351. pDest->Release();
  352. }
  353. }
  354. return WBEM_S_NO_ERROR;
  355. }
  356. HRESULT CEventAggregator::PostponeIndicate(CAbstractEventSink* pDest,
  357. IWbemEvent* pEvent)
  358. {
  359. CPostponedList* pList = GetCurrentPostponedEventList();
  360. if(pList == NULL)
  361. return pDest->Indicate(1, &pEvent, NULL);
  362. CPostponedIndicate* pReq = new CPostponedIndicate(pDest, pEvent);
  363. if(pReq == NULL)
  364. return WBEM_E_OUT_OF_MEMORY;
  365. return pList->AddRequest( m_pNamespace, pReq );
  366. }
  367. HRESULT CEventAggregator::Deactivate(bool bFire)
  368. {
  369. HRESULT hres;
  370. //
  371. // First remove all timer instructions that may still be scheduled.
  372. // Timer instructions have a ref-count on us (and therefore our owner),
  373. // so we may not disconnect until we are done
  374. //
  375. CAggregatorInstructionTest Test(this);
  376. CTimerGenerator& Generator = m_pNamespace->GetTimerGenerator();
  377. hres = Generator.Remove(&Test);
  378. //
  379. // If requested, fire all buckets, albeit not right now
  380. //
  381. if(bFire)
  382. PostponeFireAllBuckets();
  383. Disconnect();
  384. return hres;
  385. }
  386. HRESULT CEventAggregator::PostponeFireAllBuckets()
  387. {
  388. HRESULT hres;
  389. while((hres = PostponeDispatchFirstBucket()) != S_FALSE);
  390. if(FAILED(hres))
  391. return hres;
  392. else
  393. return WBEM_S_NO_ERROR;
  394. }
  395. HRESULT CEventAggregator::CopyStateTo(CEventAggregator* pDest)
  396. {
  397. CInCritSec ics(&m_cs);
  398. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  399. {
  400. CBucket* pNewBucket = m_apBuckets[i]->Clone();
  401. if(pNewBucket == NULL)
  402. return WBEM_E_OUT_OF_MEMORY;
  403. if(pDest->m_apBuckets.Add(pNewBucket) < 0)
  404. {
  405. delete pNewBucket;
  406. return WBEM_E_OUT_OF_MEMORY;
  407. }
  408. }
  409. return S_OK;
  410. }
  411. CEventAggregator::CBucket::CBucket(IWbemEvent* pEvent,
  412. CVarVector* pvvData)
  413. : m_pvvData(pvvData), m_dwCount(1), m_pRepresentative(NULL)
  414. {
  415. pEvent->Clone(&m_pRepresentative);
  416. }
  417. CEventAggregator::CBucket::~CBucket()
  418. {
  419. delete m_pvvData;
  420. if(m_pRepresentative)
  421. m_pRepresentative->Release();
  422. }
  423. BOOL CEventAggregator::CBucket::CompareTo(CVarVector& vv)
  424. {
  425. return m_pvvData->CompareTo(vv, TRUE);
  426. }
  427. HRESULT CEventAggregator::CBucket::AddEvent(IWbemEvent* pEvent)
  428. {
  429. // Just increment the number of events in the bucket
  430. // =================================================
  431. m_dwCount++;
  432. return WBEM_S_NO_ERROR;
  433. }
  434. HRESULT CEventAggregator::CBucket::MakeAggregateEvent(
  435. IWbemClassObject** ppAggregateEvent) NOCS
  436. {
  437. HRESULT hres;
  438. // Create an instance of the aggregate event class
  439. // ===============================================
  440. if(mstatic_pClass == NULL)
  441. return WBEM_E_SHUTTING_DOWN;
  442. IWbemClassObject* pAgg;
  443. hres = mstatic_pClass->SpawnInstance(0, &pAgg);
  444. if(FAILED(hres)) return hres;
  445. // Fill in the number of events in the bucket
  446. // ==========================================
  447. VARIANT v;
  448. VariantInit(&v);
  449. V_VT(&v) = VT_I4;
  450. V_I4(&v) = (long)m_dwCount;
  451. hres = pAgg->Put(L"NumberOfEvents", 0, &v, NULL);
  452. if(FAILED(hres))
  453. {
  454. pAgg->Release();
  455. return hres;
  456. }
  457. // Fill in the representative
  458. // ==========================
  459. V_VT(&v) = VT_EMBEDDED_OBJECT;
  460. V_EMBEDDED_OBJECT(&v) = m_pRepresentative;
  461. hres = pAgg->Put(L"Representative", 0, &v, NULL);
  462. if(FAILED(hres))
  463. {
  464. pAgg->Release();
  465. return hres;
  466. }
  467. *ppAggregateEvent = pAgg;
  468. return WBEM_S_NO_ERROR;
  469. }
  470. CEventAggregator::CBucket* CEventAggregator::CBucket::Clone()
  471. {
  472. CVarVector* pNewVv = new CVarVector(*m_pvvData);
  473. if(pNewVv == NULL)
  474. return NULL;
  475. CBucket* pNewBucket = new CBucket(m_pRepresentative, pNewVv);
  476. if(pNewBucket == NULL)
  477. {
  478. delete pNewVv;
  479. return NULL;
  480. }
  481. pNewBucket->m_dwCount = m_dwCount;
  482. return pNewBucket;
  483. }
  484. CEventAggregator::CBucketInstruction::CBucketInstruction(
  485. CEventAggregator* pAggregator, CBucket* pBucket, double fSTimeout)
  486. : m_pAggregator(pAggregator), m_pBucket(pBucket), m_lRefCount(0)
  487. {
  488. m_Interval.SetMilliseconds(fSTimeout * 1000);
  489. m_pAggregator->AddRef();
  490. }
  491. CEventAggregator::CBucketInstruction::~CBucketInstruction()
  492. {
  493. m_pAggregator->Release();
  494. }
  495. void CEventAggregator::CBucketInstruction::AddRef()
  496. {
  497. InterlockedIncrement(&m_lRefCount);
  498. }
  499. void CEventAggregator::CBucketInstruction::Release()
  500. {
  501. if(InterlockedDecrement(&m_lRefCount) == 0)
  502. delete this;
  503. }
  504. int CEventAggregator::CBucketInstruction::GetInstructionType()
  505. {
  506. return INSTTYPE_AGGREGATION;
  507. }
  508. CWbemTime CEventAggregator::CBucketInstruction::GetNextFiringTime(
  509. CWbemTime LastFiringTime, OUT long* plFiringCount) const
  510. {
  511. // Only fires once.
  512. // ================
  513. return CWbemTime::GetInfinity();
  514. }
  515. CWbemTime CEventAggregator::CBucketInstruction::GetFirstFiringTime() const
  516. {
  517. // In "interval" ms from now
  518. // =========================
  519. return CWbemTime::GetCurrentTime() + m_Interval;
  520. }
  521. HRESULT CEventAggregator::CBucketInstruction::Fire(long lNumTimes,
  522. CWbemTime NextFiringTime)
  523. {
  524. m_pAggregator->DispatchBucket(m_pBucket);
  525. return WBEM_S_NO_ERROR;
  526. }
  527. BOOL CEventAggregator::CAggregatorInstructionTest::
  528. operator()(
  529. CTimerInstruction* pToTest)
  530. {
  531. if(pToTest->GetInstructionType() == INSTTYPE_AGGREGATION)
  532. {
  533. CBucketInstruction* pInst = (CBucketInstruction*)pToTest;
  534. return (pInst->GetAggregator() == m_pAgg);
  535. }
  536. else return FALSE;
  537. }