1 // This is a part of the Active Template Library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
5 // This source code is only intended as a supplement to the
6 // Active Template Library Reference and related
7 // electronic documentation provided with the library.
8 // See these sources for detailed information regarding the
9 // Active Template Library product.
11 #ifndef __ATLCACHE_H__
12 #define __ATLCACHE_H__
22 #include <atlsrvres.h>
27 #pragma warning (push)
28 #ifndef _ATL_NO_PRAGMA_WARNINGS
29 #pragma warning(disable: 4511) // copy constructor could not be generated
30 #pragma warning(disable: 4512) // assignment operator could not be generated
31 #endif //!_ATL_NO_PRAGMA_WARNINGS
33 #pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible
34 #pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible
37 #pragma warning(disable: 4702) // unreachable code
39 #pragma pack(push,_ATL_PACKING)
42 //forward declarations;
46 typedef struct __CACHEITEM
50 //Implementation of a cache that stores pointers to void
51 extern "C" __declspec(selectany
) const IID IID_IMemoryCacheClient
= {0xb721b49d, 0xbb57, 0x47bc, { 0xac, 0x43, 0xa8, 0xd4, 0xc0, 0x7d, 0x18, 0x3d } };
52 extern "C" __declspec(selectany
) const IID IID_IMemoryCache
= { 0x9c6cfb46, 0xfbde, 0x4f8b, { 0xb9, 0x44, 0x2a, 0xa0, 0x5d, 0x96, 0xeb, 0x5c } };
53 extern "C" __declspec(selectany
) const IID IID_IMemoryCacheControl
= { 0x7634b28b, 0xd819, 0x409d, { 0xb9, 0x6e, 0xfc, 0x9f, 0x3a, 0xba, 0x32, 0x9f } };
54 extern "C" __declspec(selectany
) const IID IID_IMemoryCacheStats
= { 0xd4b6df2d, 0x4bc0, 0x4734, { 0x8a, 0xce, 0xb7, 0x3a, 0xb, 0x97, 0x59, 0x56 } };
56 __interface ATL_NO_VTABLE
__declspec(uuid("b721b49d-bb57-47bc-ac43-a8d4c07d183d"))
57 IMemoryCacheClient
: public IUnknown
59 // IMemoryCacheClient methods
60 STDMETHOD( Free
)(const void *pvData
);
63 __interface ATL_NO_VTABLE
__declspec(uuid("9c6cfb46-fbde-4f8b-b944-2aa05d96eb5c"))
64 IMemoryCache
: public IUnknown
66 // IMemoryCache Methods
67 STDMETHOD(Add
)(LPCSTR szKey
, void *pvData
, DWORD dwSize
,
68 FILETIME
*pftExpireTime
,
69 HINSTANCE hInstClient
, HCACHEITEM
*phEntry
,
70 IMemoryCacheClient
*pClient
);
72 STDMETHOD(LookupEntry
)(LPCSTR szKey
, HCACHEITEM
* phEntry
);
73 STDMETHOD(GetData
)(const HCACHEITEM hEntry
, void **ppvData
, DWORD
*pdwSize
) const;
74 STDMETHOD(ReleaseEntry
)(const HCACHEITEM hEntry
);
75 STDMETHOD(RemoveEntry
)(const HCACHEITEM hEntry
);
76 STDMETHOD(RemoveEntryByKey
)(LPCSTR szKey
);
81 __interface ATL_NO_VTABLE
__declspec(uuid("7634b28b-d819-409d-b96e-fc9f3aba329f"))
82 IMemoryCacheControl
: public IUnknown
84 // IMemoryCacheControl Methods
85 STDMETHOD(SetMaxAllowedSize
)(DWORD dwSize
);
86 STDMETHOD(GetMaxAllowedSize
)(DWORD
*pdwSize
);
87 STDMETHOD(SetMaxAllowedEntries
)(DWORD dwSize
);
88 STDMETHOD(GetMaxAllowedEntries
)(DWORD
*pdwSize
);
89 STDMETHOD(ResetCache
)();
92 __interface ATL_NO_VTABLE
__declspec(uuid("d4b6df2d-4bc0-4734-8ace-b73a0b975956"))
93 IMemoryCacheStats
: public IUnknown
95 // IMemoryCacheStats Methods
96 STDMETHOD(ClearStats
)();
97 STDMETHOD(GetHitCount
)(DWORD
*pdwSize
);
98 STDMETHOD(GetMissCount
)(DWORD
*pdwSize
);
99 STDMETHOD(GetCurrentAllocSize
)(DWORD
*pdwSize
);
100 STDMETHOD(GetMaxAllocSize
)(DWORD
*pdwSize
);
101 STDMETHOD(GetCurrentEntryCount
)(DWORD
*pdwSize
);
102 STDMETHOD(GetMaxEntryCount
)(DWORD
*pdwSize
);
106 struct DLL_CACHE_ENTRY
111 CHAR szDllName
[MAX_PATH
];
114 inline bool operator==(const DLL_CACHE_ENTRY
& entry1
, const DLL_CACHE_ENTRY
& entry2
)
116 return (entry1
.hInstDll
== entry2
.hInstDll
);
121 // An interface that is used to load and unload Dlls.
123 __interface ATL_NO_VTABLE
__declspec(uuid("A12478AB-D261-42f9-B525-7589143C1C97"))
124 IDllCache
: public IUnknown
127 virtual HINSTANCE
Load(LPCSTR szFileName
, void *pPeerInfo
);
128 virtual BOOL
Free(HINSTANCE hInstance
);
129 virtual BOOL
AddRefModule(HINSTANCE hInstance
);
130 virtual BOOL
ReleaseModule(HINSTANCE hInstance
);
131 virtual HRESULT
GetEntries(DWORD dwCount
, DLL_CACHE_ENTRY
*pEntries
, DWORD
*pdwCopied
);
132 virtual HRESULT
Flush();
135 #ifndef ATL_CACHE_KEY_LENGTH
136 #define ATL_CACHE_KEY_LENGTH 128
139 typedef CFixedStringT
<CStringA
, ATL_CACHE_KEY_LENGTH
> CFixedStringKey
;
141 struct CFlusherCacheData
143 CFlusherCacheData
*pNext
;
144 CFlusherCacheData
*pPrev
;
155 // No flusher -- only expired entries will be removed from the cache
156 // Also gives the skeleton for all of the flushers
160 void Add(CFlusherCacheData
* /*pItem*/) { }
161 void Remove(CFlusherCacheData
* /*pItem*/) { }
162 void Access(CFlusherCacheData
* /*pItem*/) { }
163 CFlusherCacheData
* GetStart() const { return NULL
; }
164 CFlusherCacheData
* GetNext(CFlusherCacheData
* /*pCur*/) const { return NULL
; }
165 void Release(CFlusherCacheData
* /*pItem*/){ }
168 // Old flusher -- oldest items are flushed first
172 CFlusherCacheData
* pHead
;
173 CFlusherCacheData
* pTail
;
175 COldFlusher() : pHead(NULL
), pTail(NULL
)
179 // Add it to the tail of the list
180 void Add(CFlusherCacheData
* pItem
)
185 pItem
->pPrev
= pTail
;
188 pTail
->pNext
= pItem
;
198 void Remove(CFlusherCacheData
* pItem
)
202 CFlusherCacheData
* pPrev
= pItem
->pPrev
;
203 CFlusherCacheData
* pNext
= pItem
->pNext
;
206 pPrev
->pNext
= pNext
;
211 pNext
->pPrev
= pPrev
;
217 void Access(CFlusherCacheData
* /*pItem*/)
221 void Release(CFlusherCacheData
* /*pItem*/)
225 CFlusherCacheData
* GetStart() const
230 CFlusherCacheData
* GetNext(CFlusherCacheData
* pCur
) const
239 // Least recently used flusher -- the item that was accessed the longest time ago is flushed
240 class CLRUFlusher
: public COldFlusher
243 // Move it to the tail of the list
244 void Access(CFlusherCacheData
* pItem
)
253 // Least often used flusher
254 class CLOUFlusher
: public COldFlusher
257 // Adds to the tail of the list
258 void Add(CFlusherCacheData
* pItem
)
261 pItem
->dwAccessed
= 1;
262 COldFlusher::Add(pItem
);
265 void Access(CFlusherCacheData
* pItem
)
270 CFlusherCacheData
* pMark
= static_cast<CFlusherCacheData
*>(pItem
->pPrev
);
271 if (!pMark
) // The item is already at the head
274 if (pMark
->dwAccessed
>= pItem
->dwAccessed
) // The element before it has
275 return; // been accessed more times
279 while (pMark
&& (pMark
->dwAccessed
< pItem
->dwAccessed
))
280 pMark
= static_cast<CFlusherCacheData
*>(pMark
->pPrev
);
282 // pMark points to the first element that has been accessed more times,
283 // so add pItem after pMark
286 CFlusherCacheData
*pNext
= static_cast<CFlusherCacheData
*>(pMark
->pNext
);
287 pMark
->pNext
= pItem
;
288 pItem
->pPrev
= pMark
;
290 pItem
->pNext
= pNext
;
291 pNext
->pPrev
= pItem
;
293 else // Ran out of items -- put it on the head
295 pItem
->pNext
= pHead
;
298 pHead
->pPrev
= pItem
;
299 else // the list was empty
305 // We start at the tail and move forward for this flusher
306 CFlusherCacheData
* GetStart() const
311 CFlusherCacheData
* GetNext(CFlusherCacheData
* pCur
) const
314 return static_cast<CFlusherCacheData
*>(pCur
->pPrev
);
320 template <class CFirst
, class CSecond
>
334 m_bWhich
= !m_bWhich
;
338 void Add(CFlusherCacheData
* pItem
)
345 void Remove(CFlusherCacheData
* pItem
)
348 m_First
.Remove(pItem
);
349 m_Second
.Remove(pItem
);
352 void Access(CFlusherCacheData
* pItem
)
355 m_First
.Access(pItem
);
356 m_Second
.Access(pItem
);
358 void Release(CFlusherCacheData
* pItem
)
361 m_First
.Release(pItem
);
362 m_Second
.Release(pItem
);
365 CFlusherCacheData
* GetStart() const
368 return m_First
.GetStart();
370 return m_Second
.GetStart();
373 CFlusherCacheData
* GetNext(CFlusherCacheData
* pCur
) const
376 return m_First
.GetNext(pCur
);
378 return m_Second
.GetNext(pCur
);
382 struct CCullerCacheData
390 CCullerCacheData
*pNext
;
391 CCullerCacheData
*pPrev
;
393 CFileTime cftExpireTime
;
396 class CNoExpireCuller
399 void Add(CCullerCacheData
* /*pItem*/) { }
400 void Commit(CCullerCacheData
* /*pItem*/) { }
401 void Access(CCullerCacheData
* /*pItem*/) { }
402 void Remove(CCullerCacheData
* /*pItem*/) { }
404 BOOL
IsExpired(CCullerCacheData
* /*pItem*/) { return FALSE
; }
405 CCullerCacheData
* GetExpired() { return NULL
; }
406 void Release(CCullerCacheData
* /*pItem*/){}
413 CFileTime m_cftCurrent
;
414 CCullerCacheData
*pHead
;
415 CCullerCacheData
*pTail
;
423 // Element is being added -- perform necessary initialization
424 void Add(CCullerCacheData
* pItem
)
430 // Expiration data has been set -- add to main list
431 // Head is the first item to expire
432 // a FILETIME of 0 indicates that the item should never expire
433 void Commit(CCullerCacheData
* pItem
)
445 if (CFileTime(pItem
->cftExpireTime
) == 0)
447 pTail
->pNext
= pItem
;
448 pItem
->pPrev
= pTail
;
454 CCullerCacheData
* pMark
= pHead
;
455 while (pMark
&& (pMark
->cftExpireTime
< pItem
->cftExpireTime
))
456 pMark
= pMark
->pNext
;
458 if (pMark
) // An entry was found that expires after the added entry
460 CCullerCacheData
*pPrev
= pMark
->pPrev
;
462 pPrev
->pNext
= pItem
;
466 pItem
->pNext
= pMark
;
467 pItem
->pPrev
= pPrev
;
468 pMark
->pPrev
= pItem
;
470 else // Ran out of items -- put it on the tail
473 pTail
->pNext
= pItem
;
474 pItem
->pPrev
= pTail
;
480 void Access(CCullerCacheData
* /*pItem*/)
484 void Release(CCullerCacheData
* /*pItem*/)
488 void Remove(CCullerCacheData
* pItem
)
491 CCullerCacheData
*pPrev
= pItem
->pPrev
;
492 CCullerCacheData
*pNext
= pItem
->pNext
;
495 pPrev
->pNext
= pNext
;
500 pNext
->pPrev
= pPrev
;
506 // About to start culling
509 m_cftCurrent
= CFileTime::GetCurrentTime();
512 BOOL
IsExpired(CCullerCacheData
*pItem
)
514 if ((pItem
->cftExpireTime
!= 0) &&
515 m_cftCurrent
> pItem
->cftExpireTime
)
521 // Get the next expired entry
522 CCullerCacheData
* GetExpired()
526 if (IsExpired(pHead
))
533 class CLifetimeCuller
: public CExpireCuller
536 void Add(CCullerCacheData
* pItem
)
539 pItem
->nLifespan
= 0;
540 CExpireCuller::Add(pItem
);
543 void Commit(CCullerCacheData
* pItem
)
546 if (pItem
->nLifespan
== 0)
547 pItem
->cftExpireTime
= 0;
549 pItem
->cftExpireTime
= CFileTime(CFileTime::GetCurrentTime().GetTime() + pItem
->nLifespan
);
550 CExpireCuller::Commit(pItem
);
553 void Access(CCullerCacheData
* pItem
)
556 CExpireCuller::Remove(pItem
);
560 CCullerCacheData
* GetExpired()
562 return static_cast<CCullerCacheData
*>(CExpireCuller::GetExpired());
566 template <__int64 ftLifespan
>
567 class CFixedLifetimeCuller
: public CExpireCuller
570 void Commit(CCullerCacheData
* pItem
)
573 __int64 nLifeSpan
= ftLifespan
;
575 pItem
->cftExpireTime
= 0;
577 pItem
->cftExpireTime
= CFileTime::GetCurrentTime() + CFileTimeSpan(ftLifespan
);
579 CExpireCuller::Commit(pItem
);
582 void Access(CCullerCacheData
* pItem
)
585 CExpireCuller::Remove(pItem
);
589 CCullerCacheData
* GetExpired()
591 return static_cast<CCullerCacheData
*>(CExpireCuller::GetExpired());
596 template <class CFirst
, class CSecond
>
602 void Add(CCullerCacheData
* pItem
)
608 void Access(CCullerCacheData
* pItem
)
610 m_First
.Access(pItem
);
611 m_Second
.Access(pItem
);
614 void Remove(CCullerCacheData
* pItem
)
616 m_First
.Remove(pItem
);
617 m_Second
.Remove(pItem
);
626 void Release(CCullerCacheData
*pItem
)
628 m_First
.Release(pItem
);
629 m_Second
.Release(pItem
);
632 void Commit(CCullerCacheData
* pItem
)
634 m_First
.Commit(pItem
);
635 m_Second
.Commit(pItem
);
637 CCullerCacheData
* GetExpired()
639 CCullerCacheData
*pItem
= m_First
.GetExpired();
641 pItem
= m_Second
.GetExpired();
646 BOOL
IsExpired(CCullerCacheData
* pItem
)
648 return (m_First
.IsExpired(pItem
) || m_Second
.IsExpired(pItem
));
655 // This class provides the implementation of a generic cache that stores
656 // elements in memory. CMemoryCacheBase uses the CCacheDataBase generic
657 // cache element structure to hold items in the cache. The cache is
658 // implemented using the CAtlMap map class. CMemoryCache uses a wide
659 // character string as it's Key type to identify entries. Entries must
660 // have unique key values. If you try to add an entry with a key that
661 // is exactly the same as an existing key, the existing entry will be
664 // Template Parameters:
665 // T: The class that inherits from this class. This class must implement
666 // void OnDestroyEntry(NodeType *pEntry);
667 // DataType: Specifies the type of the element to be stored in the memory
668 // cache such as CString or void*
669 // NodeInfo: Specifies any additional data that should be stored in each item
671 // keyType, keyTrait : specifies the key type and traits (see CAtlMap)
672 // Flusher : the class responsible for determining which data should be flushed
673 // when the cache is at a configuration limit
674 // Culler : the class responsible for determining which data should be removed
675 // from the cache due to expiration
676 // SyncClass:Specifies the class that will be used for thread synchronization
677 // when accessing the cache. The class interface for SyncClass must
678 // be identical to that of CComCriticalSection (see atlbase.h)
679 // StatClass: Class used to contain statistics about this cache.
682 class NodeInfo
=CCacheDataBase
,
683 class keyType
=CFixedStringKey
,
684 class KeyTrait
=CStringElementTraits
<CFixedStringKey
>,
685 class Flusher
=COldFlusher
,
686 class Culler
=CExpireCuller
,
687 class SyncClass
=CComCriticalSection
,
688 class StatClass
=CStdStatClass
>
689 class CMemoryCacheBase
692 typedef keyType keytype
;
693 struct NodeType
: public __CACHEITEM
,
695 public CFlusherCacheData
,
696 public CCullerCacheData
711 typedef CAtlMap
<keyType
, NodeType
*, KeyTrait
> mapType
;
717 //memory cache configuration parameters
718 DWORD m_dwMaxAllocationSize
;
719 DWORD m_dwMaxEntries
;
726 m_dwMaxAllocationSize(0xFFFFFFFF),
727 m_dwMaxEntries(0xFFFFFFFF),
728 m_bInitialized(FALSE
)
733 //Initializes the cache and the cache synchronization object
734 //Also the performance monitoring
738 return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED
);
740 hr
= m_syncObj
.Init();
743 hr
= m_statObj
.Initialize();
745 m_bInitialized
= TRUE
;
750 //removes all entries whether or not they are initialized.
751 HRESULT
Uninitialize()
756 //clear out the hash table
757 HRESULT hr
= m_syncObj
.Lock();
762 m_statObj
.Uninitialize();
767 m_bInitialized
= FALSE
;
772 //Adds an entry to the cache.
773 //Also, adds an initial reference on the entry if phEntry is not NULL
775 const keyType
&Key
, //key for entry
776 const DataType
&data
, //See the DataType template parameter
777 DWORD dwSize
, //Size of memory to be stored in the cache
778 HCACHEITEM
*phEntry
= NULL
//out pointer that will contain a handle to the new
779 //cache entry on success.
784 ATLASSUME(m_bInitialized
);
786 CAutoPtr
<NodeType
> spEntry(new NodeType
);
789 return E_OUTOFMEMORY
;
791 NodeType
*pEntry
= spEntry
;
796 *phEntry
= static_cast<HCACHEITEM
>(pEntry
);
800 pEntry
->dwSize
= dwSize
;
802 CComCritSecLock
<SyncClass
> lock(m_syncObj
, false);
804 HRESULT hr
= lock
.Lock();
810 POSITION pos
= (POSITION
)m_hashTable
.Lookup(Key
);
814 RemoveAt(pos
, FALSE
);
815 m_hashTable
.GetValueAt(pos
) = pEntry
;
819 pos
= m_hashTable
.SetAt(Key
, pEntry
);
824 m_statObj
.AddElement(dwSize
);
825 m_flusher
.Add(pEntry
);
826 m_culler
.Add(pEntry
);
831 return CommitEntry(static_cast<HCACHEITEM
>(pEntry
));
841 // Commits the entry to the cache
842 HRESULT
CommitEntry(const HCACHEITEM hEntry
)
844 ATLASSUME(m_bInitialized
);
845 if (!hEntry
|| hEntry
== INVALID_HANDLE_VALUE
)
848 HRESULT hr
= m_syncObj
.Lock();
854 NodeType
*pEntry
= static_cast<NodeType
*>(hEntry
);
855 m_culler
.Commit(pEntry
);
860 // Looks up an entry and returns a handle to it,
861 // also updates access count and reference count
862 HRESULT
LookupEntry(const keyType
&Key
, HCACHEITEM
* phEntry
)
864 ATLASSUME(m_bInitialized
);
865 HRESULT hr
= m_syncObj
.Lock();
873 POSITION pos
= (POSITION
)m_hashTable
.Lookup(Key
);
876 NodeType
* pEntry
= m_hashTable
.GetValueAt(pos
);
877 m_flusher
.Access(pEntry
);
878 m_culler
.Access(pEntry
);
882 *phEntry
= static_cast<HCACHEITEM
>(pEntry
);
899 // Gets the data based on the handle. Is thread-safe as long as there is a
900 // reference on the data
901 HRESULT
GetEntryData(const HCACHEITEM hEntry
, DataType
*pData
, DWORD
*pdwSize
) const
903 ATLASSUME(m_bInitialized
);
904 ATLASSERT(pData
!= NULL
|| pdwSize
!= NULL
); // At least one should not be NULL
906 if (!hEntry
|| hEntry
== INVALID_HANDLE_VALUE
)
909 NodeType
* pEntry
= static_cast<NodeType
*>(hEntry
);
911 *pData
= pEntry
->Data
;
913 *pdwSize
= pEntry
->dwSize
;
918 // Unreferences the entry based on the handle
919 DWORD
ReleaseEntry(const HCACHEITEM hEntry
)
921 ATLASSUME(m_bInitialized
);
922 if (!hEntry
|| hEntry
== INVALID_HANDLE_VALUE
)
925 HRESULT hr
= m_syncObj
.Lock();
929 NodeType
* pEntry
= static_cast<NodeType
*>(hEntry
);
930 m_flusher
.Release(pEntry
);
931 m_culler
.Release(pEntry
);
932 ATLASSERT(pEntry
->dwRef
> 0);
934 DWORD dwRef
= --pEntry
->dwRef
;
935 if ((pEntry
->pos
== NULL
) && (pEntry
->dwRef
== 0))
936 InternalRemoveEntry(pEntry
);
943 // Increments the entry's reference count
944 DWORD
AddRefEntry(const HCACHEITEM hEntry
)
946 ATLASSUME(m_bInitialized
);
947 if (!hEntry
|| hEntry
== INVALID_HANDLE_VALUE
)
950 HRESULT hr
= m_syncObj
.Lock();
954 NodeType
* pEntry
= static_cast<NodeType
*>(hEntry
);
955 m_flusher
.Access(pEntry
);
956 m_culler
.Access(pEntry
);
957 DWORD dwRef
= ++pEntry
->dwRef
;
963 // Removes an entry from the cache regardless of whether or
964 // not it has expired. If there are references, it detaches
965 // the entry so that future lookups will fail, and when
966 // the ref count drops to zero, it will be deleted
967 HRESULT
RemoveEntryByKey(const keyType
&Key
)
969 ATLASSUME(m_bInitialized
);
971 HRESULT hr
= LookupEntry(Key
, &hEntry
);
973 hr
= RemoveEntry(hEntry
);
978 // Removes the element from the cache. If there are still
979 // references, then the entry is detached.
980 HRESULT
RemoveEntry(const HCACHEITEM hEntry
)
982 ATLASSUME(m_bInitialized
);
983 if (!hEntry
|| hEntry
== INVALID_HANDLE_VALUE
)
988 CComCritSecLock
<SyncClass
> lock(m_syncObj
, false);
990 HRESULT hr
= lock
.Lock();
994 NodeType
* pEntry
= static_cast<NodeType
*>(hEntry
);
995 m_flusher
.Release(pEntry
);
996 m_culler
.Release(pEntry
);
997 ATLASSERT(pEntry
->dwRef
> 0);
1000 RemoveAt(pEntry
->pos
, TRUE
);
1001 else if ((long)pEntry
->dwRef
== 0)
1002 InternalRemoveEntry(pEntry
);
1007 return E_OUTOFMEMORY
;
1013 // CullEntries removes all expired items
1014 HRESULT
CullEntries()
1016 ATLASSUME(m_bInitialized
);
1020 CComCritSecLock
<SyncClass
> lock(m_syncObj
, false);
1021 HRESULT hr
= lock
.Lock();
1027 while (NodeType
*pNode
= static_cast<NodeType
*>(m_culler
.GetExpired()))
1028 RemoveAt(pNode
->pos
, TRUE
);
1034 return E_OUTOFMEMORY
;
1040 // FlushEntries reduces the cache to meet the configuration requirements
1041 HRESULT
FlushEntries()
1043 ATLASSUME(m_bInitialized
);
1044 HRESULT hr
= CullEntries();
1050 CComCritSecLock
<SyncClass
> lock(m_syncObj
, false);
1055 NodeType
* pNode
= static_cast<NodeType
*>(m_flusher
.GetStart());
1058 (((m_statObj
.GetCurrentEntryCount() > m_dwMaxEntries
)) ||
1059 ((m_statObj
.GetCurrentAllocSize() > m_dwMaxAllocationSize
))))
1061 NodeType
*pNext
= static_cast<NodeType
*>(m_flusher
.GetNext(pNode
));
1063 if (pNode
->dwRef
== 0)
1064 RemoveAt(pNode
->pos
, TRUE
);
1072 return E_OUTOFMEMORY
;
1078 HRESULT STDMETHODCALLTYPE
SetMaxAllowedSize(DWORD dwSize
)
1080 m_dwMaxAllocationSize
= dwSize
;
1084 HRESULT STDMETHODCALLTYPE
GetMaxAllowedSize(DWORD
*pdwSize
)
1088 *pdwSize
= m_dwMaxAllocationSize
;
1092 HRESULT STDMETHODCALLTYPE
SetMaxAllowedEntries(DWORD dwSize
)
1094 m_dwMaxEntries
= dwSize
;
1098 HRESULT STDMETHODCALLTYPE
GetMaxAllowedEntries(DWORD
*pdwSize
)
1102 *pdwSize
= m_dwMaxEntries
;
1107 HRESULT
ResetCache()
1109 ATLASSUME(m_bInitialized
);
1110 HRESULT hr
= E_UNEXPECTED
;
1111 if (SUCCEEDED(ClearStats()))
1112 hr
= RemoveAllEntries();
1116 HRESULT
ClearStats()
1118 m_statObj
.ResetCounters();
1122 HRESULT
RemoveAllEntries()
1124 ATLASSUME(m_bInitialized
);
1125 HRESULT hr
= m_syncObj
.Lock();
1129 m_hashTable
.DisableAutoRehash();
1130 POSITION pos
= m_hashTable
.GetStartPosition();
1135 m_hashTable
.GetNext(pos
);
1136 RemoveAt(oldpos
, TRUE
);
1138 m_hashTable
.EnableAutoRehash();
1146 // Checks to see if the cache can accommodate any new entries within
1147 // its allocation and entry count limits.
1148 bool CanAddEntry(DWORD dwSizeToAdd
)
1150 return CheckAlloc(dwSizeToAdd
) && CheckEntryCount(1);
1153 // Checks to see if the cache can accommodate dwSizeToAdd additional
1154 // allocation within its allocation limit.
1155 bool CheckAlloc(DWORD dwSizeToAdd
)
1157 if (m_dwMaxAllocationSize
== 0xFFFFFFFF)
1158 return true; //max allocation size setting hasn't been set
1159 DWORD dwNew
= m_statObj
.GetCurrentAllocSize() + dwSizeToAdd
;
1160 return dwNew
< m_dwMaxAllocationSize
;
1164 // Checks to see if the cache can accommodate dwNumEntriesToAdd
1165 // additional entries within its limits.
1166 bool CheckEntryCount(DWORD dwNumEntriesToAdd
)
1168 if (m_dwMaxEntries
== 0xFFFFFFFF)
1169 return true; //max entry size hasn't been set
1170 DWORD dwNew
= m_statObj
.GetCurrentEntryCount() + dwNumEntriesToAdd
;
1171 return dwNew
< m_dwMaxEntries
;
1176 // Takes the element at pos in the hash table and removes it from
1177 // the cache. If there are no references, then the entry is
1178 // deleted, otherwise it is deleted by ReleaseEntry when the
1179 // refcount goes to zero.
1180 HRESULT
RemoveAt(POSITION pos
, BOOL bDelete
)
1183 ATLASSERT(pos
!= NULL
);
1184 NodeType
* pEntry
= m_hashTable
.GetValueAt(pos
);
1185 m_flusher
.Remove(pEntry
);
1186 m_culler
.Remove(pEntry
);
1188 m_hashTable
.RemoveAtPos(pos
);
1190 if ((long)pEntry
->dwRef
== 0)
1191 hr
= InternalRemoveEntry(pEntry
);
1198 // Does the actual destruction of the node. Deletes the
1199 // NodeType struct and calls the inherited class's
1200 // OnDestroyEntry function, where other necessary destruction
1201 // can take place. Also updates the cache statistics.
1202 // Inherited classes should call RemoveAt unless the element's
1203 // refcount is zero and it has been removed from the
1204 // culler and flusher lists.
1205 HRESULT
InternalRemoveEntry(NodeType
* pEntry
)
1207 ATLENSURE(pEntry
!= NULL
);
1209 T
* pT
= static_cast<T
*>(this);
1211 ATLASSERT((long)pEntry
->dwRef
== 0);
1213 pT
->OnDestroyEntry(pEntry
);
1215 m_statObj
.ReleaseElement(pEntry
->dwSize
);
1221 }; // CMemoryCacheBase
1223 class CCacheDataBase
1227 struct CCacheDataEx
: public CCacheDataBase
1235 HINSTANCE hInstance
;
1236 IMemoryCacheClient
* pClient
;
1240 template <typename DataType
,
1241 class StatClass
=CStdStatClass
,
1242 class FlushClass
=COldFlusher
,
1243 class keyType
=CFixedStringKey
, class KeyTrait
=CStringElementTraits
<CFixedStringKey
>,
1244 class SyncClass
=CComCriticalSection
,
1245 class CullClass
=CExpireCuller
>
1247 public CMemoryCacheBase
<CMemoryCache
<DataType
, StatClass
, FlushClass
, keyType
, KeyTrait
, SyncClass
, CullClass
>, DataType
, CCacheDataEx
,
1248 keyType
, KeyTrait
, FlushClass
, CullClass
, SyncClass
, StatClass
>
1251 CComPtr
<IServiceProvider
> m_spServiceProv
;
1252 CComPtr
<IDllCache
> m_spDllCache
;
1253 typedef CMemoryCacheBase
<CMemoryCache
<DataType
, StatClass
, FlushClass
, keyType
, KeyTrait
, SyncClass
, CullClass
>, DataType
, CCacheDataEx
,
1254 keyType
, KeyTrait
, FlushClass
, CullClass
, SyncClass
, StatClass
> baseClass
;
1256 virtual ~CMemoryCache()
1260 HRESULT
Initialize(IServiceProvider
* pProvider
)
1262 baseClass::Initialize();
1263 m_spServiceProv
= pProvider
;
1265 return m_spServiceProv
->QueryService(__uuidof(IDllCache
), __uuidof(IDllCache
), (void**)&m_spDllCache
);
1272 const DataType
&data
,
1274 FILETIME
* pftExpireTime
= NULL
,
1275 HINSTANCE hInstance
= NULL
,
1276 IMemoryCacheClient
* pClient
= NULL
,
1277 HCACHEITEM
*phEntry
= NULL
1283 NodeType
* pEntry
= NULL
;
1284 hr
= baseClass::AddEntry(Key
, data
, dwSize
, (HCACHEITEM
*)&pEntry
);
1288 pEntry
->hInstance
= hInstance
;
1289 pEntry
->pClient
= pClient
;
1291 pEntry
->cftExpireTime
= *pftExpireTime
;
1293 if (hInstance
&& m_spDllCache
)
1294 m_spDllCache
->AddRefModule(hInstance
);
1296 baseClass::CommitEntry(static_cast<HCACHEITEM
>(pEntry
));
1299 *phEntry
= static_cast<HCACHEITEM
>(pEntry
);
1301 baseClass::ReleaseEntry(static_cast<HCACHEITEM
>(pEntry
));
1311 virtual void OnDestroyEntry(const NodeType
* pEntry
)
1317 if (pEntry
->pClient
)
1318 pEntry
->pClient
->Free((void *)&pEntry
->Data
);
1319 if (pEntry
->hInstance
&& m_spDllCache
)
1320 m_spDllCache
->ReleaseModule(pEntry
->hInstance
);
1324 // CStdStatData - contains the data that CStdStatClass keeps track of
1325 #define ATL_PERF_CACHE_OBJECT 100
1327 struct CPerfStatObject
: public CPerfObject
1329 DECLARE_PERF_CATEGORY(CPerfStatObject
, ATL_PERF_CACHE_OBJECT
, IDS_PERFMON_CACHE
, IDS_PERFMON_CACHE_HELP
, -1);
1331 BEGIN_COUNTER_MAP(CPerfStatObject
)
1332 DEFINE_COUNTER(m_nHitCount
, IDS_PERFMON_HITCOUNT
, IDS_PERFMON_HITCOUNT_HELP
, PERF_COUNTER_RAWCOUNT
, -1)
1333 DEFINE_COUNTER(m_nMissCount
, IDS_PERFMON_MISSCOUNT
, IDS_PERFMON_MISSCOUNT_HELP
, PERF_COUNTER_RAWCOUNT
, -1)
1334 DEFINE_COUNTER(m_nCurrentAllocations
, IDS_PERFMON_CURRENTALLOCATIONS
, IDS_PERFMON_CURRENTALLOCATIONS_HELP
, PERF_COUNTER_RAWCOUNT
, -3)
1335 DEFINE_COUNTER(m_nMaxAllocations
, IDS_PERFMON_MAXALLOCATIONS
, IDS_PERFMON_MAXALLOCATIONS_HELP
, PERF_COUNTER_RAWCOUNT
, -3)
1336 DEFINE_COUNTER(m_nCurrentEntries
, IDS_PERFMON_CURRENTENTRIES
, IDS_PERFMON_CURRENTENTRIES_HELP
, PERF_COUNTER_RAWCOUNT
, -1)
1337 DEFINE_COUNTER(m_nMaxEntries
, IDS_PERFMON_MAXENTRIES
, IDS_PERFMON_MAXENTRIES_HELP
, PERF_COUNTER_RAWCOUNT
, -1)
1342 long m_nCurrentAllocations
;
1343 long m_nMaxAllocations
;
1344 long m_nCurrentEntries
;
1348 // CCachePerfMon - the interface to CPerfMon, with associated definitions
1349 class CCachePerfMon
: public CPerfMon
1352 BEGIN_PERF_MAP(_T("ATL Server:Cache"))
1353 CHAIN_PERF_CATEGORY(CPerfStatObject
)
1360 // This class provides the implementation of a standard cache statistics accounting class
1364 CPerfStatObject
* m_pStats
;
1365 CPerfStatObject m_stats
;
1371 m_pStats
= &m_stats
;
1374 // This function is not thread safe by design
1375 HRESULT
Initialize(CPerfStatObject
* pStats
= NULL
)
1380 m_pStats
= &m_stats
;
1386 // This function is not thread safe by design
1387 HRESULT
Uninitialize()
1389 m_pStats
= &m_stats
;
1395 InterlockedIncrement(&m_pStats
->m_nHitCount
);
1400 InterlockedIncrement(&m_pStats
->m_nMissCount
);
1403 void AddElement(DWORD dwBytes
)
1405 DWORD nCurrentEntries
= InterlockedIncrement(&m_pStats
->m_nCurrentEntries
);
1406 AtlInterlockedUpdateMax(nCurrentEntries
, &m_pStats
->m_nMaxEntries
);
1408 DWORD nCurrentAllocations
= dwBytes
+ AtlInterlockedExchangeAdd(&m_pStats
->m_nCurrentAllocations
, dwBytes
);
1409 AtlInterlockedUpdateMax(nCurrentAllocations
, &m_pStats
->m_nMaxAllocations
);
1412 void ReleaseElement(DWORD dwBytes
)
1414 InterlockedDecrement(&m_pStats
->m_nCurrentEntries
);
1415 AtlInterlockedExchangeAdd(&m_pStats
->m_nCurrentAllocations
, -((long)dwBytes
));
1420 return m_pStats
->m_nHitCount
;
1423 DWORD
GetMissCount()
1425 return m_pStats
->m_nMissCount
;
1428 DWORD
GetCurrentAllocSize()
1430 return m_pStats
->m_nCurrentAllocations
;
1433 DWORD
GetMaxAllocSize()
1435 return m_pStats
->m_nMaxAllocations
;
1438 DWORD
GetCurrentEntryCount()
1440 return m_pStats
->m_nCurrentEntries
;
1443 DWORD
GetMaxEntryCount()
1445 return m_pStats
->m_nMaxEntries
;
1448 void ResetCounters()
1450 m_pStats
->m_nHitCount
= 0;
1451 m_pStats
->m_nMissCount
= 0;
1452 m_pStats
->m_nCurrentAllocations
= 0;
1453 m_pStats
->m_nMaxAllocations
= 0;
1454 m_pStats
->m_nCurrentEntries
= 0;
1455 m_pStats
->m_nMaxEntries
= 0;
1461 // This is a noop stat class
1465 HRESULT
Initialize(){ return S_OK
; }
1466 HRESULT
Uninitialize(){ return S_OK
; }
1469 void AddElement(DWORD
){ }
1470 void ReleaseElement(DWORD
){ }
1471 DWORD
GetHitCount(){ return 0; }
1472 DWORD
GetMissCount(){ return 0; }
1473 DWORD
GetCurrentAllocSize(){ return 0; }
1474 DWORD
GetMaxAllocSize(){ return 0; }
1475 DWORD
GetCurrentEntryCount(){ return 0; }
1476 DWORD
GetMaxEntryCount(){ return 0; }
1477 void ResetCounters(){ }
1483 // This class provides the implementation of a cache statistics gathering class
1484 // with PerfMon support
1485 class CPerfStatClass
: public CStdStatClass
1487 CPerfStatObject
* m_pPerfObject
;
1488 CCachePerfMon m_PerfMon
;
1492 HRESULT
Initialize(__in_z_opt LPWSTR szName
=NULL
)
1495 WCHAR szPath
[MAX_PATH
];
1499 // default name is the name of the module
1500 // we don't care about possible truncation if longer than max_path
1501 // we just need an identifier
1502 HINSTANCE hInst
= _AtlBaseModule
.GetModuleInstance();
1503 if (::GetModuleFileNameW(hInst
, szPath
, MAX_PATH
) == 0)
1507 szPath
[MAX_PATH
-1] = 0;
1511 m_pPerfObject
= NULL
;
1512 ATLTRACE(atlTraceCache
, 2, _T("Initializing m_PerfMon\n"));
1513 hr
= m_PerfMon
.Initialize();
1516 CPerfLock
lock(&m_PerfMon
);
1517 if (FAILED(hr
= lock
.GetStatus()))
1522 hr
= m_PerfMon
.CreateInstance(ATL_PERF_CACHE_OBJECT
, 0, szName
, reinterpret_cast<CPerfObject
**>(&m_pPerfObject
));
1528 CStdStatClass::Initialize(m_pPerfObject
);
1531 ATLASSUME(m_pPerfObject
== NULL
);
1536 HRESULT
Uninitialize()
1538 CStdStatClass::Uninitialize();
1540 if (m_pPerfObject
!= NULL
) // Initialized m_pPerfObject successfully above
1542 HRESULT hr
= m_PerfMon
.ReleaseInstance(m_pPerfObject
);
1546 m_PerfMon
.UnInitialize();
1551 }; // CPerfStatClass
1553 #ifndef ATL_BLOB_CACHE_TIMEOUT
1555 #define ATL_BLOB_CACHE_TIMEOUT 1000
1557 #define ATL_BLOB_CACHE_TIMEOUT 5000
1559 #endif // ATL_BLOB_CACHE_TIMEOUT
1564 // Implements a cache that stores pointers to void. Uses the generic CMemoryCacheBase class
1565 // as the implementation.
1566 template <class MonitorClass
,
1567 class StatClass
=CStdStatClass
,
1568 class SyncObj
=CComCriticalSection
,
1569 class FlushClass
=COldFlusher
,
1570 class CullClass
=CExpireCuller
>
1571 class CBlobCache
: public CMemoryCache
<void*, StatClass
, FlushClass
, CFixedStringKey
,
1572 CStringElementTraits
<CFixedStringKey
>, SyncObj
, CullClass
>,
1573 public IMemoryCache
,
1574 public IMemoryCacheControl
,
1575 public IMemoryCacheStats
,
1576 public IWorkerThreadClient
1578 typedef CMemoryCache
<void*, StatClass
, FlushClass
, CFixedStringKey
,
1579 CStringElementTraits
<CFixedStringKey
>, SyncObj
, CullClass
> cacheBase
;
1581 MonitorClass m_Monitor
;
1587 CBlobCache() : m_hTimer(NULL
)
1591 HRESULT
Initialize(IServiceProvider
*pProv
)
1593 HRESULT hr
= cacheBase::Initialize(pProv
);
1596 hr
= m_Monitor
.Initialize();
1599 return m_Monitor
.AddTimer(ATL_BLOB_CACHE_TIMEOUT
,
1600 static_cast<IWorkerThreadClient
*>(this), (DWORD_PTR
) this, &m_hTimer
);
1603 template <class ThreadTraits
>
1604 HRESULT
Initialize(IServiceProvider
*pProv
, CWorkerThread
<ThreadTraits
> *pWorkerThread
)
1606 ATLASSERT(pWorkerThread
);
1608 HRESULT hr
= cacheBase::Initialize(pProv
);
1612 hr
= m_Monitor
.Initialize(pWorkerThread
);
1616 return m_Monitor
.AddTimer(ATL_BLOB_CACHE_TIMEOUT
,
1617 static_cast<IWorkerThreadClient
*>(this), (DWORD_PTR
) this, &m_hTimer
);
1620 HRESULT
Execute(DWORD_PTR dwParam
, HANDLE
/*hObject*/)
1622 CBlobCache
* pCache
= (CBlobCache
*)dwParam
;
1629 HRESULT
CloseHandle(HANDLE hObject
)
1631 ATLASSUME(m_hTimer
== hObject
);
1633 ::CloseHandle(hObject
);
1637 virtual ~CBlobCache()
1641 ATLENSURE(SUCCEEDED(m_Monitor
.RemoveHandle(m_hTimer
)));
1645 HRESULT
Uninitialize()
1647 HRESULT hrMonitor
=S_OK
;
1650 hrMonitor
=m_Monitor
.RemoveHandle(m_hTimer
);
1653 HRESULT hrShut
=m_Monitor
.Shutdown();
1654 HRESULT hrCache
=cacheBase::Uninitialize();
1655 if(FAILED(hrMonitor
))
1666 HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid
, void **ppv
)
1668 HRESULT hr
= E_NOINTERFACE
;
1673 if (InlineIsEqualGUID(riid
, __uuidof(IUnknown
)) ||
1674 InlineIsEqualGUID(riid
, __uuidof(IMemoryCache
)))
1676 *ppv
= (IUnknown
*) (IMemoryCache
*) this;
1680 if (InlineIsEqualGUID(riid
, __uuidof(IMemoryCacheStats
)))
1682 *ppv
= (IUnknown
*) (IMemoryCacheStats
*)this;
1686 if (InlineIsEqualGUID(riid
, __uuidof(IMemoryCacheControl
)))
1688 *ppv
= (IUnknown
*) (IMemoryCacheControl
*)this;
1697 ULONG STDMETHODCALLTYPE
AddRef()
1702 ULONG STDMETHODCALLTYPE
Release()
1707 // IMemoryCache Methods
1708 HRESULT STDMETHODCALLTYPE
Add(LPCSTR szKey
, void *pvData
, DWORD dwSize
,
1709 FILETIME
*pftExpireTime
,
1710 HINSTANCE hInstClient
,
1711 HCACHEITEM
*phEntry
,
1712 IMemoryCacheClient
*pClient
)
1714 HRESULT hr
= E_FAIL
;
1715 //if it's a multithreaded cache monitor we'll let the monitor take care of
1716 //cleaning up the cache so we don't overflow our configuration settings.
1717 //if it's not a threaded cache monitor, we need to make sure we don't
1718 //overflow the configuration settings by adding a new element
1719 if (m_Monitor
.GetThreadHandle()==NULL
)
1721 if (!cacheBase::CanAddEntry(dwSize
))
1723 //flush the entries and check again to see if we can add
1724 cacheBase::FlushEntries();
1725 if (!cacheBase::CanAddEntry(dwSize
))
1726 return E_OUTOFMEMORY
;
1731 hr
= cacheBase::AddEntry(szKey
, pvData
, dwSize
,
1732 pftExpireTime
, hInstClient
, pClient
, phEntry
);
1741 HRESULT STDMETHODCALLTYPE
LookupEntry(LPCSTR szKey
, HCACHEITEM
* phEntry
)
1743 return cacheBase::LookupEntry(szKey
, phEntry
);
1746 HRESULT STDMETHODCALLTYPE
GetData(const HCACHEITEM hKey
, void **ppvData
, DWORD
*pdwSize
) const
1748 return cacheBase::GetEntryData(hKey
, ppvData
, pdwSize
);
1751 HRESULT STDMETHODCALLTYPE
ReleaseEntry(const HCACHEITEM hKey
)
1753 return cacheBase::ReleaseEntry(hKey
);
1756 HRESULT STDMETHODCALLTYPE
RemoveEntry(const HCACHEITEM hKey
)
1758 return cacheBase::RemoveEntry(hKey
);
1761 HRESULT STDMETHODCALLTYPE
RemoveEntryByKey(LPCSTR szKey
)
1763 return cacheBase::RemoveEntryByKey(szKey
);
1766 HRESULT STDMETHODCALLTYPE
Flush()
1768 return cacheBase::FlushEntries();
1772 HRESULT STDMETHODCALLTYPE
SetMaxAllowedSize(DWORD dwSize
)
1774 return cacheBase::SetMaxAllowedSize(dwSize
);
1777 HRESULT STDMETHODCALLTYPE
GetMaxAllowedSize(DWORD
*pdwSize
)
1779 return cacheBase::GetMaxAllowedSize(pdwSize
);
1782 HRESULT STDMETHODCALLTYPE
SetMaxAllowedEntries(DWORD dwSize
)
1784 return cacheBase::SetMaxAllowedEntries(dwSize
);
1787 HRESULT STDMETHODCALLTYPE
GetMaxAllowedEntries(DWORD
*pdwSize
)
1789 return cacheBase::GetMaxAllowedEntries(pdwSize
);
1792 HRESULT STDMETHODCALLTYPE
ResetCache()
1794 return cacheBase::ResetCache();
1797 // IMemoryCacheStats methods
1798 HRESULT STDMETHODCALLTYPE
ClearStats()
1800 m_statObj
.ResetCounters();
1804 HRESULT STDMETHODCALLTYPE
GetHitCount(DWORD
*pdwSize
)
1808 *pdwSize
= m_statObj
.GetHitCount();
1812 HRESULT STDMETHODCALLTYPE
GetMissCount(DWORD
*pdwSize
)
1816 *pdwSize
= m_statObj
.GetMissCount();
1820 HRESULT STDMETHODCALLTYPE
GetMaxAllocSize(DWORD
*pdwSize
)
1824 *pdwSize
= m_statObj
.GetMaxAllocSize();
1828 HRESULT STDMETHODCALLTYPE
GetCurrentAllocSize(DWORD
*pdwSize
)
1832 *pdwSize
= m_statObj
.GetCurrentAllocSize();
1836 HRESULT STDMETHODCALLTYPE
GetMaxEntryCount(DWORD
*pdwSize
)
1840 *pdwSize
= m_statObj
.GetMaxEntryCount();
1844 HRESULT STDMETHODCALLTYPE
GetCurrentEntryCount(DWORD
*pdwSize
)
1848 *pdwSize
= m_statObj
.GetCurrentEntryCount();
1857 // This class manages a cache to handle calls to LoadLibrary
1859 // It keeps dlls loaded even after the last call to free library
1860 // a worker thread then calls FreeLibrary on unused dlls
1862 #ifndef ATL_DLL_CACHE_TIMEOUT
1864 #define ATL_DLL_CACHE_TIMEOUT 1000 // 1 sec default for debug builds
1866 #define ATL_DLL_CACHE_TIMEOUT 10*60000 // 10 minute default for retail builds
1870 class CNoDllCachePeer
1877 BOOL
Add(HINSTANCE
/*hInst*/, DllInfo
* /*pInfo*/)
1882 void Remove(HINSTANCE
/*hInst*/, DllInfo
* /*pInfo*/)
1888 // Implements IDllCache, an interface that is used to load and unload Dlls.
1889 // To use it, construct an instance of a CDllCache and call Initialize.
1890 // The Initialize call has to match with the type of monitor class you
1891 // templatize on. The monitor thread will call IWorkerThreadClient::Execute
1892 // after its timeout expires. Make sure to Uninitialize the object before
1893 // it is destroyed by calling Uninitialize
1895 template <class MonitorClass
, class Peer
=CNoDllCachePeer
>
1896 class CDllCache
: public IDllCache
,
1897 public IWorkerThreadClient
1900 CComCriticalSection m_critSec
;
1901 CSimpleArray
<DLL_CACHE_ENTRY
> m_Dlls
;
1902 CSimpleArray
<typename
Peer::DllInfo
> m_DllInfos
;
1903 MonitorClass m_Monitor
;
1906 void RemoveDllEntry(DLL_CACHE_ENTRY
& entry
)
1908 ::FreeLibrary(entry
.hInstDll
);
1909 entry
.hInstDll
= NULL
;
1910 m_Dlls
.RemoveAt(m_Dlls
.GetSize()-1);
1922 HRESULT
Initialize(DWORD dwTimeout
=ATL_DLL_CACHE_TIMEOUT
)
1924 HRESULT hr
= m_critSec
.Init();
1927 hr
= m_Monitor
.Initialize();
1930 return m_Monitor
.AddTimer(dwTimeout
, this, 0, &m_hTimer
);
1933 template <class ThreadTraits
>
1934 HRESULT
Initialize(CWorkerThread
<ThreadTraits
> *pWorkerThread
,
1935 DWORD dwTimeout
=ATL_DLL_CACHE_TIMEOUT
)
1937 HRESULT hr
= m_critSec
.Init();
1940 hr
= m_Monitor
.Initialize(pWorkerThread
);
1943 return m_Monitor
.AddTimer(dwTimeout
, this, 0, &m_hTimer
);
1946 HRESULT
Uninitialize()
1949 HRESULT hrLatest
= S_OK
;
1952 hrLatest
=m_Monitor
.RemoveHandle(m_hTimer
);
1953 if(FAILED(hrLatest
) && SUCCEEDED(hr
))
1959 m_Monitor
.Shutdown();
1961 // free all the libraries we've cached
1962 int nLen
= m_Dlls
.GetSize();
1963 for (int i
=0; i
<nLen
; i
++)
1965 DLL_CACHE_ENTRY
& entry
= m_Dlls
[i
];
1966 ATLASSERT(entry
.dwRefs
== 0);
1967 BOOL bRet
= ::FreeLibrary(entry
.hInstDll
);
1971 hrLatest
= AtlHresultFromLastError();
1972 if(FAILED(hrLatest
) && SUCCEEDED(hr
))
1976 ATLTRACE(atlTraceCache
, 0, _T("Free library failed on shutdown of dll cache : hr = 0x%08x)"), hr
);
1986 HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid
, void **ppv
)
1990 if (InlineIsEqualGUID(riid
, __uuidof(IUnknown
)) ||
1991 InlineIsEqualGUID(riid
, __uuidof(IDllCache
)))
1993 *ppv
= (IUnknown
*) this;
1997 return E_NOINTERFACE
;
2000 ULONG STDMETHODCALLTYPE
AddRef()
2005 ULONG STDMETHODCALLTYPE
Release()
2010 // IDllCache methods
2011 HINSTANCE
Load(LPCSTR szDllName
, void *pPeerInfo
) throw(...)
2013 HRESULT hr
= m_critSec
.Lock();
2017 int nLen
= m_Dlls
.GetSize();
2018 for (int i
=0; i
<nLen
; i
++)
2020 DLL_CACHE_ENTRY
& entry
= m_Dlls
[i
];
2021 if (!_stricmp(entry
.szDllName
, szDllName
))
2027 Peer::DllInfo
*pl
= (Peer::DllInfo
*)pPeerInfo
;
2028 *pl
= m_DllInfos
[i
];
2030 return entry
.hInstDll
;
2033 DLL_CACHE_ENTRY entry
;
2034 entry
.hInstDll
= ::LoadLibraryA(szDllName
);
2035 if (!entry
.hInstDll
)
2040 if (!SafeStringCopy(entry
.szDllName
, szDllName
))
2042 ::FreeLibrary(entry
.hInstDll
);
2047 entry
.bAlive
= TRUE
;
2050 Peer::DllInfo
*pdllInfo
= (Peer::DllInfo
*)pPeerInfo
;
2052 // m_Peer could throw an exception from user code. We
2053 // pass that exception from here to a higher context (we
2054 // won't deal with user exception here).
2055 if (!m_Peer
.Add(entry
.hInstDll
, pdllInfo
))
2057 RemoveDllEntry(entry
);
2061 if ((entry
.hInstDll
!= NULL
) && (!m_DllInfos
.Add(*pdllInfo
)))
2063 RemoveDllEntry(entry
);
2067 return entry
.hInstDll
;
2070 BOOL
Free(HINSTANCE hInstDll
)
2072 HRESULT hr
= m_critSec
.Lock();
2076 int nLen
= m_Dlls
.GetSize();
2077 for (int i
=0; i
<nLen
; i
++)
2079 DLL_CACHE_ENTRY
&entry
= m_Dlls
[i
];
2080 if (entry
.hInstDll
== hInstDll
)
2082 ATLASSERT(entry
.dwRefs
> 0);
2083 entry
.bAlive
= TRUE
;
2091 // the dll wasn't found
2092 // in the cache, so just
2093 // pass along to ::FreeLibrary
2094 return ::FreeLibrary(hInstDll
);
2097 BOOL
AddRefModule(HINSTANCE hInstDll
)
2099 HRESULT hr
= m_critSec
.Lock();
2103 int nLen
= m_Dlls
.GetSize();
2104 for (int i
=0; i
<nLen
; i
++)
2106 DLL_CACHE_ENTRY
&entry
= m_Dlls
[i
];
2107 if (entry
.hInstDll
== hInstDll
)
2109 ATLASSERT(entry
.dwRefs
> 0);
2120 BOOL
ReleaseModule(HINSTANCE hInstDll
)
2122 HRESULT hr
= m_critSec
.Lock();
2126 int nLen
= m_Dlls
.GetSize();
2127 for (int i
=0; i
<nLen
; i
++)
2129 DLL_CACHE_ENTRY
&entry
= m_Dlls
[i
];
2130 if (entry
.hInstDll
== hInstDll
)
2132 ATLASSERT(entry
.dwRefs
> 0);
2133 entry
.bAlive
= TRUE
;
2143 HRESULT
GetEntries(DWORD dwCount
, DLL_CACHE_ENTRY
*pEntries
, DWORD
*pdwCopied
)
2148 HRESULT hr
= m_critSec
.Lock();
2152 if (dwCount
==0 || pEntries
==NULL
)
2154 // just return the required size
2155 *pdwCopied
= m_Dlls
.GetSize();
2160 if (dwCount
> (DWORD
) m_Dlls
.GetSize())
2161 dwCount
= m_Dlls
.GetSize();
2162 Checked::memcpy_s(pEntries
, dwCount
*sizeof(DLL_CACHE_ENTRY
), m_Dlls
.GetData(), dwCount
*sizeof(DLL_CACHE_ENTRY
));
2163 *pdwCopied
= dwCount
;
2170 HRESULT hr
= m_critSec
.Lock();
2174 int nLen
= m_Dlls
.GetSize();
2175 for (int i
=0; i
<nLen
; i
++)
2177 DLL_CACHE_ENTRY
&entry
= m_Dlls
[i
];
2178 if (entry
.dwRefs
== 0 && !entry
.bAlive
)
2182 m_Peer
.Remove(entry
.hInstDll
, &m_DllInfos
[i
]);
2186 ATLTRACE(atlTraceCache
, 2, _T("Exception thrown from user code in CDllCache::Flush\n"));
2189 ::FreeLibrary(entry
.hInstDll
);
2191 m_DllInfos
.RemoveAt(i
);
2195 entry
.bAlive
= FALSE
;
2202 HRESULT
Execute(DWORD_PTR
/*dwParam*/, HANDLE
/*hObject*/)
2208 HRESULT
CloseHandle(HANDLE hObject
)
2210 ATLASSUME(m_hTimer
== hObject
);
2212 ::CloseHandle(hObject
);
2220 //IStencilCache is used by a stencil processor to cache pointers to CStencil
2224 // {8702269B-707D-49cc-AEF8-5FFCB3D6891B}
2225 extern "C" __declspec(selectany
) const IID IID_IStencilCache
= { 0x8702269b, 0x707d, 0x49cc, { 0xae, 0xf8, 0x5f, 0xfc, 0xb3, 0xd6, 0x89, 0x1b } };
2227 __interface ATL_NO_VTABLE
__declspec(uuid("8702269B-707D-49cc-AEF8-5FFCB3D6891B"))
2228 IStencilCache
: public IUnknown
2230 // IStencilCache methods
2231 STDMETHOD(CacheStencil
)(LPCSTR szName
, //a name for this cache entry
2232 void *pStencil
, //a pointer to a CStencil derived object
2233 DWORD dwSize
, //sizeof pStencil
2234 HCACHEITEM
*pHandle
, //out pointer to a handle to the this cache entry
2235 HINSTANCE hInst
, //HINSTANCE of the module putting this entry
2237 IMemoryCacheClient
*pClient
//Interface used to free this instance
2239 STDMETHOD(LookupStencil
)(LPCSTR szName
, HCACHEITEM
* phStencil
);
2240 STDMETHOD(GetStencil
)(const HCACHEITEM hStencil
, void ** ppStencil
) const;
2241 STDMETHOD(AddRefStencil
)(const HCACHEITEM hStencil
);
2242 STDMETHOD(ReleaseStencil
)(const HCACHEITEM hStencil
);
2245 // {55DEF119-D7A7-4eb7-A876-33365E1C5E1A}
2246 extern "C" __declspec(selectany
) const IID IID_IStencilCacheControl
= { 0x55def119, 0xd7a7, 0x4eb7, { 0xa8, 0x76, 0x33, 0x36, 0x5e, 0x1c, 0x5e, 0x1a } };
2247 __interface ATL_NO_VTABLE
__declspec(uuid("55DEF119-D7A7-4eb7-A876-33365E1C5E1A"))
2248 IStencilCacheControl
: public IUnknown
2250 //IStencilCacheControl
2251 STDMETHOD(RemoveStencil
)(const HCACHEITEM hStencil
); // Removes the stencil if there are no references,
2252 // otherwise detaches it
2253 STDMETHOD(RemoveStencilByName
)(LPCSTR szStencil
); //removes a stencil if there are no
2255 STDMETHOD(RemoveAllStencils
)(); //removes all stencils that don't have references on them
2256 STDMETHOD(SetDefaultLifespan
)(unsigned __int64 dwdwLifespan
); //sets the lifespan for all stencils
2257 //in the cache (in 100 nanosecond units (10,000,000=1 second)).
2258 STDMETHOD(GetDefaultLifespan
)(unsigned __int64
*pdwdwLifespan
);
2261 #ifndef ATL_STENCIL_CACHE_TIMEOUT
2263 #define ATL_STENCIL_CACHE_TIMEOUT 1000
2265 #define ATL_STENCIL_CACHE_TIMEOUT 5000
2267 #endif // ATL_STENCIL_CACHE_TIMEOUT
2269 #ifndef ATL_STENCIL_LIFESPAN
2271 #define ATL_STENCIL_LIFESPAN CFileTime::Second
2273 #define ATL_STENCIL_LIFESPAN CFileTime::Hour
2277 // timeout before we check if the file
2278 // has changed in m.s.
2279 #ifndef ATL_STENCIL_CHECK_TIMEOUT
2280 #define ATL_STENCIL_CHECK_TIMEOUT 1000
2283 template <class MonitorClass
,
2284 class StatClass
=CStdStatClass
,
2285 class SyncClass
=CComCriticalSection
,
2286 class FlushClass
=COldFlusher
,
2287 class CullClass
=CLifetimeCuller
>
2288 class CStencilCache
:
2289 public CMemoryCacheBase
<CStencilCache
<MonitorClass
, StatClass
, SyncClass
, FlushClass
, CullClass
>, void *, CCacheDataEx
,
2290 CFixedStringKey
, CStringElementTraitsI
<CFixedStringKey
>,
2291 FlushClass
, CullClass
, SyncClass
, StatClass
>,
2292 public IStencilCache
,
2293 public IStencilCacheControl
,
2294 public IWorkerThreadClient
,
2295 public IMemoryCacheStats
,
2296 public CComObjectRootEx
<CComGlobalsThreadModel
>
2299 typedef CMemoryCacheBase
<CStencilCache
<MonitorClass
, StatClass
, SyncClass
, FlushClass
, CullClass
>, void *, CCacheDataEx
,
2300 CFixedStringKey
, CStringElementTraitsI
<CFixedStringKey
>,
2301 FlushClass
, CullClass
, SyncClass
, StatClass
> cacheBase
;
2302 unsigned __int64 m_dwdwStencilLifespan
;
2304 MonitorClass m_Monitor
;
2306 CComPtr
<IDllCache
> m_spDllCache
;
2311 m_dwdwStencilLifespan(ATL_STENCIL_LIFESPAN
),
2321 ATLENSURE(SUCCEEDED(m_Monitor
.RemoveHandle(m_hTimer
)));
2325 HRESULT
Execute(DWORD_PTR dwParam
, HANDLE
/*hObject*/)
2327 CStencilCache
* pCache
= (CStencilCache
*)dwParam
;
2329 pCache
->FlushEntries();
2333 HRESULT
CloseHandle(HANDLE hObject
)
2335 ATLASSUME(m_hTimer
== hObject
);
2337 ::CloseHandle(hObject
);
2341 HRESULT
Initialize(IServiceProvider
*pProv
, DWORD dwStencilCacheTimeout
=ATL_STENCIL_CACHE_TIMEOUT
,
2342 __int64 dwdwStencilLifespan
=ATL_STENCIL_LIFESPAN
)
2344 m_dwdwStencilLifespan
= dwdwStencilLifespan
;
2345 HRESULT hr
= cacheBase::Initialize();
2350 hr
= pProv
->QueryService(__uuidof(IDllCache
), __uuidof(IDllCache
), (void**)&m_spDllCache
);
2353 hr
= m_Monitor
.Initialize();
2356 return m_Monitor
.AddTimer(dwStencilCacheTimeout
, this, (DWORD_PTR
) this, &m_hTimer
);
2359 template <class ThreadTraits
>
2360 HRESULT
Initialize(IServiceProvider
*pProv
, CWorkerThread
<ThreadTraits
> *pWorkerThread
,
2361 DWORD dwStencilCacheTimeout
=ATL_STENCIL_CACHE_TIMEOUT
, __int64 dwdwStencilLifespan
=ATL_STENCIL_LIFESPAN
)
2363 m_dwdwStencilLifespan
= dwdwStencilLifespan
;
2364 HRESULT hr
= cacheBase::Initialize();
2369 hr
= pProv
->QueryService(__uuidof(IDllCache
), __uuidof(IDllCache
), (void**)&m_spDllCache
);
2372 hr
= m_Monitor
.Initialize(pWorkerThread
);
2375 return m_Monitor
.AddTimer(dwStencilCacheTimeout
, this, (DWORD_PTR
) this, &m_hTimer
);
2379 BEGIN_COM_MAP(CStencilCache
)
2380 COM_INTERFACE_ENTRY(IMemoryCacheStats
)
2381 COM_INTERFACE_ENTRY(IStencilCache
)
2382 COM_INTERFACE_ENTRY(IStencilCacheControl
)
2384 //IStencilCache methods
2385 STDMETHOD(CacheStencil
)(LPCSTR szName
, void *pStencil
, DWORD dwSize
, HCACHEITEM
*phEntry
,
2386 HINSTANCE hInstance
, IMemoryCacheClient
*pClient
)
2388 NodeType
* pEntry
= NULL
;
2389 HRESULT hr
= m_syncObj
.Lock();
2395 hr
= cacheBase::AddEntry(szName
, pStencil
, dwSize
, (HCACHEITEM
*)&pEntry
);
2407 pEntry
->hInstance
= hInstance
;
2408 pEntry
->pClient
= pClient
;
2409 pEntry
->nLifespan
= m_dwdwStencilLifespan
;
2410 if (hInstance
&& m_spDllCache
)
2411 m_spDllCache
->AddRefModule(hInstance
);
2413 cacheBase::CommitEntry(static_cast<HCACHEITEM
>(pEntry
));
2416 *phEntry
= static_cast<HCACHEITEM
>(pEntry
);
2418 cacheBase::ReleaseEntry(static_cast<HCACHEITEM
>(pEntry
));
2424 STDMETHOD(LookupStencil
)(LPCSTR szName
, HCACHEITEM
* phStencil
)
2426 return cacheBase::LookupEntry(szName
, phStencil
);
2429 STDMETHOD(GetStencil
)(const HCACHEITEM hStencil
, void ** pStencil
) const
2431 return cacheBase::GetEntryData(hStencil
, pStencil
, NULL
);
2434 STDMETHOD(AddRefStencil
)(const HCACHEITEM hStencil
)
2436 return cacheBase::AddRefEntry(hStencil
);
2439 STDMETHOD(ReleaseStencil
)(const HCACHEITEM hStencil
)
2441 return cacheBase::ReleaseEntry(hStencil
);
2444 //IStencilCacheControl
2446 STDMETHOD(RemoveStencil
)(const HCACHEITEM hStencil
)
2448 return cacheBase::RemoveEntry(hStencil
);
2451 STDMETHOD(RemoveStencilByName
)(LPCSTR szStencil
)
2453 return cacheBase::RemoveEntryByKey(szStencil
);
2456 STDMETHOD(RemoveAllStencils
)()
2458 return cacheBase::RemoveAllEntries();
2461 STDMETHOD(SetDefaultLifespan
)(unsigned __int64 dwdwLifespan
)
2463 m_dwdwStencilLifespan
= dwdwLifespan
;
2467 STDMETHOD(GetDefaultLifespan
)(unsigned __int64
*pdwdwLifepsan
)
2469 HRESULT hr
= E_POINTER
;
2472 *pdwdwLifepsan
= m_dwdwStencilLifespan
;
2478 virtual void OnDestroyEntry(const NodeType
* pEntry
)
2484 if (pEntry
->pClient
)
2485 pEntry
->pClient
->Free((void *)&pEntry
->Data
);
2486 if (pEntry
->hInstance
&& m_spDllCache
)
2487 m_spDllCache
->ReleaseModule(pEntry
->hInstance
);
2490 HRESULT
Uninitialize()
2492 HRESULT hrMonitor
=S_OK
;
2495 hrMonitor
=m_Monitor
.RemoveHandle(m_hTimer
);
2498 m_Monitor
.Shutdown();
2499 HRESULT hrCache
=cacheBase::Uninitialize();
2500 if(FAILED(hrMonitor
))
2506 // IMemoryCacheStats methods
2507 HRESULT STDMETHODCALLTYPE
ClearStats()
2509 m_statObj
.ResetCounters();
2513 HRESULT STDMETHODCALLTYPE
GetHitCount(DWORD
*pdwSize
)
2517 *pdwSize
= m_statObj
.GetHitCount();
2521 HRESULT STDMETHODCALLTYPE
GetMissCount(DWORD
*pdwSize
)
2525 *pdwSize
= m_statObj
.GetMissCount();
2529 HRESULT STDMETHODCALLTYPE
GetMaxAllocSize(DWORD
*pdwSize
)
2533 *pdwSize
= m_statObj
.GetMaxAllocSize();
2537 HRESULT STDMETHODCALLTYPE
GetCurrentAllocSize(DWORD
*pdwSize
)
2541 *pdwSize
= m_statObj
.GetCurrentAllocSize();
2545 HRESULT STDMETHODCALLTYPE
GetMaxEntryCount(DWORD
*pdwSize
)
2549 *pdwSize
= m_statObj
.GetMaxEntryCount();
2553 HRESULT STDMETHODCALLTYPE
GetCurrentEntryCount(DWORD
*pdwSize
)
2557 *pdwSize
= m_statObj
.GetCurrentEntryCount();
2562 // {105A8866-4059-45fe-86AE-FA0EABBFBBB4}
2563 extern "C" __declspec(selectany
) const IID IID_IFileCache
= { 0x105a8866, 0x4059, 0x45fe, { 0x86, 0xae, 0xfa, 0xe, 0xab, 0xbf, 0xbb, 0xb4 } };
2565 __interface ATL_NO_VTABLE
__declspec(uuid("105A8866-4059-45fe-86AE-FA0EABBFBBB4"))
2566 IFileCache
: public IUnknown
2568 // IFileCache Methods
2572 LPCSTR szTempFileName
,
2573 FILETIME
*pftExpireTime
,
2575 HCACHEITEM
* phKey
);
2576 STDMETHOD(LookupFile
)(LPCSTR szFileName
, HCACHEITEM
* phKey
);
2577 STDMETHOD(GetFile
)(const HCACHEITEM hKey
, LPSTR
* pszFileName
, void **ppPeerInfo
);
2578 STDMETHOD(ReleaseFile
)(const HCACHEITEM hKey
);
2579 STDMETHOD(RemoveFile
)(const HCACHEITEM hKey
);
2580 STDMETHOD(RemoveFileByName
)(LPCSTR szFileName
);
2584 #ifndef ATL_FILE_CACHE_TIMEOUT
2585 #define ATL_FILE_CACHE_TIMEOUT 1000
2588 class CNoFileCachePeer
2595 static BOOL
Add(PeerInfo
* /*pDest*/, PeerInfo
* /*pSrc*/)
2600 static BOOL
Remove(const PeerInfo
* /*pFileInfo*/)
2606 template <class Peer
>
2607 struct CCacheDataPeer
: public CCacheDataBase
2609 typename
Peer::PeerInfo PeerData
;
2612 // A class to keep track of files, with maintenance -- maximum size of cache,
2613 // maximum number of entries, expiration of entries, etc. -- inherits from
2617 class StatClass
=CStdStatClass
,
2618 class FileCachePeer
=CNoFileCachePeer
,
2619 class FlushClass
=COldFlusher
,
2620 class SyncClass
=CComCriticalSection
,
2621 class CullClass
=CExpireCuller
>
2623 public CMemoryCacheBase
<CFileCache
<MonitorClass
, StatClass
, FileCachePeer
, FlushClass
, SyncClass
, CullClass
>, LPSTR
, CCacheDataPeer
<FileCachePeer
>,
2624 CFixedStringKey
, CStringElementTraits
<CFixedStringKey
>,
2625 FlushClass
, CullClass
, SyncClass
, StatClass
>,
2626 public IWorkerThreadClient
,
2628 public IMemoryCacheControl
,
2629 public IMemoryCacheStats
2631 typedef CMemoryCacheBase
<CFileCache
<MonitorClass
, StatClass
, FileCachePeer
, FlushClass
, SyncClass
, CullClass
>, LPSTR
, CCacheDataPeer
<FileCachePeer
>,
2632 CFixedStringKey
, CStringElementTraits
<CFixedStringKey
>,
2633 FlushClass
, CullClass
, SyncClass
, StatClass
> cacheBase
;
2635 MonitorClass m_Monitor
;
2642 CFileCache() : m_hTimer(NULL
)
2646 HRESULT
Initialize()
2648 HRESULT hr
= cacheBase::Initialize();
2651 hr
= m_Monitor
.Initialize();
2654 return m_Monitor
.AddTimer(ATL_FILE_CACHE_TIMEOUT
,
2655 static_cast<IWorkerThreadClient
*>(this), (DWORD_PTR
) this, &m_hTimer
);
2658 template <class ThreadTraits
>
2659 HRESULT
Initialize(CWorkerThread
<ThreadTraits
> *pWorkerThread
)
2661 ATLASSERT(pWorkerThread
);
2663 HRESULT hr
= cacheBase::Initialize();
2666 hr
= m_Monitor
.Initialize(pWorkerThread
);
2669 return m_Monitor
.AddTimer(ATL_FILE_CACHE_TIMEOUT
,
2670 static_cast<IWorkerThreadClient
*>(this), (DWORD_PTR
) this, &m_hTimer
);
2674 // Callback for CWorkerThread
2675 HRESULT
Execute(DWORD_PTR dwParam
, HANDLE
/*hObject*/)
2677 CFileCache
* pCache
= (CFileCache
*)dwParam
;
2684 HRESULT
CloseHandle(HANDLE hObject
)
2686 ATLASSUME(m_hTimer
== hObject
);
2688 ::CloseHandle(hObject
);
2696 ATLENSURE(SUCCEEDED(m_Monitor
.RemoveHandle(m_hTimer
)));
2701 HRESULT
Uninitialize()
2703 HRESULT hrMonitor
=S_OK
;
2706 hrMonitor
=m_Monitor
.RemoveHandle(m_hTimer
);
2709 m_Monitor
.Shutdown();
2710 HRESULT hrCache
=cacheBase::Uninitialize();
2711 if(FAILED(hrMonitor
))
2720 HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid
, void **ppv
)
2722 HRESULT hr
= E_NOINTERFACE
;
2727 if (InlineIsEqualGUID(riid
, __uuidof(IUnknown
)) ||
2728 InlineIsEqualGUID(riid
, __uuidof(IFileCache
)))
2730 *ppv
= (IUnknown
*) (IFileCache
*) this;
2734 if (InlineIsEqualGUID(riid
, __uuidof(IMemoryCacheStats
)))
2736 *ppv
= (IMemoryCacheStats
*)this;
2740 if (InlineIsEqualGUID(riid
, __uuidof(IMemoryCacheControl
)))
2742 *ppv
= (IMemoryCacheControl
*)this;
2751 ULONG STDMETHODCALLTYPE
AddRef()
2756 ULONG STDMETHODCALLTYPE
Release()
2761 // Adds a file to the cache. A file is created with a
2762 // temporary name, and then Add is called with the temp
2763 // file name and the final file name, along with expiration data,
2764 // etc. A search on the file name will return the name of
2765 // the file on disk (i.e. the temporary file)
2766 HRESULT STDMETHODCALLTYPE
AddFile(
2768 LPCSTR szTempFileName
,
2769 FILETIME
*pftExpireTime
,
2771 HCACHEITEM
* phKey
= NULL
)
2773 WIN32_FILE_ATTRIBUTE_DATA fadData
;
2774 BOOL bRet
= GetFileAttributesExA(szTempFileName
, GetFileExInfoStandard
, &fadData
);
2776 return AtlHresultFromLastError();
2778 __int64 ddwFileSize
= (static_cast<__int64
>(fadData
.nFileSizeHigh
) << 32) + fadData
.nFileSizeLow
;
2780 DWORD dwRecordedFileSize
= (DWORD
) (ddwFileSize
>> 10);
2781 // Round the file size up to 1K if it is < 1K
2782 if (dwRecordedFileSize
== 0)
2783 dwRecordedFileSize
= 1;
2785 if (m_Monitor
.GetThreadHandle()==NULL
)
2787 if (!cacheBase::CanAddEntry(dwRecordedFileSize
))
2789 cacheBase::FlushEntries();
2790 if (!cacheBase::CanAddEntry(dwRecordedFileSize
))
2791 return E_OUTOFMEMORY
;
2795 NodeType
*pEntry
= NULL
;
2796 HRESULT hr
= m_syncObj
.Lock();
2802 // Make a private copy of the file name
2803 CHeapPtr
<char> szTempFileCopy
;
2804 if (szTempFileCopy
.Allocate(MAX_PATH
))
2806 if (strlen(szTempFileName
) >= MAX_PATH
)
2811 Checked::strncpy_s(szTempFileCopy
, MAX_PATH
, szTempFileName
, _TRUNCATE
);
2815 hr
= cacheBase::AddEntry(szFileName
, szTempFileCopy
, dwRecordedFileSize
, (HCACHEITEM
*)&pEntry
);
2816 szTempFileCopy
.Detach();
2831 hr
= (TRUE
== FileCachePeer::Add(&pEntry
->PeerData
,
2832 static_cast<FileCachePeer::PeerInfo
*>(pPeerInfo
)) ? S_OK
: E_FAIL
);
2834 hr
= cacheBase::CommitEntry(static_cast<HCACHEITEM
>(pEntry
));
2838 cacheBase::RemoveEntry(static_cast<HCACHEITEM
>(pEntry
));
2845 pEntry
->cftExpireTime
= *pftExpireTime
;
2848 *phKey
= static_cast<HCACHEITEM
>(pEntry
);
2850 cacheBase::ReleaseEntry(pEntry
);
2856 // Action to take when the entry is removed from the cache
2857 virtual void OnDestroyEntry(const NodeType
* pEntry
)
2862 FileCachePeer::Remove(&pEntry
->PeerData
);
2865 DeleteFileA(pEntry
->Data
);
2867 const_cast<NodeType
*>(pEntry
)->Data
= NULL
;
2871 // Looks up a file by name. Must be released after use
2872 HRESULT STDMETHODCALLTYPE
LookupFile(LPCSTR szFileName
, HCACHEITEM
* phKey
)
2874 return cacheBase::LookupEntry(szFileName
, phKey
);
2877 // Gets the name of the file on disk
2878 HRESULT STDMETHODCALLTYPE
GetFile(__in
const HCACHEITEM hKey
, __deref_out_z_opt LPSTR
* pszFileName
, __deref_out_opt
void **ppPeerInfo
)
2880 NodeType
*pEntry
= (NodeType
*)hKey
;
2882 *ppPeerInfo
= &pEntry
->PeerData
;
2883 return cacheBase::GetEntryData(hKey
, pszFileName
, NULL
);
2887 HRESULT STDMETHODCALLTYPE
ReleaseFile(const HCACHEITEM hKey
)
2889 return cacheBase::ReleaseEntry(hKey
);
2892 // Releases a file and marks it for deletion
2893 HRESULT STDMETHODCALLTYPE
RemoveFile(const HCACHEITEM hKey
)
2895 return cacheBase::RemoveEntry(hKey
);
2898 // Removes a file by name -- this calls IMemoryCacheClient->Free
2899 // on the file name, which by default (for CFileCache) deletes the
2901 HRESULT STDMETHODCALLTYPE
RemoveFileByName(LPCSTR szFileName
)
2903 return cacheBase::RemoveEntryByKey(szFileName
);
2906 // Flushes the entries in the cache, eliminates expired entries,
2907 // or if the cache exceeds the parameters (alloc size, num entries),
2908 // culls items based on the sweep mode
2909 HRESULT STDMETHODCALLTYPE
Flush()
2911 return cacheBase::FlushEntries();
2914 // IMemoryCacheControl methods
2915 HRESULT STDMETHODCALLTYPE
SetMaxAllowedSize(DWORD dwSize
)
2917 return cacheBase::SetMaxAllowedSize(dwSize
);
2920 HRESULT STDMETHODCALLTYPE
GetMaxAllowedSize(DWORD
*pdwSize
)
2922 return cacheBase::GetMaxAllowedSize(pdwSize
);
2925 HRESULT STDMETHODCALLTYPE
SetMaxAllowedEntries(DWORD dwSize
)
2927 return cacheBase::SetMaxAllowedEntries(dwSize
);
2930 HRESULT STDMETHODCALLTYPE
GetMaxAllowedEntries(DWORD
*pdwSize
)
2932 return cacheBase::GetMaxAllowedEntries(pdwSize
);
2935 HRESULT STDMETHODCALLTYPE
ResetCache()
2937 return cacheBase::ResetCache();
2941 // IMemoryCacheStats methods
2942 HRESULT STDMETHODCALLTYPE
ClearStats()
2944 m_statObj
.ResetCounters();
2948 HRESULT STDMETHODCALLTYPE
GetHitCount(DWORD
*pdwSize
)
2952 *pdwSize
= m_statObj
.GetHitCount();
2956 HRESULT STDMETHODCALLTYPE
GetMissCount(DWORD
*pdwSize
)
2960 *pdwSize
= m_statObj
.GetMissCount();
2964 HRESULT STDMETHODCALLTYPE
GetMaxAllocSize(DWORD
*pdwSize
)
2968 *pdwSize
= m_statObj
.GetMaxAllocSize();
2972 HRESULT STDMETHODCALLTYPE
GetCurrentAllocSize(DWORD
*pdwSize
)
2976 *pdwSize
= m_statObj
.GetCurrentAllocSize();
2980 HRESULT STDMETHODCALLTYPE
GetMaxEntryCount(DWORD
*pdwSize
)
2984 *pdwSize
= m_statObj
.GetMaxEntryCount();
2988 HRESULT STDMETHODCALLTYPE
GetCurrentEntryCount(DWORD
*pdwSize
)
2992 *pdwSize
= m_statObj
.GetCurrentEntryCount();
2997 class CDataConnection
; // see atldbcli.h
2998 __interface
__declspec(uuid("52E7759B-D6CC-4a03-BDF3-80A6BDCA1F94"))
2999 IDataSourceCache
: public IUnknown
3003 // szConn: Connection string of data source to connect to
3004 // ppDS: Out pointer to the newly added data source
3006 // Attempts to open a connection to the specified data source
3007 // using a CDataSource object. Once the connection is open, the
3008 // CDatasource is cached.
3009 STDMETHOD(Add
)(LPCTSTR szID
, LPCOLESTR szConn
, CDataConnection
*pDS
);
3013 // szConn: Specifies the connection string of the connection to close
3015 // Closes the specified connection and removes it's entry from the cache
3016 STDMETHOD(Remove
)(LPCTSTR szID
);
3020 // szConn: Specifies the connection string of the connection to look up
3021 // ppDS: Out pointer to CDataSource object that is connected to the specified
3023 STDMETHOD(Lookup
)(LPCTSTR szID
, CDataConnection
*pDS
);
3025 // Method: Uninitialize
3029 // Closes removes all connections from the cache.
3030 STDMETHOD(Uninitialize
)();
3033 #ifndef ATL_DS_CONN_STRING_LEN
3034 #define ATL_DS_CONN_STRING_LEN 512
3038 class CElementTraits
< CDataConnection
> :
3039 public CElementTraitsBase
< CDataConnection
>
3042 static ULONG
Hash( INARGTYPE t
)
3044 return( ULONG( ULONG_PTR( &t
) ) );
3047 static bool CompareElements( INARGTYPE element1
, INARGTYPE element2
)
3049 return( element1
.m_session
.m_spOpenRowset
== element2
.m_session
.m_spOpenRowset
);
3052 static int CompareElementsOrdered( INARGTYPE
/*element1*/, INARGTYPE
/*element2*/ )
3060 typedef CFixedStringT
<CString
, ATL_DS_CONN_STRING_LEN
> atlDataSourceKey
;
3061 typedef CAtlMap
<atlDataSourceKey
, CDataConnection
,
3062 CStringElementTraits
<atlDataSourceKey
>, CElementTraits
<CDataConnection
> > atlDataSourceCacheMap
;
3064 template <class TCritSec
=CComFakeCriticalSection
>
3065 class CDataSourceCache
:
3066 public IDataSourceCache
,
3067 public CComObjectRootEx
<CComGlobalsThreadModel
>
3070 BEGIN_COM_MAP(CDataSourceCache
)
3071 COM_INTERFACE_ENTRY(IDataSourceCache
)
3079 virtual ~CDataSourceCache ()
3084 STDMETHOD(Uninitialize
)()
3086 HRESULT hr
= m_cs
.Lock();
3089 m_ConnectionMap
.RemoveAll();
3096 STDMETHOD(Add
)(LPCTSTR szID
, LPCOLESTR szConn
, CDataConnection
*pSession
)
3098 HRESULT hr
= E_FAIL
;
3101 return E_INVALIDARG
; // must have session name
3103 // Do a lookup to make sure we don't add multiple entries
3104 // with the same name. Adding multiple entries with the same name
3105 // could cause some entries to get orphaned.
3112 const atlDataSourceCacheMap::CPair
*pPair
=
3113 m_ConnectionMap
.Lookup(szID
);
3116 // try to open connection
3118 hr
= DS
.Open(szConn
);
3123 if (m_ConnectionMap
.SetAt(szID
, DS
))
3125 if (pSession
) // we allow NULL here
3126 *pSession
= DS
; // copy connection to output.
3130 hr
= E_FAIL
; // map add failed
3138 else // lookup succeeded, entry is already in cache
3140 // Instead of opening a new connection, just copy
3141 // the one we already have in the cache.
3143 *pSession
= pPair
->m_value
;
3150 STDMETHOD(Remove
)(LPCTSTR szID
)
3152 HRESULT hr
= E_INVALIDARG
;
3154 return hr
; // must have session name
3159 hr
= m_ConnectionMap
.RemoveKey(szID
) ? S_OK
: E_FAIL
;
3166 STDMETHOD(Lookup
)(LPCTSTR szID
, CDataConnection
*pSession
)
3168 if (!szID
||!pSession
)
3171 HRESULT hr
= m_cs
.Lock();
3175 bRet
= m_ConnectionMap
.Lookup(szID
, *pSession
);
3179 return (bRet
&& (bool)*pSession
)? hr
: E_FAIL
;
3183 atlDataSourceCacheMap m_ConnectionMap
;
3188 // Some helpers for using the datasource cache.
3190 // Function: GetDataSource
3192 // pProvider: Pointer to IServiceProvider that provides the
3193 // data source cache service
3194 // szID: The name of the connection (can be same as szDS)
3195 // szDS: OLEDB connection string for data source
3196 // ppDS: Out pointer to CDataSource. The CDataSource will be connected
3197 // to the OLEDB provider specified by szDS on successful return.
3199 // Returns S_OK on success.
3200 static HRESULT ATL_NOINLINE
GetDataSource(IServiceProvider
*pProvider
,
3201 LPCTSTR szID
, LPCOLESTR szConn
,
3202 CDataConnection
*pSession
)
3204 if (!pProvider
|| !szID
|| !szConn
)
3207 CComPtr
<IDataSourceCache
> spDSCache
;
3209 hr
= pProvider
->QueryService(__uuidof(IDataSourceCache
), __uuidof(IDataSourceCache
), (void**)&spDSCache
);
3210 if (hr
== S_OK
&& spDSCache
)
3212 hr
= spDSCache
->Add(szID
, szConn
, pSession
);
3218 // Function: RemoveDataSource
3220 // pProvider: Pointer to IServiceProvider that provides the
3221 // data source cache service
3222 // szID: Name of the datasource connection to remove from the cache
3226 // Removes the datasource entry from the datasource cache. Since entries are
3227 // copied to the client on calls to lookup and add, removing an entry will not
3228 // release the connections of existing clients.
3229 static HRESULT ATL_NOINLINE
RemoveDataSource(IServiceProvider
*pProvider
, LPCTSTR szID
)
3231 if (!pProvider
|| !szID
)
3234 CComPtr
<IDataSourceCache
> spDSCache
;
3235 HRESULT hr
= pProvider
->QueryService(__uuidof(IDataSourceCache
), __uuidof(IDataSourceCache
), (void**)&spDSCache
);
3237 hr
= spDSCache
->Remove(szID
);
3244 #pragma warning (pop)
3246 #endif // __ATLCACHE_H__