/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: INTERNALMERGER.H Abstract: CInternalMerger class. History: 30-Nov-00 sanjes Created. --*/ #ifndef _INTERNALMERGER_H_ #define _INTERNALMERGER_H_ #include "mergerthrottling.h" #include "wstlallc.h" // Forward class definitions class CWmiMergerRecord; // Base class for merger sinks - all of these will be created by the // merger and will AddRef() the merger. The merger class will be used // to create the sinks. When the Merger is destroyed, it will delete // all of the sink. Internal Merger objects MUST NOT AddRef these sinks // so we don't create a circular dependency. typedef enum { eMergerFinalSink, eMergerOwnSink, eMergerChildSink, eMergerOwnInstanceSink } MergerSinkType; class CMergerSink : public CBasicObjectSink { protected: CWmiMerger* m_pMerger; long m_lRefCount; virtual HRESULT OnFinalRelease( void ) = 0; public: CMergerSink( CWmiMerger* pMerger ); virtual ~CMergerSink(); /* IUnknown methods */ STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD_(ULONG, Release)(THIS); virtual HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ) = 0L; }; class CMergerTargetSink : public CMergerSink { protected: IWbemObjectSink* m_pDest; virtual HRESULT OnFinalRelease( void ); public: CMergerTargetSink( CWmiMerger* pMerger, IWbemObjectSink* pDest ); ~CMergerTargetSink(); HRESULT STDMETHODCALLTYPE Indicate(long lObjectCount, IWbemClassObject** pObjArray); HRESULT STDMETHODCALLTYPE SetStatus( long lFlags, long lParam, BSTR strParam, IWbemClassObject* pObjParam ); // Function allows us to track the lowest level call in the merger so we can decide // if we need to automagically report all indicated objects to the arbitrator HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); }; // Causes the stl Map to use our allocator instead of the default struct CInternalMergerRecord { CWbemInstance* m_pData; DWORD m_dwObjSize; BOOL m_bOwn; }; // Defines an allocator so we can throw exceptions class CKeyToInstRecordAlloc : public wbem_allocator { }; inline bool operator==(const CKeyToInstRecordAlloc&, const CKeyToInstRecordAlloc&) { return (true); } inline bool operator!=(const CKeyToInstRecordAlloc&, const CKeyToInstRecordAlloc&) { return (false); } typedef std::map MRGRKEYTOINSTMAP; typedef std::map::iterator MRGRKEYTOINSTMAPITER; // This is the actual workhorse class for merging instances returned from // queries. class CInternalMerger { protected: // Helper class for scoped cleanup of memory usage class CScopedMemoryUsage { CInternalMerger* m_pInternalMerger; bool m_bCleanup; long m_lMemUsage; public: CScopedMemoryUsage( CInternalMerger* pInternalMerger ) : m_pInternalMerger( pInternalMerger ), m_bCleanup( false ), m_lMemUsage( 0L ) {}; ~CScopedMemoryUsage(); HRESULT ReportMemoryUsage( long lMemUsage ); HRESULT Cleanup( void ); }; class CMemberSink : public CMergerSink { protected: CInternalMerger* m_pInternalMerger; public: CMemberSink( CInternalMerger* pMerger, CWmiMerger* pWmiMerger ) : CMergerSink( pWmiMerger ), m_pInternalMerger( pMerger ) {} STDMETHOD_(ULONG, AddRef)(THIS); STDMETHOD(SetStatus)(long lFlags, long lParam, BSTR strParam, IWbemClassObject* pObjParam); }; friend CMemberSink; class COwnSink : public CMemberSink { protected: virtual HRESULT OnFinalRelease( void ); public: COwnSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger) : CMemberSink(pMerger, pWmiMerger){}; ~COwnSink(); STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray); // Function allows us to track the lowest level call in the merger so we can decide // if we need to automagically report all indicated objects to the arbitrator HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); }; friend COwnSink; class CChildSink : public CMemberSink { protected: virtual HRESULT OnFinalRelease( void ); public: CChildSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger) : CMemberSink(pMerger, pWmiMerger){}; ~CChildSink(); STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray); // Function allows us to track the lowest level call in the merger so we can decide // if we need to automagically report all indicated objects to the arbitrator HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); }; class COwnInstanceSink : public CMemberSink { CCritSec m_cs; WString m_wsInstPath; IWbemClassObject* m_pMergedInstance; bool m_bTriedRetrieve; HRESULT m_hFinalStatus; protected: virtual HRESULT OnFinalRelease( void ); public: COwnInstanceSink(CInternalMerger* pMerger, CWmiMerger* pWmiMerger) : CMemberSink(pMerger, pWmiMerger), m_pMergedInstance( NULL ), m_wsInstPath(), m_cs(), m_bTriedRetrieve( false ), m_hFinalStatus( WBEM_S_NO_ERROR ) {}; ~COwnInstanceSink(); STDMETHOD(Indicate)(long lObjectCount, IWbemClassObject** pObjArray); STDMETHOD(SetStatus)(long lFlags, long lParam, BSTR strParam, IWbemClassObject* pObjParam); // This should never be called here HRESULT Indicate(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); HRESULT SetInstancePath( LPCWSTR pwszPath ); HRESULT GetObject( IWbemClassObject** ppMergedInst ); void SetFinalStatus( HRESULT hRes ) { if ( SUCCEEDED( m_hFinalStatus ) ) m_hFinalStatus = hRes; }; }; friend CChildSink; public: // Helpers for creating sinks static HRESULT CreateMergingSink( MergerSinkType eType, CInternalMerger* pMerger, CWmiMerger* pWmiMerger, CMergerSink** ppSink ); // 2 stage initialization HRESULT Initialize( void ); protected: COwnSink* m_pOwnSink; CChildSink* m_pChildSink; CMergerSink* m_pDest; BOOL m_bDerivedFromTarget; CWbemClass* m_pOwnClass; CWbemNamespace* m_pNamespace; IWbemContext* m_pContext; CWmiMergerRecord* m_pWmiMergerRecord; MRGRKEYTOINSTMAP m_map; BOOL m_bOwnDone; BOOL m_bChildrenDone; WString m_wsClass; long m_lRef; IServerSecurity* m_pSecurity; // This is set when we encounter an error condition and are cancelled HRESULT m_hErrorRes; // m_Throttler - sounds like a Supervillain...hmmm... CMergerThrottling m_Throttler; // Helps debug how much data this internal merger is consuming long m_lTotalObjectData; // Iterator which may require state to be kept MRGRKEYTOINSTMAPITER m_DispatchOwnIter; protected: HRESULT AddOwnObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); HRESULT AddChildObjects(long lObjectCount, IWbemClassObject** pObjArray, bool bLowestLevel, long* plNumIndicated ); HRESULT AddOwnInstance( IWbemClassObject* pObj, LPCWSTR wszTargetKey, IWbemClassObject** ppMergedInstance); HRESULT RemoveInstance( LPCWSTR pwszInstancePath ); HRESULT GetObjectLength( IWbemClassObject* pObj, long* plObjectSize ); // inline helper - adjusts throttler totals, then allows it to release itself if // apropriate void AdjustThrottle( long lNumParentObjects, long lNumChildObjects ) { // Adjust the throttler now. m_Throttler.AdjustNumParentObjects( lNumParentObjects ); m_Throttler.AdjustNumChildObjects( lNumChildObjects ); // Let the Throttler release itself if it can m_Throttler.ReleaseThrottle(); } // Helper function to perform Indicating and throttling - a lot of the code is more or // less the same so this at least attempts to encapsulate it. HRESULT IndicateArrayAndThrottle( long lObjectCount, CRefedPointerArray* pObjArray, CWStringArray* pwsKeyArray, long lMapAdjustmentSize, long lNewObjectSize, bool bThrottle, bool bParent, long* plNumIndicated ); void Enter() { m_Throttler.Enter(); } void Leave() { m_Throttler.Leave(); } long AddRef(); long Release(); void OwnIsDone(); void ChildrenAreDone(); void DispatchChildren(); void DispatchOwn(); void GetKey(IWbemClassObject* pInst, WString& wsKey); HRESULT GetOwnInstance(LPCWSTR wszKey, IWbemClassObject** ppMergedInstance); BOOL IsDone() {return m_bOwnDone && m_bChildrenDone;} void AdjustLocalObjectSize( long lAdjust ) { m_lTotalObjectData += lAdjust; _DBG_ASSERT( m_lTotalObjectData >= 0L ); } HRESULT ReportMemoryUsage( long lMemUsage ); public: CInternalMerger(CWmiMergerRecord* pWmiMergerRecord, CMergerSink* pDest, CWbemClass* pOwnClass, CWbemNamespace* pNamespace = NULL, IWbemContext* pContext = NULL); ~CInternalMerger(); void SetIsDerivedFromTarget(BOOL bIs); void Cancel( HRESULT hRes = WBEM_E_CALL_CANCELLED ); CMergerSink* GetOwnSink() { if ( NULL != m_pOwnSink ) m_pOwnSink->AddRef(); return m_pOwnSink;} CMergerSink* GetChildSink() { if ( NULL != m_pChildSink ) m_pChildSink->AddRef(); return m_pChildSink; } CWmiMerger* GetWmiMerger( void ); // Helper to cancel a child sink when we don't need one (i.e. if we're fully static). //void CancelChildSink( void ) { ChildrenAreDone(); } }; #endif