Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

854 lines
19 KiB

/*++
Copyright (C) 2000-2001 Microsoft Corporation
Module Name:
Cache.h
Abstract:
Contains all caching classes and objects.
History:
a-dcrews 01-Mar-00 Created
ivanbrug 23-Jun-2000 mostly rewritten
--*/
#ifndef _CACHE_H_
#define _CACHE_H_
#include <windows.h>
#include <wbemcli.h>
#include <wbemint.h>
#include <wstlallc.h>
#include "RawCooker.h"
#include "CookerUtils.h"
#include "DynArray.h"
#include <wstring.h>
#include <map>
#include <vector>
#include <functional>
///////////////////////////////////////////////////////////////////////////////
//
// Macro Definitions
//
///////////////////////////////////////////////////////////////////////////////
#define WMI_COOKER_CACHE_INCREMENT 8 // The cache size adjustment increment
///////////////////////////////////////////////////////////////////////////////
//
// CProperty
// =========
//
// The base property - used for raw properties and the base
// class for the CookedProperty.
//
///////////////////////////////////////////////////////////////////////////////
class CProperty
{
protected:
LPWSTR m_wszName; // The property name
long m_lPropHandle; // The property handle
CIMTYPE m_ct;
public:
CProperty( LPWSTR wszName, long lHandle, CIMTYPE ct );
~CProperty();
LPWSTR GetName();
CIMTYPE GetType();
long GetHandle();
};
///////////////////////////////////////////////////////////////////////////////
//
// CCookingProperty
// ================
//
// The cooked property - used to model the data required to
// cook a property of a cooekd class
//
///////////////////////////////////////////////////////////////////////////////
class CCookingProperty : public CProperty
{
DWORD m_dwCounterType; // Counter type
DWORD m_dwReqProp; // which property are needed to perform calculation
CRawCooker m_Cooker; // The cooker object
CProperty* m_pRawCounterProp; // The raw counter property
CProperty* m_pTimeProp; // The raw time property
CProperty* m_pFrequencyProp; // The raw frequency property
CProperty* m_pBaseProp; // The raw base property OPTIONAL for most counters
__int32 m_nSampleWindow; // The number of samples used for the computation
__int32 m_nTimeWindow; // The period used for the samples
unsigned __int64 m_nTimeFreq; // The timer frequency;
long m_lScale; // The Scale factor (10 ^ (m_lScale))
BOOL m_bUseWellKnownIfNeeded;
public:
CCookingProperty( LPWSTR wszName,
DWORD dwCounterType,
long lPropHandle,
CIMTYPE ct,
DWORD dwReqProp,
BOOL bUseWellKnownIfNeeded);
virtual ~CCookingProperty();
WMISTATUS Initialize( IWbemQualifierSet* pCookingPropQualifierSet,
IWbemObjectAccess* pRawAccess,
IWbemQualifierSet* pCookingClassQSet);
WMISTATUS Cook( DWORD dwNumSamples,
__int64* aRawCounter,
__int64* aBaseCounter,
__int64* aTimeStamp,
__int64* pnResult );
CProperty* GetRawCounterProperty();
CProperty* GetBaseProperty();
CProperty* GetTimeProperty();
HRESULT SetFrequency(IWbemObjectAccess * pObjAcc);
unsigned __int64 GetFrequency(void);
BOOL IsReq(DWORD ReqProp) { return (m_dwReqProp&ReqProp); };
DWORD NumberOfActiveSamples() { return m_nSampleWindow; };
DWORD MinSamplesRequired() { return m_nSampleWindow; };
};
///////////////////////////////////////////////////////////////////////////////
//
// CPropertySampleCache
// ====================
//
// For every property in each instance, we must maintain a history of
// previous samples for the cooking. The type of cooking determines the
// number of required samples
//
///////////////////////////////////////////////////////////////////////////////
class CPropertySampleCache
{
DWORD m_dwNumSamples; // The number of current samples
DWORD m_dwTotSamples; // The size of the sample array
DWORD m_dwRefreshID;
__int64* m_aRawCounterVals; // The array of raw counter values
__int64* m_aBaseCounterVals; // The array of base counter values
__int64* m_aTimeStampVals; // The array of timestamp values
public:
CPropertySampleCache();
~CPropertySampleCache();
WMISTATUS SetSampleInfo( DWORD dwNumActiveSamples, DWORD dwMinReqSamples );
WMISTATUS SetSampleData( DWORD dwRefreshID, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp );
WMISTATUS GetData( DWORD* pdwNumSamples, __int64** paRawCounter, __int64** paBaseCounter, __int64** paTimeStamp );
};
///////////////////////////////////////////////////////////////////////////////
//
// CCookingInstance
// ================
//
// The cooking instance - used to model an instance of a cooked object. Each
// property maintains a cache of values that will be used to compute the
// final cooked value.
//
///////////////////////////////////////////////////////////////////////////////
class CCookingInstance
{
LPWSTR m_wszKey; // The instance key
IWbemObjectAccess* m_pCookingInstance; // Cooking instance data
IWbemObjectAccess* m_pRawInstance; // Raw sample source
CPropertySampleCache* m_aPropertySamples; // The cache of property samples for this instance
DWORD m_dwNumProps;
public:
CCookingInstance( IWbemObjectAccess *pCookingInstance, DWORD dwNumProps );
virtual ~CCookingInstance();
WMISTATUS InitProperty( DWORD dwProp, DWORD dwNumActiveSamples, DWORD dwMinReqSamples );
WMISTATUS SetRawSourceInstance( IWbemObjectAccess* pRawSampleSource );
WMISTATUS GetRawSourceInstance( IWbemObjectAccess** ppRawSampleSource );
WMISTATUS AddSample( DWORD dwRefresherInc, DWORD dwProp, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp );
WMISTATUS GetCachedSamples( IWbemObjectAccess** ppOldSample, IWbemObjectAccess** ppNewSample );
IWbemObjectAccess* GetInstance();
WMISTATUS UpdateSamples();
WMISTATUS CookProperty( DWORD dwProp, CCookingProperty* pProperty );
LPWSTR GetKey() { return m_wszKey; }
WMISTATUS Refresh( IWbemObjectAccess* pRawData, IWbemObjectAccess** ppCookedData );
BOOL IsValid() {
return (m_dwNumProps && m_aPropertySamples);
};
};
///////////////////////////////////////////////////////////////////////////////
//
// CRecord
// =======
//
///////////////////////////////////////////////////////////////////////////////
template<class T>
class CRecord
{
static long m_lRefIDGen; // The ID generator
long m_lID; // Instance ID
CRecord* m_pNext; // The next pointer in the list
public:
CRecord() : m_lID( m_lRefIDGen++ ), m_pNext( NULL ) {}
virtual ~CRecord() {}
void SetNext( CRecord* pRecord ) { m_pNext = pRecord; }
void SetID( long lID ) { m_lID = lID; }
CRecord* GetNext() { return m_pNext; }
long GetID() { return m_lID; }
virtual T* GetData() = 0;
};
///////////////////////////////////////////////////////////////////////////////
//
// CUnkRecord
// ==========
//
///////////////////////////////////////////////////////////////////////////////
template<class T>
class CUnkRecord : public CRecord<T>
{
T* m_pUnk;
public:
CUnkRecord( T* pUnk ) : m_pUnk( pUnk ) {}
~CUnkRecord(){ if ( NULL != m_pUnk ) m_pUnk->Release(); }
T* GetData(){ if ( NULL != m_pUnk ) m_pUnk->AddRef(); return m_pUnk; }
};
///////////////////////////////////////////////////////////////////////////////
//
// CObjRecord
// ==========
//
// A hidden class used by the cache to manage elements
//
///////////////////////////////////////////////////////////////////////////////
template<class T>
class CObjRecord : public CRecord<T>
{
WCHAR* m_wszKey;
T* m_pObj;
public:
CObjRecord( T* pObj, WCHAR* wszKey ) : m_pObj( pObj ), m_wszKey( NULL )
{
if ( NULL != wszKey )
{
m_wszKey = new WCHAR[ wcslen( wszKey ) + 1 ];
wcscpy( m_wszKey, wszKey );
}
}
~CObjRecord()
{
if ( NULL != m_pObj ) delete m_pObj;
if ( NULL != m_wszKey ) delete m_wszKey;
}
T* GetData(){ return m_pObj; }
bool IsValueByKey( WCHAR* wszKey )
{
return ( 0 == _wcsicmp( m_wszKey, wszKey ) );
}
};
///////////////////////////////////////////////////////////////////////////////
//
// CCache
// ======
//
// BT - base type
// RT - record type
//
///////////////////////////////////////////////////////////////////////////////
template<class BT, class RT>
class CCache
{
RT* m_pHead; // Head of list
RT* m_pTail; // Tail of list
RT* m_pEnumNode; // Enumerator pointer
public:
CCache();
virtual ~CCache();
WMISTATUS Add( BT* pData, WCHAR* wszKey, long* plID );
WMISTATUS Remove( long lID );
WMISTATUS RemoveAll();
WMISTATUS GetData( long lID, BT** ppData );
WMISTATUS BeginEnum();
WMISTATUS Next( BT** ppData );
WMISTATUS EndEnum();
bool FindByKey( WCHAR* wszKey, BT* pData );
};
template<class T>
long CRecord<T>::m_lRefIDGen = 0;
template<class BT, class RT>
CCache<BT,RT>::CCache() : m_pHead( NULL ), m_pTail( NULL ), m_pEnumNode( NULL )
{
}
template<class BT, class RT>
CCache<BT,RT>::~CCache()
{
RT* pNode = m_pHead;
RT* pNext = NULL;
while ( NULL != pNode )
{
pNext = (RT*)pNode->GetNext();
delete pNode;
pNode = pNext;
}
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::Add( BT *pData, WCHAR* wszKey, long* plID )
{
WMISTATUS dwStatus = S_OK;
if ( NULL == pData )
{
dwStatus = WBEM_E_INVALID_PARAMETER;
}
if ( SUCCEEDED( dwStatus ) )
{
RT* pNewRecord = new RT( pData, wszKey );
if ( NULL != pNewRecord )
{
if ( NULL == m_pHead )
{
m_pHead = pNewRecord;
m_pTail = pNewRecord;
}
else
{
m_pTail->SetNext( pNewRecord );
m_pTail = pNewRecord;
}
*plID = pNewRecord->GetID();
}
else
{
dwStatus = WBEM_E_OUT_OF_MEMORY;
}
}
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::Remove( long lID )
{
WMISTATUS dwStatus = S_FALSE;
RT* pNode = m_pHead;
RT* pNext = (RT*)pNode->GetNext();
RT* pPrev = NULL;
while ( NULL != pNode )
{
if ( pNode->GetID() == lID )
{
if ( NULL == pNext )
m_pTail = pPrev;
if ( NULL == pPrev )
m_pHead = pNext;
else
pPrev->SetNext( pNext );
delete pNode;
dwStatus = S_OK;
}
pPrev = pNode;
pNode = pNext;
if ( NULL != pNode )
pNext = (RT*)pNode->GetNext();
}
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::RemoveAll()
{
WMISTATUS dwStatus = S_FALSE;
RT* pNode = m_pHead;
RT* pNext = NULL;
while ( NULL != pNode )
{
pNext = (RT*)pNode->GetNext();
delete pNode;
pNode = pNext;
}
m_pHead = m_pTail = NULL;
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::GetData( long lID, BT** ppData )
{
WMISTATUS dwStatus = S_FALSE;
RT* pNode = m_pHead;
while ( NULL != pNode )
{
if ( pNode->GetID() == lID )
{
*ppData = pNode->GetData();
dwStatus = S_OK;
break;
}
else
{
pNode = (RT*)pNode->GetNext();
}
}
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::BeginEnum()
{
WMISTATUS dwStatus = S_OK;
m_pEnumNode = m_pHead;
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::Next( BT** ppData )
{
WMISTATUS dwStatus = WBEM_S_FALSE;
if ( NULL != m_pEnumNode )
{
*ppData = m_pEnumNode->GetData();
m_pEnumNode = (RT*)m_pEnumNode->GetNext();
dwStatus = S_OK;
}
return dwStatus;
};
template<class BT, class RT>
WMISTATUS CCache<BT,RT>::EndEnum()
{
WMISTATUS dwStatus = S_OK;
m_pEnumNode = NULL;
return dwStatus;
};
template<class BT, class RT>
bool CCache<BT,RT>::FindByKey( WCHAR* wszKey, BT* pData )
{
BT Data;
bool bRet = FALSE;
BeginEnum();
while( WBEM_S_FALSE != Next( &Data ) )
{
if ( pData->IsValueByKey( wszKey ) )
{
*pData = Data;
bRet = TRUE;
break;
}
}
EndEnum();
return bRet;
};
///////////////////////////////////////////////////////////////
//
// CInstanceCache
// ==============
//
///////////////////////////////////////////////////////////////
class CInstanceCache : public CCache<CCookingInstance,CObjRecord<CCookingInstance> >
{
public:
};
///////////////////////////////////////////////////////////////
//
// CEnumInstanceRecord
// ===================
//
///////////////////////////////////////////////////////////////
class CInstanceRecord
{
long m_lID;
LPWSTR m_wszName;
public:
CInstanceRecord( LPWSTR wszName, long lID );
virtual ~CInstanceRecord();
long GetID(){ return m_lID; }
LPWSTR GetKey(){ return m_wszName; }
};
//
// used to add/remove an instance from the coooker
// and from the fastprox enumerator
//
typedef struct tagEnumCookId {
long CookId;
long EnumId;
} EnumCookId;
///////////////////////////////////////////////////////////////
//
// CEnumeratorManager
// ==================
//
///////////////////////////////////////////////////////////////
class CWMISimpleObjectCooker;
class BstrAlloc : public wbem_allocator<WString>
{
};
class CEnumeratorManager
// Manages a single enumerator
{
DWORD m_dwSignature;
LONG m_cRef;
HRESULT m_InithRes;
CRITICAL_SECTION m_cs;
CWMISimpleObjectCooker* m_pCooker; // The class' cooker
long m_lRawID; // RawID
IWbemHiPerfEnum* m_pRawEnum; // The hiperf cooked enumerator
IWbemHiPerfEnum* m_pCookedEnum; // The hiperf cooked enumerator
IWbemClassObject* m_pCookedClass; // The class definition for the cooking class
std::vector<WString,BstrAlloc> m_pKeyProps;
WCHAR* m_wszCookingClassName;
BOOL m_IsSingleton;
// to keep track of the differences
// between the raw enum and our enum
DWORD m_dwUsage;
std::map< ULONG_PTR , EnumCookId , std::less<ULONG_PTR> ,wbem_allocator<EnumCookId> > m_mapID;
std::vector< ULONG_PTR , wbem_allocator<ULONG_PTR> > m_Delta[2];
DWORD m_dwVector;
// members
WMISTATUS Initialize( IWbemClassObject* pRawClass );
WMISTATUS CreateCookingObject( IWbemObjectAccess* pRawObject, IWbemObjectAccess** ppCookedObject );
WMISTATUS InsertCookingRecord( IWbemObjectAccess* pRawObject, EnumCookId * pStruct, DWORD dwRefreshStamp );
WMISTATUS RemoveCookingRecord( EnumCookId * pEnumCookId );
WMISTATUS GetRawEnumObjects( std::vector<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > & refArray,
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & refObjHashKeys);
WMISTATUS SortRawArray(std::vector<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > & refArray );
WMISTATUS UpdateEnums(std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & apObjAccess);
public:
CEnumeratorManager( LPCWSTR wszCookingClass, IWbemClassObject* pCookedClass, IWbemClassObject* pRawClass, IWbemHiPerfEnum* pCookedEnum, IWbemHiPerfEnum* pRawEnum, long lRawID );
virtual ~CEnumeratorManager();
HRESULT GetInithResult(){ return m_InithRes; };
WMISTATUS Refresh( DWORD dwRefreshStamp );
long GetRawId(void){ return m_lRawID; };
LONG AddRef();
LONG Release();
};
///////////////////////////////////////////////////////////////
//
// CEnumeratorCache
// ================
//
///////////////////////////////////////////////////////////////
class CEnumeratorCache
{
DWORD m_dwRefreshStamp; // The refresh counter
DWORD m_dwEnum; // The enumerator index
std::vector<CEnumeratorManager*, wbem_allocator<CEnumeratorManager*> > m_apEnumerators;
CRITICAL_SECTION m_cs;
WMISTATUS Initialize();
public:
CEnumeratorCache();
virtual ~CEnumeratorCache();
WMISTATUS AddEnum(
LPCWSTR wszCookingClass,
IWbemClassObject* pCookedClass,
IWbemClassObject* pRawClass,
IWbemHiPerfEnum* pCookedEnum,
IWbemHiPerfEnum* pRawEnum,
long lID,
DWORD* pdwID );
WMISTATUS RemoveEnum( DWORD dwID , long * pRawId);
WMISTATUS Refresh(DWORD dwRefreshStamp);
};
//
// Simple Cache based on the std::map
// It will use the ID semantics:
// Insertion will return an ID that need to be
// used for deletion
// ids are unique for the lifetime of the Cache object
//
template <class T>
class IdCache {
private:
std::map<DWORD, T> m_map;
DWORD m_NextId;
std::map<DWORD, T>::iterator m_it;
CRITICAL_SECTION m_cs;
public:
IdCache():m_NextId(0){
InitializeCriticalSection(&m_cs);
};
virtual ~IdCache(){
DeleteCriticalSection(&m_cs);
};
void Lock(){
EnterCriticalSection(&m_cs);
}
void Unlock(){
LeaveCriticalSection(&m_cs);
};
// traditional interfaces
HRESULT Add( DWORD * pId, T Elem);
HRESULT GetData(DWORD Id, T * pElem);
HRESULT Remove(DWORD Id, T * pRemovedElem);
// before calling this, delete the elements !!!!
HRESULT RemoveAll(void);
// Enumerator Style
HRESULT BeginEnum(void);
HRESULT Next(T * pElem);
HRESULT EndEnum(void);
};
template <class T>
HRESULT
IdCache<T>::Add( DWORD * pId, T Elem){
HRESULT hr;
Lock();
if (pId) {
std::map<DWORD, T>::iterator it = m_map.find(m_NextId);
if (it != m_map.end()) {
// should never happen
hr = E_FAIL;
} else {
m_map[m_NextId] = Elem;
*pId = m_NextId;
InterlockedIncrement((PLONG)&m_NextId);
hr = WBEM_S_NO_ERROR;
}
} else {
hr = WBEM_E_INVALID_PARAMETER;
}
Unlock();
return hr;
}
template <class T>
HRESULT
IdCache<T>::GetData(DWORD Id, T * pElem){
HRESULT hr = WBEM_S_NO_ERROR;
Lock();
std::map<DWORD, T>::iterator it = m_map.find(Id);
if (it != m_map.end()){
*pElem = (*it).second;
} else {
hr = WBEM_E_NOT_FOUND;
}
Unlock();
return hr;
}
template <class T>
HRESULT
IdCache<T>::Remove(DWORD Id, T * pRemovedElem){
HRESULT hr = WBEM_S_NO_ERROR;
Lock();
if (pRemovedElem) {
std::map<DWORD, T>::iterator it = m_map.find(Id);
if (it != m_map.end()) {
*pRemovedElem = (*it).second;
m_map.erase(it);
} else {
hr = WBEM_E_NOT_FOUND;
}
} else {
hr = WBEM_E_INVALID_PARAMETER;
}
Unlock();
return hr;
}
//
// DEVDEV Empty the cache before removing from std::map
//
template <class T>
HRESULT
IdCache<T>::RemoveAll(void){
Lock();
m_map.erase(m_map.begin(),m_map.end());
Unlock();
return WBEM_S_NO_ERROR;
};
//
// DEVDEV Consider using Lock if no exception ....
//
template <class T>
HRESULT
IdCache<T>::BeginEnum(void){
Lock();
m_it = m_map.begin();
return WBEM_S_NO_ERROR;
}
template <class T>
HRESULT
IdCache<T>::Next(T * pElem){
HRESULT hr;
if (pElem){
if (m_it == m_map.end()){
hr = WBEM_S_NO_MORE_DATA;
} else {
* pElem = (*m_it).second;
++m_it;
hr = WBEM_S_NO_ERROR;
}
} else {
hr = WBEM_E_INVALID_PARAMETER;
}
return hr;
}
template <class T>
HRESULT
IdCache<T>::EndEnum(void){
Unlock();
return WBEM_S_NO_ERROR;
}
#endif //_CACHE_H_