Redis_数据库

42 篇文章 0 订阅
15 篇文章 0 订阅
本文介绍了Redis数据库的数据结构,包括键空间、过期键删除策略,以及lookupKey和dbAdd/dbDelete等核心操作。重点讲解了如何处理键的过期时间和删除过程,适合深入了解Redis内部机制的开发者阅读。
摘要由CSDN通过智能技术生成

 

数据库

 

/* Redis database representation. There are multiple databases identified

* by integers from 0 (the default database) up to the max configured

* database. The database number is the 'id' field in the structure. */

typedef struct redisDb {

// 数据库键空间,保存着数据库中的所有键值对

dict *dict; /* The keyspace for this DB */

// 键的过期时间,字典的键为键,字典的值为过期事件 UNIX 时间戳

dict *expires; /* Timeout of keys with a timeout set */

// 正处于阻塞状态的键

dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */

// 可以解除阻塞的键

dict *ready_keys; /* Blocked keys that received a PUSH */

// 正在被 WATCH 命令监视的键

dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */

struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */

// 数据库号码

int id; /* Database ID */

// 数据库的键的平均 TTL ,统计信息

long long avg_ttl; /* Average TTL, just for stats */

} redisDb;

 

过期键删除策略

1.定时删除

2.惰性删除

3.定期删除

 

 

/* Low level key lookup API, not actually called directly from commands

* implementations that should instead rely on lookupKeyRead(),

* lookupKeyWrite() and lookupKeyReadWithFlags(). */

robj *lookupKey(redisDb *db, robj *key, int flags) {

dictEntry *de = dictFind(db->dict,key->ptr);

if (de) {

robj *val = dictGetVal(de);

 

/* Update the access time for the ageing algorithm.

* Don't do it if we have a saving child, as this will trigger

* a copy on write madness. */

if (server.rdb_child_pid == -1 &&

server.aof_child_pid == -1 &&

!(flags & LOOKUP_NOTOUCH))

{

if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {

updateLFU(val);

} else {

val->lru = LRU_CLOCK();

}

}

return val;

} else {

return NULL;

}

}

 

 

 

/* Add the key to the DB. It's up to the caller to increment the reference

* counter of the value if needed.

*

* 尝试将键值对 key 和 val 添加到数据库中。

*

* 调用者负责对 key 和 val 的引用计数进行增加。

*

* The program is aborted if the key already exists.

*

* 程序在键已经存在时会停止。

*/

void dbAdd(redisDb *db, robj *key, robj *val) {

 

// 复制键名

sds copy = sdsdup(key->ptr);

 

// 尝试添加键值对

int retval = dictAdd(db->dict, copy, val);

 

// 如果键已经存在,那么停止

redisAssertWithInfo(NULL, key, retval == REDIS_OK);

 

// 如果开启了集群模式,那么将键保存到槽里面

if (server.cluster_enabled) slotToKeyAdd(key);

}

 

/* Delete a key, value, and associated expiration entry if any, from the DB

*

* 从数据库中删除给定的键,键的值,以及键的过期时间。

*

* 删除成功返回 1 ,因为键不存在而导致删除失败时,返回 0 。

*/

int dbDelete(redisDb *db, robj *key) {

 

/* Deleting an entry from the expires dict will not free the sds of

* the key, because it is shared with the main dictionary. */

// 删除键的过期时间

if (dictSize(db->expires) > 0)

dictDelete(db->expires, key->ptr);

 

// 删除键值对

if (dictDelete(db->dict, key->ptr) == DICT_OK) {

// 如果开启了集群模式,那么从槽中删除给定的键

if (server.cluster_enabled)

slotToKeyDel(key);

return 1;

}

else {

// 键不存在

return 0;

}

}

/*

* 检查 key 是否已经过期,如果是的话,将它从数据库中删除。

*

* 返回 0 表示键没有过期时间,或者键未过期。

*

* 返回 1 表示键已经因为过期而被删除了。

*/

int expireIfNeeded(redisDb *db, robj *key) {

// 取出键的过期时间

mstime_t when = getExpire(db, key);

mstime_t now;

// 没有过期时间

if (when < 0)

return 0; /* No expire for this key */

 

/* Don't expire anything while loading. It will be done later. */

// 如果服务器正在进行载入,那么不进行任何过期检查

if (server.loading)

return 0;

 

/* If we are in the context of a Lua script, we claim that time is

* blocked to when the Lua script started. This way a key can expire

* only the first time it is accessed and not in the middle of the

* script execution, making propagation to slaves / AOF consistent.

* See issue #1525 on Github for more information. */

now = server.lua_caller ? server.lua_time_start : mstime();

 

/* If we are running in the context of a slave, return ASAP:

* the slave key expiration is controlled by the master that will

* send us synthesized DEL operations for expired keys.

*

* Still we try to return the right information to the caller,

* that is, 0 if we think the key should be still valid, 1 if

* we think the key is expired at this time. */

// 当服务器运行在 replication 模式时

// 附属节点并不主动删除 key

// 它只返回一个逻辑上正确的返回值

// 真正的删除操作要等待主节点发来删除命令时才执行

// 从而保证数据的同步

if (server.masterhost != NULL)

return now > when;

 

// 运行到这里,表示键带有过期时间,并且服务器为主节点

/* Return when this key has not expired */

// 如果未过期,返回 0

if (now <= when)

return 0;

/* Delete the key */

server.stat_expiredkeys++;

// 向 AOF 文件和附属节点传播过期信息

propagateExpire(db, key);

// 发送事件通知

notifyKeyspaceEvent(REDIS_NOTIFY_EXPIRED,"expired", key, db->id);

 

// 将过期键从数据库中删除

return dbDelete(db, key);

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值