//
// System.Web.Caching
//
// Author:
// Patrik Torstensson (Patrik.Torstensson@labs2.com)
//
// (C) Copyright Patrik Torstensson, 2001
//
namespace System.Web.Caching
{
///
/// Class responsible for handling time based flushing of entries in the cache. The class creates
/// and manages 60 buckets each holding every item that expires that minute. The bucket calculated
/// for an entry is one minute more than the timeout just to make sure that the item end up in the
/// bucket where it should be flushed.
///
public class CacheExpires : System.IDisposable
{
static int _intFlush;
static long _ticksPerBucket = 600000000;
static long _ticksPerCycle = _ticksPerBucket * 60;
private ExpiresBucket[] _arrBuckets;
private System.Threading.Timer _objTimer;
private Cache _objManager;
///
/// Constructor
///
/// The cache manager, used when flushing items in a bucket.
public CacheExpires(Cache objManager)
{
_objManager = objManager;
Initialize();
}
///
/// Initializes the class.
///
private void Initialize()
{
// Create one bucket per minute
_arrBuckets = new ExpiresBucket[60];
byte bytePos = 0;
do
{
_arrBuckets[bytePos] = new ExpiresBucket(bytePos, _objManager);
bytePos++;
} while (bytePos < 60);
// GC Bucket controller
_intFlush = System.DateTime.Now.Minute - 1;
_objTimer = new System.Threading.Timer(new System.Threading.TimerCallback(GarbageCleanup), null, 10000, 60000);
}
///
/// Adds a Cache entry to the correct flush bucket.
///
/// Cache entry to add.
public void Add(CacheEntry objEntry)
{
long ticksNow = System.DateTime.Now.Ticks;
lock(this)
{
// If the entry doesn't have a expires time we assume that the entry is due to expire now.
if (objEntry.Expires == 0)
{
objEntry.Expires = ticksNow;
}
_arrBuckets[GetHashBucket(objEntry.Expires)].Add(objEntry);
}
}
public void Remove(CacheEntry objEntry)
{
long ticksNow = System.DateTime.Now.Ticks;
lock(this)
{
// If the entry doesn't have a expires time we assume that the entry is due to expire now.
if (objEntry.Expires == 0)
{
objEntry.Expires = ticksNow;
}
_arrBuckets[GetHashBucket(objEntry.Expires)].Remove(objEntry);
}
}
public void Update(CacheEntry objEntry, long ticksExpires)
{
long ticksNow = System.DateTime.Now.Ticks;
lock(this)
{
// If the entry doesn't have a expires time we assume that the entry is due to expire now.
if (objEntry.Expires == 0)
{
objEntry.Expires = ticksNow;
}
_arrBuckets[GetHashBucket(objEntry.Expires)].Update(objEntry, ticksExpires);
}
}
public void GarbageCleanup(object State)
{
ExpiresBucket objBucket;
lock(this)
{
// Do cleanup of the bucket
objBucket = _arrBuckets[(++_intFlush) % 60];
}
// Flush expired items in the current bucket (defined by _intFlush)
objBucket.FlushExpiredItems();
}
private int GetHashBucket(long ticks)
{
// 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
return (int) (((((ticks + 60000) % _ticksPerCycle) / _ticksPerBucket) + 1) % 60);
}
///
/// Called by the cache for cleanup.
///
public void Dispose()
{
lock(this)
{
// Cleanup the internal timer
if (_objTimer != null)
{
_objTimer.Dispose();
_objTimer = null;
}
}
}
}
}