ExpiresBuckets.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //
  2. // System.Web.Caching
  3. //
  4. // Author:
  5. // Patrik Torstensson ([email protected])
  6. //
  7. // (C) Copyright Patrik Torstensson, 2001
  8. //
  9. namespace System.Web.Caching
  10. {
  11. /// <summary>
  12. /// Responsible for holding a cache entry in the linked list bucket.
  13. /// </summary>
  14. public struct ExpiresEntry
  15. {
  16. public CacheEntry _objEntry;
  17. public long _ticksExpires;
  18. public int _intNext;
  19. }
  20. /// <summary>
  21. /// Holds cache entries that has a expiration in a bucket list.
  22. /// </summary>
  23. public class ExpiresBucket
  24. {
  25. private static int MIN_ENTRIES = 16;
  26. private byte _byteID;
  27. private int _intSize;
  28. private int _intCount;
  29. private int _intNext;
  30. private Cache _objManager;
  31. private ExpiresEntry [] _arrEntries;
  32. /// <summary>
  33. /// Constructs a new bucket.
  34. /// </summary>
  35. /// <param name="bucket">Current bucket ID.</param>
  36. /// <param name="objManager">Cache manager reponsible for the item(s) in the expires bucket.</param>
  37. public ExpiresBucket(byte bucket, Cache objManager)
  38. {
  39. _objManager = objManager;
  40. Initialize(bucket);
  41. }
  42. /// <summary>
  43. /// Initializes the expires bucket, creates a linked list of MIN_ENTRIES.
  44. /// </summary>
  45. /// <param name="bucket">Bucket ID.</param>
  46. private void Initialize(byte bucket)
  47. {
  48. _byteID = bucket;
  49. _intNext = 0;
  50. _intCount = 0;
  51. _arrEntries = new ExpiresEntry[MIN_ENTRIES];
  52. _intSize = MIN_ENTRIES;
  53. int intPos = 0;
  54. do
  55. {
  56. _arrEntries[intPos]._intNext = intPos + 1;
  57. _arrEntries[intPos]._ticksExpires = System.DateTime.MaxValue.Ticks;
  58. intPos++;
  59. } while (intPos < _intSize);
  60. _arrEntries[_intSize - 1]._intNext = -1;
  61. }
  62. /// <summary>
  63. /// Expands the bucket linked array list.
  64. /// </summary>
  65. private void Expand()
  66. {
  67. ExpiresEntry [] arrData;
  68. int intPos = 0;
  69. int intOldSize;
  70. lock(this)
  71. {
  72. intOldSize = _intSize;
  73. _intSize *= 2;
  74. // Create a new array and copy the old data into the new array
  75. arrData = new ExpiresEntry[_intSize];
  76. do
  77. {
  78. arrData[intPos] = _arrEntries[intPos];
  79. intPos++;
  80. } while (intPos < intOldSize);
  81. _intNext = intPos;
  82. // Initialize the "new" positions.
  83. do
  84. {
  85. arrData[intPos]._intNext = intPos + 1;
  86. intPos++;
  87. } while (intPos < _intSize);
  88. arrData[_intSize - 1]._intNext = -1;
  89. _arrEntries = arrData;
  90. }
  91. }
  92. /// <summary>
  93. /// Adds a cache entry into the expires bucket.
  94. /// </summary>
  95. /// <param name="objEntry">Cache Entry object to be added.</param>
  96. public void Add(CacheEntry objEntry)
  97. {
  98. if (_intNext == -1)
  99. {
  100. Expand();
  101. }
  102. lock(this)
  103. {
  104. _arrEntries[_intNext]._ticksExpires = objEntry.Expires;
  105. _arrEntries[_intNext]._objEntry = objEntry;
  106. _intNext = _arrEntries[_intNext]._intNext;
  107. _intCount++;
  108. }
  109. }
  110. /// <summary>
  111. /// Removes a cache entry from the expires bucket.
  112. /// </summary>
  113. /// <param name="objEntry">Cache entry to be removed.</param>
  114. public void Remove(CacheEntry objEntry)
  115. {
  116. lock(this)
  117. {
  118. // Check if this is our bucket
  119. if (objEntry.ExpiresIndex != _byteID) return;
  120. if (objEntry.ExpiresIndex == System.Int32.MaxValue) return;
  121. if (_arrEntries.Length < objEntry.ExpiresIndex) return;
  122. _intCount--;
  123. _arrEntries[objEntry.ExpiresIndex]._objEntry.ExpiresBucket = byte.MaxValue;
  124. _arrEntries[objEntry.ExpiresIndex]._objEntry.ExpiresIndex = int.MaxValue;
  125. _arrEntries[objEntry.ExpiresIndex]._objEntry = null;
  126. _intNext = _arrEntries[objEntry.ExpiresIndex]._intNext;
  127. }
  128. }
  129. /// <summary>
  130. /// Updates a cache entry in the expires bucket, this is called during a hit of an item if the
  131. /// cache item has a sliding expiration. The function is responsible for updating the cache
  132. /// entry.
  133. /// </summary>
  134. /// <param name="objEntry">Cache entry to update.</param>
  135. /// <param name="ticksExpires">New expiration value for the cache entry.</param>
  136. public void Update(CacheEntry objEntry, long ticksExpires)
  137. {
  138. lock(this)
  139. {
  140. // Check if this is our bucket
  141. if (objEntry.ExpiresIndex != _byteID) return;
  142. if (objEntry.ExpiresIndex == System.Int32.MaxValue) return;
  143. if (_arrEntries.Length < objEntry.ExpiresIndex) return;
  144. _arrEntries[objEntry.ExpiresIndex]._ticksExpires = ticksExpires;
  145. _arrEntries[objEntry.ExpiresIndex]._objEntry.Expires = ticksExpires;
  146. }
  147. }
  148. /// <summary>
  149. /// Flushes all cache entries that has expired and removes them from the cache manager.
  150. /// </summary>
  151. public void FlushExpiredItems()
  152. {
  153. ExpiresEntry objEntry;
  154. CacheEntry [] arrCacheEntries;
  155. int intCachePos;
  156. int intPos;
  157. long ticksNow;
  158. ticksNow = System.DateTime.Now.Ticks;
  159. intCachePos = 0;
  160. // Lookup all items that needs to be removed, this is done in a two part
  161. // operation to minimize the locking time.
  162. lock (this)
  163. {
  164. arrCacheEntries = new CacheEntry[_intSize];
  165. intPos = 0;
  166. do
  167. {
  168. objEntry = _arrEntries[intPos];
  169. if (objEntry._objEntry != null)
  170. {
  171. if (objEntry._ticksExpires < ticksNow)
  172. {
  173. arrCacheEntries[intCachePos++] = objEntry._objEntry;
  174. objEntry._objEntry.ExpiresBucket = byte.MaxValue;
  175. objEntry._objEntry.ExpiresIndex = int.MaxValue;
  176. objEntry._objEntry = null;
  177. _intNext = objEntry._intNext;
  178. }
  179. }
  180. intPos++;
  181. } while (intPos < _intSize);
  182. }
  183. // If we have any entries to remove, go ahead and call the cache manager remove.
  184. if (intCachePos > 0)
  185. {
  186. intPos = 0;
  187. do
  188. {
  189. _objManager.Remove(arrCacheEntries[intPos].Key, CacheItemRemovedReason.Expired);
  190. intPos++;
  191. } while (intPos < intCachePos);
  192. }
  193. }
  194. /// <summary>
  195. /// Returns the current size of the expires bucket.
  196. /// </summary>
  197. public int Size
  198. {
  199. get
  200. {
  201. return _arrEntries.Length;
  202. }
  203. }
  204. /// <summary>
  205. /// Returns number of items in the bucket.
  206. /// </summary>
  207. public int Count
  208. {
  209. get
  210. {
  211. return _intCount;
  212. }
  213. }
  214. }
  215. }