/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: MERGERREQ.H Abstract: Definitions of Merger Request classes History: 28-Feb-01 sanjes Created. --*/ #ifndef _MERGERREQ_H_ #define _MERGERREQ_H_ // forward class definitions class CWmiMerger; class CWmiMergerRecord; // // Merger Requests // // In previous releases, when the query engine analyzed a query, it enqueued // a large number of requests, one for each dynamically provided class. Each // of these could be handled on a separate thread, which could cause a // significant thread explosion as each request was handed to a separate thread. // // In order to better control the threads, we are using the merger to perform // a more intelligent analysis of a query and then spin off threads only when // we reach throttling conditions. Now, instead of enqueing a large number of // requests, the merger maintains hierarchical information regarding parents and // their children in its record classes, and stores necessary requests in a // manager which doles out requests as we need them. // // The idea is, is that we will spin off a single request which will begin // executing the first topmost request, say "ClassA:. As we execute the request // for instances of "ClassA" if the request is throttled in the merger, we check // if we have submitted a request to handle children of "ClassA". If not, then // prior to throttling, we will schedule a "Children of ClassA" request. This // request will use the merger record for "ClassA" to determine what child classes // there are for "ClassA", and then we will walk the child classes, pulling the // appropriate requests from the merger request manager. // // As we process each request, it in turn may be throttled, at which point we will // spin off another child request. In this way, we limit the number of threads // required to service the query to at most one per level of a hierarchy. In each // case, once all children are processed, we will return the thread back to the // threadpool. // // Note that we are absolutely reliant on the threadpool recognizing that these // requests are all dependent requests and ensuring that they WILL be processed. // // // CMergerReq // // Base class for all merger requests. // class CMergerReq : public CNamespaceReq { private: public: CMergerReq( CWbemNamespace* pNamespace, IWbemObjectSink* pHandler, IWbemContext* pContext) : CNamespaceReq( pNamespace, pHandler, pContext, true ) {}; ~CMergerReq() {}; virtual BOOL IsStatic( void ) { return FALSE; } virtual LPCWSTR GetName( void ) { return L""; } }; // // Class Request Base Class // class CMergerClassReq : public CMergerReq { protected: CWmiMerger* m_pMerger; CWmiMergerRecord* m_pParentRecord; CBasicObjectSink* m_pSink; public: CMergerClassReq( CWmiMerger* pMerger, CWmiMergerRecord* pParentRecord, CWbemNamespace* pNamespace, CBasicObjectSink* pHandler, IWbemContext* pContext); ~CMergerClassReq(); virtual BOOL IsLongRunning() {return TRUE;} void DumpError(); }; // // Parent Class Request // class CMergerParentReq : public CMergerClassReq { public: CMergerParentReq( CWmiMerger* pMerger, CWmiMergerRecord* pParentRecord, CWbemNamespace* pNamespace, CBasicObjectSink* pHandler, IWbemContext* pContext) : CMergerClassReq( pMerger, pParentRecord, pNamespace, pHandler, pContext ) {}; ~CMergerParentReq() {}; HRESULT Execute (); LPCWSTR GetReqInfo(){ return L"MergerParentReq"; }; }; // // Child Class Request // class CMergerChildReq : public CMergerClassReq { public: CMergerChildReq( CWmiMerger* pMerger, CWmiMergerRecord* pParentRecord, CWbemNamespace* pNamespace, CBasicObjectSink* pHandler, IWbemContext* pContext) : CMergerClassReq( pMerger, pParentRecord, pNamespace, pHandler, pContext ) {}; ~CMergerChildReq() {}; HRESULT Execute (); LPCWSTR GetReqInfo(){ return L"MergerChildReq"; }; }; // Base class for Dynamic requests class CMergerDynReq : public CMergerReq { private: CVar m_varClassName; public: CMergerDynReq(CWbemObject* pClassDef, CWbemNamespace* pNamespace, IWbemObjectSink* pHandler, IWbemContext* pContext); ~CMergerDynReq() {}; LPCWSTR GetName( void ) { return m_varClassName.GetLPWSTR(); } }; // // CMergerDynReq_DynAux_GetInstances // // This request processes CreateInstanceEnum calls to providers. // class CMergerDynReq_DynAux_GetInstances : public CMergerDynReq { private: CWbemObject *m_pClassDef ; IWbemContext *m_pCtx ; long m_lFlags ; CBasicObjectSink *m_pSink ; public: CMergerDynReq_DynAux_GetInstances (CWbemNamespace *pNamespace, CWbemObject *pClassDef, long lFlags, IWbemContext *pCtx, CBasicObjectSink *pSink): CMergerDynReq (pClassDef,pNamespace,pSink,pCtx), m_pClassDef(pClassDef), m_pCtx(pCtx), m_pSink(pSink), m_lFlags(lFlags) { if (m_pClassDef) m_pClassDef->AddRef () ; if (m_pCtx) m_pCtx->AddRef () ; if (m_pSink) m_pSink->AddRef () ; } ~CMergerDynReq_DynAux_GetInstances () { if (m_pClassDef) m_pClassDef->Release () ; if (m_pCtx) m_pCtx->Release () ; if (m_pSink) m_pSink->Release () ; } HRESULT Execute (); virtual BOOL IsLongRunning() {return TRUE;} void DumpError(); LPCWSTR GetReqInfo() { _variant_t varClass; if (FAILED(m_pClassDef->Get(L"__CLASS",0,&varClass,0,0))) return L""; if (VT_BSTR == V_VT(&varClass)) { StringCchCopyW(CNamespaceReq::s_DumpBuffer,LENGTH_OF(CNamespaceReq::s_DumpBuffer)-1,V_BSTR(&varClass)); return CNamespaceReq::s_DumpBuffer; } else return L""; }; }; // // CMergerDynReq_DynAux_ExecQueryAsync // // This request processes ExecQuery calls to providers. // class CMergerDynReq_DynAux_ExecQueryAsync : public CMergerDynReq { private: CWbemObject *m_pClassDef ; BSTR m_Query ; BSTR m_QueryFormat ; IWbemContext *m_pCtx ; long m_lFlags ; CBasicObjectSink *m_pSink ; HRESULT m_Result ; public: CMergerDynReq_DynAux_ExecQueryAsync(CWbemNamespace *pNamespace, CWbemObject *pClassDef, long lFlags, LPCWSTR Query, LPCWSTR QueryFormat, IWbemContext *pCtx, CBasicObjectSink *pSink): CMergerDynReq(pClassDef, pNamespace, pSink, pCtx), m_pClassDef(pClassDef), m_pCtx(pCtx), m_pSink(pSink), m_lFlags(lFlags), m_Query(NULL), m_QueryFormat(NULL), m_Result (S_OK) { if (m_pClassDef) m_pClassDef->AddRef () ; if (m_pCtx) m_pCtx->AddRef () ; if (m_pSink) m_pSink->AddRef () ; if (Query) { m_Query = SysAllocString ( Query ) ; if ( m_Query == NULL ) { m_Result = WBEM_E_OUT_OF_MEMORY ; } } if (QueryFormat) { m_QueryFormat = SysAllocString ( QueryFormat ) ; if ( m_QueryFormat == NULL ) { m_Result = WBEM_E_OUT_OF_MEMORY ; } } } HRESULT Initialize () { return m_Result ; } ~CMergerDynReq_DynAux_ExecQueryAsync () { if (m_pClassDef) m_pClassDef->Release(); if (m_pCtx)m_pCtx->Release(); if (m_pSink) m_pSink->Release(); SysFreeString(m_Query); SysFreeString(m_QueryFormat); } HRESULT Execute (); virtual BOOL IsLongRunning() {return TRUE;} void DumpError(); LPCWSTR GetReqInfo(){ return m_Query; }; }; // // CMergerDynReq_Static_GetInstances // // This request processes CreateInstanceEnum calls to the repository. // class CMergerDynReq_Static_GetInstances : public CMergerDynReq { private: CWbemObject *m_pClassDef ; IWbemContext *m_pCtx ; long m_lFlags ; CBasicObjectSink *m_pSink ; QL_LEVEL_1_RPN_EXPRESSION* m_pParsedQuery; public: CMergerDynReq_Static_GetInstances (CWbemNamespace *pNamespace , CWbemObject *pClassDef , long lFlags , IWbemContext *pCtx , CBasicObjectSink *pSink , QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery); ~CMergerDynReq_Static_GetInstances(); HRESULT Execute(); virtual BOOL IsLongRunning() {return TRUE;} void DumpError(); BOOL IsStatic( void ) { return TRUE; } LPCWSTR GetReqInfo() { _variant_t varClass; if (FAILED(m_pClassDef->Get(L"__CLASS",0,&varClass,0,0))) return L""; if (VT_BSTR == V_VT(&varClass)) { StringCchCopyW(CNamespaceReq::s_DumpBuffer,LENGTH_OF(CNamespaceReq::s_DumpBuffer)-1,V_BSTR(&varClass)); return CNamespaceReq::s_DumpBuffer; } else return L""; }; }; // // CWmiMergerRequestMgr // // Manager class for Merger Requests. It keeps an array of sorted arrays // corresponding to the actual requests we will be performing. The sorted // arrays contain merger requests for handling calls to the various // dynamic instance providers. // class CWmiMergerRequestMgr { CWmiMerger* m_pMerger; CFlexArray m_HierarchyArray; DWORD m_dwNumRequests; DWORD m_dwMinLevel; DWORD m_dwMaxLevel; DWORD m_dwLevelMask; DWORD* m_pdwLevelMask; public: CWmiMergerRequestMgr( CWmiMerger* pMerger ); ~CWmiMergerRequestMgr(); HRESULT AddRequest( CMergerDynReq* pReq, DWORD dwLevel ); HRESULT RemoveRequest( DWORD dwLevel, LPCWSTR pwszName, wmilib::auto_ptr & pReq ); HRESULT GetTopmostParentReqName( WString& wsClassName ); BOOL HasSingleStaticRequest( void ); HRESULT Clear(); void DumpRequestHierarchy( void ); DWORD GetNumRequests( void ) { return m_dwNumRequests; } DWORD GetNumRequestsAtLevel( DWORD dwLevel ); BOOL GetRequestAtLevel( DWORD dwLevel, wmilib::auto_ptr & pReq ); }; #endif