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.

692 lines
18 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);
  107. delete pHavingExpr;
  108. return hres;
  109. }
  110. HRESULT CEventAggregator::Initialize(IWbemServices* pNamespace)
  111. {
  112. return pNamespace->GetObject( CWbemBSTR( L"__AggregateEvent" ),
  113. 0,
  114. GetCurrentEssContext(),
  115. &mstatic_pClass, NULL );
  116. }
  117. HRESULT CEventAggregator::Shutdown()
  118. {
  119. if(mstatic_pClass)
  120. mstatic_pClass->Release();
  121. mstatic_pClass = NULL;
  122. return WBEM_S_NO_ERROR;
  123. }
  124. HRESULT CEventAggregator::Indicate(long lNumEvents, IWbemEvent** apEvents,
  125. CEventContext* pContext)
  126. {
  127. HRESULT hresGlobal = S_OK;
  128. //
  129. // Note: we are going to lose the event's security context, but that is OK,
  130. // since the security check has already been done.
  131. //
  132. for(long i = 0; i < lNumEvents; i++)
  133. {
  134. HRESULT hres = Process(apEvents[i]);
  135. if(FAILED(hres))
  136. hresGlobal = hres;
  137. }
  138. return hresGlobal;
  139. }
  140. HRESULT CEventAggregator::Process(IWbemEvent* pEvent)
  141. {
  142. // Compute the event's aggregation vector
  143. // ======================================
  144. CVarVector* pvv = _new CVarVector;
  145. if(pvv == NULL)
  146. return WBEM_E_OUT_OF_MEMORY;
  147. HRESULT hres = ComputeAggregationVector(pEvent, *pvv);
  148. if(FAILED(hres))
  149. {
  150. delete pvv;
  151. return hres;
  152. }
  153. // Add event to the right bucket, creating one if needed.
  154. // THIS CALL ACQUIRES pvv!!!
  155. // ======================================================
  156. CBucket* pCreatedBucket = NULL;
  157. hres = AddEventToBucket(pEvent, pvv, &pCreatedBucket);
  158. if(FAILED(hres))
  159. {
  160. return hres;
  161. }
  162. if(pCreatedBucket)
  163. {
  164. // Create a timer instruction to empty this bucket
  165. // ===============================================
  166. CBucketInstruction* pInst =
  167. _new CBucketInstruction(this, pCreatedBucket, m_fTolerance);
  168. if(pInst == NULL)
  169. return WBEM_E_OUT_OF_MEMORY;
  170. pInst->AddRef();
  171. hres = m_pNamespace->GetTimerGenerator().Set(pInst,
  172. CWbemTime::GetZero());
  173. pInst->Release();
  174. if(FAILED(hres))
  175. {
  176. ERRORTRACE((LOG_ESS, "Failed to schedule aggregation instruction %p"
  177. "\n", pInst));
  178. return hres;
  179. }
  180. }
  181. return S_OK;
  182. }
  183. HRESULT CEventAggregator::AddEventToBucket(IWbemEvent* pEvent,
  184. ACQUIRE CVarVector* pvv, CBucket** ppCreatedBucket)
  185. {
  186. // Search for a matching bucket
  187. // ============================
  188. CInCritSec ics(&m_cs);
  189. BOOL bFound = FALSE;
  190. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  191. {
  192. CBucket* pBucket = m_apBuckets[i];
  193. if(pBucket->CompareTo(*pvv))
  194. {
  195. HRESULT hres = pBucket->AddEvent(pEvent);
  196. delete pvv;
  197. *ppCreatedBucket = NULL;
  198. return hres;
  199. }
  200. }
  201. // Need a _new bucket
  202. // ==================
  203. CBucket* pBucket = _new CBucket(pEvent, pvv); // takes over pvv
  204. if(pBucket == NULL)
  205. {
  206. delete pvv;
  207. return WBEM_E_OUT_OF_MEMORY;
  208. }
  209. if(m_apBuckets.Add(pBucket) < 0)
  210. {
  211. delete pBucket;
  212. return WBEM_E_OUT_OF_MEMORY;
  213. }
  214. *ppCreatedBucket = pBucket;
  215. return S_OK;
  216. }
  217. HRESULT CEventAggregator::ComputeAggregationVector(
  218. IN IWbemEvent* pEvent,
  219. OUT CVarVector& vv)
  220. {
  221. HRESULT hres;
  222. IWbemPropertySource* pPropSource = NULL;
  223. if(FAILED(pEvent->QueryInterface(IID_IWbemPropertySource,
  224. (void**)&pPropSource)))
  225. {
  226. return E_NOINTERFACE;
  227. }
  228. CReleaseMe rm1(pPropSource);
  229. // Go through all the properties and add their values to the array
  230. // ===============================================================
  231. for(int i = 0; i < m_lNumProperties; i++)
  232. {
  233. CPropertyName& PropName = m_aProperties[i];
  234. // Get the value
  235. // =============
  236. VARIANT v;
  237. VariantInit(&v);
  238. hres = pPropSource->GetPropertyValue(&PropName, 0, NULL, &v);
  239. if(FAILED(hres))
  240. return hres;
  241. // Add it to the array
  242. // ===================
  243. CVar* pVar = _new CVar;
  244. if(pVar == NULL)
  245. return WBEM_E_OUT_OF_MEMORY;
  246. pVar->SetVariant(&v);
  247. VariantClear(&v);
  248. if(vv.Add(pVar) < 0) // ACQUIRES pVar
  249. {
  250. delete pVar;
  251. return WBEM_E_OUT_OF_MEMORY;
  252. }
  253. }
  254. return WBEM_S_NO_ERROR;
  255. }
  256. HRESULT CEventAggregator::PostponeDispatchFirstBucket()
  257. {
  258. HRESULT hres;
  259. //
  260. // Construct the aggregate event while locked
  261. //
  262. IWbemEvent* pAggEvent = NULL;
  263. {
  264. CInCritSec ics(&m_cs);
  265. if(m_apBuckets.GetSize() == 0)
  266. return WBEM_S_FALSE;
  267. hres = m_apBuckets[0]->MakeAggregateEvent(&pAggEvent);
  268. if(FAILED(hres))
  269. return hres;
  270. m_apBuckets.RemoveAt(0);
  271. }
  272. CReleaseMe rm1(pAggEvent);
  273. return FireEvent(pAggEvent, false);
  274. }
  275. HRESULT CEventAggregator::DispatchBucket(CBucket* pBucket)
  276. {
  277. // Search for the bucket
  278. // =====================
  279. IWbemEvent* pAggEvent = NULL;
  280. {
  281. CInCritSec ics(&m_cs);
  282. BOOL bFound = FALSE;
  283. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  284. {
  285. if(m_apBuckets[i] == pBucket)
  286. {
  287. // Found it. Construct its event
  288. // =============================
  289. HRESULT hres = pBucket->MakeAggregateEvent(&pAggEvent);
  290. if(FAILED(hres))
  291. {
  292. ERRORTRACE((LOG_ESS, "Could not create an aggregate event: "
  293. "%X\n", hres));
  294. return hres;
  295. }
  296. // Delete the bucket
  297. // =================
  298. m_apBuckets.RemoveAt(i);
  299. break;
  300. }
  301. }
  302. }
  303. if(pAggEvent == NULL)
  304. {
  305. // No bucket!
  306. // ==========
  307. return WBEM_E_CRITICAL_ERROR; // internal error
  308. }
  309. CReleaseMe rm1(pAggEvent);
  310. //
  311. // We can fire this event directly on this thread, as it is ours
  312. //
  313. return FireEvent(pAggEvent, true);
  314. }
  315. HRESULT CEventAggregator::FireEvent(IWbemClassObject* pAggEvent,
  316. bool bRightNow)
  317. {
  318. // Constructed aggregate. Decorate it
  319. // ==================================
  320. HRESULT hrDec = m_pNamespace->DecorateObject(pAggEvent);
  321. if (FAILED(hrDec))
  322. return hrDec;
  323. // Check HAVING query
  324. // ==================
  325. BOOL bResult;
  326. CSortedArray aTrues;
  327. IWbemObjectAccess* pAccess;
  328. pAggEvent->QueryInterface(IID_IWbemObjectAccess, (void**)&pAccess);
  329. if(FAILED(m_pHavingTree->Evaluate(pAccess, aTrues)))
  330. {
  331. bResult = FALSE;
  332. }
  333. else
  334. {
  335. bResult = (aTrues.Size() > 0);
  336. }
  337. pAccess->Release();
  338. if(bResult)
  339. {
  340. // Get destination pointer, protecting from Deactivation
  341. // =====================================================
  342. CAbstractEventSink* pDest = NULL;
  343. {
  344. CInCritSec ics(&m_cs);
  345. pDest = m_pOwner;
  346. if(pDest)
  347. pDest->AddRef();
  348. }
  349. if(pDest)
  350. {
  351. if(bRightNow)
  352. pDest->Indicate(1, &pAggEvent, NULL);
  353. else
  354. PostponeIndicate(pDest, pAggEvent);
  355. pDest->Release();
  356. }
  357. }
  358. return WBEM_S_NO_ERROR;
  359. }
  360. HRESULT CEventAggregator::PostponeIndicate(CAbstractEventSink* pDest,
  361. IWbemEvent* pEvent)
  362. {
  363. CPostponedList* pList = GetCurrentPostponedEventList();
  364. if(pList == NULL)
  365. return pDest->Indicate(1, &pEvent, NULL);
  366. CPostponedIndicate* pReq = new CPostponedIndicate(pDest, pEvent);
  367. if(pReq == NULL)
  368. return WBEM_E_OUT_OF_MEMORY;
  369. return pList->AddRequest( m_pNamespace, pReq );
  370. }
  371. HRESULT CEventAggregator::Deactivate(bool bFire)
  372. {
  373. HRESULT hres;
  374. //
  375. // First remove all timer instructions that may still be scheduled.
  376. // Timer instructions have a ref-count on us (and therefore our owner),
  377. // so we may not disconnect until we are done
  378. //
  379. CAggregatorInstructionTest Test(this);
  380. CTimerGenerator& Generator = m_pNamespace->GetTimerGenerator();
  381. hres = Generator.Remove(&Test);
  382. //
  383. // If requested, fire all buckets, albeit not right now
  384. //
  385. if(bFire)
  386. PostponeFireAllBuckets();
  387. Disconnect();
  388. return hres;
  389. }
  390. HRESULT CEventAggregator::PostponeFireAllBuckets()
  391. {
  392. HRESULT hres;
  393. while((hres = PostponeDispatchFirstBucket()) != S_FALSE);
  394. if(FAILED(hres))
  395. return hres;
  396. else
  397. return WBEM_S_NO_ERROR;
  398. }
  399. HRESULT CEventAggregator::CopyStateTo(CEventAggregator* pDest)
  400. {
  401. CInCritSec ics(&m_cs);
  402. for(int i = 0; i < m_apBuckets.GetSize(); i++)
  403. {
  404. CBucket* pNewBucket = m_apBuckets[i]->Clone();
  405. if(pNewBucket == NULL)
  406. return WBEM_E_OUT_OF_MEMORY;
  407. if(pDest->m_apBuckets.Add(pNewBucket) < 0)
  408. {
  409. delete pNewBucket;
  410. return WBEM_E_OUT_OF_MEMORY;
  411. }
  412. }
  413. return S_OK;
  414. }
  415. CEventAggregator::CBucket::CBucket(IWbemEvent* pEvent,
  416. CVarVector* pvvData)
  417. : m_pvvData(pvvData), m_dwCount(1), m_pRepresentative(NULL)
  418. {
  419. pEvent->Clone(&m_pRepresentative);
  420. }
  421. CEventAggregator::CBucket::~CBucket()
  422. {
  423. delete m_pvvData;
  424. if(m_pRepresentative)
  425. m_pRepresentative->Release();
  426. }
  427. BOOL CEventAggregator::CBucket::CompareTo(CVarVector& vv)
  428. {
  429. return m_pvvData->CompareTo(vv, TRUE);
  430. }
  431. HRESULT CEventAggregator::CBucket::AddEvent(IWbemEvent* pEvent)
  432. {
  433. // Just increment the number of events in the bucket
  434. // =================================================
  435. m_dwCount++;
  436. return WBEM_S_NO_ERROR;
  437. }
  438. HRESULT CEventAggregator::CBucket::MakeAggregateEvent(
  439. IWbemClassObject** ppAggregateEvent) NOCS
  440. {
  441. HRESULT hres;
  442. // Create an instance of the aggregate event class
  443. // ===============================================
  444. if(mstatic_pClass == NULL)
  445. return WBEM_E_SHUTTING_DOWN;
  446. IWbemClassObject* pAgg;
  447. hres = mstatic_pClass->SpawnInstance(0, &pAgg);
  448. if(FAILED(hres)) return hres;
  449. // Fill in the number of events in the bucket
  450. // ==========================================
  451. VARIANT v;
  452. VariantInit(&v);
  453. V_VT(&v) = VT_I4;
  454. V_I4(&v) = (long)m_dwCount;
  455. hres = pAgg->Put(L"NumberOfEvents", 0, &v, NULL);
  456. if(FAILED(hres))
  457. {
  458. pAgg->Release();
  459. return hres;
  460. }
  461. // Fill in the representative
  462. // ==========================
  463. V_VT(&v) = VT_EMBEDDED_OBJECT;
  464. V_EMBEDDED_OBJECT(&v) = m_pRepresentative;
  465. hres = pAgg->Put(L"Representative", 0, &v, NULL);
  466. if(FAILED(hres))
  467. {
  468. pAgg->Release();
  469. return hres;
  470. }
  471. *ppAggregateEvent = pAgg;
  472. return WBEM_S_NO_ERROR;
  473. }
  474. CEventAggregator::CBucket* CEventAggregator::CBucket::Clone()
  475. {
  476. CVarVector* pNewVv = new CVarVector(*m_pvvData);
  477. if(pNewVv == NULL)
  478. return NULL;
  479. CBucket* pNewBucket = new CBucket(m_pRepresentative, pNewVv);
  480. if(pNewBucket == NULL)
  481. {
  482. delete pNewVv;
  483. return NULL;
  484. }
  485. pNewBucket->m_dwCount = m_dwCount;
  486. return pNewBucket;
  487. }
  488. CEventAggregator::CBucketInstruction::CBucketInstruction(
  489. CEventAggregator* pAggregator, CBucket* pBucket, double fSTimeout)
  490. : m_pAggregator(pAggregator), m_pBucket(pBucket), m_lRefCount(0)
  491. {
  492. m_Interval.SetMilliseconds(fSTimeout * 1000);
  493. m_pAggregator->AddRef();
  494. }
  495. CEventAggregator::CBucketInstruction::~CBucketInstruction()
  496. {
  497. m_pAggregator->Release();
  498. }
  499. void CEventAggregator::CBucketInstruction::AddRef()
  500. {
  501. InterlockedIncrement(&m_lRefCount);
  502. }
  503. void CEventAggregator::CBucketInstruction::Release()
  504. {
  505. if(InterlockedDecrement(&m_lRefCount) == 0)
  506. delete this;
  507. }
  508. int CEventAggregator::CBucketInstruction::GetInstructionType()
  509. {
  510. return INSTTYPE_AGGREGATION;
  511. }
  512. CWbemTime CEventAggregator::CBucketInstruction::GetNextFiringTime(
  513. CWbemTime LastFiringTime, OUT long* plFiringCount) const
  514. {
  515. // Only fires once.
  516. // ================
  517. return CWbemTime::GetInfinity();
  518. }
  519. CWbemTime CEventAggregator::CBucketInstruction::GetFirstFiringTime() const
  520. {
  521. // In "interval" ms from now
  522. // =========================
  523. return CWbemTime::GetCurrentTime() + m_Interval;
  524. }
  525. HRESULT CEventAggregator::CBucketInstruction::Fire(long lNumTimes,
  526. CWbemTime NextFiringTime)
  527. {
  528. m_pAggregator->DispatchBucket(m_pBucket);
  529. return WBEM_S_NO_ERROR;
  530. }
  531. BOOL CEventAggregator::CAggregatorInstructionTest::
  532. operator()(
  533. CTimerInstruction* pToTest)
  534. {
  535. if(pToTest->GetInstructionType() == INSTTYPE_AGGREGATION)
  536. {
  537. CBucketInstruction* pInst = (CBucketInstruction*)pToTest;
  538. return (pInst->GetAggregator() == m_pAgg);
  539. }
  540. else return FALSE;
  541. }