**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Web / System.Web.Caching / CacheExpires.cs
blob11e2377e3c18af2974d47d7b1328b4e7404cf693
1 //
2 // System.Web.Caching
3 //
4 // Author:
5 // Patrik Torstensson
6 // Daniel Cazzulino (dcazzulino@users.sf.net)
7 //
9 //
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:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
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.
30 using System;
31 using System.Collections;
32 using System.Threading;
34 namespace System.Web.Caching {
35 /// <summary>
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.
40 /// </summary>
41 internal class CacheExpires : IDisposable {
42 static int _intFlush;
43 /// <summary>
44 /// 1 bucket == 1 minute == 10M ticks (1 second) * 60
45 /// </summary>
46 static long _ticksPerBucket = 600000000;
47 /// <summary>
48 /// 1 cycle == 1 hour
49 /// </summary>
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;
60 Initialize();
63 private void Initialize () {
64 // Create one bucket per minute
65 _arrBuckets = new ExpiresBucket [60];
67 byte bytePos = 0;
68 do {
69 _arrBuckets [bytePos] = new ExpiresBucket (bytePos, _objManager);
70 bytePos++;
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);
78 /// <summary>
79 /// Adds a Cache entry to the correct flush bucket.
80 /// </summary>
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)
101 return;
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);
108 } else
109 _arrBuckets [oldBucket].Update (objEntry, ticksExpires);
112 internal void GarbageCleanup (object State) {
113 ExpiresBucket objBucket;
114 int bucket;
116 // We lock here if FlushExpiredItems take time
117 lock (_lockObj) {
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);
130 /// <summary>
131 /// Called by the cache for cleanup.
132 /// </summary>
133 public void Dispose () {
134 // Cleanup the internal timer
135 if (_objTimer != null) {
136 _objTimer.Dispose();
137 _objTimer = null;