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.

398 lines
12 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. WMIMERGER.H
  5. Abstract:
  6. Implements _IWmiMerger
  7. History:
  8. 16-Nov-00 sanjes Created.
  9. --*/
  10. #ifndef _WMIMERGER_H_
  11. #define _WMIMERGER_H_
  12. #include "internalmerger.h"
  13. #include "mergerreq.h"
  14. // forward class definitions
  15. class CWmiMerger;
  16. //
  17. // Support class for CWmiMerger.
  18. //
  19. // Basically, CWmiMerger holds onto many instances of CWmiMergerRecord
  20. //
  21. class CWmiMergerRecord
  22. {
  23. private:
  24. BOOL m_fHasInstances;
  25. BOOL m_fHasChildren;
  26. DWORD m_dwLevel;
  27. WString m_wsClass;
  28. CWmiMerger* m_pMerger;
  29. CInternalMerger* m_pInternalMerger;
  30. CMergerSink* m_pDestSink;
  31. CPointerArray<CWmiMergerRecord> m_ChildArray;
  32. bool m_bScheduledChildRequest;
  33. IWbemContext* m_pExecutionContext;
  34. bool m_bStatic;
  35. public:
  36. CWmiMergerRecord( CWmiMerger* pMerger, BOOL fHasInstances, BOOL fHasChildren,
  37. LPCWSTR pwszClass, CMergerSink* pDestSink, DWORD dwLevel,
  38. bool bStatic );
  39. ~CWmiMergerRecord();
  40. CMergerSink* GetChildSink( void );
  41. CMergerSink* GetOwnSink( void );
  42. CMergerSink* GetDestSink( void );
  43. LPCWSTR GetClass( void ) { return m_wsClass; }
  44. LPCWSTR GetName( void ) { return GetClass(); }
  45. BOOL IsClass( LPCWSTR pwszClass ) { return m_wsClass.EqualNoCase( pwszClass ); }
  46. DWORD GetLevel( void ) { return m_dwLevel; }
  47. bool IsStatic( void ) { return m_bStatic; }
  48. HRESULT AttachInternalMerger( CWbemClass* pClass, CWbemNamespace* pNamespace, IWbemContext* pCtx,
  49. BOOL fDerivedFromTarget, bool bStatic );
  50. HRESULT AddChild( CWmiMergerRecord* pRecord );
  51. CWmiMerger* GetWmiMerger( void ) { return m_pMerger; }
  52. // If we have an internal merger, we tell it to cancel
  53. void Cancel( HRESULT hRes );
  54. bool ScheduledChildRequest( void ) { return m_bScheduledChildRequest; }
  55. void SetScheduledChildRequest( void ) { m_bScheduledChildRequest = true; }
  56. CWmiMergerRecord* GetChildRecord( int nIndex );
  57. HRESULT SetExecutionContext( IWbemContext* pContext );
  58. IWbemContext* GetExecutionContext( void ) { return m_pExecutionContext; }
  59. // We can only cancel child sinks if we have an internal merger.
  60. //void CancelChildSink( void ) { if ( NULL != m_pInternalMerger ) m_pInternalMerger->CancelChildSink(); }
  61. void SetIsStatic( bool b ) { m_bStatic = b; }
  62. };
  63. // Allows us to locate values quickly by name
  64. template<class TMember>
  65. class CSortedUniquePointerArray :
  66. public CUniquePointerArray<TMember>
  67. {
  68. public:
  69. int Insert( TMember* pNewElement );
  70. TMember* Find( LPCWSTR pwszName, int* pnIndex = NULL );
  71. int RemoveAtNoDelete( int nIndex );
  72. BOOL Verify( void );
  73. };
  74. template <class TMember>
  75. int CSortedUniquePointerArray<TMember>::Insert( TMember* pNewElement )
  76. {
  77. int nLowIndex = 0,
  78. nHighIndex = m_Array.Size();
  79. // Binary search of the ids to find an index at which to insert
  80. // If we find our element, this is a failure.
  81. while ( nLowIndex < nHighIndex )
  82. {
  83. int nMid = (nLowIndex + nHighIndex) / 2;
  84. int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pNewElement->GetName() );
  85. if ( nTest < 0 )
  86. {
  87. nLowIndex = nMid + 1;
  88. }
  89. else if ( nTest > 0 )
  90. {
  91. nHighIndex = nMid;
  92. }
  93. else
  94. {
  95. _DBG_ASSERT( 0 );
  96. // Index already exists
  97. return -1;
  98. }
  99. } // WHILE looking for index
  100. // Found the location, if it's at the end, check if we need to do an insert or add
  101. // We insert if the element at the end is > the element we want to insert
  102. BOOL bInsert = true;
  103. if ( nLowIndex == GetSize() - 1 )
  104. {
  105. bInsert = ( _wcsicmp( ((TMember*) m_Array[nLowIndex])->GetName(), pNewElement->GetName() ) > 0 );
  106. }
  107. // Stick it in (careful to add to the end if the selected index is the end
  108. // and the current element is not greater than the new one).
  109. if ( bInsert )
  110. {
  111. return InsertAt( nLowIndex, pNewElement );
  112. }
  113. return Add( pNewElement );
  114. }
  115. template <class TMember>
  116. TMember* CSortedUniquePointerArray<TMember>::Find( LPCWSTR pwszName, int* pnIndex )
  117. {
  118. int nLowIndex = 0,
  119. nHighIndex = m_Array.Size();
  120. // Binary search of the values to find a the requested name.
  121. while ( nLowIndex < nHighIndex )
  122. {
  123. int nMid = (nLowIndex + nHighIndex) / 2;
  124. int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pwszName );
  125. if ( nTest < 0 )
  126. {
  127. nLowIndex = nMid + 1;
  128. }
  129. else if ( nTest > 0 )
  130. {
  131. nHighIndex = nMid;
  132. }
  133. else
  134. {
  135. // Found it
  136. if ( NULL != pnIndex )
  137. {
  138. *pnIndex = nMid;
  139. }
  140. return (TMember*) m_Array[nMid];
  141. }
  142. } // WHILE looking for index
  143. // Didn't find it
  144. return NULL;
  145. }
  146. // Removes the element, but does not auto-delete it
  147. template <class TMember>
  148. int CSortedUniquePointerArray<TMember>::RemoveAtNoDelete( int nIndex )
  149. {
  150. if ( nIndex >= m_Array.Size() )
  151. {
  152. return -1;
  153. }
  154. m_Array.RemoveAt( nIndex );
  155. return nIndex;
  156. }
  157. template <class TMember>
  158. BOOL CSortedUniquePointerArray<TMember>::Verify( void )
  159. {
  160. BOOL fReturn = TRUE;
  161. for ( int x = 0; fReturn && x < GetSize() - 1; x++ )
  162. {
  163. // Should be in ascending order
  164. LPCWSTR pwszFirst = GetAt( x )->GetName();
  165. LPCWSTR pwszSecond = GetAt( x+1 )->GetName();
  166. fReturn = ( _wcsicmp( GetAt( x )->GetName(), GetAt( x+1 )->GetName() ) < 0 );
  167. _DBG_ASSERT( fReturn );
  168. if ( !fReturn )
  169. {
  170. CSortedUniquePointerArray<TMember> tempArray;
  171. for ( int y = 0; y < GetSize(); y++ )
  172. {
  173. tempArray.Insert( GetAt( y ) );
  174. }
  175. }
  176. }
  177. return fReturn;
  178. }
  179. //******************************************************************************
  180. //******************************************************************************
  181. //
  182. // class CWmiMerger
  183. //
  184. // This class implements the WMI Merger.
  185. //
  186. //******************************************************************************
  187. class CWmiMerger : public _IWmiArbitratee, public _IWmiArbitratedQuery
  188. {
  189. private:
  190. long m_lRefCount;
  191. WString m_wsTargetClassName;
  192. CMergerTargetSink* m_pTargetSink;
  193. _IWmiCoreHandle* m_pTask;
  194. _IWmiArbitrator* m_pArbitrator;
  195. CWbemNamespace* m_pNamespace;
  196. DWORD m_dwProviderDeliveryPing;
  197. DWORD m_dwMaxLevel;
  198. DWORD m_dwMinReqLevel;
  199. CSortedUniquePointerArray<CWmiMergerRecord> m_MergerRecord;
  200. //
  201. // the sinks of the merger are wired objects
  202. // thy have a refcount a-la-COM, but they are destructed by the
  203. // Manager of the m_MergerSinks Array
  204. //
  205. CUniquePointerArray<CMergerSink> m_MergerSinks;
  206. long m_lNumArbThrottled;
  207. HRESULT m_hOperationRes;
  208. bool m_bMergerThrottlingEnabled;
  209. CCritSec m_cs;
  210. long m_lDebugMemUsed;
  211. CWmiMergerRequestMgr* m_pRequestMgr;
  212. void CleanChildRequests(CWmiMergerRecord* pParentRecord, int startingWith);
  213. public:
  214. // No access
  215. CWmiMerger( CWbemNamespace* pNamespace );
  216. ~CWmiMerger();
  217. protected:
  218. HRESULT GetLevelAndSuperClass( _IWmiObject* pObj, DWORD* pdwLevel,
  219. _variant_t & vSuperClass );
  220. public:
  221. /* IUnknown methods */
  222. STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
  223. STDMETHOD_(ULONG, AddRef)(THIS);
  224. STDMETHOD_(ULONG, Release)(THIS);
  225. /* _IWmiArbitratee methods */
  226. STDMETHOD(SetOperationResult)( ULONG uFlags, HRESULT hRes );
  227. STDMETHOD(SetTaskHandle)( _IWmiCoreHandle* pTask );
  228. STDMETHOD(DumpDebugInfo)( ULONG uFlags, const BSTR strFile );
  229. /* _IWmiArbitratedQuery methods */
  230. STDMETHOD(IsMerger)( void );
  231. // Sets initial parameters for merger. Establishes the target class and sink for the
  232. // query associated with the merger
  233. STDMETHOD(Initialize)( _IWmiArbitrator* pArbitrator, _IWmiCoreHandle* pTask, LPCWSTR pwszTargetClass, IWbemObjectSink* pTargetSink, CMergerSink** ppFinalSink );
  234. // Called to request a delivery sink for a class in the query chain. The returned
  235. // sink is determined by the specified flags as well as settings on the parent class
  236. STDMETHOD(RegisterSinkForClass)( LPCWSTR pwszClass, _IWmiObject* pClass, IWbemContext* pContext,
  237. BOOL fHasChildren, BOOL fHasInstances, BOOL fDerivedFromTarget,
  238. bool bStatic, CMergerSink* pDestSink, CMergerSink** ppOwnSink, CMergerSink** ppChildSink );
  239. // Called to request a delivery sink for child classes in the query chain. This is especially
  240. // important when instances are merged under the covers.
  241. STDMETHOD(GetChildSink)( LPCWSTR pwszClass, CBasicObjectSink** ppSink );
  242. // Can be used to holdoff indicates - if we're merging instances from multiple providers, we need
  243. // to ensure that we don't get lopsided in the number of objects we've got queued up for merging.
  244. STDMETHOD(Throttle)( void );
  245. // Merger will hold information regarding the total number of objects it has queued up waiting
  246. // for merging and the amount of memory consumed by those objects.
  247. STDMETHOD(GetQueuedObjectInfo)( DWORD* pdwNumQueuedObjects, DWORD* pdwQueuedObjectMemSize );
  248. // If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
  249. // objects. This will also automatically free up resources consumed by queued objects.
  250. STDMETHOD(Cancel)( void );
  251. // Helper function for creating our sinks - this will add the sink to our array of
  252. // sinks which will get destroyed when we are released
  253. HRESULT CreateMergingSink( MergerSinkType eType, IWbemObjectSink* pDestSink, CInternalMerger* pMerger, CMergerSink** ppSink );
  254. // If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
  255. // objects. This will also automatically free up resources consumed by queued objects.
  256. HRESULT Cancel( HRESULT hRes );
  257. // Final Shutdown. Called when the target sink is released. At this point, we should
  258. // unregister ourselves from the world
  259. HRESULT Shutdown( void );
  260. // Registers arbitrated requests
  261. HRESULT RegisterArbitratedInstRequest( CWbemObject* pClassDef, long lFlags, IWbemContext* pCtx,
  262. CBasicObjectSink* pSink, BOOL bComplexQuery, CWbemNamespace* pNs );
  263. HRESULT RegisterArbitratedQueryRequest( CWbemObject* pClassDef, long lFlags, LPCWSTR Query,
  264. LPCWSTR QueryFormat, IWbemContext* pCtx, CBasicObjectSink* pSink,
  265. CWbemNamespace* pNs );
  266. HRESULT RegisterArbitratedStaticRequest( CWbemObject* pClassDef, long lFlags,
  267. IWbemContext* pCtx, CBasicObjectSink* pSink, CWbemNamespace* pNs,
  268. QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery );
  269. // Executes a Merger Parent Request - Cycles through parent object requests and executes
  270. // them as appropriate
  271. HRESULT Exec_MergerParentRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
  272. // Executes a Merger Child Request - Cycles through child classes of the given parent
  273. // class, and executes the appropriate requests
  274. HRESULT Exec_MergerChildRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
  275. // Schedules a Merger Parent Request if one is necessary
  276. HRESULT ScheduleMergerParentRequest( IWbemContext* pCtx );
  277. // Schedules a Merger Child Request
  278. HRESULT ScheduleMergerChildRequest( CWmiMergerRecord* pParentRecord );
  279. // Enables/Disables merger throttling in all records (on by default)
  280. void EnableMergerThrottling( bool b ) { m_bMergerThrottlingEnabled = b; }
  281. // Returns whether or not we have a single static request in the merger
  282. BOOL IsSingleStaticRequest( void );
  283. bool MergerThrottlingEnabled( void ) { return m_bMergerThrottlingEnabled; }
  284. _IWmiCoreHandle* GetTask( void ) { return m_pTask; }
  285. // Help us track that *something* is going on
  286. // We are intentionally not wrapping thread safety around these guys, since assigning and
  287. // retrieving the value is an atomic operation and realistically, if any contention occurs
  288. // setting the values, they should all, more or less reflect the same tick (remember, they're
  289. // all jumping in at the same time, so this shouldn't really be a problem.
  290. void PingDelivery( DWORD dwLastPing ) { m_dwProviderDeliveryPing = dwLastPing; }
  291. DWORD GetLastDeliveryTime( void ) { return m_dwProviderDeliveryPing; }
  292. HRESULT ReportMemoryUsage( long lAdjustment );
  293. // Helper functions for tracking the number of threads potentially being throttled by
  294. // the arbitrator
  295. long IncrementArbitratorThrottling( void ) { return InterlockedIncrement( &m_lNumArbThrottled ); }
  296. long DecrementArbitratorThrottling( void ) { return InterlockedDecrement( &m_lNumArbThrottled ); }
  297. long NumArbitratorThrottling( void ) { return m_lNumArbThrottled ; }
  298. };
  299. #endif
  300.