using System; using System.Collections.Generic; using System.Text; using System.Threading; using CYQ.Data.Tool; using CYQ.Data.Table; using CYQ.Data.SQL; using System.IO; namespace CYQ.Data.Cache { /// /// 单机缓存类 /// 为兼容.NET Core 去掉Web.Caching,重写 /// internal class LocalCache : CacheManage { private MDictionary theCache = new MDictionary(2048, StringComparer.OrdinalIgnoreCase);//key,cache private MDictionary theKeyTime = new MDictionary(2048, StringComparer.OrdinalIgnoreCase);//key,time private MDictionary theFileName = new MDictionary();//key,filename private SortedDictionary> theTime = new SortedDictionary>();//worktime,keylist private MDictionary theFolderWatcher = new MDictionary();//folderPath,watch private MDictionary> theFolderKeys = new MDictionary>();//folderPath,keylist private static object lockObj = new object(); private DateTime workTime, startTime; private MDataTable _CacheSchemaTable; private MDataTable CacheSchemaTable { get { if (_CacheSchemaTable == null || _CacheSchemaTable.Columns.Count == 0) { _CacheSchemaTable = new MDataTable(CacheType.ToString()); _CacheSchemaTable.Columns.Add("Key", System.Data.SqlDbType.NVarChar); _CacheSchemaTable.Columns.Add("Value", System.Data.SqlDbType.NVarChar); } return _CacheSchemaTable; } } private DateTime getCacheTableTime = DateTime.Now;//获取缓存表的数据的时间。 /// /// 获取缓存信息对象列表 /// public override MDataTable CacheInfo { get { if (CacheSchemaTable.Rows.Count == 0 || getCacheTableTime.AddSeconds(20) < DateTime.Now) { getCacheTableTime = DateTime.Now; CacheSchemaTable.Rows.Clear(); CacheSchemaTable.NewRow(true).Set(0, "CacheCount").Set(1, theCache.Count); CacheSchemaTable.NewRow(true).Set(0, "TimeCount").Set(1, theTime.Count); CacheSchemaTable.NewRow(true).Set(0, "FileCount").Set(1, theFileName.Count); CacheSchemaTable.NewRow(true).Set(0, "KeyTimeCount").Set(1, theKeyTime.Count); CacheSchemaTable.NewRow(true).Set(0, "FolderWatcherCount").Set(1, theFolderWatcher.Count); CacheSchemaTable.NewRow(true).Set(0, "TaskStartTime").Set(1, startTime); CacheSchemaTable.NewRow(true).Set(0, "TaskWorkCount").Set(1, taskCount); CacheSchemaTable.NewRow(true).Set(0, "ErrorCount").Set(1, errorCount); } return _CacheSchemaTable; } } internal LocalCache() { try { ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(ClearState)); ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(DalCreate.CheckConnIsOk));//主从链接的检测机制。 if (AppConfig.Cache.IsAutoCache) { ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(AutoCache.ClearCache)); } } catch (Exception err) { errorCount++; Log.WriteLogToTxt(err); } } int taskCount = 0, taskInterval = 5;//5分钟清一次缓存。 private static DateTime errTime = DateTime.MinValue; private void ClearState(object threadID) { startTime = DateTime.Now; while (true) { try { workTime = startTime.AddMinutes((taskCount + 1) * taskInterval); TimeSpan ts = workTime - DateTime.Now; if (ts.TotalSeconds > 0) { Thread.Sleep(ts);//taskInterval * 60 * 1000);//10分钟休眠时间 } #region 新的机制 if (theTime.ContainsKey(taskCount)) { RemoveList(theTime[taskCount].GetList()); theTime.Remove(taskCount); } #endregion } catch (ThreadAbortException e) { } catch (OutOfMemoryException) { errorCount++; } catch (Exception err) { errorCount++; if (errTime == DateTime.MinValue || errTime.AddMinutes(10) < DateTime.Now) // 10分钟记录一次 { errTime = DateTime.Now; Log.WriteLogToTxt("LocalCache.ClearState:" + Log.GetExceptionMessage(err)); } } finally { taskCount++; if (taskCount % 10 == 9) { try { if (theCache.Count > 100000)// theKey.Count > 100000) { NoSqlAction.ResetStaticVar(); GC.Collect(); } } catch { errorCount++; } } } } } private int errorCount = 0;//缓存捕异常次数 /// /// 内存工作信息 /// public override string WorkInfo { get { JsonHelper js = new JsonHelper(false, false); js.Add("TaskCount", taskCount.ToString(), true); js.Add("ErrorCount", errorCount.ToString(), true); js.Add("NextTaskTime", workTime.ToString()); js.AddBr(); return js.ToString(); // return string.Format("try catch error count:{0}--clear count:{1}--next clear work time at:{2}", errorCount, taskCount, workTime); } } /// /// 获和缓存总数 /// public override int Count { get { return theCache.Count; // return theKey.Count; } } /// /// 获得一个Cache对象 /// /// 标识 public override object Get(string key) { if (Contains(key)) { return theCache[key];// && theCache.ContainsKey(key) 内部已有判断和Lock } return null; } /// /// 是否存在缓存 /// /// 标识 /// public override bool Contains(string key) { return theCache.ContainsKey(key) && theKeyTime.ContainsKey(key) && theKeyTime[key] > DateTime.Now; } /// /// 添加一个Cache对象 /// /// 标识 /// 对象值 public override void Set(string key, object value) { Set(key, value, AppConfig.Cache.DefaultCacheTime); } /// 缓存时间(单位分钟) public override void Set(string key, object value, double cacheMinutes) { Set(key, value, cacheMinutes, null); } /// 文件依赖路径 public override void Set(string key, object value, double cacheMinutes, string fileName) { try { lock (lockObj) { if (theCache.ContainsKey(key)) { theCache[key] = value; } else { theCache.Add(key, value);//2:设置value } double cacheTime = cacheMinutes; if (cacheMinutes <= 0) { cacheTime = AppConfig.Cache.DefaultCacheTime; } DateTime cTime = DateTime.Now.AddMinutes(cacheTime); int workCount = GetWorkCount(cTime); if (theKeyTime.ContainsKey(key)) { int wc = GetWorkCount(theKeyTime[key]); if (wc != workCount && theTime.ContainsKey(wc)) { if (theTime[wc].Contains(key)) { theTime[wc].Remove(key); //移除旧值 } } theKeyTime[key] = cTime; } else { theKeyTime.Add(key, cTime); } if (theTime.ContainsKey(workCount))//3:设置time { if (!theTime[workCount].Contains(key)) { theTime[workCount].Add(key); } } else { MList list = new MList(); list.Add(key); theTime.Add(workCount, list); } if (!string.IsNullOrEmpty(fileName))//3:设置file { if (fileName.IndexOf("\\\\") > -1) { fileName = fileName.Replace("\\\\", "\\"); } if (!theFileName.ContainsKey(key)) { theFileName.Add(key, fileName); } string folder = Path.GetDirectoryName(fileName); if (!theFolderWatcher.ContainsKey(folder) && Directory.Exists(folder)) { theFolderWatcher.Add(folder, CreateFileSystemWatcher(folder)); } if (theFolderKeys.ContainsKey(folder)) { if (!theFolderKeys[folder].Contains(key)) { theFolderKeys[folder].Add(key); } } else { MList list = new MList(); list.Add(key); theFolderKeys.Add(folder, list); } } } } catch { errorCount++; } } private int GetWorkCount(DateTime cTime) { TimeSpan ts = cTime - startTime; return (int)ts.TotalMinutes / taskInterval;//计算出离开始有多少个间隔时间。 } /// /// 删除一个Cache对象 /// /// 标识 public override void Remove(string key) { theCache.Remove(key);//清除Cache,其它数据在定义线程中移除 } /// /// 移除Key和Value /// /// private void RemoveList(List removeKeys) { if (removeKeys != null && removeKeys.Count > 0) { lock (lockObj) { foreach (string key in removeKeys) { try { if (theCache.ContainsKey(key)) { theCache.Remove(key); } if (theKeyTime.ContainsKey(key)) { theKeyTime.Remove(key); } if (theFileName.ContainsKey(key)) { string folder = Path.GetDirectoryName(theFileName[key]); MList keys = theFolderKeys[folder]; keys.Remove(key); if (keys.Count == 0) { theFolderWatcher[folder].Changed -= new FileSystemEventHandler(fsy_Changed);//取消事件 theFolderWatcher.Remove(folder);//文件夹下没有要监视的文件,取消事件和对象。 theFolderKeys.Remove(folder);//移除对象。 } theFileName.Remove(key);//file } //file } catch { errorCount++; break; } } } } } /// /// 清除所有缓存 /// public override void Clear() { try { lock (lockObj) { TableSchema.tableCache.Clear(); TableSchema.columnCache.Clear(); theCache.Clear(); theTime.Clear(); theFileName.Clear(); theKeyTime.Clear(); for (int i = 0; i < theFolderWatcher.Count; i++) { theFolderWatcher[i].Changed -= new FileSystemEventHandler(fsy_Changed); theFolderWatcher[i] = null; } theFolderWatcher.Clear(); theFolderKeys.Clear(); } } catch { errorCount++; } } public override CacheType CacheType { get { return CacheType.LocalCache; } } #region 处理文件依赖 private FileSystemWatcher CreateFileSystemWatcher(string folderName) { FileSystemWatcher fsy = new FileSystemWatcher(folderName, "*.*"); fsy.EnableRaisingEvents = true; fsy.IncludeSubdirectories = false; fsy.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.DirectoryName; fsy.Changed += new FileSystemEventHandler(fsy_Changed); return fsy; } private static readonly object obj2 = new object(); void fsy_Changed(object sender, FileSystemEventArgs e) { lock (obj2) { string fileName = e.FullPath; string folder = Path.GetDirectoryName(fileName); if (theFolderKeys.ContainsKey(folder)) { MList keys = theFolderKeys[folder];//.GetList(); int count = keys.Count; for (int i = 0; i < count; i++) { if (i < keys.Count) { if (string.Compare(theFileName[keys[i]], fileName, StringComparison.OrdinalIgnoreCase) == 0) { Remove(keys[i]); keys.Remove(keys[i]); i--; } } } } } } #endregion } }