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.

2225 lines
76 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. INTERNALMERGER.CPP
  5. Abstract:
  6. CInternalMerger class.
  7. History:
  8. 30-Nov-00 sanjes Created.
  9. --*/
  10. #include "precomp.h"
  11. #pragma warning (disable : 4786)
  12. #include <wbemcore.h>
  13. #include <map>
  14. #include <vector>
  15. #include <genutils.h>
  16. #include <oahelp.inl>
  17. #include <wqllex.h>
  18. #include "wmimerger.h"
  19. #include "internalmerger.h"
  20. static long g_lNumMergers = 0L;
  21. //***************************************************************************
  22. //
  23. // class CInternalMerger
  24. //
  25. // This class is a 'reverse fork'. It consumes two sinks and outputs
  26. // one. Its purpose is to merge instances of the same key in a given
  27. // dynasty. Each CInternalMerger has two inputs, (a) instances of the class
  28. // in question, (b) instances of from another Merger representing
  29. // instances of subclasses. Given classes A,B:A,C:B, for example,
  30. // where "<--" is a sink:
  31. //
  32. // | own:Instances of A
  33. // <---| | own:Instances of B
  34. // | child: <--------|
  35. // | child:Instances of C
  36. //
  37. //
  38. // The two input sinks for CInternalMerger are <m_pOwnSink> which receives
  39. // instances from the provider for "A", for example, and the <m_pChildSink>
  40. // which receives instances from the underyling Merger.
  41. //
  42. // The mergers operate asynchronously to each other. Therefore,
  43. // the instances for A may arrive in its CInternalMerger sink before instances
  44. // of the child classes have arrived in theirs.
  45. //
  46. // As objects arrive in the owning CInternalMerger for a class, AddOwnObject()
  47. // is called. As objects arrive from a child sink, AddChildObject()
  48. // is called. In either case, if the object with a given key
  49. // arrives for the first time, it is simply added to the map. If
  50. // it is already there (via a key lookup), then a merge is performed
  51. // via CWbemInstance::AsymmetricMerge. Immediately after this merge,
  52. // the object is dispatched up to the next parent sink via the parent's
  53. // AddChildObject and removed from the map.
  54. //
  55. // Note that in a class hierarchy {A,B:A,C:B} an enumeration/query is
  56. // performed only against the classes in the CDynasty referenced in
  57. // the query. This logic occurs in CQueryEngine::EvaluateSubQuery.
  58. // For example, if "select * from B" is the query, only queries
  59. // for B and C are performed. The CInternalMerger logic will do individual
  60. // 'get object' calls for any instances needed in A to complete
  61. // the merged B/C instances while merging is taking place.
  62. //
  63. //***************************************************************************
  64. #pragma warning(disable:4355)
  65. static long g_lNumInternalMergers = 0L;
  66. CInternalMerger::CInternalMerger(
  67. CWmiMergerRecord* pWmiMergerRecord,
  68. CMergerSink* pDest,
  69. CWbemClass* pOwnClass,
  70. CWbemNamespace* pNamespace,
  71. IWbemContext* pContext
  72. )
  73. : m_pDest(pDest), m_bOwnDone(FALSE),
  74. m_bChildrenDone(FALSE), m_pNamespace(pNamespace), m_pContext(pContext),
  75. m_pOwnClass(pOwnClass), m_bDerivedFromTarget(TRUE), m_lRef(0),
  76. m_pSecurity(NULL), m_pWmiMergerRecord( pWmiMergerRecord ),
  77. m_pOwnSink( NULL ), m_pChildSink( NULL ), m_hErrorRes( WBEM_S_NO_ERROR ),
  78. m_lTotalObjectData( 0L ), m_Throttler()
  79. {
  80. // We do want to AddRef() in this case, since we will potentially be the only ones holding
  81. // onto the destination sink. In this case, our child and owner sink will AddRef() us. When
  82. // they perform a final release on us, we will release the destination sink. If, on the other
  83. // hand we are outright deleted if this value is non-NULL we will clean up there as well
  84. m_pDest->AddRef();
  85. if(m_pContext)
  86. m_pContext->AddRef();
  87. if(m_pNamespace)
  88. m_pNamespace->AddRef();
  89. if(m_pOwnClass)
  90. {
  91. m_pOwnClass->AddRef();
  92. CVar v;
  93. if (SUCCEEDED(pOwnClass->GetClassName(&v)))
  94. m_wsClass = v.GetLPWSTR();
  95. // delegate Initialzie to check
  96. }
  97. // Retrieve call security. Need to create a copy for use on another thread
  98. // =======================================================================
  99. m_pSecurity = CWbemCallSecurity::MakeInternalCopyOfThread();
  100. // Keep the count up to date
  101. InterlockedIncrement( &g_lNumInternalMergers );
  102. }
  103. //***************************************************************************
  104. //
  105. //***************************************************************************
  106. CInternalMerger::~CInternalMerger()
  107. {
  108. if ( NULL != m_pDest )
  109. {
  110. m_pDest->Release();
  111. m_pDest = NULL;
  112. }
  113. // Map should be empty whenever we destruct
  114. _DBG_ASSERT( m_map.size() == 0 );
  115. _DBG_ASSERT( m_lTotalObjectData == 0L );
  116. if(m_pNamespace)
  117. m_pNamespace->Release();
  118. if(m_pContext)
  119. m_pContext->Release();
  120. if(m_pOwnClass)
  121. m_pOwnClass->Release();
  122. if(m_pSecurity)
  123. m_pSecurity->Release();
  124. // Keep the count up to date
  125. InterlockedDecrement( &g_lNumInternalMergers );
  126. }
  127. //***************************************************************************
  128. //
  129. //***************************************************************************
  130. long CInternalMerger::AddRef()
  131. {
  132. return InterlockedIncrement(&m_lRef);
  133. }
  134. //***************************************************************************
  135. //
  136. //***************************************************************************
  137. long CInternalMerger::Release()
  138. {
  139. long lRef = InterlockedDecrement(&m_lRef);
  140. // On Final Release, we will clear up the actual destination sink
  141. if(lRef == 0)
  142. {
  143. // Enter the critical section, save off the sink pointer in a
  144. // temporary variable, set the member to NULL and then release
  145. // the sink. This will prevent reentrancy issues with the merger
  146. // (e.g. during a Cancel).
  147. Enter();
  148. CMergerSink* pSink = m_pDest;
  149. m_pDest = NULL;
  150. Leave();
  151. pSink->Release();
  152. }
  153. return lRef;
  154. }
  155. HRESULT CInternalMerger::Initialize( void )
  156. {
  157. if (m_pOwnClass)
  158. if (NULL == (WCHAR *)m_wsClass)
  159. return WBEM_E_OUT_OF_MEMORY;
  160. HRESULT hr = m_Throttler.Initialize();
  161. if ( SUCCEEDED( hr ) )
  162. {
  163. hr = m_pWmiMergerRecord->GetWmiMerger()->CreateMergingSink( eMergerOwnSink, NULL, this, (CMergerSink**) &m_pOwnSink );
  164. if ( SUCCEEDED( hr ) )
  165. {
  166. hr = m_pWmiMergerRecord->GetWmiMerger()->CreateMergingSink( eMergerChildSink, NULL, this, (CMergerSink**) &m_pChildSink );
  167. }
  168. } // IF throttler initialized
  169. return hr;
  170. }
  171. //***************************************************************************
  172. //
  173. //***************************************************************************
  174. void CInternalMerger::GetKey(IWbemClassObject* pObj, WString& wsKey)
  175. {
  176. LPWSTR wszRelPath = ((CWbemInstance*)pObj)->GetRelPath();
  177. if (wszRelPath == NULL)
  178. {
  179. ERRORTRACE((LOG_WBEMCORE, "Object with no path submitted to a merge\n"));
  180. wsKey.Empty();
  181. return;
  182. }
  183. WCHAR* pwcDot = wcschr(wszRelPath, L'.');
  184. if (pwcDot == NULL)
  185. {
  186. ERRORTRACE((LOG_WBEMCORE, "Object with invalid path %S submitted to a merge\n",
  187. wszRelPath));
  188. wsKey.Empty();
  189. // Clean up the path
  190. delete [] wszRelPath;
  191. return;
  192. }
  193. wsKey = pwcDot+1;
  194. delete [] wszRelPath;
  195. }
  196. //***************************************************************************
  197. //
  198. //***************************************************************************
  199. void CInternalMerger::SetIsDerivedFromTarget(BOOL bIs)
  200. {
  201. m_bDerivedFromTarget = bIs;
  202. if (!bIs)
  203. {
  204. // We will need our OwnSink for GetObject calls
  205. // ============================================
  206. m_pOwnSink->AddRef();
  207. }
  208. }
  209. //
  210. // The algorithm for reporting memory usage is as follows:
  211. //
  212. // Lowest level indicate (i.e. the one coming in from a provider), will iterate
  213. // all objects sent down by the provider and report them to the arbitrator. At
  214. // the end of processing we will report the negative of this value. Reason for
  215. // this is that we will be holding onto all of these objects for the length of
  216. // the function, and may get throttled at any time.
  217. //
  218. // During processing, we will account for objects added to the map, and removed
  219. // from the map. When we remove objects from the map, we add them to an array
  220. // which we indicate. Usually we merge objects, sometimes we pass the objects
  221. // straight down. We need to account for these objects during the call to
  222. // indicate, so we will total these and report usage BEFORE calling Indicate.
  223. // After Indicate returns we will remove their usage, since we will be releasing
  224. // them and hence no longer care about them.
  225. //
  226. // Except for the case of the lowest level indicate, we will not account for
  227. // pass-through objects - those that are sent in and sent out. It is assumed
  228. // that the calling function has accounted for these objects.
  229. //
  230. // There will be small windows where a single object may get reported multiple
  231. // times. This would occur if we reported a new object prior to indicate,
  232. // then in the call to indicate the merger added to the map, or the finalizer
  233. // added to its list. When the call returns, we will report removal. The object
  234. // may actually get removed on another thread, but if we get throttled, we
  235. // still need to account for it. In tight memory conditions if multiple threads
  236. // cause addition/removal at jus tthe right times and are then throttled, we will
  237. // get stuck sleeping and each could report an object multiple times. However, this
  238. // should only occur in relatively stressful conditions, and should be rare.
  239. //
  240. //***************************************************************************
  241. //
  242. //***************************************************************************
  243. HRESULT CInternalMerger::IndicateArrayAndThrottle(
  244. long lObjectCount, CRefedPointerArray<IWbemClassObject>* pObjArray,
  245. CWStringArray* pwsKeyArray, long lMapAdjustmentSize, long lNewObjectSize, bool bThrottle,
  246. bool bParent, long* plNumIndicated )
  247. {
  248. // In this case, we report the size of the objects as they were adjusted in the map
  249. // in addition to new objects we created. The new objects will be released after
  250. // we indicate, so we will account for them post-indicate, since we will no longer
  251. // be holding onto them
  252. HRESULT hRes = ReportMemoryUsage( lMapAdjustmentSize);
  253. // Use scoped memory cleanup to handle the new objects
  254. // Note that in the event of an exception this will cleanup properly
  255. CScopedMemoryUsage scopedMemUsage( this );
  256. if ( SUCCEEDED( hRes ) )
  257. {
  258. hRes = scopedMemUsage.ReportMemoryUsage( lNewObjectSize );
  259. }
  260. // If the value is > 0L, and we succeeded, we can go ahead indicate the objects now.
  261. // The refed pointer array should properly clean up.
  262. if ( SUCCEEDED( hRes ) )
  263. {
  264. // If we have "own instances" in the array, we need to retrieve those objects.
  265. // Each is retrieved individually
  266. if ( NULL != pwsKeyArray && pwsKeyArray->Size() > 0 )
  267. {
  268. for ( int x = 0; SUCCEEDED( hRes ) && x < pwsKeyArray->Size(); x++ )
  269. {
  270. IWbemClassObject* pMergedInstance = NULL;
  271. hRes = GetOwnInstance( pwsKeyArray->GetAt( x ), &pMergedInstance );
  272. CReleaseMe rm( pMergedInstance );
  273. // If we retrieved a merged instance at this time, we should place it in
  274. // the array for indicating
  275. if ( SUCCEEDED( hRes ) && NULL != pMergedInstance )
  276. {
  277. // Handle object size here. This is a merged object, so we must
  278. // account for it in the size variable
  279. long lObjSize = 0L;
  280. hRes = GetObjectLength( pMergedInstance, &lObjSize );
  281. if ( SUCCEEDED( hRes ) )
  282. {
  283. if ( pObjArray->Add( pMergedInstance ) < 0L )
  284. {
  285. hRes = WBEM_E_OUT_OF_MEMORY;
  286. ERRORTRACE((LOG_WBEMCORE, "Add to array failed in IndicateArrayAndThrottle, hresult is 0x%x",
  287. hRes));
  288. continue;
  289. }
  290. lNewObjectSize += lObjSize;
  291. lObjectCount++;
  292. // Report size now, since each call to GetOwnInstance() may take some time
  293. hRes = scopedMemUsage.ReportMemoryUsage( lObjSize );
  294. } // IF SUCCEEDED( hRes )
  295. } // IF we retrieved an object
  296. } // FOR enum WStringArray
  297. } // IF need to retrieve OWN instances
  298. if ( SUCCEEDED( hRes ) )
  299. {
  300. // If we have stuff to indicate, we will trust that indicate to do
  301. // proper throttling. Otherwise, the buck stops here, so we will
  302. // request throttling
  303. if ( lObjectCount > 0L )
  304. {
  305. // Not a lowest level indicate
  306. hRes = m_pDest->Indicate( lObjectCount, pObjArray->GetArrayPtr(), false, plNumIndicated );
  307. }
  308. } // IF success after retrieving parent instances
  309. } // IF SUCCESS after reporting memory usage
  310. // Release all Indicated objects here in order to reduce memory overhead in case
  311. // we sleep.
  312. pObjArray->RemoveAll();
  313. // Finally, since we are no longer really responsible for new objects, we
  314. // will report removal to the arbitrator now if appropriate, and catch any
  315. // errors as they come up. We do this manually since we may end up
  316. // throttling for awhile
  317. HRESULT hrTemp = scopedMemUsage.Cleanup();
  318. // If this failed and we previously had a success code, record the
  319. // failure
  320. if ( SUCCEEDED( hRes ) && FAILED( hrTemp ) )
  321. {
  322. hRes = hrTemp;
  323. }
  324. // Now, if we're *still* successful, and it is appropriate to
  325. // throttle, we should do merger specific throttling now if it
  326. // is enabled.
  327. if ( SUCCEEDED( hRes ) && bThrottle && m_pWmiMergerRecord->GetWmiMerger()->MergerThrottlingEnabled() )
  328. {
  329. hRes = m_Throttler.Throttle( bParent, m_pWmiMergerRecord );
  330. }
  331. return hRes;
  332. }
  333. //***************************************************************************
  334. //
  335. //***************************************************************************
  336. HRESULT CInternalMerger::AddOwnObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated )
  337. {
  338. // Ping the throttler
  339. m_Throttler.Ping( true, m_pWmiMergerRecord->GetWmiMerger() );
  340. // On the lowest level indicate, we will walk all of the objects and log them to the arbitrator
  341. // since we will effectively be holding them for the duration of this operation
  342. long lIndicateSize = 0L;
  343. // Use scoped memory cleanup to handle the new objects
  344. // Note that in the event of an exception this will cleanup properly
  345. CScopedMemoryUsage scopedMemUsage( this );
  346. HRESULT hRes = S_OK ;
  347. if ( bLowestLevel )
  348. {
  349. for ( long lCtr = 0L; lCtr < lObjectCount; lCtr++ )
  350. {
  351. lIndicateSize += ((CWbemObject*) pObjArray[lCtr])->GetBlockLength();
  352. }
  353. // If we're going further, we also report the total size of the indicate, since we
  354. // may be sitting on the memory for awhile what with throttling and all.
  355. hRes = scopedMemUsage.ReportMemoryUsage( lIndicateSize );
  356. }
  357. // Used to track dispersion of objects so we can keep the throttler adjusted
  358. // properly
  359. long lNumChildObjAdjust = 0L;
  360. long lNumOwnObjAdjust = 0L;
  361. CRefedPointerArray<IWbemClassObject> objArray;
  362. long lNumToIndicate = 0L;
  363. // Following variables track the memory size adjustments for the arbitrator and
  364. // batching
  365. long lMapAdjustmentSize = 0L;
  366. long lSizeMergedObjects = 0L;
  367. long lBatchSize = 0L;
  368. // Scoped for proper cleanup if anything bad happens
  369. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  370. // If we've been cancelled, then we should bail out.
  371. if ( SUCCEEDED( hRes ) )
  372. {
  373. if ( FAILED ( m_hErrorRes ) )
  374. {
  375. hRes = m_hErrorRes;
  376. }
  377. else
  378. {
  379. // We shouldn't be here if m_bOwnDone is set!
  380. _DBG_ASSERT( !m_bOwnDone );
  381. if ( m_bOwnDone )
  382. {
  383. hRes = WBEM_E_INVALID_OPERATION;
  384. }
  385. }
  386. } // IF still in a success State
  387. try
  388. {
  389. for ( long x = 0; SUCCEEDED( hRes ) && x < lObjectCount; x++ )
  390. {
  391. // If we've been cancelled, then we should bail out.
  392. // We need to do the check in here, since this loop can
  393. // exit and reeenter the critical section in the middle
  394. // of processing.
  395. if ( FAILED( m_hErrorRes ) )
  396. {
  397. hRes = m_hErrorRes;
  398. continue;
  399. }
  400. IWbemClassObject* pObj = pObjArray[x];
  401. WString wsKey;
  402. // Track the size for batching
  403. lBatchSize += ((CWbemObject*) pObj)->GetBlockLength();
  404. GetKey(pObj, wsKey);
  405. MRGRKEYTOINSTMAPITER it = m_map.find(wsKey);
  406. if (it == m_map.end())
  407. {
  408. // Not there. Check if there is any hope for children
  409. // ==================================================
  410. if (m_bChildrenDone)
  411. {
  412. if (m_bDerivedFromTarget)
  413. {
  414. // We queue up all results for the ensuing indicate into a single batch we will
  415. // send down the line after we exit our critical section. This is especially
  416. // important since we may get blocked during the call to indicate by the
  417. // finalizer.
  418. if ( objArray.Add( pObj ) < 0L ) // SEC:REVIEWED 2002-03-22 : Needs EH
  419. {
  420. hRes = WBEM_E_OUT_OF_MEMORY;
  421. ERRORTRACE((LOG_WBEMCORE, "Add to array failed in AddOwnObject, hresult is 0x%x",
  422. hRes));
  423. continue;
  424. }
  425. lNumToIndicate++;
  426. }
  427. else
  428. {
  429. // ignore
  430. }
  431. }
  432. else
  433. {
  434. // Insert
  435. CInternalMergerRecord& rRecord = m_map[wsKey];
  436. rRecord.m_pData = (CWbemInstance*) pObj;
  437. pObj->AddRef();
  438. rRecord.m_bOwn = TRUE;
  439. rRecord.m_dwObjSize = ((CWbemObject*)pObj)->GetBlockLength();
  440. // We just added a parent object to the map, so reflect that in the totals
  441. lNumOwnObjAdjust++;
  442. // Add since we are adding to the map
  443. lMapAdjustmentSize += rRecord.m_dwObjSize;
  444. }
  445. }
  446. else if(it->second.m_bOwn)
  447. {
  448. ERRORTRACE((LOG_WBEMCORE, "Provider supplied duplicate instances for key %S\n", wsKey));
  449. }
  450. else
  451. {
  452. // Attempt to merge
  453. // ================
  454. hRes = CWbemInstance::AsymmetricMerge(
  455. (CWbemInstance*)pObj,
  456. (CWbemInstance*)it->second.m_pData);
  457. if(FAILED(hRes))
  458. {
  459. ERRORTRACE((LOG_WBEMCORE, "Merge conflict for instances with key %S\n", wsKey));
  460. continue;
  461. }
  462. // We queue up all results for the ensuing indicate into a single batch we will
  463. // send down the line after we exit our critical section. This is especially
  464. // important since we may get blocked during the call to indicate by the
  465. // finalizer.
  466. if ( objArray.Add( (IWbemClassObject*) it->second.m_pData ) < 0L ) // SEC:REVIEWED 2002-03-22 : Needs EH
  467. {
  468. hRes = WBEM_E_OUT_OF_MEMORY;
  469. ERRORTRACE((LOG_WBEMCORE, "Add to array failed in AddOwnObject, hresult is 0x%x",
  470. hRes));
  471. continue;
  472. }
  473. // Account for objects we have created/modified on the fly
  474. lSizeMergedObjects += ((CWbemObject*)it->second.m_pData)->GetBlockLength();
  475. lNumToIndicate++;
  476. // Subtract since we are removing from the map
  477. lMapAdjustmentSize -= it->second.m_dwObjSize;
  478. // Tricky
  479. // If Children are done and the DispatchOwnIter happens to be pointing
  480. // at the object we are about to erase, we should point it to the result
  481. // of the call to erase so we won't potentially access released memory
  482. // when DispatchOwn reenters its critical section
  483. bool bSaveErase = false;
  484. if ( m_bChildrenDone )
  485. {
  486. bSaveErase = ( m_DispatchOwnIter == it );
  487. }
  488. it->second.m_pData->Release();
  489. if ( bSaveErase )
  490. {
  491. m_DispatchOwnIter = m_map.erase(it);
  492. }
  493. else
  494. {
  495. m_map.erase(it);
  496. }
  497. // We just removed a child object from the map, so reflect that in the totals
  498. lNumChildObjAdjust--;
  499. }
  500. if ( SUCCEEDED( hRes ) )
  501. {
  502. // If we have reached a complete batch, or reached the last object we need to
  503. // send stuff down the wire.
  504. if ( m_Throttler.IsCompleteBatch( lBatchSize ) || x == ( lObjectCount - 1 ) )
  505. {
  506. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  507. // section. Note that we may not be in a critical section here, but that would be if something
  508. // happened when trying to retrieve an instance. In that case, we'll be returning an error, so
  509. // the adjustment should be 0L anyway.
  510. _DBG_ASSERT( SUCCEEDED( hRes ) || lMapAdjustmentSize == 0L );
  511. AdjustLocalObjectSize( lMapAdjustmentSize );
  512. if ( SUCCEEDED( hRes ) )
  513. {
  514. // Adjust the throttler now.
  515. AdjustThrottle( lNumOwnObjAdjust, lNumChildObjAdjust );
  516. }
  517. // This object is smart enough to recognize if we've already left and not do
  518. // so again, if we have.
  519. ics.Leave();
  520. // Now go ahead and perform the indicate we've been leading ourselves up to
  521. if ( SUCCEEDED( hRes ) )
  522. {
  523. hRes = IndicateArrayAndThrottle( lNumToIndicate,
  524. &objArray,
  525. NULL,
  526. lMapAdjustmentSize,
  527. lSizeMergedObjects,
  528. true,
  529. true, // Child
  530. plNumIndicated );
  531. // If we are in a success state and we have not enumerated all objects
  532. // we should reset the size counters and reenter the critical section
  533. if ( SUCCEEDED( hRes ) && x < ( lObjectCount ) - 1 )
  534. {
  535. lMapAdjustmentSize = 0L;
  536. lSizeMergedObjects = 0L;
  537. lBatchSize = 0L;
  538. lNumToIndicate = 0L;
  539. lNumOwnObjAdjust = 0L;
  540. lNumChildObjAdjust = 0L;
  541. ics.Enter();
  542. }
  543. }
  544. } // IF we should send the objects out
  545. } // IF we are in a success state
  546. } // FOR enum objects
  547. }
  548. catch( CX_MemoryException )
  549. {
  550. hRes = WBEM_E_OUT_OF_MEMORY;
  551. }
  552. catch(...)
  553. {
  554. ExceptionCounter c;
  555. hRes = WBEM_E_CRITICAL_ERROR;
  556. }
  557. // Check error one last time
  558. if ( FAILED( m_hErrorRes ) )
  559. {
  560. hRes = m_hErrorRes;
  561. }
  562. // We may have looped, entered the critical section and exited, so make
  563. // sure we force our way out in case we're about to cancel
  564. ics.Leave();
  565. // If we are the lowest level and no objects made it out of the merger
  566. // we will ask the arbitrator to throttle this call
  567. if ( SUCCEEDED( hRes ) && bLowestLevel && *plNumIndicated == 0L )
  568. {
  569. // Since we don't want the fact we're sleeping in the arbitrator to
  570. // cause the merger to cancel operations, we'll increase the count
  571. // of threads throttling, and decrement when we return
  572. m_pWmiMergerRecord->GetWmiMerger()->IncrementArbitratorThrottling();
  573. // If we get an error indicating we were throttled, that is okay
  574. hRes = m_pWmiMergerRecord->GetWmiMerger()->Throttle();
  575. m_pWmiMergerRecord->GetWmiMerger()->DecrementArbitratorThrottling();
  576. if ( WBEM_E_ARB_THROTTLE == hRes || WBEM_S_ARB_NOTHROTTLING == hRes )
  577. {
  578. hRes = WBEM_S_NO_ERROR;
  579. }
  580. }
  581. if ( hRes == WBEM_E_ARB_CANCEL )
  582. {
  583. hRes = WBEM_E_CALL_CANCELLED ;
  584. }
  585. // If we are in a failed state, nothing is going to matter from this point on,
  586. // so tell the merger to cancel all underlying sinks.
  587. if ( FAILED( hRes ) )
  588. {
  589. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hRes );
  590. }
  591. return hRes;
  592. }
  593. //***************************************************************************
  594. //
  595. //***************************************************************************
  596. HRESULT CInternalMerger::AddChildObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated )
  597. {
  598. HRESULT hRes = S_OK ;
  599. // Ping the throttler
  600. m_Throttler.Ping( false, m_pWmiMergerRecord->GetWmiMerger() );
  601. // On the lowest level indicate, we will walk all of the objects and log them to the arbitrator
  602. // since we will effectively be holding them for the duration of this operation
  603. long lIndicateSize = 0L;
  604. long lTotalIndicated = 0L;
  605. // Use scoped memory cleanup to handle the new objects
  606. // Note that in the event of an exception this will cleanup properly
  607. CScopedMemoryUsage scopedMemUsage( this );
  608. if ( bLowestLevel )
  609. {
  610. for ( long lCtr = 0L; lCtr < lObjectCount; lCtr++ )
  611. {
  612. lIndicateSize += ((CWbemObject*) pObjArray[lCtr])->GetBlockLength();
  613. }
  614. // If we're going further, we also report the total size of the indicate, since we
  615. // may be sitting on the memory for awhile what with throttling and all.
  616. hRes = scopedMemUsage.ReportMemoryUsage( lIndicateSize );
  617. }
  618. // Used to track dispersion of objects so we can keep the throttler adjusted
  619. // properly
  620. long lNumChildObjAdjust = 0L;
  621. long lNumOwnObjAdjust = 0L;
  622. CRefedPointerArray<IWbemClassObject> objArray;
  623. long lNumToIndicate = 0L;
  624. // Following variables track the memory size adjustments for the arbitrator and
  625. // batching
  626. long lMapAdjustmentSize = 0L;
  627. long lSizeMergedObjects = 0L;
  628. long lBatchSize = 0L;
  629. // Used to keep track of instance keys we need to retrieve using
  630. // GetOwnInstance
  631. CWStringArray wsOwnInstanceKeyArray; // SEC:REVIEWED 2002-03-22 : Needs EH
  632. // Scoped for proper cleanup if anything bad happens
  633. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  634. // If we've been cancelled, then we should bail out.
  635. if ( SUCCEEDED( hRes ) )
  636. {
  637. if ( FAILED ( m_hErrorRes ) )
  638. {
  639. hRes = m_hErrorRes;
  640. }
  641. else
  642. {
  643. // We shouldn't be here if m_bChildrenDone is set!
  644. _DBG_ASSERT( !m_bChildrenDone );
  645. if ( m_bChildrenDone )
  646. {
  647. hRes = WBEM_E_INVALID_OPERATION;
  648. }
  649. }
  650. } // IF still in a success State
  651. try
  652. {
  653. for ( long x = 0; SUCCEEDED( hRes ) && x < lObjectCount; x++ )
  654. {
  655. // If we've been cancelled, then we should bail out.
  656. // We need to do the check in here, since this loop can
  657. // exit and reeenter the critical section in the middle
  658. // of processing.
  659. if ( FAILED( m_hErrorRes ) )
  660. {
  661. hRes = m_hErrorRes;
  662. continue;
  663. }
  664. IWbemClassObject* pObj = pObjArray[x];
  665. // Track the size for batching
  666. lBatchSize += ((CWbemObject*) pObj)->GetBlockLength();
  667. WString wsKey;
  668. GetKey(pObj, wsKey);
  669. MRGRKEYTOINSTMAPITER it = m_map.find(wsKey);
  670. if (it == m_map.end())
  671. {
  672. // Check if there is any hope for parent
  673. // =====================================
  674. if(m_bOwnDone)
  675. {
  676. // BSTR str = NULL;
  677. // pObj->GetObjectText(0, &str);
  678. // The following was commented out because it actually incorrectly logs
  679. // an error if the child provider enumerates when the parent provider
  680. // interprets a query and returns fewer instances. Neither provider is wrong,
  681. // but this error message causes needless worry. In Quasar, we have to fix
  682. // this whole merger thing to be smarter anyway.
  683. //
  684. // ERRORTRACE((LOG_WBEMCORE, "[Chkpt_1] [%S] Orphaned object %S returned by "
  685. // "provider\n", LPWSTR(m_wsClass), str));
  686. // SysFreeString(str);
  687. // m_pDest->Add(pObj);
  688. }
  689. else
  690. {
  691. // insert
  692. CInternalMergerRecord& rRecord = m_map[wsKey];
  693. rRecord.m_pData = (CWbemInstance*)pObj;
  694. pObj->AddRef();
  695. rRecord.m_bOwn = FALSE;
  696. rRecord.m_dwObjSize = ((CWbemObject*)pObj)->GetBlockLength();
  697. // We just added a child object to the map, so reflect that in the totals
  698. lNumChildObjAdjust++;
  699. // Add since we are adding to the map
  700. lMapAdjustmentSize += rRecord.m_dwObjSize;
  701. // Check if parent's retrieval is needed
  702. // =====================================
  703. if (!m_bDerivedFromTarget)
  704. {
  705. // Add the instance name to the key array. We will perform retrieval
  706. // of these parent instances *outside* of our critical section
  707. if ( wsOwnInstanceKeyArray.Add( wsKey ) != CFlexArray::no_error ) // SEC:REVIEWED 2002-03-22 : Needs EH
  708. {
  709. hRes = WBEM_E_OUT_OF_MEMORY;
  710. }
  711. } // IF !m_bDerivedFromTarget
  712. }
  713. }
  714. else if(!it->second.m_bOwn)
  715. {
  716. ERRORTRACE((LOG_WBEMCORE, "Two providers supplied conflicting "
  717. "instances for key %S\n", wsKey));
  718. }
  719. else
  720. {
  721. // Attempt to merge
  722. // ================
  723. hRes = CWbemInstance::AsymmetricMerge(
  724. (CWbemInstance*)it->second.m_pData,
  725. (CWbemInstance*)pObj
  726. );
  727. if (FAILED(hRes))
  728. {
  729. ERRORTRACE((LOG_WBEMCORE, "Merge conflict for instances with "
  730. "key %S\n", wsKey));
  731. continue;
  732. }
  733. // We queue up all results for the ensuing indicate into a single batch we will
  734. // send down the line after we exit our critical section. This is especially
  735. // important since we may get blocked during the call to indicate by the
  736. // finalizer.
  737. if ( objArray.Add( pObj ) < 0L ) // SEC:REVIEWED 2002-03-22 : Needs EH
  738. {
  739. hRes = WBEM_E_OUT_OF_MEMORY;
  740. ERRORTRACE((LOG_WBEMCORE, "Add to array failed in AddChildObject, hresult is 0x%x",
  741. hRes));
  742. continue;
  743. }
  744. // Account for objects we have created on the fly
  745. lSizeMergedObjects += ((CWbemObject*) pObj)->GetBlockLength();
  746. lNumToIndicate++;
  747. // Subtract since we are removing from the map
  748. lMapAdjustmentSize -= it->second.m_dwObjSize;
  749. it->second.m_pData->Release();
  750. m_map.erase(it);
  751. // We just removed a parent object from the map, so reflect that in the totals
  752. lNumOwnObjAdjust--;
  753. }
  754. if ( SUCCEEDED( hRes ) )
  755. {
  756. // If we have reached a complete batch, or reached the last object we need to
  757. // send stuff down the wire.
  758. if ( m_Throttler.IsCompleteBatch( lBatchSize ) || x == ( lObjectCount - 1 ) )
  759. {
  760. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  761. // section. Note that we may not be in a critical section here, but that would be if something
  762. // happened when trying to retrieve an instance. In that case, we'll be returning an error, so
  763. // the adjustment should be 0L anyway.
  764. _DBG_ASSERT( SUCCEEDED( hRes ) || lMapAdjustmentSize == 0L );
  765. AdjustLocalObjectSize( lMapAdjustmentSize );
  766. if ( SUCCEEDED( hRes ) )
  767. {
  768. // Adjust the throttler now.
  769. AdjustThrottle( lNumOwnObjAdjust, lNumChildObjAdjust );
  770. }
  771. // This object is smart enough to recognize if we've already left and not do
  772. // so again, if we have.
  773. ics.Leave();
  774. // Now go ahead and perform the indicate we've been leading ourselves up to
  775. if ( SUCCEEDED( hRes ) )
  776. {
  777. hRes = IndicateArrayAndThrottle( lNumToIndicate,
  778. &objArray,
  779. &wsOwnInstanceKeyArray,
  780. lMapAdjustmentSize,
  781. lSizeMergedObjects,
  782. true,
  783. false, // Child
  784. plNumIndicated
  785. );
  786. // If we are in a success state and we have not enumerated all objects
  787. // we should reset the size counters and reenter the critical section
  788. if ( SUCCEEDED( hRes ) && x < ( lObjectCount ) - 1 )
  789. {
  790. lMapAdjustmentSize = 0L;
  791. lSizeMergedObjects = 0L;
  792. lBatchSize = 0L;
  793. lNumToIndicate = 0L;
  794. lNumOwnObjAdjust = 0L;
  795. lNumChildObjAdjust = 0L;
  796. // Clear out the array
  797. wsOwnInstanceKeyArray.Empty();
  798. ics.Enter();
  799. }
  800. }
  801. } // IF we should send the objects out
  802. } // IF we are in a success state
  803. } // FOR Enum Objects
  804. }
  805. catch( CX_MemoryException )
  806. {
  807. hRes = WBEM_E_OUT_OF_MEMORY;
  808. }
  809. catch(...)
  810. {
  811. ExceptionCounter c;
  812. hRes = WBEM_E_CRITICAL_ERROR;
  813. }
  814. // Check error one last time
  815. if ( FAILED( m_hErrorRes ) )
  816. {
  817. hRes = m_hErrorRes;
  818. }
  819. // We may have looped, entered the critical section and exited, so make
  820. // sure we force our way out in case we're about to cancel
  821. ics.Leave();
  822. // If we are the lowest level and no objects made it out of the merger
  823. // we will ask the arbitrator to throttle this call
  824. if ( SUCCEEDED( hRes ) && bLowestLevel && *plNumIndicated == 0L )
  825. {
  826. // Since we don't want the fact we're sleeping in the arbitrator to
  827. // cause the merger to cancel operations, we'll increase the count
  828. // of threads throttling, and decrement when we return
  829. m_pWmiMergerRecord->GetWmiMerger()->IncrementArbitratorThrottling();
  830. // If we get an error indicating we were throttled, that is okay
  831. hRes = m_pWmiMergerRecord->GetWmiMerger()->Throttle();
  832. m_pWmiMergerRecord->GetWmiMerger()->DecrementArbitratorThrottling();
  833. if ( WBEM_E_ARB_THROTTLE == hRes || WBEM_S_ARB_NOTHROTTLING == hRes )
  834. {
  835. hRes = WBEM_S_NO_ERROR;
  836. }
  837. }
  838. if ( hRes == WBEM_E_ARB_CANCEL )
  839. {
  840. hRes = WBEM_E_CALL_CANCELLED ;
  841. }
  842. // If we are in a failed state, nothing is going to matter from this point on,
  843. // so tell the merger to cancel all underlying sinks.
  844. if ( FAILED( hRes ) )
  845. {
  846. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hRes );
  847. }
  848. return hRes;
  849. }
  850. //***************************************************************************
  851. //
  852. //***************************************************************************
  853. HRESULT CInternalMerger::AddOwnInstance( IWbemClassObject* pObj, LPCWSTR pwszTargetPath, IWbemClassObject** ppMergedInstance)
  854. {
  855. HRESULT hRes = S_OK ;
  856. WString wsKey;
  857. // Ping the throttler
  858. m_Throttler.Ping( true, m_pWmiMergerRecord->GetWmiMerger() );
  859. // Scoped for proper cleanup if anything bad happens
  860. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  861. // If we've been cancelled, then we should bail out.
  862. if ( FAILED( m_hErrorRes ) )
  863. {
  864. hRes = m_hErrorRes;
  865. }
  866. GetKey(pObj, wsKey);
  867. // Find the instance - it should already be in the map. If not, we shouldn't be
  868. // here
  869. long lArbitratorAdjust = 0L;
  870. long lNumChildObjAdjust = 0L;
  871. MRGRKEYTOINSTMAPITER it = m_map.find(wsKey);
  872. if (it != m_map.end())
  873. {
  874. // Attempt to merge
  875. // ================
  876. hRes = CWbemInstance::AsymmetricMerge(
  877. (CWbemInstance*)pObj,
  878. (CWbemInstance*)it->second.m_pData);
  879. if ( SUCCEEDED( hRes ) )
  880. {
  881. *ppMergedInstance = (IWbemClassObject*) it->second.m_pData;
  882. (*ppMergedInstance)->AddRef();
  883. // Subtract since we are removing from the map
  884. lArbitratorAdjust -= it->second.m_dwObjSize;
  885. it->second.m_pData->Release();
  886. m_map.erase(it);
  887. // We just removed a child object from the map, so reflect that in the totals
  888. lNumChildObjAdjust--;
  889. }
  890. else
  891. {
  892. ERRORTRACE((LOG_WBEMCORE, "Merge conflict for instances with "
  893. "key %S\n", wsKey));
  894. }
  895. }
  896. else
  897. {
  898. BSTR str = NULL;
  899. pObj->GetObjectText(0, &str);
  900. CSysFreeMe sfm( str );
  901. // The provider has indicated an improper instance to an OwnInstance request.
  902. // We should always be able to find an instance in here. We'll toss the instance
  903. // but we should output something to the error log since it sounds like
  904. // we have a broken provider
  905. //
  906. ERRORTRACE((LOG_WBEMCORE, "Provider responded to request for instance %S, with object %S not in map\n", pwszTargetPath, str ));
  907. }
  908. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  909. // section
  910. AdjustLocalObjectSize( lArbitratorAdjust );
  911. if ( SUCCEEDED( hRes ) )
  912. {
  913. // Adjust the throttler now.
  914. AdjustThrottle( 0L, lNumChildObjAdjust );
  915. }
  916. // This object is smart enough to recognize if we've already left and not do
  917. // so again, if we have.
  918. ics.Leave();
  919. // Always report adjustments
  920. hRes = ReportMemoryUsage( lArbitratorAdjust );
  921. // If we are in a failed state, nothing is going to matter from this point on,
  922. // so tell the merger to cancel all underlying sinks.
  923. if ( FAILED( hRes ) )
  924. {
  925. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hRes );
  926. }
  927. return hRes;
  928. }
  929. //***************************************************************************
  930. //
  931. //***************************************************************************
  932. HRESULT CInternalMerger::RemoveInstance( LPCWSTR pwszTargetPath )
  933. {
  934. HRESULT hRes = S_OK ;
  935. WString wsKey;
  936. // Track what we clean up
  937. long lNumChildObjAdjust = 0L;
  938. long lArbitratorAdjust = 0L;
  939. // Scoped for proper cleanup if anything bad happens
  940. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  941. // If we've been cancelled, then we should bail out.
  942. if ( FAILED( m_hErrorRes ) )
  943. {
  944. hRes = m_hErrorRes;
  945. }
  946. // If the instance path is in our map, we should remove it
  947. MRGRKEYTOINSTMAPITER it = m_map.find( pwszTargetPath );
  948. if (it != m_map.end())
  949. {
  950. // Subtract since we are removing from the map
  951. lArbitratorAdjust -= it->second.m_dwObjSize;
  952. it->second.m_pData->Release();
  953. m_map.erase(it);
  954. // We just removed a child object from the map, so reflect that in the totals
  955. lNumChildObjAdjust--;
  956. }
  957. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  958. // section
  959. AdjustLocalObjectSize( lArbitratorAdjust );
  960. if ( SUCCEEDED( hRes ) )
  961. {
  962. // Adjust the throttler now.
  963. AdjustThrottle( 0L, lNumChildObjAdjust );
  964. }
  965. // This object is smart enough to recognize if we've already left and not do
  966. // so again, if we have.
  967. ics.Leave();
  968. // Always report adjustments (this should be negative).
  969. hRes = ReportMemoryUsage( lArbitratorAdjust );
  970. // If we are in a failed state, nothing is going to matter from this point on,
  971. // so tell the merger to cancel all underlying sinks.
  972. if ( FAILED( hRes ) )
  973. {
  974. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hRes );
  975. }
  976. return hRes;
  977. }
  978. //***************************************************************************
  979. //
  980. //***************************************************************************
  981. void CInternalMerger::DispatchChildren()
  982. {
  983. long lNumChildObjAdjust = 0L;
  984. long lArbitratorAdjust = 0L;
  985. // Scoped for proper cleanup if anything bad happens
  986. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  987. MRGRKEYTOINSTMAPITER it = m_map.begin();
  988. while (it != m_map.end())
  989. {
  990. if (!it->second.m_bOwn)
  991. {
  992. // BSTR str = NULL;
  993. // it->second.m_pData->GetObjectText(0, &str);
  994. // The following was commented out because it actually incorrectly logs
  995. // an error if the child provider enumerates when the parent provider
  996. // interprets a query and returns fewer instances. Neither provider is wrong,
  997. // but this error message causes needless worry. In Quasar, we have to fix
  998. // this whole merger thing to be smarter anyway.
  999. //
  1000. // ERRORTRACE((LOG_WBEMCORE, "Chkpt2 [%S] Orphaned object %S returned by "
  1001. // "provider\n", LPWSTR(m_wsClass), str));
  1002. // SysFreeString(str);
  1003. // m_pDest->Add(it->second.m_pData);
  1004. // Subtract since we are removing from the map
  1005. lArbitratorAdjust -= it->second.m_dwObjSize;
  1006. // Tricky
  1007. // If Children are done and the DispatchOwnIter happens to be pointing
  1008. // at the object we are about to erase, we should point it to the result
  1009. // of the call to erase so we won't potentially access released memory
  1010. // when DispatchOwn reenters its critical section
  1011. bool bSaveErase = false;
  1012. if ( m_bChildrenDone )
  1013. {
  1014. bSaveErase = ( m_DispatchOwnIter == it );
  1015. }
  1016. it->second.m_pData->Release();
  1017. it = m_map.erase(it);
  1018. if ( bSaveErase )
  1019. {
  1020. m_DispatchOwnIter = it;
  1021. }
  1022. // We are removing child objects, so we need to adjust the throttling
  1023. // totals appropriately
  1024. lNumChildObjAdjust--;
  1025. }
  1026. else it++;
  1027. }
  1028. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  1029. // section
  1030. AdjustLocalObjectSize( lArbitratorAdjust );
  1031. // Apply the adjustment now.
  1032. m_Throttler.AdjustNumChildObjects( lNumChildObjAdjust );
  1033. // Mark the appropriate flags now this will also release throttling
  1034. OwnIsDone();
  1035. ics.Leave();
  1036. // Always report adjustments
  1037. HRESULT hrArbitrate = ReportMemoryUsage( lArbitratorAdjust );
  1038. // If we get a failure we're over, the function will filter out noise, such as
  1039. // requests to throttle (we're should actually *always* decrease the value here)
  1040. if ( FAILED( hrArbitrate ) )
  1041. {
  1042. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hrArbitrate );
  1043. }
  1044. }
  1045. //***************************************************************************
  1046. //
  1047. //***************************************************************************
  1048. void CInternalMerger::DispatchOwn()
  1049. {
  1050. HRESULT hRes = S_OK;
  1051. long lNumOwnObjAdjust = 0L;
  1052. // Temporary object storage
  1053. CRefedPointerArray<IWbemClassObject> objArray;
  1054. // Used for tracking object sizes
  1055. long lTotalMapAdjust = 0L;
  1056. // Scoped for proper cleanup if anything bad happens
  1057. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  1058. // Mark the appropriate flags now this will also release throttling
  1059. ChildrenAreDone();
  1060. try
  1061. {
  1062. // Walk the map, and for all own objects, store the pointer and record the size, then
  1063. // clear the element from the map. None of these objects should be merged, but we want
  1064. // them out of the map before we start batch processing them
  1065. // We use a member variable since we may leave a critical section while iterating
  1066. // and it is possible for AddOwnObject or Cancel to cause the iterator to be cleared
  1067. // before we reenter the critical section - This is the only please we have code
  1068. // like this
  1069. m_DispatchOwnIter = m_map.begin();
  1070. int x = 0;
  1071. int y = 0;
  1072. while ( SUCCEEDED( hRes ) && m_DispatchOwnIter != m_map.end())
  1073. {
  1074. // If we are not derived from the target class, this more or less
  1075. // just cleans up the array. Otherwise, instances left in the map
  1076. // are instances provided at this level, but not by children, so we
  1077. // need to send them up the line with an Indicate
  1078. if(m_DispatchOwnIter->second.m_bOwn)
  1079. {
  1080. IWbemClassObject* pObjToIndicate = NULL;
  1081. long lMapAdjust = 0L;
  1082. // If we are not derived from the target class, this more or less
  1083. // just cleans up the array. Otherwise, instances left in the map
  1084. // are instances provided at this level, but not by children, so we
  1085. // need to send them up the line with an Indicate
  1086. if ( m_bDerivedFromTarget )
  1087. {
  1088. // We will actually just go one object at a time.
  1089. if ( objArray.Add( m_DispatchOwnIter->second.m_pData ) < 0L ) // SEC:REVIEWED 2002-03-22 : Needs EH
  1090. {
  1091. hRes = WBEM_E_OUT_OF_MEMORY;
  1092. ERRORTRACE((LOG_WBEMCORE, "Add to array failed in AddChildObject, hresult is 0x%x",
  1093. hRes));
  1094. continue;
  1095. }
  1096. lMapAdjust -= m_DispatchOwnIter->second.m_dwObjSize;
  1097. // Store the actual adjustment size
  1098. } // IF m_bDerivedFromTarget
  1099. // Adjust the total map size (this is in case we are not derived from
  1100. // target and are just removing objects).
  1101. lTotalMapAdjust -= m_DispatchOwnIter->second.m_dwObjSize;
  1102. m_DispatchOwnIter->second.m_pData->Release();
  1103. m_DispatchOwnIter = m_map.erase(m_DispatchOwnIter);
  1104. // Apply the object adjustment now.
  1105. m_Throttler.AdjustNumParentObjects( -1 );
  1106. if ( objArray.GetSize() > 0L )
  1107. {
  1108. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  1109. // section
  1110. AdjustLocalObjectSize( lMapAdjust );
  1111. // This object is smart enough to recognize if we've already left and not do
  1112. // so again, if we have.
  1113. ics.Leave();
  1114. // Now go ahead and perform the indicate we've been leading ourselves up to, adjustment
  1115. // will be negative, but conversely, we'll be holding onto that size of objects if anything
  1116. // is indicated, so call as follows...oh yeah, and don't throttle explicitly
  1117. if ( SUCCEEDED( hRes ) )
  1118. {
  1119. hRes = IndicateArrayAndThrottle( 1,
  1120. &objArray,
  1121. NULL,
  1122. lMapAdjust,
  1123. -lMapAdjust,
  1124. false,
  1125. false, // no throttling here
  1126. NULL
  1127. );
  1128. // If we are in a success state we should reenter the critical section
  1129. if ( SUCCEEDED( hRes ) )
  1130. {
  1131. ics.Enter();
  1132. }
  1133. }
  1134. } // IF NULL != pObjToIndicate
  1135. } // IF !m_bOwn
  1136. else
  1137. {
  1138. m_DispatchOwnIter++;
  1139. }
  1140. } // WHILE enuming objects
  1141. } // try
  1142. catch(...)
  1143. {
  1144. ExceptionCounter c;
  1145. }
  1146. if ( !m_bDerivedFromTarget )
  1147. {
  1148. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  1149. // section.
  1150. AdjustLocalObjectSize( lTotalMapAdjust );
  1151. }
  1152. // Any further code MUST be executed outside of a critical
  1153. // section
  1154. ics.Leave();
  1155. if ( !m_bDerivedFromTarget )
  1156. {
  1157. // Report to the arbitrator now.
  1158. if ( 0L != lTotalMapAdjust )
  1159. {
  1160. ReportMemoryUsage( lTotalMapAdjust );
  1161. }
  1162. }
  1163. // If something went wrong, we need to cancel at this point.
  1164. if ( FAILED( hRes ) )
  1165. {
  1166. // If we are in a failed state, nothing is going to matter from this point on,
  1167. // so tell the merger to cancel all underlying sinks.
  1168. m_pWmiMergerRecord->GetWmiMerger()->Cancel( hRes );
  1169. }
  1170. }
  1171. //***************************************************************************
  1172. //
  1173. //***************************************************************************
  1174. HRESULT CInternalMerger::GetOwnInstance(LPCWSTR wszKey, IWbemClassObject** ppMergedInstance)
  1175. {
  1176. HRESULT hRes = WBEM_S_NO_ERROR;
  1177. if (NULL == wszKey)
  1178. return WBEM_E_OUT_OF_MEMORY;
  1179. size_t tmpLength = wcslen(wszKey) + m_wsClass.Length() + 2; // SEC:REVIEWED 2002-03-22 : OK ; precondition that these are valid
  1180. WCHAR * wszPath = new WCHAR[tmpLength];
  1181. if (NULL == wszPath) return WBEM_E_OUT_OF_MEMORY;
  1182. CVectorDeleteMe<WCHAR> dm(wszPath);
  1183. if (wcslen(wszKey)) // SEC:REVIEWED 2002-03-22 : OK; precondition that this is valid
  1184. {
  1185. StringCchPrintf(wszPath, tmpLength, L"%s.%s", (LPCWSTR)m_wsClass, wszKey);
  1186. IServerSecurity * pSec = NULL;
  1187. hRes = CoGetCallContext(IID_IServerSecurity,(void **)&pSec);
  1188. CReleaseMe rmSec(pSec);
  1189. if (RPC_E_CALL_COMPLETE == hRes ) hRes = S_OK; // no call context
  1190. if (FAILED(hRes)) return hRes;
  1191. BOOL bImper = (pSec)?pSec->IsImpersonating():FALSE;
  1192. if (pSec && bImper && FAILED(hRes = pSec->RevertToSelf())) return hRes;
  1193. COwnInstanceSink* pOwnInstanceSink = NULL;
  1194. hRes = m_pWmiMergerRecord->GetWmiMerger()->CreateMergingSink( eMergerOwnInstanceSink,
  1195. NULL, this, (CMergerSink**) &pOwnInstanceSink );
  1196. if ( SUCCEEDED( hRes ) )
  1197. {
  1198. // Scoped release
  1199. pOwnInstanceSink->AddRef();
  1200. CReleaseMe rm( pOwnInstanceSink );
  1201. hRes = pOwnInstanceSink->SetInstancePath( wszKey );
  1202. if ( SUCCEEDED( hRes ) )
  1203. {
  1204. // Impersonate original client
  1205. IUnknown* pOld;
  1206. hRes = CoSwitchCallContext(m_pSecurity, &pOld);
  1207. if (SUCCEEDED(hRes))
  1208. {
  1209. {
  1210. // Revert to self this will succeed is the first has succeeded
  1211. IUnknown* pThis;
  1212. OnDelete2<IUnknown *,IUnknown **,HRESULT(*)(IUnknown *,IUnknown **),CoSwitchCallContext> SwitchBack(pOld, &pThis);
  1213. hRes = m_pNamespace->DynAux_GetSingleInstance(m_pOwnClass,
  1214. 0, wszPath,
  1215. m_pContext,
  1216. pOwnInstanceSink); // throw
  1217. }
  1218. if ( SUCCEEDED( hRes ) )
  1219. {
  1220. hRes = pOwnInstanceSink->GetObject( ppMergedInstance );
  1221. // Means there was no object to retrieve
  1222. if ( WBEM_S_FALSE == hRes )
  1223. {
  1224. hRes = WBEM_S_NO_ERROR;
  1225. }
  1226. }
  1227. else if ( WBEM_E_NOT_FOUND == hRes )
  1228. {
  1229. // In this case, this is really not an error
  1230. hRes = WBEM_S_NO_ERROR;
  1231. }
  1232. }
  1233. }
  1234. } // If created sink
  1235. if (bImper && pSec)
  1236. {
  1237. HRESULT hrInner = pSec->ImpersonateClient();
  1238. if (FAILED(hrInner)) return hrInner;
  1239. }
  1240. }
  1241. return hRes;
  1242. }
  1243. //***************************************************************************
  1244. //
  1245. //***************************************************************************
  1246. void CInternalMerger::OwnIsDone()
  1247. {
  1248. // Let the throttler know what's up
  1249. m_Throttler.SetParentDone();
  1250. m_bOwnDone = TRUE;
  1251. m_pOwnSink = NULL;
  1252. }
  1253. //***************************************************************************
  1254. //
  1255. //***************************************************************************
  1256. void CInternalMerger::ChildrenAreDone()
  1257. {
  1258. // Let the throttler know what's up
  1259. m_Throttler.SetChildrenDone();
  1260. m_bChildrenDone = TRUE;
  1261. m_pChildSink = NULL;
  1262. if(!m_bDerivedFromTarget)
  1263. {
  1264. // Don't need that ref count on pOwnSink anymore
  1265. // =============================================
  1266. m_pOwnSink->Release();
  1267. }
  1268. }
  1269. //***************************************************************************
  1270. //
  1271. //***************************************************************************
  1272. HRESULT CInternalMerger::GetObjectLength( IWbemClassObject* pObj, long* plObjectSize )
  1273. {
  1274. _IWmiObject* pWmiObject = NULL;
  1275. HRESULT hr = pObj->QueryInterface( IID__IWmiObject, (void**) &pWmiObject );
  1276. if ( SUCCEEDED( hr ) )
  1277. {
  1278. CReleaseMe rm1( pWmiObject );
  1279. CWbemObject* pWbemObj = NULL;
  1280. hr = pWmiObject->_GetCoreInfo( 0L, (void**) &pWbemObj );
  1281. if ( SUCCEEDED( hr ) )
  1282. {
  1283. CReleaseMe rm2( (IWbemClassObject*) pWbemObj );
  1284. *plObjectSize = pWbemObj->GetBlockLength();
  1285. }
  1286. }
  1287. return hr;
  1288. }
  1289. //***************************************************************************
  1290. //
  1291. //***************************************************************************
  1292. //
  1293. ULONG CInternalMerger::CMemberSink::AddRef()
  1294. {
  1295. // We keep an internal ref count and also pass up to the
  1296. // merger
  1297. // On first reference we AddRef() the internal merger as well
  1298. // Note that our internal ref count is really a bookkeeping count on
  1299. // the sink. The actual ref count that controls the destruction is
  1300. // that on the merger. When the merger hits zero the sink will be deleted
  1301. if ( InterlockedIncrement( &m_lRefCount ) == 1 )
  1302. {
  1303. m_pInternalMerger->AddRef();
  1304. }
  1305. return m_pMerger->AddRef();
  1306. }
  1307. //***************************************************************************
  1308. //
  1309. //***************************************************************************
  1310. STDMETHODIMP CInternalMerger::CMemberSink::
  1311. SetStatus(long lFlags, long lParam, BSTR strParam, IWbemClassObject* pObjParam)
  1312. {
  1313. if(lFlags == 0 && lParam == WBEM_E_NOT_FOUND)
  1314. lParam = WBEM_S_NO_ERROR;
  1315. // Propagate error to error combining sink
  1316. // =======================================
  1317. HRESULT hRes = m_pInternalMerger->m_pDest->SetStatus(lFlags, lParam, strParam,
  1318. pObjParam);
  1319. if ( FAILED ( hRes ) || !SUCCEEDED( lParam ) )
  1320. {
  1321. HRESULT hrSet = ( FAILED( hRes ) ? hRes : lParam );
  1322. m_pInternalMerger->m_pWmiMergerRecord->GetWmiMerger()->Cancel( hrSet );
  1323. }
  1324. return hRes;
  1325. }
  1326. //***************************************************************************
  1327. //
  1328. //***************************************************************************
  1329. CInternalMerger::COwnSink::~COwnSink()
  1330. {
  1331. }
  1332. //***************************************************************************
  1333. //
  1334. //***************************************************************************
  1335. STDMETHODIMP
  1336. CInternalMerger::COwnSink::Indicate(long lNumObjects, IWbemClassObject** apObjects)
  1337. {
  1338. long lNumIndicated = 0L;
  1339. // Internal calls don't use this, so we know we're the lowest level
  1340. return m_pInternalMerger->AddOwnObjects( lNumObjects, apObjects, true, &lNumIndicated );
  1341. }
  1342. //***************************************************************************
  1343. //
  1344. //***************************************************************************
  1345. HRESULT
  1346. CInternalMerger::COwnSink::Indicate(long lObjectCount, IWbemClassObject** pObjArray,
  1347. bool bLowestLevel, long* plNumIndicated )
  1348. {
  1349. // Really just a place holder here. Just call the standard version
  1350. return m_pInternalMerger->AddOwnObjects( lObjectCount, pObjArray, bLowestLevel, plNumIndicated );
  1351. }
  1352. //***************************************************************************
  1353. //
  1354. //***************************************************************************
  1355. HRESULT CInternalMerger::COwnSink::OnFinalRelease( void )
  1356. {
  1357. // Final cleanup occurs here.
  1358. m_pInternalMerger->DispatchChildren();
  1359. m_pInternalMerger->Release();
  1360. return WBEM_S_NO_ERROR;
  1361. }
  1362. //***************************************************************************
  1363. //
  1364. //***************************************************************************
  1365. CInternalMerger::CChildSink::~CChildSink()
  1366. {
  1367. }
  1368. //***************************************************************************
  1369. //
  1370. //***************************************************************************
  1371. STDMETHODIMP
  1372. CInternalMerger::CChildSink::Indicate(long lNumObjects, IWbemClassObject** apObjects)
  1373. {
  1374. long lNumIndicated = 0L;
  1375. // Internal calls don't use this, so we know we're the lowest level
  1376. return m_pInternalMerger->AddChildObjects( lNumObjects, apObjects,
  1377. true, &lNumIndicated );
  1378. }
  1379. //***************************************************************************
  1380. //
  1381. //***************************************************************************
  1382. HRESULT
  1383. CInternalMerger::CChildSink::Indicate(long lObjectCount,
  1384. IWbemClassObject** pObjArray,
  1385. bool bLowestLevel, long* plNumIndicated )
  1386. {
  1387. // Pass the lowest level parameter on
  1388. return m_pInternalMerger->AddChildObjects( lObjectCount, pObjArray, bLowestLevel, plNumIndicated );
  1389. }
  1390. //***************************************************************************
  1391. //
  1392. //***************************************************************************
  1393. HRESULT CInternalMerger::CChildSink::OnFinalRelease( void )
  1394. {
  1395. // Final cleanup occurs here.
  1396. m_pInternalMerger->DispatchOwn();
  1397. m_pInternalMerger->Release();
  1398. return WBEM_S_NO_ERROR;
  1399. }
  1400. //***************************************************************************
  1401. //
  1402. //***************************************************************************
  1403. HRESULT CInternalMerger::CreateMergingSink( MergerSinkType eType, CInternalMerger* pMerger, CWmiMerger* pWmiMerger, CMergerSink** ppSink )
  1404. {
  1405. if ( eType == eMergerOwnSink )
  1406. {
  1407. *ppSink = new COwnSink( pMerger, pWmiMerger );
  1408. }
  1409. else if ( eType == eMergerChildSink )
  1410. {
  1411. *ppSink = new CChildSink( pMerger, pWmiMerger );
  1412. }
  1413. else if ( eType == eMergerOwnInstanceSink )
  1414. {
  1415. *ppSink = new COwnInstanceSink( pMerger, pWmiMerger );
  1416. }
  1417. return ( NULL == *ppSink ? WBEM_E_OUT_OF_MEMORY : WBEM_S_NO_ERROR );
  1418. }
  1419. // Sets our error state, and cleans up objects we're holding onto -
  1420. // no further objects should get in. When we cancel the throttler,
  1421. // it will release any threads it is holding onto.
  1422. void CInternalMerger::Cancel( HRESULT hRes /* = WBEM_E_CALL_CANCELLED */ )
  1423. {
  1424. long lArbitratorAdjust = 0L;
  1425. // Scoped for proper cleanup if anything bad happens
  1426. CCheckedInCritSec ics( m_Throttler.GetCritSec() ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  1427. // Only cancel if we're not already cancelled
  1428. if ( WBEM_S_NO_ERROR == m_hErrorRes )
  1429. {
  1430. m_hErrorRes = hRes;
  1431. // Dump the map
  1432. MRGRKEYTOINSTMAPITER it = m_map.begin();
  1433. while ( it != m_map.end())
  1434. {
  1435. // Subtract since we are removing from the map
  1436. lArbitratorAdjust -= it->second.m_dwObjSize;
  1437. // Inform the arbitrator of the removed object size
  1438. it->second.m_pData->Release();
  1439. it = m_map.erase(it);
  1440. } // WHILE dumping map
  1441. // Adjust total object size now. Actual Arbitrator adjustment should occur outside a critical
  1442. // section
  1443. AdjustLocalObjectSize( lArbitratorAdjust );
  1444. // This will prevent DispatchOwn() from continuing with a now bogus
  1445. // iteration
  1446. m_DispatchOwnIter = m_map.end();
  1447. m_Throttler.Cancel();
  1448. ics.Leave();
  1449. // Always report adjustments
  1450. HRESULT hrArbitrate = ReportMemoryUsage( lArbitratorAdjust );
  1451. // No sense reporting errors here, since we've just told the arbitrator to cancel anyway
  1452. } // IF not already cancelled
  1453. }
  1454. HRESULT CInternalMerger::ReportMemoryUsage( long lMemUsage )
  1455. {
  1456. // Always report adjustments
  1457. HRESULT hRes = m_pWmiMergerRecord->GetWmiMerger()->ReportMemoryUsage( lMemUsage );
  1458. // An indication we *should* throttle is not considered an error for purposes
  1459. // of this function.
  1460. if ( WBEM_E_ARB_THROTTLE == hRes || WBEM_S_ARB_NOTHROTTLING == hRes )
  1461. {
  1462. hRes = WBEM_S_NO_ERROR;
  1463. }
  1464. return hRes;
  1465. }
  1466. //***************************************************************************
  1467. //
  1468. // CMergerSink::QueryInterface
  1469. //
  1470. // Exports IWbemOnjectSink interface.
  1471. //
  1472. //***************************************************************************
  1473. STDMETHODIMP CMergerSink::QueryInterface(
  1474. IN REFIID riid,
  1475. OUT LPVOID *ppvObj
  1476. )
  1477. {
  1478. *ppvObj = 0;
  1479. if (IID_IUnknown==riid || IID_IWbemObjectSink==riid)
  1480. {
  1481. *ppvObj = (IWbemObjectSink*)this;
  1482. AddRef();
  1483. return S_OK;
  1484. }
  1485. return E_NOINTERFACE;
  1486. }
  1487. //***************************************************************************
  1488. //
  1489. //***************************************************************************
  1490. //
  1491. ULONG CMergerSink::AddRef()
  1492. {
  1493. // We keep an internal ref count and also pass up to the
  1494. // merger
  1495. InterlockedIncrement( &m_lRefCount );
  1496. return m_pMerger->AddRef();
  1497. }
  1498. //***************************************************************************
  1499. //
  1500. //***************************************************************************
  1501. //
  1502. ULONG CMergerSink::Release()
  1503. {
  1504. // We keep an internal ref count and also pass up to the
  1505. // merger
  1506. long lRef = InterlockedDecrement( &m_lRefCount );
  1507. // Ref Count should never go below 0L
  1508. _DBG_ASSERT( lRef >= 0 );
  1509. // If we are at the final release for the sink, we will perform cleanup.
  1510. // otherwise, the sink is more or less dead and just waiting for the WMI
  1511. // Merger object to be destructed so we get cleaned up.
  1512. if ( lRef == 0 )
  1513. {
  1514. OnFinalRelease();
  1515. }
  1516. return m_pMerger->Release();
  1517. }
  1518. CMergerTargetSink::CMergerTargetSink( CWmiMerger* pMerger, IWbemObjectSink* pDest )
  1519. : CMergerSink( pMerger ),
  1520. m_pDest( pDest )
  1521. {
  1522. if ( NULL != m_pDest )
  1523. {
  1524. m_pDest->AddRef();
  1525. }
  1526. }
  1527. CMergerTargetSink::~CMergerTargetSink()
  1528. {
  1529. if ( NULL != m_pDest )
  1530. {
  1531. m_pDest->Release();
  1532. }
  1533. }
  1534. HRESULT STDMETHODCALLTYPE CMergerTargetSink::Indicate(long lObjectCount, IWbemClassObject** pObjArray)
  1535. {
  1536. // Since we don't want the fact we're sleeping in the arbitrator to
  1537. // cause the merger to cancel operations, we'll increase the count
  1538. // of threads throttling, and decrement when we return.
  1539. // We do this here because the call to Indicate goes outside the scope
  1540. // of the merger, and this call may end up throttling.
  1541. m_pMerger->IncrementArbitratorThrottling();
  1542. HRESULT hr = m_pDest->Indicate( lObjectCount, pObjArray );
  1543. m_pMerger->DecrementArbitratorThrottling();
  1544. return hr;
  1545. }
  1546. HRESULT STDMETHODCALLTYPE CMergerTargetSink::SetStatus( long lFlags, long lParam, BSTR strParam,
  1547. IWbemClassObject* pObjParam )
  1548. {
  1549. return m_pDest->SetStatus( lFlags, lParam, strParam, pObjParam );
  1550. }
  1551. HRESULT CMergerTargetSink::Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated )
  1552. {
  1553. // Well, we're indicating this number of objects, aren't we?
  1554. if ( NULL != plNumIndicated )
  1555. {
  1556. *plNumIndicated = lObjectCount;
  1557. }
  1558. // Really just a place holder here. Just call the standard version
  1559. return Indicate( lObjectCount, pObjArray );
  1560. }
  1561. HRESULT CMergerTargetSink::OnFinalRelease( void )
  1562. {
  1563. // This is where we will send the actual status *and* tell the merger we're done
  1564. return m_pMerger->Shutdown();
  1565. }
  1566. long g_lNumMergerSinks = 0L;
  1567. CMergerSink::CMergerSink( CWmiMerger* pMerger )
  1568. : m_pMerger( pMerger ), m_lRefCount( 0L )
  1569. {
  1570. InterlockedIncrement( &g_lNumMergerSinks );
  1571. }
  1572. CMergerSink::~CMergerSink( void )
  1573. {
  1574. InterlockedDecrement( &g_lNumMergerSinks );
  1575. }
  1576. // OwnInstance Sink
  1577. CInternalMerger::COwnInstanceSink::~COwnInstanceSink()
  1578. {
  1579. if ( NULL != m_pMergedInstance )
  1580. {
  1581. m_pMergedInstance->Release();
  1582. }
  1583. }
  1584. // Called in response to a request for GetObject(). In this case, there should be only
  1585. // one object indicated. Additionally, it should match the requested path.
  1586. HRESULT STDMETHODCALLTYPE CInternalMerger::COwnInstanceSink::Indicate(long lObjectCount, IWbemClassObject** pObjArray )
  1587. {
  1588. HRESULT hRes = WBEM_S_NO_ERROR;
  1589. if ( lObjectCount > 0L )
  1590. {
  1591. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  1592. // Only do this if we don't have a merged instance
  1593. if ( NULL == m_pMergedInstance )
  1594. {
  1595. if ( !m_bTriedRetrieve )
  1596. {
  1597. // This call doesn't throttle, so don't worry about crit secs here
  1598. for ( long x = 0; SUCCEEDED( hRes ) && x < lObjectCount; x++ )
  1599. {
  1600. hRes = m_pInternalMerger->AddOwnInstance( pObjArray[x], m_wsInstPath, &m_pMergedInstance );
  1601. }
  1602. // Record the final status if we need to
  1603. if ( FAILED( hRes ) )
  1604. {
  1605. SetFinalStatus( hRes );
  1606. }
  1607. }
  1608. else
  1609. {
  1610. // The following call can and will throttle, so do it
  1611. // outside of our critical section
  1612. ics.Leave();
  1613. // Clearly a lowest level indicate
  1614. hRes = m_pInternalMerger->AddOwnObjects( lObjectCount, pObjArray, true, NULL );
  1615. // We beefed - reflect this in the final status
  1616. if ( FAILED( hRes ) )
  1617. {
  1618. ics.Enter();
  1619. SetFinalStatus( hRes );
  1620. }
  1621. }
  1622. }
  1623. else
  1624. {
  1625. hRes = WBEM_E_INVALID_OPERATION;
  1626. }
  1627. }
  1628. return hRes;
  1629. }
  1630. HRESULT STDMETHODCALLTYPE CInternalMerger::COwnInstanceSink::SetStatus( long lFlags, long lParam, BSTR strParam,
  1631. IWbemClassObject* pObjParam )
  1632. {
  1633. HRESULT hr = WBEM_S_NO_ERROR;
  1634. // If we got a complete, remove the instance if it was never merged
  1635. if ( lFlags == WBEM_STATUS_COMPLETE )
  1636. {
  1637. CCheckedInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  1638. if ( SUCCEEDED( lParam ) )
  1639. {
  1640. if ( NULL == m_pMergedInstance )
  1641. {
  1642. hr = m_pInternalMerger->RemoveInstance( m_wsInstPath );
  1643. // If we tanked here, we are so busted.
  1644. if ( FAILED( hr ) )
  1645. {
  1646. lParam = hr;
  1647. }
  1648. } // IF NULL == m_pMergedInstance
  1649. }
  1650. else
  1651. {
  1652. // Remove the Instance now as well
  1653. hr = m_pInternalMerger->RemoveInstance( m_wsInstPath );
  1654. // If we tanked here, we are so busted.
  1655. if ( FAILED( hr ) )
  1656. {
  1657. lParam = hr;
  1658. }
  1659. // We should record the final status if it is not WBEM_E_NOT_FOUND
  1660. if ( WBEM_E_NOT_FOUND != lParam )
  1661. {
  1662. SetFinalStatus( lParam );
  1663. }
  1664. // If we got a failure status, axe the instance now
  1665. if ( NULL != m_pMergedInstance )
  1666. {
  1667. m_pMergedInstance->Release();
  1668. m_pMergedInstance = NULL;
  1669. }
  1670. }
  1671. ics.Leave();
  1672. // Always pass down to the base class
  1673. hr = CMemberSink::SetStatus( lFlags, lParam, strParam, pObjParam );
  1674. }
  1675. else
  1676. {
  1677. // Always pass down to the base class
  1678. hr = CMemberSink::SetStatus( lFlags, lParam, strParam, pObjParam );
  1679. }
  1680. return hr;
  1681. }
  1682. HRESULT CInternalMerger::COwnInstanceSink::Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated )
  1683. {
  1684. // This should Never be called
  1685. _DBG_ASSERT( 0 );
  1686. return WBEM_E_INVALID_OPERATION;
  1687. }
  1688. HRESULT CInternalMerger::COwnInstanceSink::SetInstancePath( LPCWSTR pwszPath )
  1689. {
  1690. HRESULT hRes = WBEM_S_NO_ERROR;
  1691. try
  1692. {
  1693. m_wsInstPath = pwszPath;
  1694. }
  1695. catch( CX_MemoryException )
  1696. {
  1697. hRes = WBEM_E_OUT_OF_MEMORY;
  1698. }
  1699. catch(...)
  1700. {
  1701. ExceptionCounter c;
  1702. hRes = WBEM_E_FAILED;
  1703. }
  1704. return hRes;
  1705. }
  1706. HRESULT CInternalMerger::COwnInstanceSink::GetObject( IWbemClassObject** ppMergedInst )
  1707. {
  1708. HRESULT hRes = WBEM_S_NO_ERROR;
  1709. CInCritSec ics( &m_cs ); // SEC:REVIEWED 2002-03-22 : Assumes entry
  1710. // If final status on this sink shows a failure, then we should return that failure
  1711. // mostly cause we're doomed anyway at this point
  1712. if ( SUCCEEDED( m_hFinalStatus ) )
  1713. {
  1714. if ( NULL != m_pMergedInstance )
  1715. {
  1716. m_pMergedInstance->AddRef();
  1717. *ppMergedInst = m_pMergedInstance;
  1718. }
  1719. else
  1720. {
  1721. hRes = WBEM_S_FALSE;
  1722. }
  1723. }
  1724. else
  1725. {
  1726. hRes = m_hFinalStatus;
  1727. }
  1728. // We tried to retrieve it once - so if further indicates come in,
  1729. // they will be passed off to AddOwnObjects
  1730. m_bTriedRetrieve = true;
  1731. return hRes;
  1732. }
  1733. HRESULT CInternalMerger::COwnInstanceSink::OnFinalRelease( void )
  1734. {
  1735. // Wer should clean this up
  1736. m_pInternalMerger->Release();
  1737. return WBEM_S_NO_ERROR;
  1738. }
  1739. // Only reports negative memory usage if the original number was positive
  1740. CInternalMerger::CScopedMemoryUsage::~CScopedMemoryUsage( void )
  1741. {
  1742. Cleanup();
  1743. }
  1744. // Reports memory usage and accounts for errors as deemed appropriate
  1745. HRESULT CInternalMerger::CScopedMemoryUsage::ReportMemoryUsage( long lMemUsage )
  1746. {
  1747. _DBG_ASSERT( m_lMemUsage >= 0L );
  1748. HRESULT hr = m_pInternalMerger->ReportMemoryUsage( lMemUsage );
  1749. // If we get a suceess code or WBEM_E_ARB_CANCEL, we need to cleanup
  1750. // the memory usage when we go out of scope.
  1751. if ( ( SUCCEEDED( hr ) || hr == WBEM_E_ARB_CANCEL ) )
  1752. {
  1753. m_lMemUsage += lMemUsage;
  1754. m_bCleanup = true;
  1755. }
  1756. return hr;
  1757. }
  1758. // Cleans up any memory usage as we deemed appropriate
  1759. HRESULT CInternalMerger::CScopedMemoryUsage::Cleanup( void )
  1760. {
  1761. _DBG_ASSERT( m_lMemUsage >= 0L );
  1762. HRESULT hr = WBEM_S_NO_ERROR;
  1763. // Cleanup as appropriate
  1764. if ( m_bCleanup && m_lMemUsage > 0L )
  1765. {
  1766. hr = m_pInternalMerger->ReportMemoryUsage( -m_lMemUsage );
  1767. }
  1768. m_bCleanup = false;
  1769. m_lMemUsage = 0L;
  1770. return hr;
  1771. }