首页 > 代码库 > Redis学习笔记之底层数据结构

Redis学习笔记之底层数据结构

1.简单动态字符串(simple dynamic string, SDS)

  定义:

  struct sdshdr {

         int len;//记录buf中使用的字节数量

         int free;//记录buf中未使用的字节数量

         char buf[];//字节数组,用于保存字符串

         //buf字节数组以’\0’结束,但是’\0’不计算在len之中,对于用户来说是透明的

  }

  SDS与C中的字符串相比,优势在于:

         O(1)时间复杂度获取字符串长度;杜绝缓冲区溢出(每次修改buf时会检查空间是否充足);提高修改字符串的效率(空间预分配和惰性释放空间,客观的说会浪费一定的空间,空间换时间);二进制安全(支持字符串中有空字符串);

2.链表和链表节点

  定义:双向链表的节点

  typedef struct listNode {

           struct listNode *prev;//前置节点

           struct listNode *next;//后置节点

           void *value;//节点的值

  } listNode;

  用如下结构来管理链表:

  typedef struct list {

           listNode *head;//链表头

           listNode *tail;//链表尾

           unsigned long len;//链表节点数

           void *(*dup) (void *ptr);//节点值复制函数

           void (*free) (void *ptr);//节点值释放函数

           int (*match) (void *ptr, void *key);//节点值对比函数

  } list;

  优点:很多值或者节点都存储起来了,访问节点长度、尾节点等时间复杂度降低,多态(value的类型是void*)

3.字典——哈希键的底层实现之一

  哈希表结构:

  typedef struct dictht {

           dictEntry **table;//哈希表数组

           unsigned long size;//哈希表大小

           unsigned long sizemask;//哈希表大小掩码

           unsigned long used;//哈希表已有节点数量

  } dictht;

  哈希表节点结构:

  type struct dictEntry {

           void *key;//

           union {//

                  void *val;

                  unit64_tu64;

                  int64_ts64;

           } v;

           struct dictEntry *next;//指向下个哈希表节点,形成链表

  } dictEntry;

  字典结构:

  typedef struct dict {

                dictType *type;//字典类型,为创建多态字典

                void *privdata;//保存需要传给类型特性函数的参数

                dictht ht[2];//字典只使用ht[0],rehash时才使用ht[1]

                int rehashidx;//记录了rehash的进度,默认是-1

  } dict;

  Redis的哈希表使用链地址法,rehash时将ht[0]上的值rehash到ht[1]上(涉及ht[1]的空间分配大小问题),然后把ht[1]作为ht[0],把ht[1]设置为空白哈希表

  渐进式rehash:在每一次增删改操作的时候,将ht[0]上对应的键值对写到ht[1]上,在某个时间点时,ht[0]上的值全部写到ht[1]上

4.跳跃表

  实现:主要由两个结构组成,zskiplist用于保存跳跃表信息,zskiplistNode用于表示跳跃表节点;每一个zskiplistNode有若干(1~32随机)层(每一层都有前进指针和跨度),还有后退指针、分值、成员对象obj;成员对象唯一,分值可相同;节点按照分值的大小进行排序,分值相同时按照成员对象的大小排序。

  用处:有序集合、集群节点中用作内部数据结构

5.整数集合

  定义:

  typedef struct intset {

                uint32_t encoding;

                uint32_t length;

                int8_t contents[];

  } intset;

  重点:整数集合升级,contents中保存的数据可能是16位、32位、64位的,会根据存入数据的位数对集合进行升级;不支持降级

  用处:集合元素全是整数的情况

6.压缩列表——列表键和哈希键的底层实现之一

  结构:zlbytes zltail zllen entry1 entry2…entryN zlend

  zlbytes:uint32_t,记录整个压缩列表的字节数

  zltail:uint32_t,记录压缩列表尾节点距离列表首地址有多少个字节

  zllen:uint16_t,记录压缩列表包含的节点数量

  entryN:压缩列表包含的节点

          previous_entry_length   前一节点的大小

          encoding   记录了节点content所保存的数据的类型和值

          content   节点的值

  zlend:uint8_t,特殊值0XFF,用于标记压缩列表的末端

  连锁更新:节点中previous_entry_length的长度是根据值的大小确定的,所以当更新前一节点的长度时,这个值所占的字节数可能会引起改变,因此需要更新更新节点的后续节点。如果更新节点的后续节点全部都需要更新,那么效率会很低,但是需要全部节点更新的概率极低,因此不需要考虑对效率的影响。

Redis学习笔记之底层数据结构