/*++ 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 #include #include #include #include #include "RawCooker.h" #include "CookerUtils.h" #include #include #include #include /////////////////////////////////////////////////////////////////////////////// // // 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: #ifdef _VERBOSE LPWSTR m_wszName; // The property name #endif long m_lPropHandle; // The property handle CIMTYPE m_ct; public: CProperty( LPWSTR wszName, long lHandle, CIMTYPE ct ); ~CProperty(); #ifdef _VERBOSE LPWSTR GetName(); #endif 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 CRecord { long m_lID; // Instance ID CRecord* m_pNext; // The next pointer in the list static long m_lRefIDGen; // The ID generator 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; }; /////////////////////////////////////////////////////////////////////////////// // // CObjRecord // ========== // // A hidden class used by the cache to manage elements // /////////////////////////////////////////////////////////////////////////////// template class CObjRecord : public CRecord { WCHAR* m_wszKey; T* m_pObj; public: CObjRecord( T* pObj, WCHAR* wszKey ) : m_pObj( pObj ), m_wszKey( NULL ) { if ( NULL != wszKey ) { size_t length = wcslen( wszKey ) + 1; m_wszKey = new WCHAR[ length ]; if (m_wszKey) StringCchCopyW( m_wszKey, length , wszKey ); else throw CX_MemoryException(); } } ~CObjRecord() { delete m_pObj; 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 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 long CRecord::m_lRefIDGen = 0; template CCache::CCache() : m_pHead( NULL ), m_pTail( NULL ), m_pEnumNode( NULL ) { } template CCache::~CCache() { RT* pNode = m_pHead; RT* pNext = NULL; while ( NULL != pNode ) { pNext = (RT*)pNode->GetNext(); delete pNode; pNode = pNext; } }; template WMISTATUS CCache::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 WMISTATUS CCache::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 WMISTATUS CCache::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 WMISTATUS CCache::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 WMISTATUS CCache::BeginEnum() { WMISTATUS dwStatus = S_OK; m_pEnumNode = m_pHead; return dwStatus; }; template WMISTATUS CCache::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 WMISTATUS CCache::EndEnum() { WMISTATUS dwStatus = S_OK; m_pEnumNode = NULL; return dwStatus; }; template bool CCache::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; }; // // 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 CEnumeratorManager // Manages a single enumerator { private: DWORD m_dwSignature; LONG m_cRef; HRESULT m_InithRes; CCritSec 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 > 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 ,wbem_allocator > m_mapID; std::vector< ULONG_PTR , wbem_allocator > 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 > & refArray, std::vector > & refObjHashKeys); WMISTATUS UpdateEnums(std::vector > & 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 > m_apEnumerators; CCritSec 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 IdCache { private: std::map, wbem_allocator > m_map; DWORD m_NextId; typename std::map, wbem_allocator >::iterator m_it; CCritSec m_cs; public: IdCache():m_NextId(0){}; virtual ~IdCache(){}; void Lock(){ m_cs.Enter(); } void Unlock(){m_cs.Leave();}; // 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 HRESULT IdCache::Add( DWORD * pId, T Elem) { HRESULT hr; CInCritSec ics(&m_cs); if (pId) { std::map, wbem_allocator >::iterator it = m_map.find(m_NextId); if (it != m_map.end()) hr = E_FAIL; else { try { m_map[m_NextId] = Elem; *pId = m_NextId; InterlockedIncrement((PLONG)&m_NextId); hr = WBEM_S_NO_ERROR; } catch(...) { hr = E_FAIL; } } } else { hr = WBEM_E_INVALID_PARAMETER; } return hr; } template HRESULT IdCache::GetData(DWORD Id, T * pElem) { CInCritSec ics(&m_cs); HRESULT hr = WBEM_S_NO_ERROR; std::map, wbem_allocator >::iterator it = m_map.find(Id); if (it != m_map.end()) *pElem = (*it).second; else hr = WBEM_E_NOT_FOUND; return hr; } template HRESULT IdCache::Remove(DWORD Id, T * pRemovedElem) { CInCritSec ics(&m_cs); HRESULT hr = WBEM_S_NO_ERROR; if (pRemovedElem) { std::map, wbem_allocator >::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; return hr; } // // DEVDEV Empty the cache before removing from std::map // template HRESULT IdCache::RemoveAll(void) { CInCritSec ics(&m_cs); m_map.erase(m_map.begin(),m_map.end()); return WBEM_S_NO_ERROR; }; template HRESULT IdCache::BeginEnum(void) { Lock(); m_it = m_map.begin(); return WBEM_S_NO_ERROR; } // // assume inside CritSec // ///////////////////////////// template HRESULT IdCache::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 HRESULT IdCache::EndEnum(void) { Unlock(); return WBEM_S_NO_ERROR; } #endif //_CACHE_H_