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