wtxnpw 发表于 2015-8-31 12:11:54

为memcached增加缓存依赖的程序实现

节前的一篇文章中提出了为memcached增加缓存依赖的初步设想,本文对第一个思路进行实现。
  实现思路
  key1发生变化时,不立即移除 key2,key3。在每次返回key2,key3对象时检查key1是否发生变化。如果发生变化再移除key2,key3。
  为了方便阅读,再把上文中的图贴出来。


  参考程序
  DiscuzNT:http://download.comsenz.com/DiscuzNT/src/

  我是对DiscuzNT3.0中的缓存部分做的修改。请先自行下载dnt3_src.zip。
程序实现

  CacheKeys

  参照上图,首先将四个缓存域的Key前缀定义下来。



    public class CacheKeys
    {
      //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表示缓存依赖类型,目前只实现了缓存之间的键依赖。



    public interface ICacheDependency
    {
      string Dependkey { get; set; }
      EnumDependType DependType { get; set; }
    }
    /// <summary>
    /// 缓存依赖类型
    /// </summary>
    public enum EnumDependType
    {
      CacheDepend = 0,
       // FileDepend = 1,
    }  MemCacheDependency的实现也非常简单,就是初始化Dependkey和DependType。



    public class MemCacheDependency:ICacheDependency
    {
      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>
    /// 公共缓存策略接口
    /// </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的实现:



    /// <summary>
    /// 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;
                string depctime_key = CacheKeys.DEPCTIME + objId;
                object depctime_value = RetrieveCache(CacheKeys.CTIME + 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的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>
    /// 缓存进行全局控制管理
    /// </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。

  

  

  

  

  

  
页: [1]
查看完整版本: 为memcached增加缓存依赖的程序实现