【转载】遍历memcached缓存对象(C#)

原文地址:遍历memcached缓存对象(C#)

 

 

遍历memcached缓存对象(C#)

STATS命令

出于性能考虑,memcached没有提供遍历功能,不过我们可以通过以下两个stats命令得到所有的缓存对象。

1、stats items

     显示各个slab中item的数目。

2、stats cachedump slab_id limit_num
     显示某个slab中的前limit_num个key列表,显示格式:ITEM key_name [ value_length b; expire_time|access_time s]

除了上面两个,memcached还提供了以下命令:

3、stats  
4、 stats reset  
5、 stats malloc  
6、 stats maps  
7、 stats sizes 
8、 stats slabs 
9、 stats detail [on|off|dump] 

命令的用法就不一一说了,请自行google。 关于memcached的数据存储和内存分配以后有机会再写。

添加缓存

在本地添加几个key,如下:

程序实现

因为要用c#调用,所以需要客户端执行 STATS 命令,这个可以直接参考DiscuzNT3.0中的实现。

DiscuzNT下载地址:http://download.comsenz.com/DiscuzNT/src/

下载完程序以后,在Discuz.Cache项目中找到这两个类:MemCached.cs和MemCachedClient.cs。

 我们要用到的方法有:

MemCached.GetStats

ExpandedBlockStart.gif 代码
         ///   <summary>
        
///  获取服务器端缓存的数据信息
        
///   </summary>
        
///   <param name="serverArrayList"> 要访问的服务列表 </param>
        
///   <returns> 返回信息 </returns>
         public   static  ArrayList GetStats(ArrayList serverArrayList, Stats statsCommand,  string  param)
        {
            ArrayList statsArray  =   new  ArrayList();
            param  =   Utils.StrIsNullOrEmpty(param)  ?   ""  : param.Trim().ToLower();

            
string  commandstr  =   " stats " ;
            
// 转换stats命令参数
             switch  (statsCommand)
            {
                
case  Stats.Reset: { commandstr  =   " stats reset " break ; }
                
case  Stats.Malloc: { commandstr  =   " stats malloc " break ; }
                
case  Stats.Maps: { commandstr  =   " stats maps " break ; }
                
case  Stats.Sizes: { commandstr  =   " stats sizes " break ; }
                
case  Stats.Slabs: { commandstr  =   " stats slabs " break ; }
                
case  Stats.Items: { commandstr  =   " stats " break ; }
                
case  Stats.CachedDump: 
                {
                    
string [] statsparams  =  Utils.SplitString(param,  "   " );
                    
if (statsparams.Length  ==   2 )
                        
if (Utils.IsNumericArray(statsparams))
                            commandstr  =   " stats cachedump   "   +  param; 

                    
break ;                     
                }
                
case  Stats.Detail: 
                    { 
                        
if ( string .Equals(param,  " on " ||   string .Equals(param,  " off " ||   string .Equals(param,  " dump " ))
                            commandstr  =   " stats detail  "   +  param.Trim(); 

                        
break
                    }
                
default : { commandstr  =   " stats " break ; }
            }
            
// 加载返回值
            Hashtable stats  =  MemCachedManager.CacheClient.Stats(serverArrayList, commandstr);
            
foreach  ( string  key  in  stats.Keys)
            {
                statsArray.Add(key);
                Hashtable values  =  (Hashtable)stats[key];
                
foreach  ( string  key2  in  values.Keys)
                {
                    statsArray.Add(key2  +   " : "   +  values[key2]);
                }
            }
            
return  statsArray;
        }

MemCachedClient.Stats

ExpandedBlockStart.gif 代码
public  Hashtable Stats(ArrayList servers,  string  command) 
        {

            
//  get SockIOPool instance
            SockIOPool pool  =  SockIOPool.GetInstance(_poolName);

            
//  return false if unable to get SockIO obj
             if (pool  ==   null
            {
                
// if(log.IsErrorEnabled)
                
// {
                
//     log.Error(GetLocalizedString("unable to get socket pool"));
                
// }
                 return   null ;
            }

            
//  get all servers and iterate over them
             if  (servers  ==   null )
                servers  =  pool.Servers;

            
//  if no servers, then return early
             if (servers  ==   null   ||  servers.Count  <=   0
            {
                
// if(log.IsErrorEnabled)
                
// {
                
//     log.Error(GetLocalizedString("stats no servers"));
                
// }
                 return   null ;
            }

            
//  array of stats Hashtables
            Hashtable statsMaps  =   new  Hashtable();

            
for ( int  i  =   0 ; i  <  servers.Count; i ++
            {

                SockIO sock  =  pool.GetConnection(( string )servers[i]);
                
if (sock  ==   null
                {
                    
// if(log.IsErrorEnabled)
                    
// {
                    
//     log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers[i].ToString()));
                    
// }
                     continue ;
                }

                
//  build command
                command  =  Discuz.Common.Utils.StrIsNullOrEmpty(command)  ?    " stats\r\n " : command  +   " \r\n " ;

                
try  
                {
                    sock.Write(UTF8Encoding.UTF8.GetBytes(command));
                    sock.Flush();

                    
//  map to hold key value pairs
                    Hashtable stats  =   new  Hashtable();

                    
//  loop over results
                     while ( true
                    {
                        
string  line  =  sock.ReadLine();
                        
// if(log.IsDebugEnabled)
                        
// {
                        
//     log.Debug(GetLocalizedString("stats line").Replace("$$Line$$", line));
                        
// }

                        
if (line.StartsWith(STATS)) 
                        {
                            
string [] info  =  line.Split( '   ' );
                            
string  key     =  info[ 1 ];
                            
string  val   =  info[ 2 ];

                            
// if(log.IsDebugEnabled)
                            
// {
                            
//     log.Debug(GetLocalizedString("stats success").Replace("$$Key$$", key).Replace("$$Value$$", val));
                            
// }

                            stats[ key ]  =  val;

                        }
                        
else   if (END  ==  line) 
                        {
                            
//  finish when we get end from server
                            
// if(log.IsDebugEnabled)
                            
// {
                            
//     log.Debug(GetLocalizedString("stats finished"));
                            
// }
                             break ;
                        }

                        statsMaps[ servers[i] ]  =  stats;
                    }
                }
                
catch // (IOException e) 
                {
                    
// if(log.IsErrorEnabled)
                    
// {
                    
//     log.Error(GetLocalizedString("stats IOException"), e);
                    
// }

                    
try  
                    {
                        sock.TrueClose();
                    }
                    
catch // (IOException) 
                    {
                        
// if(log.IsErrorEnabled)
                        
// {
                        
//     log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()));
                        
// }
                    }

                    sock  =   null ;
                }

                
if (sock  !=   null )
                    sock.Close();
            }

            
return  statsMaps;
        }

有了这两个方法我们就可以得到memcached中的缓存项了。

基本思路是,先得到cache中所有的item(stats items),再通过itemid 取出cachekey和cachevalue(stats cachedump)

程序实现如下:

     private    void  GetItems()
    {
        ArrayList itemarr  =   new  ArrayList();

        ArrayList arrayList  =   new  ArrayList();
        StringBuilder sb  =   new  StringBuilder();

        
foreach  ( string  server  in  MemCachedManager.ServerList)
        {
            arrayList.Add(server);
        }
        ArrayList arr  =  MemCachedManager.GetStats(arrayList, MemCachedManager.Stats.Items,  null );
        
foreach  ( string  a  in  arr)
        {
            
string [] tmparr  =  a.Split( ' : ' );
            
if  (tmparr.Length  >   1 )
            {
                
int  item_id  =   0 ;
                
int .TryParse(tmparr[ 1 ],  out  item_id);

                
bool  find  =   false ;
                
foreach  ( int  item  in  itemarr)
                {
                    
if  (item  ==  item_id)
                        find  =   true ;
                }
                
if  ( ! find  &&  item_id  >   0   &&  item_id  !=   11211 )
                    itemarr.Add(item_id);
            }
        }
        
foreach  ( int  item  in  itemarr)
        {
            sb.Append( " item  "   +  item  +   " <br /> " );
            ArrayList cachearr  =  MemCachedManager.GetStats(arrayList, MemCachedManager.Stats.CachedDump,  ""   +  item  +   "  10 " );
            
foreach  ( string  cache  in  cachearr)
            {
                sb.Append(cache);
                sb.Append( " <br /> " );
            }
        }
        Response.Write(sb.ToString());
    }

运行程序:


为什么没有输出缓存项呢?

DiscuzNT3.0中的bug

于是我找啊找,发现是DiscuzNT3.0中的一个bug导致。

在MemCachedClient.Stats中,有这样的一段代码:

if (line.StartsWith(STATS)) 
{
    
string [] info  =  line.Split( '   ' );
    
string  key     =  info[ 1 ];
    
string  val   =  info[ 2 ];
    stats[ key ]  =  val;

}
else   if (END  ==  line) 
{
    
break ;
}

原来是忽略了stats cachedump 的结果是以ITEM开头的,所以什么都没有输出。简单修改一下:

if (line.StartsWith(STATS) ) 
{
    
string [] info  =  line.Split( '   ' );
    
string  key     =  info[ 1 ];
    
string  val   =  info[ 2 ];
    stats[ key ]  =  val;

}
else   if  (line.StartsWith( " ITEM " ))
{
    
string [] info  =  line.Split( ' [ ' );
    
string  key  =  info[ 0 ].Split( '   ' )[ 1 ];
    
string  val  =   " [ "   +  info[ 1 ];

    stats[key]  =  val;
}
else   if  (END  ==  line)
{
    
break ;
}

再看一下输出结果,显示正常。


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值