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

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
WMIMERGER.H
Abstract:
Implements _IWmiMerger
History:
16-Nov-00 sanjes Created.
--*/
#ifndef _WMIMERGER_H_
#define _WMIMERGER_H_
#include "internalmerger.h"
#include "mergerreq.h"
// forward class definitions
class CWmiMerger;
//
// Support class for CWmiMerger.
//
// Basically, CWmiMerger holds onto many instances of CWmiMergerRecord
//
class CWmiMergerRecord
{
private:
BOOL m_fHasInstances;
BOOL m_fHasChildren;
DWORD m_dwLevel;
WString m_wsClass;
CWmiMerger* m_pMerger;
CInternalMerger* m_pInternalMerger;
CMergerSink* m_pDestSink;
CPointerArray<CWmiMergerRecord> m_ChildArray;
bool m_bScheduledChildRequest;
IWbemContext* m_pExecutionContext;
bool m_bStatic;
public:
CWmiMergerRecord( CWmiMerger* pMerger, BOOL fHasInstances, BOOL fHasChildren,
LPCWSTR pwszClass, CMergerSink* pDestSink, DWORD dwLevel,
bool bStatic );
~CWmiMergerRecord();
CMergerSink* GetChildSink( void );
CMergerSink* GetOwnSink( void );
CMergerSink* GetDestSink( void );
LPCWSTR GetClass( void ) { return m_wsClass; }
LPCWSTR GetName( void ) { return GetClass(); }
BOOL IsClass( LPCWSTR pwszClass ) { return m_wsClass.EqualNoCase( pwszClass ); }
DWORD GetLevel( void ) { return m_dwLevel; }
bool IsStatic( void ) { return m_bStatic; }
HRESULT AttachInternalMerger( CWbemClass* pClass, CWbemNamespace* pNamespace, IWbemContext* pCtx,
BOOL fDerivedFromTarget, bool bStatic );
HRESULT AddChild( CWmiMergerRecord* pRecord );
CWmiMerger* GetWmiMerger( void ) { return m_pMerger; }
// If we have an internal merger, we tell it to cancel
void Cancel( HRESULT hRes );
bool ScheduledChildRequest( void ) { return m_bScheduledChildRequest; }
void SetScheduledChildRequest( void ) { m_bScheduledChildRequest = true; }
CWmiMergerRecord* GetChildRecord( int nIndex );
HRESULT SetExecutionContext( IWbemContext* pContext );
IWbemContext* GetExecutionContext( void ) { return m_pExecutionContext; }
// We can only cancel child sinks if we have an internal merger.
//void CancelChildSink( void ) { if ( NULL != m_pInternalMerger ) m_pInternalMerger->CancelChildSink(); }
void SetIsStatic( bool b ) { m_bStatic = b; }
};
// Allows us to locate values quickly by name
template<class TMember>
class CSortedUniquePointerArray :
public CUniquePointerArray<TMember>
{
public:
int Insert( TMember* pNewElement );
TMember* Find( LPCWSTR pwszName, int* pnIndex = NULL );
int RemoveAtNoDelete( int nIndex );
BOOL Verify( void );
};
template <class TMember>
int CSortedUniquePointerArray<TMember>::Insert( TMember* pNewElement )
{
int nLowIndex = 0,
nHighIndex = m_Array.Size();
// Binary search of the ids to find an index at which to insert
// If we find our element, this is a failure.
while ( nLowIndex < nHighIndex )
{
int nMid = (nLowIndex + nHighIndex) / 2;
int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pNewElement->GetName() );
if ( nTest < 0 )
{
nLowIndex = nMid + 1;
}
else if ( nTest > 0 )
{
nHighIndex = nMid;
}
else
{
_DBG_ASSERT( 0 );
// Index already exists
return -1;
}
} // WHILE looking for index
// Found the location, if it's at the end, check if we need to do an insert or add
// We insert if the element at the end is > the element we want to insert
BOOL bInsert = true;
if ( nLowIndex == GetSize() - 1 )
{
bInsert = ( _wcsicmp( ((TMember*) m_Array[nLowIndex])->GetName(), pNewElement->GetName() ) > 0 );
}
// Stick it in (careful to add to the end if the selected index is the end
// and the current element is not greater than the new one).
if ( bInsert )
{
return InsertAt( nLowIndex, pNewElement );
}
return Add( pNewElement );
}
template <class TMember>
TMember* CSortedUniquePointerArray<TMember>::Find( LPCWSTR pwszName, int* pnIndex )
{
int nLowIndex = 0,
nHighIndex = m_Array.Size();
// Binary search of the values to find a the requested name.
while ( nLowIndex < nHighIndex )
{
int nMid = (nLowIndex + nHighIndex) / 2;
int nTest = _wcsicmp( ((TMember*) m_Array[nMid])->GetName(), pwszName );
if ( nTest < 0 )
{
nLowIndex = nMid + 1;
}
else if ( nTest > 0 )
{
nHighIndex = nMid;
}
else
{
// Found it
if ( NULL != pnIndex )
{
*pnIndex = nMid;
}
return (TMember*) m_Array[nMid];
}
} // WHILE looking for index
// Didn't find it
return NULL;
}
// Removes the element, but does not auto-delete it
template <class TMember>
int CSortedUniquePointerArray<TMember>::RemoveAtNoDelete( int nIndex )
{
if ( nIndex >= m_Array.Size() )
{
return -1;
}
m_Array.RemoveAt( nIndex );
return nIndex;
}
template <class TMember>
BOOL CSortedUniquePointerArray<TMember>::Verify( void )
{
BOOL fReturn = TRUE;
for ( int x = 0; fReturn && x < GetSize() - 1; x++ )
{
// Should be in ascending order
LPCWSTR pwszFirst = GetAt( x )->GetName();
LPCWSTR pwszSecond = GetAt( x+1 )->GetName();
fReturn = ( _wcsicmp( GetAt( x )->GetName(), GetAt( x+1 )->GetName() ) < 0 );
_DBG_ASSERT( fReturn );
if ( !fReturn )
{
CSortedUniquePointerArray<TMember> tempArray;
for ( int y = 0; y < GetSize(); y++ )
{
tempArray.Insert( GetAt( y ) );
}
}
}
return fReturn;
}
//******************************************************************************
//******************************************************************************
//
// class CWmiMerger
//
// This class implements the WMI Merger.
//
//******************************************************************************
class CWmiMerger : public _IWmiArbitratee, public _IWmiArbitratedQuery
{
private:
long m_lRefCount;
WString m_wsTargetClassName;
CMergerTargetSink* m_pTargetSink;
_IWmiCoreHandle* m_pTask;
_IWmiArbitrator* m_pArbitrator;
CWbemNamespace* m_pNamespace;
DWORD m_dwProviderDeliveryPing;
DWORD m_dwMaxLevel;
DWORD m_dwMinReqLevel;
CSortedUniquePointerArray<CWmiMergerRecord> m_MergerRecord;
//
// the sinks of the merger are wired objects
// thy have a refcount a-la-COM, but they are destructed by the
// Manager of the m_MergerSinks Array
//
CUniquePointerArray<CMergerSink> m_MergerSinks;
long m_lNumArbThrottled;
HRESULT m_hOperationRes;
bool m_bMergerThrottlingEnabled;
CCritSec m_cs;
long m_lDebugMemUsed;
CWmiMergerRequestMgr* m_pRequestMgr;
void CleanChildRequests(CWmiMergerRecord* pParentRecord, int startingWith);
public:
// No access
CWmiMerger( CWbemNamespace* pNamespace );
~CWmiMerger();
protected:
HRESULT GetLevelAndSuperClass( _IWmiObject* pObj, DWORD* pdwLevel,
_variant_t & vSuperClass );
public:
/* IUnknown methods */
STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG, AddRef)(THIS);
STDMETHOD_(ULONG, Release)(THIS);
/* _IWmiArbitratee methods */
STDMETHOD(SetOperationResult)( ULONG uFlags, HRESULT hRes );
STDMETHOD(SetTaskHandle)( _IWmiCoreHandle* pTask );
STDMETHOD(DumpDebugInfo)( ULONG uFlags, const BSTR strFile );
/* _IWmiArbitratedQuery methods */
STDMETHOD(IsMerger)( void );
// Sets initial parameters for merger. Establishes the target class and sink for the
// query associated with the merger
STDMETHOD(Initialize)( _IWmiArbitrator* pArbitrator, _IWmiCoreHandle* pTask, LPCWSTR pwszTargetClass, IWbemObjectSink* pTargetSink, CMergerSink** ppFinalSink );
// Called to request a delivery sink for a class in the query chain. The returned
// sink is determined by the specified flags as well as settings on the parent class
STDMETHOD(RegisterSinkForClass)( LPCWSTR pwszClass, _IWmiObject* pClass, IWbemContext* pContext,
BOOL fHasChildren, BOOL fHasInstances, BOOL fDerivedFromTarget,
bool bStatic, CMergerSink* pDestSink, CMergerSink** ppOwnSink, CMergerSink** ppChildSink );
// Called to request a delivery sink for child classes in the query chain. This is especially
// important when instances are merged under the covers.
STDMETHOD(GetChildSink)( LPCWSTR pwszClass, CBasicObjectSink** ppSink );
// Can be used to holdoff indicates - if we're merging instances from multiple providers, we need
// to ensure that we don't get lopsided in the number of objects we've got queued up for merging.
STDMETHOD(Throttle)( void );
// Merger will hold information regarding the total number of objects it has queued up waiting
// for merging and the amount of memory consumed by those objects.
STDMETHOD(GetQueuedObjectInfo)( DWORD* pdwNumQueuedObjects, DWORD* pdwQueuedObjectMemSize );
// If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
// objects. This will also automatically free up resources consumed by queued objects.
STDMETHOD(Cancel)( void );
// Helper function for creating our sinks - this will add the sink to our array of
// sinks which will get destroyed when we are released
HRESULT CreateMergingSink( MergerSinkType eType, IWbemObjectSink* pDestSink, CInternalMerger* pMerger, CMergerSink** ppSink );
// If this is called, all underlying sinks will be cancelled in order to prevent accepting additional
// objects. This will also automatically free up resources consumed by queued objects.
HRESULT Cancel( HRESULT hRes );
// Final Shutdown. Called when the target sink is released. At this point, we should
// unregister ourselves from the world
HRESULT Shutdown( void );
// Registers arbitrated requests
HRESULT RegisterArbitratedInstRequest( CWbemObject* pClassDef, long lFlags, IWbemContext* pCtx,
CBasicObjectSink* pSink, BOOL bComplexQuery, CWbemNamespace* pNs );
HRESULT RegisterArbitratedQueryRequest( CWbemObject* pClassDef, long lFlags, LPCWSTR Query,
LPCWSTR QueryFormat, IWbemContext* pCtx, CBasicObjectSink* pSink,
CWbemNamespace* pNs );
HRESULT RegisterArbitratedStaticRequest( CWbemObject* pClassDef, long lFlags,
IWbemContext* pCtx, CBasicObjectSink* pSink, CWbemNamespace* pNs,
QL_LEVEL_1_RPN_EXPRESSION* pParsedQuery );
// Executes a Merger Parent Request - Cycles through parent object requests and executes
// them as appropriate
HRESULT Exec_MergerParentRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
// Executes a Merger Child Request - Cycles through child classes of the given parent
// class, and executes the appropriate requests
HRESULT Exec_MergerChildRequest( CWmiMergerRecord* pParentRecord, CBasicObjectSink* pSink );
// Schedules a Merger Parent Request if one is necessary
HRESULT ScheduleMergerParentRequest( IWbemContext* pCtx );
// Schedules a Merger Child Request
HRESULT ScheduleMergerChildRequest( CWmiMergerRecord* pParentRecord );
// Enables/Disables merger throttling in all records (on by default)
void EnableMergerThrottling( bool b ) { m_bMergerThrottlingEnabled = b; }
// Returns whether or not we have a single static request in the merger
BOOL IsSingleStaticRequest( void );
bool MergerThrottlingEnabled( void ) { return m_bMergerThrottlingEnabled; }
_IWmiCoreHandle* GetTask( void ) { return m_pTask; }
// Help us track that *something* is going on
// We are intentionally not wrapping thread safety around these guys, since assigning and
// retrieving the value is an atomic operation and realistically, if any contention occurs
// setting the values, they should all, more or less reflect the same tick (remember, they're
// all jumping in at the same time, so this shouldn't really be a problem.
void PingDelivery( DWORD dwLastPing ) { m_dwProviderDeliveryPing = dwLastPing; }
DWORD GetLastDeliveryTime( void ) { return m_dwProviderDeliveryPing; }
HRESULT ReportMemoryUsage( long lAdjustment );
// Helper functions for tracking the number of threads potentially being throttled by
// the arbitrator
long IncrementArbitratorThrottling( void ) { return InterlockedIncrement( &m_lNumArbThrottled ); }
long DecrementArbitratorThrottling( void ) { return InterlockedDecrement( &m_lNumArbThrottled ); }
long NumArbitratorThrottling( void ) { return m_lNumArbThrottled ; }
};
#endif