Redis是一个键值对数据库(key-value pairs database),所以它的数据库本身也是一个字典(也称键值空间:key space):
** 字典的键是一个字符串对象
**字典的值则可以是字符串、列表、哈希表、集合、有序集的任一种Redis类型的对象。
在redisDB结构的dict属性(键值对数据字典)中保存着数据的所有键值对数据。下图展示了一个三个键的数据库,其中键依次为:number/book/memssage三个字符串,而对应的键值则依次为:一个列表、一个哈希表、和一个字符串。如图:
由于数据库本身是一个字典,所以对数据的操作基本就是对字典的操作,以及一些维护操作,维护操作主要包括:
*更新键的命中率和不命中率
*更新键的LRU时间
*删除过期键
*如果键被修改了,则将键设为脏(用于事务监视),并将服务器设为脏(等待RDB保存)
*将键的修改发送到AOF文件和附属节点,以保持数据的一致
其中对过期时间的设置以及过期键的处理也是本节的一大内容。 redisDB的expires属性即过期字典,里面保存了键值对字典dict中的键值的过期是时间(过期字典的键指针和键值对字典的键指针指向同一键字符串,而过期字典的值则是键的过期时间)。
因此整个redisDB的基本结构如下图(上面一个字典是键值对,下面即为过期字典,两个字典的键实际是指向同一键字符串的):
对过期键的处理:
Redis选择内存与CPU时间的折中考虑,采用了惰性删除与定期删除相结合的方式来清除过期的键值以及过期字典中的过期时间。
一:惰性删除处理: 只有当对某个键进行读写操作时,才主动检查该键的过期时间,如果过期则删除。
二:定期删除:系统每过一定时间(由Redis的例行处理程序serverCron执行时调用处理)就在限定时间内执行一次尽量对所有的数据库遍历一次,随机检查一部分键的过期时间,如果过期则删除。
根据以上分析,整个db.c文件可分为四部分:
*一*DB的API函数:这些函数都是对字典函数的封装调用(主要是对键值对字典函数封装)
*二*DB的操纵命令函数:调用第一部分的API函数、和客户端、服务器的交互操作等
*三*该部分主要是对过期时间的处理(过期字典)的API函数:过期时间的设置,过期键的删除等
*四*:过期字典的操作命令函数
以下对其中的主要函数进行分析:
数据库结构:
//数据库 结构(
typedef struct redisDb {
dict *dict; //保存着数据库的所有键值对 的字典(该属性也被称为键空间:key space) /* The keyspace for this DB */
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 */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; //数据库号码
long long avg_ttl; /* Average TTL, just for stats */
} redisDb;
数据库的API函数:
/*
* 从数据库 db 中取出键 key 的值(对象)
*
* 如果 key 的值存在,那么返回该值;否则ÿ