Friday, 5 February 2010

C# Sample Cache with timeout

public enum CacheEventType
{
  ADD,
  REMOVE
}
public class Cache<K, V>
{
  public const int CheckInterval = 1000;
  private int _timeoutSeconds;
  private SortedList<Timeout, K> timeouts = new SortedList<Timeout, K>();
  private Dictionary<K, V> items = new Dictionary<K, V>();
  private Timer timer;
  private object locker = new object();
  public delegate void CacheEventHandler(object source, CacheEvent<K, V> e);
  public event CacheEventHandler changed;
  public Cache(int timeoutSeconds) : this(timeoutSeconds,CheckInterval){}
  public Cache(int timeoutSeconds, int checkInterval)
  {
    this._timeoutSeconds = timeoutSeconds;
    timer = new Timer(PurgeCache, "Cache", checkInterval, checkInterval); //purge cache
  }
  private void PurgeCache(object data)
  {
    lock (locker)
    {
      for (int i = timeouts.Count - 1; i >= 0; i--)
      {
        if (timeouts.Keys[i].IsExpired())
        {
          K key = timeouts.Values[i];
          timeouts.RemoveAt(i);
          V value = items[key];
          items.Remove(key);
          FireCacheEvent(key, value, CacheEventType.REMOVE);
        }
        else
        {
          break; //don't need to loop further
        }
      }
    }
  }
  public void Put(K key, V value)
  {
    Put(key, value, _timeoutSeconds);
  }
  public void Put(K key, V value, int timeoutSeconds)
  {
    lock (locker)
    {
      timeouts.Add(new Timeout(timeoutSeconds), key);
      items.Add(key, value);
      FireCacheEvent(key, value, CacheEventType.ADD);
    }
  }
  public V Get(K key)
  {
    lock (locker)
    {
      if (items.ContainsKey(key))
      {
        return items[key];
      }
      return default(V);
    }
  }
  public bool Contains(K key)
  {
    lock (locker)
    {
      return items.ContainsKey(key);
    }
  }
  private void FireCacheEvent(K key, V value, CacheEventType type)
  {
    if (changed != null)
    {
      changed(this, new CacheEvent<K, V>(key, value, type));
    }
  }
}
public class Timeout : IComparable<Timeout>
{
  private readonly DateTime exitTime;
  public Timeout(int seconds)
  {
    exitTime = DateTime.Now.AddSeconds(seconds);
  }
  public bool IsExpired()
  {
    if (exitTime < DateTime.Now)
    {
      return true;
    }
    return false;
  }
  public int CompareTo(Timeout timeout)
  {
    return timeout.exitTime.CompareTo(exitTime);
  }
  public override string ToString()
  {
    return exitTime.ToString("yyyyMMdd HH:mm:ss");
  }
}
public class CacheEvent<K, V> : EventArgs
{
  private K _key;
  private V _value;
  private readonly CacheEventType _type;
  public CacheEvent(K key, V value, CacheEventType type)
  {
    _key = key;
    _value = value;
    _type = type;
  }
  public K Key
  {
    get { return _key; }
  }
  public V Value
  {
    get { return _value; }
  }
  public CacheEventType Type
  {
    get { return _type; }
  }
}
//Sample Form with TextBox & ListBox that allows you to add items to cache
//and shows you the current content of cache
public partial class Form1 : Form
{
	private Cache<string, string> cache = new Cache<string, string>(5);
	DataTable itemsDT = new DataTable();
	public Form1()
  {
    InitializeComponent();
    itemsDT.Columns.Add("Item");
    this.itemListBox.DataSource = itemsDT;
    this.itemListBox.DisplayMember = "Item";
    this.itemListBox.ValueMember = "Item";
    cache.changed += new Cache<string, string>.CacheEventHandler(cache_changed);
  }
  void cache_changed(object source, CacheEvent<string, string> e)
  {
    if (this.InvokeRequired)
    {
      this.Invoke(new Cache<string, string>.CacheEventHandler(cache_changed), new object[] { source, e }
      );
    }
    else
    {
      if(e.Type==CacheEventType.ADD)
      {
        DataRow row = itemsDT.NewRow();
        row["Item"] = e.Value;
        itemsDT.Rows.Add(row);
      }
      else if (e.Type == CacheEventType.REMOVE)
      {
        DataRow[] row = itemsDT.Select(String.Format("Item='{0}'", e.Value));
        itemsDT.Rows.Remove(row[0]);
      }
    }
  }
  private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
  {            
    if(e.KeyChar==(char)Keys.Enter)
    {
      if (!cache.Exists(itemTextBox.Text))
      {
        cache.Put(itemTextBox.Text, itemTextBox.Text);                    
      }
      itemTextBox.Clear();
    }
  }
}

No comments:

Post a Comment