using System; using System.Threading; using System.Diagnostics; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using DotNet.Utilities; namespace ETD.Frame { public class Bytecached : IDisposable { private readonly IDictionary _caches; private readonly IDictionary _times; private long _size; private readonly ReaderWriterLock _readerWriterLock; private readonly BackgroundWorker _checkWorker; /// /// 最大容量/B /// public long MaxSize { get; set; } /// /// 是否启用缓存 /// public bool Enabled { get; set; } /// /// 超时时间 /// public TimeSpan Timeout { get; set; } /// /// 一次清理数量 /// public int ClearCount { get; set; } /// /// 是否正在检查并清理超时缓存 /// public bool Checking { get; private set; } /// /// 构造 /// /// 定时检查时间 public Bytecached(TimeSpan timingcheck) { timingcheck = default(TimeSpan); _caches = new Dictionary(); _times = new Dictionary(); _readerWriterLock = new ReaderWriterLock(); MaxSize = 64 * 1024 * 1024; Enabled = true; ClearCount = 1; #region 检查并清理缓存 if (timingcheck == default(TimeSpan)) { _checkWorker = new BackgroundWorker(); _checkWorker.DoWork += CheckWorker_DoWork; } else { new Thread(obj => { while (true) { var swt = new Stopwatch(); swt.Start(); CheckWorker_DoWork(null, null); swt.Stop(); Thread.Sleep(timingcheck); } }) { IsBackground = true }.Start(); } #endregion } public bool Set(string key, byte[] value) { return Set(key, value, DateTime.Now.Add(Timeout)); } public bool Set(string key, byte[] value, DateTime effectiveDate) { if (!Enabled) return false; _readerWriterLock.AcquireWriterLock(-1); try { if (_caches.ContainsKey(key)) { _size -= _caches[key].Length; _caches[key] = value; _times[key] = effectiveDate; } else { _caches.Add(key, value); _times.Add(key, effectiveDate); } _size += value.Length; } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Set", er); return false; } finally { _readerWriterLock.ReleaseWriterLock(); } #region 检查并清理缓存 try { if (_checkWorker != null && !_checkWorker.IsBusy) { _checkWorker.RunWorkerAsync(); } } catch (Exception er) { // LogUtil.WriteLog("检查并清理缓存", er); } #endregion return true; } public byte[] Get(string key) { var expiry = Timeout == TimeSpan.Zero ? default(DateTime) : DateTime.Now.Add(Timeout); return Get(key, expiry); } public byte[] Get(string key, DateTime effectiveDate) { if (!Enabled) return null; _readerWriterLock.AcquireReaderLock(-1); var exist = false; try { byte[] v; exist = _caches.TryGetValue(key, out v); return v; } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Get", er); return null; } finally { _readerWriterLock.ReleaseReaderLock(); if (exist && effectiveDate != default(DateTime)) { #region 刷新缓存 new Thread(obj => { var k = (string)((object[])obj)[0]; var edate = (DateTime)((object[])obj)[1]; while (!Refresh(k, edate)) { Thread.Sleep(100); } }) { IsBackground = true }.Start(new object[] { key, effectiveDate }); #endregion } } } public bool ContainsKey(string key) { if (!Enabled) return false; _readerWriterLock.AcquireReaderLock(-1); try { return _caches.ContainsKey(key); } catch (Exception er) { // LogUtil.WriteLog("Bytecached.ContainsKey", er); return false; } finally { _readerWriterLock.ReleaseReaderLock(); } } public bool Refresh(string key) { return Timeout != TimeSpan.Zero && Refresh(key, DateTime.Now.Add(Timeout)); } public bool Refresh(string key, DateTime effectiveDate) { _readerWriterLock.AcquireWriterLock(-1); try { if (_caches.ContainsKey(key)) { _times[key] = effectiveDate; } } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Refresh", er); return false; } finally { _readerWriterLock.ReleaseWriterLock(); } return true; } public IList Keys { get { _readerWriterLock.AcquireReaderLock(-1); try { return _caches.Keys.ToList(); } catch (Exception er) { // LogUtil.WriteLog("Bytecached.Keys", er); return new List(); } finally { _readerWriterLock.ReleaseReaderLock(); } } } public ICollection Values { get { _readerWriterLock.AcquireReaderLock(-1); try { return _caches.Values; } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Keys", er); return new List(); } finally { _readerWriterLock.ReleaseReaderLock(); } } } public ICollection Times { get { _readerWriterLock.AcquireReaderLock(-1); try { return _times.Values; } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Times", er); return new Collection(); } finally { _readerWriterLock.ReleaseReaderLock(); } } } /// /// 移除指定数据 /// /// /// public bool Remove(string key) { _readerWriterLock.AcquireWriterLock(-1); try { if (_caches.ContainsKey(key)) { _size -= _caches[key].Length; _caches.Remove(key); _times.Remove(key); } } catch (Exception er) { // LogUtil.WriteLog("Bytecached.Remove_key", er); return false; } finally { _readerWriterLock.ReleaseWriterLock(); } return true; } public void Clear() { _readerWriterLock.AcquireWriterLock(-1); try { _size = 0; _caches.Clear(); _times.Clear(); } catch (Exception er) { // LogUtil.WriteLog("Bytecached.Clear", er); } finally { _readerWriterLock.ReleaseWriterLock(); } } private void CheckWorker_DoWork(object sender, DoWorkEventArgs e) { Checking = true; try { bool clearSize; bool collect; IEnumerable clearKeys; var count = 0; var swt = new Stopwatch(); var t = new Stopwatch(); #region 清理超时记录 _readerWriterLock.AcquireReaderLock(-1); swt.Start(); try { clearKeys = from time in _times where time.Value <= DateTime.Now orderby time.Value select time.Key; } finally { _readerWriterLock.ReleaseReaderLock(); swt.Stop(); } Thread.Sleep(10); _readerWriterLock.AcquireWriterLock(-1); t.Start(); swt.Reset(); swt.Start(); try { foreach (var clearKey in clearKeys) { if (t.ElapsedMilliseconds > 20) { _readerWriterLock.ReleaseWriterLock(); Thread.Sleep(10); _readerWriterLock.AcquireWriterLock(-1); t.Reset(); } if (_caches.ContainsKey(clearKey)) { _size -= _caches[clearKey].Length; _caches.Remove(clearKey); _times.Remove(clearKey); } count++; } } finally { clearSize = _size >= MaxSize; collect = count > 0 || clearSize; _readerWriterLock.ReleaseWriterLock(); t.Stop(); swt.Stop(); } #endregion if (clearSize) { #region 清理超量记录 Thread.Sleep(10); _readerWriterLock.AcquireReaderLock(-1); swt.Reset(); swt.Start(); try { clearKeys = from time in _times orderby time.Value select time.Key; } finally { _readerWriterLock.ReleaseReaderLock(); swt.Stop(); } Thread.Sleep(10); _readerWriterLock.AcquireWriterLock(-1); t.Reset(); t.Start(); swt.Reset(); swt.Start(); count = 0; try { var i = 0; foreach (var clearKey in clearKeys) { if (i == ClearCount - 1) i = 0; if (i == 0 && _size < MaxSize) break; if (t.ElapsedMilliseconds > 20) { _readerWriterLock.ReleaseWriterLock(); Thread.Sleep(10); _readerWriterLock.AcquireWriterLock(-1); t.Reset(); } if (_caches.ContainsKey(clearKey)) { _size -= _caches[clearKey].Length; _caches.Remove(clearKey); _times.Remove(clearKey); } i++; count++; } } finally { _readerWriterLock.ReleaseWriterLock(); t.Stop(); swt.Stop(); } #endregion } if (collect) { ThreadPool.QueueUserWorkItem(obj => GC.Collect()); } } finally { Checking = false; } } public int Count { get { _readerWriterLock.AcquireReaderLock(-1); try { return _caches.Count; } catch (Exception er) { // LogUtil.WriteLog("Bytecached.Count", er); return 0; } finally { _readerWriterLock.ReleaseReaderLock(); } } } public long Size { get { _readerWriterLock.AcquireReaderLock(-1); try { return _size; } catch (Exception er) { //LogUtil.WriteLog("Bytecached.Size", er); return 0; } finally { _readerWriterLock.ReleaseReaderLock(); } } } public object[][] List { get { _readerWriterLock.AcquireReaderLock(-1); try { return _caches.Select(obj => new object[] { obj.Key, obj.Value.Length, _times[obj.Key] }).ToArray(); } catch (Exception er) { // LogUtil.WriteLog("Bytecached.List", er); return new object[3][]; } finally { _readerWriterLock.ReleaseReaderLock(); } } } public void Dispose() { Clear(); } } }