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是以毫秒为单位,然后者用的是以秒为单位。源码分析
在这里我简单的列举几点你们仅供参考:网站