Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
5.7 KiB

  1. #ifndef _GENCACHE_H_
  2. #define _GENCACHE_H_
  3. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4. //
  5. // GENCACHE.H
  6. //
  7. // Header for generic cache classes.
  8. //
  9. // Copyright 1997 Microsoft Corporation, All Rights Reserved
  10. //
  11. #ifdef _DAVCDATA_
  12. #error "buffer.h uses throwing allocators"
  13. #endif
  14. // Include the non-exdav-safe/throwing allocators
  15. #include <mem.h>
  16. #include <autoptr.h>
  17. #include <synchro.h>
  18. // Include exdav-safe CCache definition header
  19. #include <ex\gencache.h>
  20. // ========================================================================
  21. //
  22. // TEMPLATE CLASS CMTCache
  23. //
  24. // Multithread-safe generic cache.
  25. //
  26. template<class _K, class _Ty>
  27. class CMTCache
  28. {
  29. typedef CCache<_K, _Ty> CBaseCache;
  30. //
  31. // The cache
  32. //
  33. CBaseCache m_cache;
  34. //
  35. // Multi-reader/single-writer lock to protect the cache
  36. //
  37. mutable CMRWLock m_mrw;
  38. // NOT IMPLEMENTED
  39. //
  40. CMTCache& operator=( const CMTCache& );
  41. CMTCache( const CMTCache& );
  42. public:
  43. typedef typename CBaseCache::IOp IOp;
  44. // CREATORS
  45. //
  46. CMTCache()
  47. {
  48. if ( !m_mrw.FInitialize() )
  49. throw CLastErrorException();
  50. // If this fails, our allocators will throw for us.
  51. m_cache.FInit();
  52. }
  53. // ACCESSORS
  54. //
  55. BOOL FFetch( const _K& key, _Ty * pValueRet ) const
  56. {
  57. CSynchronizedReadBlock blk(m_mrw);
  58. return m_cache.FFetch(key, pValueRet);
  59. }
  60. void ForEach( IOp& op ) const
  61. {
  62. CSynchronizedReadBlock blk(m_mrw);
  63. m_cache.ForEach(op);
  64. }
  65. // MANIPULATORS
  66. //
  67. void Set( const _K& key, const _Ty& value )
  68. {
  69. CSynchronizedWriteBlock blk(m_mrw);
  70. // If this fails, our allocators will throw for us.
  71. (void)m_cache.FSet(key, value);
  72. }
  73. void Add( const _K& key, const _Ty& value )
  74. {
  75. CSynchronizedWriteBlock blk(m_mrw);
  76. // If this fails, our allocators will throw for us.
  77. (void)m_cache.FAdd(key, value);
  78. }
  79. void Remove( const _K& key )
  80. {
  81. CSynchronizedWriteBlock blk(m_mrw);
  82. m_cache.Remove(key);
  83. }
  84. void Clear()
  85. {
  86. CSynchronizedWriteBlock blk(m_mrw);
  87. m_cache.Clear();
  88. }
  89. };
  90. // ========================================================================
  91. //
  92. // CLASS CAccInv
  93. //
  94. // Access/Invalidate synchronization logic.
  95. // This class encapsulates the logic needed to safely read
  96. // (access) from a datasource that may be invalidated (invalidate)
  97. // by an asynchronous, external event. (IN-ternal events
  98. // should ALWAYS use the synch mechanisms we provide DIRECTLY.)
  99. //
  100. class IEcb;
  101. class CAccInv
  102. {
  103. //
  104. // Multi-reader/single-writer lock to synchronize
  105. // access and invalidation functions
  106. //
  107. CMRWLock m_mrw;
  108. //
  109. // Flag to indicate whether the object is invalid.
  110. // If 0, the object is invalid and and will
  111. // be refreshed the next time it is accessed.
  112. //
  113. LONG m_lValid;
  114. // NOT IMPLEMENTED
  115. //
  116. CAccInv& operator=( const CAccInv& );
  117. CAccInv( const CAccInv& );
  118. public:
  119. // Forward declaration
  120. //
  121. class IAccCtx;
  122. protected:
  123. //
  124. // Refresh operation to be provided by derived class
  125. //
  126. virtual void RefreshOp( const IEcb& ecb ) = 0;
  127. void Access( const IEcb& ecb, IAccCtx& context )
  128. {
  129. //
  130. // Repeat the following validity check, refresh, and
  131. // access, and recheck sequence until the access succeeds
  132. // and the object is valid from start to finish.
  133. //
  134. for (;;)
  135. {
  136. //
  137. // Check validity, and refresh if invalid.
  138. //
  139. while ( !m_lValid )
  140. {
  141. CTryWriteBlock blk(m_mrw);
  142. //
  143. // Only one thread should refresh the object.
  144. // Other threads detecting that the object is invalid
  145. // periodically retry checking validity (spin waiting)
  146. // until the object becomes valid.
  147. //
  148. if ( blk.FTryEnter() )
  149. {
  150. //
  151. // By being the first to enter the write lock,
  152. // this thread gets to refresh the object.
  153. //
  154. //
  155. // Mark the object as valid BEFORE actually
  156. // refreshing it so that it is possible to
  157. // tell if the object gets marked invalid by
  158. // another thread while it is being refreshed.
  159. //
  160. InterlockedExchange( &m_lValid, 1 );
  161. //
  162. // Refresh the object
  163. //
  164. RefreshOp(ecb);
  165. }
  166. else
  167. {
  168. //
  169. // Give up the rest of this thread's time slice so
  170. // that the thread holding the write lock may finish
  171. // as soon as possible.
  172. //
  173. Sleep(0);
  174. }
  175. }
  176. //
  177. // The object is valid (or at least it was a tiny instant
  178. // ago) so go ahead and access it. Apply a read lock
  179. // to prevent other threads from refreshing it during
  180. // access (if the object is marked invalid during access).
  181. //
  182. {
  183. CSynchronizedReadBlock blk(m_mrw);
  184. context.AccessOp( *this );
  185. //
  186. // Test whether the object is still valid after access.
  187. // (Do this while holding the read lock to prevent other
  188. // threads from marking the object as invalid and refreshing
  189. // it since it was accessed on this thread.) If the
  190. // object is still valid now, then it was valid for
  191. // the entire operation, so we're done.
  192. //
  193. if ( m_lValid )
  194. break;
  195. }
  196. }
  197. }
  198. public:
  199. class IAccCtx
  200. {
  201. public:
  202. //
  203. // Method on the cache context to perform the access operation.
  204. // This allows for caches to support multiple access methods for
  205. // both ::Lookup() and ::ForEach() mechanisms
  206. //
  207. virtual void AccessOp( CAccInv& cache ) = 0;
  208. };
  209. // The object is initially considered invalid. It will be refreshed
  210. // the first time it is accessed.
  211. //
  212. CAccInv() :
  213. m_lValid(0)
  214. {
  215. if ( !m_mrw.FInitialize() )
  216. throw CLastErrorException();
  217. }
  218. void Invalidate()
  219. {
  220. InterlockedExchange( &m_lValid, 0 );
  221. }
  222. };
  223. #endif // !_GENCACHE_H_