实现思路
key1发生变化时,不立即移除 key2,key3。在每次返回key2,key3对象时检查key1是否发生变化。如果发生变化再移除key2,key3。
为了方便阅读,再把上文中的图贴出来。
参考程序
DiscuzNT:http://download.comsenz.com/DiscuzNT/src/
我是对DiscuzNT3.0中的缓存部分做的修改。请先自行下载dnt3_src.zip。
程序实现
CacheKeys
参照上图,首先将四个缓存域的Key前缀定义下来。
{
//DATA域 CTIME域 DEPEND域 DEPCTIME域
public const string DATA = "DATA_";
public const string CTIME = "CTIME_";
public const string DEPEND = "DEPEND_";
public const string DEPCTIME = "DEPCTIME_";
}
MemCacheDependency
在ASP.NET中有一个CacheDependency类,我创建了一个简化版的MemCacheDependency,并继承自接口ICacheDependency。同时用一个枚举类型的EnumDependType表示缓存依赖类型,目前只实现了缓存之间的键依赖。
{
string Dependkey { get; set; }
EnumDependType DependType { get; set; }
}
/// <summary>
/// 缓存依赖类型
/// </summary>
public enum EnumDependType
{
CacheDepend = 0,
// FileDepend = 1,
}
MemCacheDependency的实现也非常简单,就是初始化Dependkey和DependType。
{
public string Dependkey { get; set; }
public EnumDependType DependType { get; set; }
/// <summary>
/// 初始化
/// </summary>
/// <param name="dependkey">缓存依赖项key</param>
public MemCacheDependency(string dependkey)
{
Dependkey = dependkey;
DependType = EnumDependType.CacheDepend;
}
}
MemCachedStrategy
上面引入了MemCacheDependency,创建cache时增加了以下方法。
void AddObjectWithDepend(string objId, object o, ICacheDependency dep);
先修改策略接口
/// 公共缓存策略接口
/// </summary>
public interface ICacheStrategy
{
/// <summary>
/// 添加指定ID的对象
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
void AddObject(string objId, object o);
/// <summary>
/// 添加指定ID的对象(关联指定文件组)
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
/// <param name="files"></param>
void AddObjectWithFileChange(string objId, object o, string[] files);
/// <summary>
/// 添加指定ID的对象(关联指定键值组)
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
/// <param name="dependKey"></param>
void AddObjectWithDepend(string objId, object o, string[] dependKey);
/// <summary>
/// 添加指定ID的对象(关联ICacheDependency)
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
/// <param name="dep"></param>
void AddObjectWithDepend(string objId, object o, ICacheDependency dep);
/// <summary>
/// 移除指定ID的对象
/// </summary>
/// <param name="objId"></param>
void RemoveObject(string objId);
/// <summary>
/// 返回指定ID的对象
/// </summary>
/// <param name="objId">key1</param>
/// <returns></returns>
object RetrieveObject(string objId);
/// <summary>
/// 返回指定ID的cache
/// </summary>
/// <param name="objId">DATA_key1,CTIME_key1,DEPEND_key1,DEPCTIME_key1</param>
/// <returns></returns>
object RetrieveCache(string objId);
/// <summary>
/// 到期时间,单位:分钟
/// </summary>
int TimeOut { set;get;}
}
接口中,新增了一个方法RetrieveCache,他和RetrieveObject的不同:
RetrieveObject
objId:创建cache时的key,如:上图中的key1,key2,key3。返回DATA_key1,DATA_key2,DATA_key3的value。
RetrieveCache
objId:cache中实际存在的key,如:CTIME_key1,DEPEND_key1等。返回对应的value。
下面是MemCachedStrategy的实现:
/// MemCache缓存策略类
/// </summary>
public class MemCachedStrategy : Lee.Cache.ICacheStrategy
{
/// <summary>
/// 到期时间
/// </summary>
public int TimeOut { set; get; }
#region 操作指定key的Cache
private void AddCache(string objId, object o)
{
RemoveCache(objId);
if (TimeOut > 0)
MemCachedManager.CacheClient.Set(objId, o, System.DateTime.Now.AddMinutes(TimeOut));
else
MemCachedManager.CacheClient.Set(objId, o);
}
private void RemoveCache(string objId)
{
if (MemCachedManager.CacheClient.KeyExists(objId))
MemCachedManager.CacheClient.Delete(objId);
}
private bool KeyExists(string objId)
{
return MemCachedManager.CacheClient.KeyExists(objId);
}
public object RetrieveCache(string objId)
{
return MemCachedManager.CacheClient.Get(objId);
}
#endregion
/// <summary>
/// 添加指定ID的cache 没有依赖项
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
public void AddObject(string objId, object o)
{
string data_key = CacheKeys.DATA + objId;
string ctime_key = CacheKeys.CTIME + objId;
string ctime_value = System.DateTime.Now.ToString("yyyyMMddHHmmssfff");
//DATA
AddCache(data_key, o);
//CTIME
AddCache(ctime_key, ctime_value);
}
/// <summary>
/// 添加指定ID的cache 有依赖项
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
/// <param name="dependkey">依赖项key,目前只支持设置一个依赖key</param>
public void AddObjectWithDepend(string objId, object o, string[] dependkey)
{
if (dependkey.Length > 0)
{
string depend_key = CacheKeys.DEPEND + objId;
string depend_value = dependkey[0];
string depctime_key = CacheKeys.DEPCTIME + objId;
object depctime_value = RetrieveCache(CacheKeys.CTIME + dependkey[0]);
//判断dependkey是否存在
if (depctime_value != null)
{
AddObject(objId, o);
//Depend key
AddCache(depend_key, depend_value);
//DEPTIME
AddCache(depctime_key, depctime_value);
}
else
{
}
}
}
/// <summary>
/// 添加指定ID的cache 有依赖项
/// </summary>
/// <param name="objId"></param>
/// <param name="o"></param>
/// <param name="dep">ICacheDependency</param>
public void AddObjectWithDepend(string objId, object o, ICacheDependency dep)
{
if (dep.DependType == EnumDependType.CacheDepend)
{
string depend_key = CacheKeys.DEPEND + objId;
string depend_value = dep.Dependkey;
string depctime_key = CacheKeys.DEPCTIME + objId;
object depctime_value = RetrieveCache(CacheKeys.CTIME + dep.Dependkey);
//判断dependkey是否存在
if (depctime_value != null)
{
AddObject(objId, o);
//Depend key
AddCache(depend_key, depend_value);
//DEPTIME
AddCache(depctime_key, depctime_value);
}
else
{
}
}
}
/// <summary>
/// 移除指定ID的对象
/// </summary>
/// <param name="objId"></param>
public void RemoveObject(string objId)
{
string data_key = CacheKeys.DATA + objId;
string ctime_key = CacheKeys.CTIME + objId;
string depend_key = CacheKeys.DEPEND + objId;
string depctime_key = CacheKeys.DEPCTIME + objId;
RemoveCache(data_key);
RemoveCache(ctime_key);
RemoveCache(depend_key);
RemoveCache(depctime_key);
}
/// <summary>
/// 返回指定ID的对象,并根据缓存依赖做失效操作
/// </summary>
/// <param name="objId"></param>
/// <returns></returns>
public object RetrieveObject(string objId)
{
string data_key = CacheKeys.DATA + objId;
string ctime_key = CacheKeys.CTIME + objId;
string depend_key = CacheKeys.DEPEND + objId;
string depctime_key = CacheKeys.DEPCTIME + objId;
object obj = null;
//判断objId是否依赖于其他key
if (!KeyExists(depend_key) && !KeyExists(depctime_key))
{
obj = RetrieveCache(data_key);
}
else
{
object depkey = RetrieveCache(depend_key);//depend key
string oldtime = RetrieveCache(depctime_key).ToString();
string newtime = System.Convert.ToString(RetrieveCache(CacheKeys.CTIME + depkey.ToString()));
//判断依赖项的key是否过期
if (oldtime == newtime)
{
obj = RetrieveCache(data_key);
}
else
{
RemoveObject(objId);
}
}
return obj;
}
public void AddObjectWithFileChange(string objId, object o, string[] files)
{
;
}
}
其中的AddObject、AddObjectWithDepend、RemoveObject和RetrieveObject方法可以参照实现思路进行理解。更详细介绍请参考为 memcached增加缓存依赖的初步设想。
CacheContext
下面是对CacheContext的改造,同样增加了包含ICacheDependency类型参数的AddObject方法。
/// 缓存进行全局控制管理
/// </summary>
public class CacheContext
{
private static ICacheStrategy cs;
private static volatile CacheContext instance = null;
private static object lockHelper = new object();
private static System.Timers.Timer cacheConfigTimer = new System.Timers.Timer(15000);
private static bool applyMemCached = false;
/// <summary>
/// 构造函数
/// </summary>
private CacheContext()
{
if(MemCachedConfigs.GetConfig() != null && MemCachedConfigs.GetConfig().ApplyMemCached)
applyMemCached = true;
if (applyMemCached)
cs = new MemCachedStrategy();
else
{
cs = new DefaultCacheStrategy();
}
}
/// <summary>
/// 单体模式返回当前类的实例
/// </summary>
/// <returns></returns>
public static CacheContext GetCacheService()
{
if (instance == null)
{
lock (lockHelper)
{
if (instance == null)
{
instance = new CacheContext();
}
}
}
return instance;
}
public virtual void AddObject(string objectId, object o)
{
lock (lockHelper)
{
cs.AddObject(objectId, o);
}
}
public virtual void AddObject(string objectId, object o,string[] keys)
{
lock (lockHelper)
{
cs.AddObjectWithDepend(objectId, o, keys);
}
}
public virtual void AddObject(string objectId, object o,ICacheDependency dep)
{
lock (lockHelper)
{
cs.AddObjectWithDepend(objectId, o, dep);
}
}
public virtual object GetObject(string objid)
{
try
{
object cacheObject = cs.RetrieveObject(objid);
return cacheObject;
}
catch
{
return null;
}
}
public virtual object GetCache(string objid)
{
try
{
object cacheObject = cs.RetrieveCache(objid);
return cacheObject;
}
catch
{
return null;
}
}
public virtual void RemoveObject(string objid)
{
lock (lockHelper)
{
cs.RemoveObject(objid);
}
}
/// <summary>
/// 加载指定的缓存策略
/// </summary>
/// <param name="ics"></param>
public void LoadCacheStrategy(ICacheStrategy ics)
{
lock (lockHelper)
{
//当不使用MemCached时
if (!applyMemCached)
{
cs = ics;
}
}
}
/// <summary>
/// 加载默认的缓存策略
/// </summary>
public void LoadDefaultCacheStrategy()
{
lock (lockHelper)
{
//当不使用MemCached时
if (applyMemCached)
{
cs = new MemCachedStrategy();
}
else
{
cs = new DefaultCacheStrategy();
}
}
}
}
策略模式
上面的实现用到了策略模式(Strategy),可以参考吕老师的文章:http://www.cnblogs.com/zhenyulu/articles/82017.html。