6 // Daniel Cazzulino (dcazzulino@users.sf.net)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Collections
;
32 using System
.Threading
;
34 namespace System
.Web
.Caching
{
36 /// Class responsible for handling time based flushing of entries in the cache. The class creates
37 /// and manages 60 buckets each holding every item that expires that minute. The bucket calculated
38 /// for an entry is one minute more than the timeout just to make sure that the item end up in the
39 /// bucket where it should be flushed.
41 internal class CacheExpires
: IDisposable
{
44 /// 1 bucket == 1 minute == 10M ticks (1 second) * 60
46 static long _ticksPerBucket
= 600000000;
50 static long _ticksPerCycle
= _ticksPerBucket
* 60;
52 private ExpiresBucket
[] _arrBuckets
;
53 private Timer _objTimer
;
54 private Cache _objManager
;
56 private object _lockObj
= new object ();
58 internal CacheExpires (Cache objManager
) {
59 _objManager
= objManager
;
63 private void Initialize () {
64 // Create one bucket per minute
65 _arrBuckets
= new ExpiresBucket
[60];
69 _arrBuckets
[bytePos
] = new ExpiresBucket (bytePos
, _objManager
);
71 } while (bytePos
< 60);
73 // GC Bucket controller
74 _intFlush
= System
.DateTime
.UtcNow
.Minute
- 1;
75 _objTimer
= new System
.Threading
.Timer (new System
.Threading
.TimerCallback (GarbageCleanup
), null, 10000, 60000);
79 /// Adds a Cache entry to the correct flush bucket.
81 /// <param name="objEntry">Cache entry to add.</param>
82 internal void Add (CacheEntry objEntry
) {
83 long now
= DateTime
.UtcNow
.Ticks
;
84 if (objEntry
.Expires
< now
)
85 objEntry
.Expires
= now
;
87 _arrBuckets
[GetHashBucket (objEntry
.Expires
)].Add (objEntry
);
90 internal void Remove (CacheEntry objEntry
) {
91 if (objEntry
.ExpiresBucket
!= CacheEntry
.NoBucketHash
)
92 _arrBuckets
[objEntry
.ExpiresBucket
].Remove (objEntry
);
95 internal void Update (CacheEntry objEntry
, long ticksExpires
) {
96 // If the entry doesn't have a expires time we assume that the entry is due to expire now.
97 int oldBucket
= objEntry
.ExpiresBucket
;
98 int newBucket
= GetHashBucket (ticksExpires
);
100 if (oldBucket
== CacheEntry
.NoBucketHash
)
103 // Check if we need to move the item
104 if (oldBucket
!= newBucket
) {
105 _arrBuckets
[oldBucket
].Remove (objEntry
);
106 objEntry
.Expires
= ticksExpires
;
107 _arrBuckets
[newBucket
].Add (objEntry
);
109 _arrBuckets
[oldBucket
].Update (objEntry
, ticksExpires
);
112 internal void GarbageCleanup (object State
) {
113 ExpiresBucket objBucket
;
116 // We lock here if FlushExpiredItems take time
118 bucket
= (++_intFlush
) % 60;
121 // Flush expired items in the current bucket (defined by _intFlush)
122 _arrBuckets
[bucket
].FlushExpiredItems ();
125 private int GetHashBucket (long ticks
) {
126 // Get bucket to add expire item into, add one minute to the bucket just to make sure that we get it in the bucket gc
127 return (int) (((((ticks
+ 60000) % _ticksPerCycle
) / _ticksPerBucket
) + 1) % 60);
131 /// Called by the cache for cleanup.
133 public void Dispose () {
134 // Cleanup the internal timer
135 if (_objTimer
!= null) {