Graperedis
命令含義:爲給定 key 設置生存時間,當 key 過時時(生存時間爲 0 ),它會被自動刪除。
命令格式:數組
EXPIRE key seconds
命令實戰:緩存
redis> EXPIRE cache_page 30000 # 更新過時時間 (integer) 1
返回值:安全
設置成功返回 1 。
當 key 不存在或者不能爲 key 設置生存時間時(好比在低於 2.1.3 版本的 Redis 中你嘗試更新 key 的生存時間),返回 0 。服務器
expire對應的函數是expireCommand:異步
/* EXPIRE key seconds */ void expireCommand(client *c) { // 調用通用處理函數 expireGenericCommand(c,mstime(),UNIT_SECONDS); } /*這是expire、pexpire、expireat和pexpireat的通用命令實現。由於commad第二個參數能夠是相對的, 也能夠是絕對的,因此「base time」參數用來表示基本時間是什麼(對於命令的at變量,或者相對過時的當前時間)。 單位是單位秒或者單位毫秒,僅用於argv[2]參數。基本時間老是以毫秒爲單位指定的。*/ void expireGenericCommand(client *c, long long basetime, int unit) { robj *key = c->argv[1], *param = c->argv[2]; long long when; /*when被設置爲毫秒. */ /* 取出param中的整數值或者嘗試將param中的數據儘量轉換成整數值存在when中, 成功返回OK失敗則返回ERR*/ if (getLongLongFromObjectOrReply(c, param, &when, NULL) != C_OK) return; /*若是傳入的過時時間是以秒爲單位的,那麼將它轉換爲毫秒*/ if (unit == UNIT_SECONDS) when *= 1000; when += basetime; /* 查詢一下該鍵是否存在,不存在給客戶端返回信息 */ if (lookupKeyWrite(c->db,key) == NULL) { addReply(c,shared.czero); return; } /* * 在載入AOF數據時,或者服務器爲附屬節點時, * 即便 EXPIRE 的 TTL 爲負數,或者 EXPIREAT 提供的時間戳已通過期, * 服務器也不會主動刪除這個鍵,而是等待主節點發來顯式的 DEL 命令。 */ if (when <= mstime() && !server.loading && !server.masterhost) { //進入這個函數的條件:when 提供的時間已通過期,未載入數據且服務器爲主節點(注意主服務器的masterhost==NULL) robj *aux; /*刪除該鍵,此處能夠看del命令的解析,在del命令解析中有分析redis同步和異步刪除的策略決定,此處再也不贅述*/ int deleted = server.lazyfree_lazy_expire ? dbAsyncDelete(c->db,key) : dbSyncDelete(c->db,key); serverAssertWithInfo(c,key,deleted); server.dirty++; /* Replicate/AOF this as an explicit DEL or UNLINK. */ /* 傳播 DEL 或者unlink命令到AOF或者從服務器 */ aux = server.lazyfree_lazy_expire ? shared.unlink : shared.del; /*修改客戶端的參數數組*/ rewriteClientCommandVector(c,2,aux,key); /* 發送鍵更改通知 */ signalModifiedKey(c->db,key); notifyKeyspaceEvent(NOTIFY_GENERIC,"del",key,c->db->id); addReply(c, shared.cone); return; } else { // 設置鍵的過時時間 // 若是服務器爲附屬節點,或者服務器正在載入,根據上個if中的條件來推斷,至少when提供時間過時爲附屬節點就會設置 // 這點猜想在redis中從屬節點不去主動作刪除操做,除非主節點同步del命令 // 那麼這個 when 有可能已通過期的 setExpire(c,c->db,key,when); addReply(c,shared.cone); signalModifiedKey(c->db,key); notifyKeyspaceEvent(NOTIFY_GENERIC,"expire",key,c->db->id); server.dirty++; return; } } //設置expire void setExpire(client *c, redisDb *db, robj *key, long long when) { dictEntry *kde, *de; /* Reuse the sds from the main dict in the expire dict */ /*首先從dict中查找,這個過程就是從db的dict根據key來查找的過程,首先會判斷是否有安全迭代器,若是沒有就會 進行rehash,防止哈 *希表混亂。而後進行hash,獲取索引值。經過索引咱們能夠遍歷dict的鏈表來拿到值。這裏會有dict上有hash值同樣的狀況,在這裏 *redis是用while循環來比較,知道key相同返回這一項。 */ kde = dictFind(db->dict,key->ptr); serverAssertWithInfo(NULL,key,kde != NULL); /* dictAddRaw()的變通,只是多了一個若是有key則返回的一個過程,若是存在則返回爲null並返回當前項,反之將key進行hash索引 *index增長到dict中並返回dict。 */ de = dictAddOrFind(db->expires,dictGetKey(kde)); /* 設置鍵的過時時間 * 這裏是直接使用整數值來保存過時時間,不是用 INT 編碼的 String 對象 */ dictSetSignedIntegerVal(de,when); int writable_slave = server.masterhost && server.repl_slave_ro == 0; if (c && writable_slave && !(c->flags & CLIENT_MASTER)) rememberSlaveKeyWithExpire(db,key); }
咱們gdb一個合法的例子來看一看他的流程:函數
redis此類命令有三種:EXPIREAT,PEXPIRE,PEXPIREAT
EXPIREAT 的做用和 EXPIRE 相似,都用於爲 key 設置生存時間。
不一樣在於 EXPIREAT 命令接受的時間參數是 UNIX 時間戳(unix timestamp)。
而PEXPIRE,PEXPIREAT和EXPIRE和EXPIREAT的區別在於PEXPIRE,PEXPIREAT是以毫秒爲單位,然後者用的是以秒爲單位。源碼分析
在這裏我簡單的列舉幾點你們僅供參考:網站