Redis学习笔记之底层数据结构
2017-04-11 10:36
459 查看
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的长度是根据值的大小确定的,所以当更新前一节点的长度时,这个值所占的字节数可能会引起改变,因此需要更新更新节点的后续节点。如果更新节点的后续节点全部都需要更新,那么效率会很低,但是需要全部节点更新的概率极低,因此不需要考虑对效率的影响。
定义:
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学习笔记-Redis内部数据结构
- Redis学习总结_1_底层数据结构
- 2.redis学习笔记:redis List底层数据实现(通用双端链表)
- 数据结构学习笔记一:数据结构基础
- 数据结构——链表学习笔记
- Cocoa2d-X学习笔记第三篇:基础数据结构
- Python简明教程学习笔记4--数据结构
- 数据结构 学习笔记之:顺序栈的C语言实现
- JAVA 数据结构与算法学习笔记一(转载)
- siebel学习笔记-数据结构层次,BC之间的关系
- 我的OpenCV学习笔记(24):详细讨论OpenCV中的数据结构
- 二 redis学习笔记之数据类型
- 【数据结构】单链表学习笔记
- 数据结构(殷人琨版)学习笔记之单链表
- NSGA 2 学习笔记 -- 数据结构
- C#2005 .NET3.0高级编程学习笔记————类和结构,类的数据成员,类的函数成员(方法、属性)
- 二 redis学习笔记之数据类型
- Python学习笔记(1)--数据结构
- Redis学习笔记~五大数据结果的测试
- opencv学习笔记[9]:Opencv的基本数据类型和矩阵结构