基于STSdb和fastJson的磁盘/内存缓存

2022-04-14 00:00:00 缓存 磁盘 的是 内存 便可

需求

业务系统用的是数据库,数据量大,部分只读或相对稳定业务查询复杂,每次页面加载都要花耗不少时间(不讨论异步),觉得可以做一下高速缓存,譬如用nosql那种key/value快速存取结果

目的

这里不是要做一个大家都适用的磁盘/内存缓存库,这个做法,部分是展示STSdb的用法,部分是提供一个简单易用的解决方案。

磁盘/内存

为什么不用memcached或者AppFabric Cache这样的现成解决方案呢?因为业务要缓存的内存或大或小,小的几KB,大的几MB,如果用户一多,势必对内存有过度的需求。所以选择做一个基于磁盘的。

当然,这个解决方案是支持内存缓存的。构造的时候传递空字符串便可。

STSdb是什么

再来说明一下STSdb是什么:STSdb是C#写的开源嵌入式数据库和虚拟文件系统,支持实时索引,性能是同类产品的几倍到几十倍,访问官方网站。

我之前介绍过:STSdb,强纯C#开源NoSQL和虚拟文件系统 和 STSdb,强纯C#开源NoSQL和虚拟文件系统 4.0 RC2 支持C/S架构 ,大家可以先看看。

实现

存取

因为是基于磁盘,所以需要使用到高效的Key/Value存取方案,碰巧我们有STSdb :)

序列化

因为要求简便快速,用的是fastJson。

代码

代码比较简单,花了2个小时写的,很多情况没考虑,譬如磁盘空间不足、过期空间回收等,这些留给大家做家庭作业吧。另外,为了发布方便,STSdb和fastJson的代码都合并到一个项目里。

CahceEngine.cs

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using STSdb4.Database;  
  6. using fastJSON;  
  7. using System.IO;  
  8.   
  9. namespace Com.SuperCache.Engine  
  10. {  
  11.     public class CacheEngine  
  12.     {  
  13.         private const string KeyExpiration = "Expiration";  
  14.         private string dataPath;  
  15.         private static IStorageEngine memoryInstance = null;  
  16.         private static object syncRoot = new object();  
  17.         private bool isMemory = false;  
  18.   
  19.         public CacheEngine(string DataPath)  
  20.         {  
  21.             dataPath = DataPath;  
  22.             if (!dataPath.EndsWith(Path.DirectorySeparatorChar.ToString()))  
  23.                 dataPath += Path.DirectorySeparatorChar;  
  24.   
  25.             isMemory = string.IsNullOrEmpty(DataPath);  
  26.         }  
  27.   
  28.         public void Add<K>(string Category, K Key, object Data)  
  29.         {  
  30.             Add(Category, Key, Data, null);  
  31.         }  
  32.   
  33.         private IStorageEngine Engine  
  34.         {  
  35.             get  
  36.             {  
  37.                 if (isMemory)  
  38.                 {  
  39.                     lock (syncRoot)  
  40.                     {  
  41.                         if (memoryInstance == null)  
  42.                             memoryInstance = STSdb.FromMemory();  
  43.                     }  
  44.                     return memoryInstance;  
  45.                 }  
  46.                 else  
  47.                     return STSdb.FromFile(GetFile(false), GetFile(true));  
  48.             }  
  49.         }  
  50.   
  51.         public void Add<K>(string Category, K Key, object Data, DateTime? ExpirationDate)  
  52.         {  
  53.             var engine = Engine;  
  54.             var table = engine.OpenXIndex<K, string>(Category);  
  55.             var result = Data is string ? (string)Data : JSON.Instance.ToJSON(Data);  
  56.             table[Key] = result;  
  57.             table.Flush();  
  58.   
  59.             var expiration = engine.OpenXIndex<K, DateTime>(KeyExpiration);  
  60.             var expirationDate = ExpirationDate == null || ExpirationDate <= DateTime.Now ? DateTime.Now.AddMinutes(30) : (DateTime)ExpirationDate;  
  61.             expiration[Key] = expirationDate;  
  62.             expiration.Flush();  
  63.   
  64.             engine.Commit();  
  65.   
  66.             if (!isMemory)  
  67.                 engine.Dispose();  
  68.         }  
  69.   
  70.         private string GetFile(bool IsData)  
  71.         {  
  72.             if (!Directory.Exists(dataPath))  
  73.                 Directory.CreateDirectory(dataPath);  
  74.             return dataPath + "SuperCache." + (IsData ? "dat" : "sys");  
  75.         }  
  76.   
  77.         public V Get<K, V>(string Category, K Key)  
  78.         {  
  79.             var engine = Engine;  
  80.             var table = engine.OpenXIndex<K, string>(Category);  
  81.             string buffer;  
  82.             V result;  
  83.             if (table.TryGet(Key, out buffer))  
  84.             {  
  85.                 result = typeof(V) == typeof(string) ? (V)(object)buffer : JSON.Instance.ToObject<V>(buffer);  
  86.                 var expiration = engine.OpenXIndex<K, DateTime>(KeyExpiration);  
  87.                 DateTime expirationDate;  
  88.                 if (expiration.TryGet(Key, out expirationDate))  
  89.                 {  
  90.                     if (expirationDate < DateTime.Now)  
  91.                     {  
  92.                         result = default(V);  
  93.                         table.Delete(Key);  
  94.                         table.Flush();  
  95.                         expiration.Delete(Key);  
  96.                         expiration.Flush();  
  97.                         engine.Commit();  
  98.                     }  
  99.                 }  
  100.             }  
  101.             else  
  102.                 result = default(V);  
  103.   
  104.             if (!isMemory)  
  105.                 engine.Dispose();  
  106.   
  107.             return result;  
  108.         }  
  109.     }  
  110. }  

相关文章