Graperedis
命令含义:反序列化给定的序列化值,并将它和给定的 key 关联。算法
RESTORE key ttl serialized-value [REPLACE] [ABSTTL] [IDLETIME seconds] [FREQ frequency]
redis> DEL mykey 0 redis> RESTORE mykey 0 "\n\x17\x17\x00\x00\x00\x12\x00\x00\x00\x03\x00\ x00\xc0\x01\x00\x04\xc0\x02\x00\x04\xc0\x03\x00\ xff\x04\x00u#<\xc0;.\xe9\xdd" OK redis> TYPE mykey list redis> LRANGE mykey 0 -1 1) "1" 2) "2" 3) "3"
若是反序列化成功那么返回 OK ,不然返回一个错误。数据结构
源码分析部分咱们分为几个部分来说解。ide
void restoreCommand(client *c) { long long ttl, lfu_freq = -1, lru_idle = -1, lru_clock = -1; rio payload; int j, type, replace = 0, absttl = 0; robj *obj; /* 解析参数 */ for (j = 4; j < c->argc; j++) { int additional = c->argc-j-1; if (!strcasecmp(c->argv[j]->ptr,"replace")) { replace = 1; } else if (!strcasecmp(c->argv[j]->ptr,"absttl")) { absttl = 1; } else if (!strcasecmp(c->argv[j]->ptr,"idletime") && additional >= 1 && lfu_freq == -1) { if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lru_idle,NULL) != C_OK) return; if (lru_idle < 0) { addReplyError(c,"Invalid IDLETIME value, must be >= 0"); return; } lru_clock = LRU_CLOCK(); j++; /* Consume additional arg. */ } else if (!strcasecmp(c->argv[j]->ptr,"freq") && additional >= 1 && lru_idle == -1) { if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lfu_freq,NULL) != C_OK) return; if (lfu_freq < 0 || lfu_freq > 255) { addReplyError(c,"Invalid FREQ value, must be >= 0 and <= 255"); return; } j++; /* Consume additional arg. */ } else { addReply(c,shared.syntaxerr); return; } }
在上边咱们提到了restore命令格式,咱们能够看到,在第四个参数开始都是可选参数,因此解析参数中是从j=4开始遍历的,在遍历的过程当中会根据不一样的参数作不一样的操做。
咱们依次来看下这四个命令:源码分析
/* 此处是确保这个key是否存在,这个操做仅在replace等于0的时候进行*/ if (!replace && lookupKeyWrite(c->db,c->argv[1]) != NULL) { addReply(c,shared.busykeyerr); return; } /* 检查ttl合法,规则是是否小于0且是否可转为数字*/ if (getLongLongFromObjectOrReply(c,c->argv[2],&ttl,NULL) != C_OK) { return; } else if (ttl < 0) { addReplyError(c,"Invalid TTL value, must be >= 0"); return; } // 检查RDB版本和数据校验和。若是它们不匹配,则返回错误。 if (verifyDumpPayload(c->argv[3]->ptr,sdslen(c->argv[3]->ptr)) == C_ERR) { addReplyError(c,"DUMP payload version or checksum are wrong"); return; } rioInitWithBuffer(&payload,c->argv[3]->ptr); if (((type = rdbLoadObjectType(&payload)) == -1) || ((obj = rdbLoadObject(type,&payload)) == NULL)) { addReplyError(c,"Bad data format"); return; } // 若是是replace模式,删除key if (replace) dbDelete(c->db,c->argv[1]);
/* Create the key and set the TTL if any */ dbAdd(c->db,c->argv[1],obj); //若是key存在,则报错 if (ttl) { if (!absttl) ttl+=mstime(); setExpire(c,c->db,c->argv[1],ttl); } //建立新的key。 //若是存在ttl就设置. // 若是ttl为0,则建立密钥时不会有任何过时,不然将设置指定的过时时间(以毫秒为单位) objectSetLRUOrLFU(obj,lfu_freq,lru_idle,lru_clock); //设置频率和时间范围限制值 signalModifiedKey(c->db,c->argv[1]); addReply(c,shared.ok); server.dirty++; }
Least Frequently Used algorithm.LFU是首先淘汰必定时期内被访问次数最少的页!spa
算法根据数据的历史访问频率来淘汰数据,其核心思想是“若是数据过去被访问屡次,那么未来被访问的频率也更高”。
具体的算法流程以下所示:操作系统
Least Recently Used algorithm.LRU是首先淘汰最长时间未被使用的页面!设计
算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“若是数据最近被访问过,那么未来被访问的概率也更高”。
具体的算法流程以下所示:rest
FIFO(First in First out),先进先出。
其实在操做系统的设计理念中不少地方都利用到了先进先出的思想,好比做业调度(先来先服务),为何这个原则在不少地方都会用到呢?由于这个原则简单、且符合人们的惯性思惟,具有公平性,而且实现起来简单,直接使用数据结构中的队列便可实现。code