【Redis】Redis数据类型底层结构

参考:《Redis设计与实现》

RedisObject

Redis底层的所有数据结构:都是基于对象的;RedisObject

  • 类型;
  • 编码;
  • 指向实际数据的指针;
typedef struct redisObject{
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 指向底层实现数据结构的指针
    void *ptr;
}
  • type:记录是什么类型(String,List,Hah表,set,Zset)

  • encoding:对象使用的编码;

  • *ptr:数据指针(比如String,ptr就指向了一个SDS动态字符串)

一个String类型数据如下图:

【Redis】Redis数据类型底层结构

String

Redis的字符串底层使用SDS(动态字符串),而不是C语言的字符串;

// SDS的定义
strcut sdshdr{
    // 记录字符串长度
    int len;
    // 记录未使用的buf;
    int free;
    // 字符串数组,存放实际的字符串
    char buf[];
}

【Redis】Redis数据类型底层结构

为什么不使用C的字符串?

C字符串SDS
获取字符串长度复杂度:O(N)获取字符串长度复杂度:O(1)
不安全,可能缓冲区溢出安全,不会溢出,不会泄露
修改字符串,必须执行N次内存的重新分配修改字符串,除非是全部改需要N次内存分配

【Redis】Redis数据类型底层结构

跳跃表

是一种有序数据结构,通过每个节点中维持多个指向其他节点指针,达到快速访问;

多个节点指针:意味着跳跃表的层数;

【Redis】Redis数据类型底层结构

  • 层:每个节点的多个指针,是一个指针集合List;同层之前指针关联;
  • 前进指针:每一层的从头指向后面的指针;
  • 跨度:记录两个节点间的距离;
  • 后退指针:每个节点,只有一个后退指针,也就是全部后退指针相当于一个单链表;
  • 分值Score:跳跃表,按照Score大小排序;
  • 成员:也就是此节点的value;

复杂度:增删改查O(logn),最坏O(n)

结构源码:

// zset结构
typedef struct zskiplist{
    // 头节点,尾节点
    structz skiplisNode *header , *tail;
    // 节点数量
    unsigned long length;
    // 最大的节点层数;
    int level;
}

// 跳跃表的结构
typedef struct skiplisNode{
	// 层:是一个节点集合
    struct zskiplistLevel{
        // 前进指针
        struct zskiplistNode *forward;
        // 跨度
        unsigned int span;
    } level[];
	// 后退指针
    struct zskiplistNode *backward;
    // 分值
    double score;
    // 成员对象
    robj *obj;

}

Hash表

RedisObject中的ptr指针,指向的就是哈希对象:

typedef struct dict{
    // 指向对哈希表操作的函数
    dictType *type;
    // 私有数据
    void *privdata;
    // ht[1]指向真正的哈希表结构,ht[2]用于备用扩容,指向正在扩容的哈希表
    dictht ht[2];
    // 是否在rehash:如果不在rehash,此值为-1;
    int trehashidx;
}

哈希表:

typedef struct dictht{
    // 哈希数组
    dictEntry **table;
    // 哈希表大小
    unsigned long size;
    // 记录尾部:size-1
    unsigned long sizemask;
    // 已使用的大小
    unsigned long used;
}

哈希节点对象:

typedef struct dictEntry{
    // key
    void *key;
    // value
    union{
        void *val;
        unit64_tu64;
        int64_ts64;
    } v;
    // next指针
    struct dictEntry *next;
} dictEntry;

【Redis】Redis数据类型底层结构

  • 上面的整个哈希表,出现了哈希冲突,使用链地址法解决哈希冲突;

哈希表的扩容

【Redis】Redis数据类型底层结构