Redis是支持时间事件的,所谓时间事件,是为某个键值对设置过期时间,时间一到,Redis会自动删除该键值对。例如使用SET命令添加字符串类型的键值对
127.0.0.1:6379> SET blog redis ex 10 //添加键值对<blog, redis>,10秒后删除
OK
127.0.0.1:6379> GET blog //添加后马上查找,可以获取redis
"redis"
127.0.0.1:6379> GET blog //上趟厕所回来,发现找不到了
(nil)
Redis是如何实现定时删除的呢,在数据库结构redisDb中,可以发现除了上篇提到的用于保存键值对的dict字典外,另有一个字典变量expires,实际上正是它保存着键和其过期时间(绝对时间)。当执行完SET命令后,两个字典的数据分布为
//server.h
typedef struct redisDb {
dict *dict; /* 保存键值对的字典 */
dict *expires; /* 保存键和过期时间 */
int id; /* 数据库唯一id */
...
} redisDb;
dict字典
blog --> redis
expires字典
blog --> blog的过期时间
设置,获取,删除过期时间
以下键节点指字典中的哈希节点,保存键和值
设置键的过期时间
//db.c
/*
* 设置键的过期时间
* db : 数据库
* key : 键
* when : 过期时间(绝对时间)
*/
void setExpire(redisDb *db, robj *key, long long when) {
dictEntry *kde, *de;
/* Reuse the sds from the main dict in the expire dict */
/* 从数据字典中寻找键节点 */
kde = dictFind(db->dict,key->ptr);
serverAssertWithInfo(NULL,key,kde != NULL);
/* 从时间字典中寻找键节点,如果不存在则创建一个 */
de = dictReplaceRaw(db->expires,dictGetKey(kde));
/* 设置键节点的值,值为过期时间(绝对时间) */
dictSetSignedIntegerVal(de,when);
}
dictSetSignedIntegerVal是宏定义,设置键节点de的值为when。因为哈希节点中的值结构是联合,可以存储不同大小的数字