baiyan命令用法命令含义:查看指定key的一些信息,一般用于调试或查看内部编码使用命令格式:OBJECT子命令[key]OBJECT有4个选项选用的子命令:OBJECTREFCOUNT:查看当前key的引用计数OBJECTENCODING:查看当前key的编码OBJECTIDLETIME:查看当前key的空闲时间OBJECTFREQ:查看当前key最近访问频率的对数OBJECTHELP:查看OBJECT命令帮助信息命令实战:127.0.0.1:6379>setkey1value1OK127.0.0.1:6379>objectrefcountkey1(integer)1127.0.0.1:6379>objectencodingkey1"embstr"127.0.0.1:6379>objectidletimekey1(integer)20127.0.0.1:6379>objectidletimekey1(integer)23127.0.0.1:6379>objecthelp1)OBJECTargarg...arg。子命令是:2)ENCODING--返回用于存储与键关联的值的内部表示类型。3)FREQ--返回key的访问频率索引。返回的整数与该键最近访问频率的对数成正比。4)IDLETIME--返回key的空闲时间,即近似值自上次访问密钥以来经过的秒数。5)REFCOUNT--返回与指定键关联的值的引用次数。返回值:REFCOUNT和IDLETIME返回数;ENCODING返回对应的编码类型注:idletime是指key的空闲时间,idle是指key还没有被读或写step的时间。同样的,对象指令的入口是objectCommand():voidobjectCommand(client*c){robj*o;//如果执行OBJECT帮助命令,打印帮助信息if(c->argc==2&&!strcasecmp(c->argv[1]->ptr,"help")){constchar*help[]={"ENCODING--返回用于存储与键关联的值的内部表示类型。","FREQ--返回键的访问频率索引。返回的整数与对数成正比键的最近访问频率。","IDLETIME--返回键的空闲时间,即自上次访问键以来经过的近似秒数。","REFCOUNT--返回与指定键关联的值的引用数。",NULL};addReplyHelp(c,帮助);//直接返回帮助信息}elseif(!strcasecmp(c->argv[1]->ptr,"refcount")&&c->argc==3){//如果执行OBJECTrefcountkey命令if((o=objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))//去key空间寻找key的robj对象==NULL)return;addReplyLongLong(c,o->refcount);//取出robjrefcount字段并返回}elseif(!strcasecmp(c->argv[1]->ptr,"encoding")&&c->argc==3){//如果OBJECT编码键命令被执行if((o=objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))//去key空间找到key的robj对象==NULL)return;addReplyBulkCString(c,strEncoding(o->encoding));//取出robj的编码字段并返回}elseif(!strcasecmp(c->argv[1]->ptr,"idletime")&&c->argc==3){//如果OBJECTidletimekeycommand被执行if((o=objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))//去key空间找到key的robj对象==NULL)return;if(server.maxmemory_policy&MAXMEMORY_FLAG_LFU){//如果启用如果使用LFU淘汰策略,则不会跟踪空闲时间,命令addReplyError(c,"选择了LFUmaxmemory策略,不跟踪空闲时间。请注意切换时运行时LRU和LFU数据之间的策略将需要一些时间来调整。,"freq")&&c->argc==3){//如果执行OBJECTfreq键命令if((o=objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))==NULL)return;if(!(server.maxmemory_policy&MAXMEMORY_FLAG_LFU)){addReplyError(c,"未选择LFU最大内存策略,未跟踪访问频率。请注意,在运行时在策略之间切换时,LRU和LFU数据将采取调整time.");return;}addReplyLongLong(c,LFUDecrAndReturn(o));}else{//不是这些子命令之一,直接报错addReplySubcommandSyntaxError(c);}}参数校验,因为OBJECT命令有多个子命令命令,因此需要参数验证来确定它是哪种类型的子命令:...elseif(!strcasecmp(c->argv[1]->ptr,"refcount")&&c->argc==3){//如果执行O北京ECTrefcountkeycommand...Dictionarylookup不管是什么类型的子命令,都是accesskey的robj结构中的基本字段信息。要获取这些信息,首先需要去字典中找出关键结构:if((o=objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))==NULL){}这里通过调用objectCommandLookupOrReply()函数实现了对key的查找:如果(!o)添加回复(c,回复);returno;}robj*objectCommandLookup(client*c,robj*key){dictEntry*de;//去字典键空间找键if((de=dictFind(c->db->dict,key->ptr))==NULL)returnNULL;返回(robj*)dictGetVal(de);//根据key查找value,强制为robj类型}找到??key后,直接引用robj中的某个字段(如refcount)即可获取当前key的引用计数信息并返回.命令执行结束:addReplyLongLong(c,o->refcount);扩展redis中的数据结构编码首先看下面的例子:redis>setfoo1000OKredis>objectencodingfoo"int"redis>appendfoobar(integer)7redis>getfoo"1000bar"redis>objectencodingfoo"raw"的上面的例子说明redis会根据输入的数据,自动选择时间复杂度和空间复杂度最低的数据结构来存储数据。如上例所示,当foo键的值为1000时,redis会选择int结构进行存储;而在最后加上bar之后,它的值就变成了“1000bar”,不能再用int类型来存储了,所以redis只能退一步,用raw结构来存储。在切换数据结构的临界点的选择上,redis根据底层数据结构增删改查的时间复杂度和空间复杂度做了很多取舍。Redis一共有五种基本数据结构。这五种数据结构的编码方式有以下几种选择:字符串可以编码为int、embstr或raw。当字符串可以转换为整数时使用int,当字符串很短时使用embstr,raw可以表示任意长度的字符串列表,可以编码为ziplist或linkedlist。ziplist是一种特殊的表示形式,可以为小尺寸列表节省空间。集合可以编码为intset或hashtable。intset是仅存储数字的小型集合的特殊表示。哈希表可以编码为zipmap或哈希表。zipmap是小型哈希表的一种特殊表示。排序的集合可以编码为ziplist或skiplist格式。ziplist用于表示小的已排序集合,而skiplist用于表示任意大小的已排序集合。每种数据结构的具体优缺点上面已经讨论过了,这里不再赘述。