1.简单动态字符串(SDS)
在C语言原有的字符串基础上添加了记录字符串长度和空闲长度信息和空间预分配的处理。
记录字符串长度信息,获取字符串长度时间复杂度为O(1)。
杜绝缓冲区溢出,通过拼接字符串前判断SDS是否有足够的内存分配空间,如果不足先进行扩容后再进行字符串拼接。
空间预分配和惰性空间释放减少修改字符串时带来的内存重新分配次数。
二进制安全,通过字符串长度判断该字符串是否已经是结尾,避免C字符串通过/0判断字符串结尾,可以用来保存二进制数据。
2.链表
采用双向无环链表的设计,结构中存储了链表的头结点和尾节点以及链表的长度,在获取头结点,尾节点,节点前驱和后继和链表长度时间复杂度均为O(1)。
3.字典
内部维护一个长度为2哈希表数据,和指向类型特定函数和私有数据的指针,以及一个trehashidx字段,用于哈希表扩容时候记录扩容索引位置,没有进行扩容时候为-1。
哈希表的构造与JAVA中HashMap的构造类似,通过哈希算法与数组长度-1进行与运算计算出键值对在数组中的具体位置,每个数组的索引位置上都维护了一个单向链表,新添加的数据会放在单向链表的表头,并将next指针指向之前的表头。
随着操作的不断执行,哈希表保存的键值对会逐渐地增多或者减少,为了让哈希表的负载因子维持在一个合理范围之内,当哈希表保存的键值对数量太多或者太少的时候,程序需要对哈希表的大小进行相应的扩展或者收缩,即rehash。
长度为2的哈希表数据ht[]会把ht[1]进行扩展操作,扩展为原有使用长度的2次幂(2次幂有两个好处,避免与哈希值相与的最大索引值(哈希表数组长度-1)的二进制数尾数为0,导致相与结果的尾数均为0,从而导致数组中二进制尾数为1,即索引值为奇数的位置空闲;扩容后对原有位置的索引值重新计算只需判断左边新增加的位是0还是1,从而计算新的索引值,避免重新进行哈希碰撞)
ht[0]会渐进式得将原有的键值对转移到ht[1]中,并将当前转移的索引位置记录在trehashidx字段中,当全部转移完毕ht[0]和ht[1]交换位置,trehashidx重置为-1,为下次rehash做准备。
4.跳跃表
当数据量越大时候,使其查找复杂度为O(logN)。
5.整数集合
通过encoding、length、contents[]三个字段结构表示一个整数集合,它可以保存int16_t,int_32_t和int64_t的整数值,具体类型通过encoding字段决定,当我们将一个新元素添加时,如果新元素类型比整数集合现有类型都要长的时候,整数集合需要先进行升级。原有整数数据升级为新的encoding整数类型,然后添加新元素,且整数集合不支持降级操作。
6.压缩列表
zlbytes 记录整个压缩列表占用内存字节数
zltail 记录压缩列表表尾列表节点距离压缩列表的起始地址有多少字节
zllen 记录压缩列表包含的节点数
entryX 列表节点(previous_entry_lenth 上一节点内存字节长度 encoding 节点编码 content 节点数据)
zlend 特殊值 0XFF 用于标记压缩列表的末端
7.对象
type字段记录了redis对象提供的对象的基本类型(STRING,LIST,HASH,SET,ZSET)
encoding 记录了对象所使用的编码,通过type和encoding可以确定redis底层的具体实现
ptr指针指向一个具体的实现
随着操作,数据的增加或者减少,编码或底层实现也会发生具体的变化,发生变化的阈值可通过参数具体配置。