范围:
本文主要介绍redis底层的7种数据结构,它们是redis对象实现的基础
- 简单动态字符串
应用:简单动态字符串作为redis string 的底层实现
string 与 C 语言的string字符串部分功能是相同,相关区别如下:
项目 | SDS | C字符串 |
---|---|---|
获取字符串长度 | O(1) | O(N) |
字符串拼接时缓冲区溢出处理 | 通过free与当前待拼接的串作比较查看是否内存是否足够。如果不够会做自动内存再分配。2*n(n为扩充之后的字符串长度) | |
惰性释放内存 | 对字符串执行trim操作之后不会立即将多出来的内存释放。而是记录在free里面待使用 |
2. 双端链表
数据结构:
/*
* 双端链表结构
*/
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;
特点:
查找给定节点的前一个节点,后一个节点复杂度为O(1),往表头或者表尾插入节点复杂度为O(1).
删除给定节点,遍历给定节点的复杂度为O(N)
应用范围:
列表键,发布与订阅,慢查询,监视器
3. 字典
应用范围:
计算hash键:当被用来作为数据库底层实现或者哈希键的底层实现时,用murmurhash2算法
解决冲突:
使用链地址法(seperate chaining),将冲突键放在采用一个链表串起来
当字典超过负载因子时,采用rehash算法:
应用场景:当hash表保存的哈希键值对太多或者太少时,需要对当前的哈希表重新进行扩展或者收缩
扩充后的大小为: 第一个大于或者等于 use * 2(2^n) 的值
收缩后的大小为: 第一个大于或者等于 use 的值
渐进式rehash(分成多次将键值对由ht[0]移到ht[1],结束的标志为rehashidx=-1 --rehash时使用)
step:
1.为ht[1]分配空间(分配方式见rehash扩展or收缩算法),让字典同时持有ht[0]和ht[1]
2.在rehash期间,每次从ht[0]移动数据到ht[1],rehashidx++,
3.每次对字典进行查找操作,现在ht[0]中查找是否存在该键值对。如果找不到查看是否进行rehash操作,如果正在进行rehash操作会继续在ht[1]中查找
4.新增键值时,只会在ht[1]中新增。确保ht[0]处于收敛状态
5.当ht[0]的use=0时,表示rehash操作已经完成。将ht[1]赋值给ht[0]。释放ht[1]内存
- 跳跃表
应用范围:
有序集合的底层实现,集群节点中使用
数据结构
/*
* 跳跃表节点
*/
typedef struct zskiplistNode {
// 成员对象
robj *obj;
// 分值,用于排序
double score;
// 后退指针
struct zskiplistNode *backward;
// 层,在生成一个节点时按照幂等定律随机生成1-32的层,一个节点包含的层数越多,被访问是越快
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 跨度,举例其他节点的跨度,用来进行排位
unsigned int span;
} level[];
} zskiplistNode;
/*
* 跳跃表
*/
typedef struct zskiplist {
// 表头节点和表尾节点
struct zskiplistNode *header, *tail;
// 表中节点的数量
unsigned long length;
// 表中层数最大的节点的层数
int level;
} zskiplist;
5. 整数集合
应用:
用来存放元素均为整数的数据结构
集合键的底层实现
数据结构:
typedef struct intset {
// 编码方式,决定了content数组内容的大小
uint32_t encoding;
// 集合包含的元素数量
uint32_t length;
// 保存元素的数组,数组中元素的排序方式是有序的。因此查找元素的效率为logN
int8_t contents[];
} intset;
- 压缩列表
应用场景
列表键和哈希键的底层实现之一。当列表或者哈希表中包含的键值对是整数或者长度比较小的字符串时,会采用压缩列表作为底层实现之一
目的是为了节约内存