都说redis性能高是因为作者几乎把操作系统和c语言的能力压榨到了极致,所以瞥了一眼源代码。有缘就持续更新
底层数据结构
字符串
redis基本数据类型之一,也是最广泛使用的数据类型,所以redis自动构建了名为动态字符串(SDS)的抽象类型。用于存储键值对(字符串对象,列表对象(列表键))和AOF缓冲区
/*
* 保存字符串对象的结构
*/
struct sdshdr {
// buf 中已占用空间的长度
int len;
// buf 中剩余可用空间的长度
int free;
// 数据空间
char buf[];
};
redis的字符串封装成一个结构体,具有以下功能:
- 快速计算长度
- 自动扩容
- 自动回收空间
- 二进制安全(以处理二进制的方式处理字符)
- 兼容c字符串
链表
用于列表键的底层实现,当一个列表键包含了数量比较多的元素,或者元素字符串的长队比较长,就用链表实现。此外,发布订阅,慢查询,监视器也用到。。。
*
* 双端链表节点
*/
typedef struct listNode {
// 前置节点
struct listNode *prev;
// 后置节点
struct listNode *next;
// 节点的值
void *value;
} listNode;
/*
* 双端链表迭代器
*/
typedef struct listIter {
// 当前迭代到的节点
listNode *next;
// 迭代的方向
int direction;
} listIter;
/*
* 双端链表结构
*/
typedef struct list {
// 表头节点
listNode *head;
// 表尾节点
listNode *tail;
// 节点值复制函数
void *(*dup)(void *ptr);
// 节点值释放函数
void (*free)(void *ptr);
// 节点值对比函数
int (*match)(void *ptr, void *key);
// 链表所包含的节点数量
unsigned long len;
} list;
- 广泛用于redis各种功能,如列表建,发布与订阅,慢查询,监视器
- 双端链表,无环链表,提供头尾节点指针
- 数据类型未void*,可以保存不同类型的数据
字典
/*
* 哈希表节点
*/
typedef struct dictEntry {
// 键
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 指向下个哈希表节点,形成链表
struct dictEntry *next;
} dictEntry;
/*
* 哈希表
*
* 每个字典都使用两个哈希表,从而实现渐进式 rehash 。
*/
typedef struct dictht {
// 哈希表数组
dictEntry **table;
// 哈希表大小
unsigned long size;
// 哈希表大小掩码,用于计算索引值
// 总是等于 size - 1
unsigned long sizemask;
// 该哈希表已有节点的数量
unsigned long used;
} dictht;
/*
* 字典
*/
typedef struct dict {
// 类型特定函数
dictType *type;
// 私有数据
void *privdata;
// 哈希表
dictht ht[2];
// rehash 索引
// 当 rehash 不在进行时,值为 -1
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
// 目前正在运行的安全迭代器的数量
int iterators; /* number of iterators currently running */
} dict;
- hash表
- 链式地址解决冲突
- 根绝负载因子定扩容
- 渐进式rehash(操作驱动):update和put都插入到新的ht上,get先去检测ht[0],找到的话rehash到ht[1]上,找不到去检测ht[1]
跳跃表
每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的,查找时间复杂度为平均log(n),最坏O(n)。是redis中底层有序集合键的实现。