Redis 五种数据结构

2021-03-14  本文已影响0人  猿来是八阿哥

一、SDS 简单动态字符串

Redis 在存储 可能发生改变、非字面量 的字符串时,都会使用 SDS,比如:redis 的 key 和 value 等。

1. 结构体定义
struct sdshdr{
    // 字符串真是长度
    int len;
    // buf 中空闲的长度
    int free;
    // 存储字符串的 char 数组
    char buf[];
}
2. SDS 和 C 字符串的区别

二、链表

redis 通过链表,实现了 队列 相关的操作。

1. 结构体
typedef struct listNode {
    // 前置节点
    struct listNode *prev;
    // 后置节点
    struct listNode *next;
    // 节点值
    void *value;
} listNode;
typedef stuct list {
    // 头结点
    listNode *head;
    // 尾节点
    listNode *tail;
    // 链表长度
    unsigned long len;
    // 节点复制函数
    void *(*dup)(void *ptr);
    // 节点释放函数
    void (*free)(void *ptr);
    // 节点值对比函数
    int (*match)(void *ptr, void *key);
} list;
2. 特点
3. 部分API
函数 作用 时间复杂度
listLength 获取链表长度 0(1)
listFirst 获取链表头节点 0(1)
listLast 获取链表尾节点 0(1)
listPrevNode 获取指定节点的前置节点 0(1)
listNextNode 获取指定节点的后置节点 0(1)
listNodeValue 获取指定节点的值 0(1)
listAddNodeHead 设置新的头节点 0(1)
listAddNodeTail 设置新的尾节点 0(1)

三、字典

详见:
redis 源码分析(一)HashTable 上篇
redis 源码分析(二)HashTable 下篇

四、跳跃表

redis 的有序结合,当有序集合的 元素数量比较多 或者 元素的值是比较长的字符串 时,redis 使用跳跃表来实现 有序集合

1. 结构体
typedef struct zskiplistNode {
    // 前一个节点的指针
    struct zskiplistNode *backword;
    // 当前节点的分值
    double score;
    // 当前节点的值对象
    robj *obj;
    struct zskiplistLevel {
        // 下一个节点的指针
        zskiplistNode *forword;
        // 到下一个节点的跨度
        unsigned int span;
    } level[];
    
} zskiplistNode;
typedef struct zskiplist {
    // 跳跃表头节点
    struct zskiplistNode *head;
    // 跳跃表尾节点
    struct zskiplistNode *tail;
    // 跳跃表的长度
    unsigned long length;
    // 跳跃表中层数最大的节点的层数
    int level;
} zskiplist;
2. 有序集合的 查找
typedef struct DoubleLinkedListNode {
    // 后一个节点的指针
    struct DoubleLinkedListNode *next;
    // 前一个节点的指针
    struct DoubleLinkedListNode *prev;
    // 当前节点的分值
    double score;
    // 当前节点的值对象
    robj *obj;
} DoubleLinkedListNode;

如上图,假设一个跳跃表存储了 a1 到 a100001 这 10 万个元素,他们的分数分别是 1.0 到 100001.0

3. 其他有序集合操作

其他有序集合操作,像 范围查找(正向、逆向)是否存在 等,其实都是基于 查找 的结果,利用 前置、后置指针 进行的遍历。

五、整数集合

当集合中的元素都是整数时,Redis 会使用 整数集合 作为集合的底层实现

1. 结构体
typedef struct intset {
    // 编码方式
    uint32_t encoding;
    // 集合长度
    uint32_t length;
    // 集合元素
    int8_t contents[];
} intset;

其中,encoding 指明了 contents 中的数据类型:

2. 编码升级

当一个编码为更小范围,如 INTSET_ENC_INT16 ,的整数集合,要添加一个更大范围,如 INTSET_ENC_INT32,的元素时,整体集合的编码方式需要升级。具体思路是:

3. 升级的好处
4. 不存在降级

升级后的整数集合,并不会因为,唯一一个更大范围的元素被删除,就进行降级。

上一篇 下一篇

猜你喜欢

热点阅读