Redis源码研究之底层数据结构
2018-04-25 本文已影响23人
wenmingxing
本文主要介绍Redis的几种底层数据结构的数据结构部分,其接口部分以后会分别说明。
建议阅读:
1、Redis的几种数据结构的理论说明见:Redis中的对象底层实现。
I、dict
字典是数据库最基本的数据类型,因为数据库几乎都是以key-value形式存储的。
// 字典数据结构,Redis 的所有键值对都会存储在这里。其中包含两个哈希表,为了应对rehash。
/*src/dict.h/dict*/
typedef struct dict {
// 哈希表的类型,包括哈希函数,比较函数,键值的内存释放函数
dictType *type;
// 存储一些额外的数据
void *privdata;
// 两个哈希表,ht[1]用于完成rehash
dictht ht[2];
// 哈希表重置下标,指定的是哈希数组的数组下标
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
// 绑定到哈希表的迭代器个数
int iterators; /* number of iterators currently running */
} dict;
II、redisObject
在Redis的数据库存储结构中,每个value都会被包装为一个redisObject(其中包含了指定value的类型,编码方式等属性):
/*src/redis.h/redisObject*/
typedef struct redisObject {
// 刚刚好32 bits
// 对象的类型,字符串/列表/集合/哈希表
unsigned type:4;
// 编码的方式,Redis 为了节省空间,提供多种方式来保存一个数据
// 譬如:“123456789” 会被存储为整数123456789
unsigned encoding:4;
// 当内存紧张,淘汰数据的时候用到
unsigned lru:22; /* lru time (relative to server.lruclock) */
// 引用计数,用于整型字符串,为节省空间实现了共享内存
int refcount;
// 数据指针,指向实际的value
void *ptr;
} robj;
III、zset
zset为有序集合,主要为一个skiplist+dict,其是一种AVL树的替代品,实现简单:
/*src/redis.h/zset*/
typedef struct zset {
// 哈希表
dict *dict; //为了在O(1)时间查找
// 跳表
zskiplist *zsl; //为了有序,并顺序查找
} zset;
/* src/redis.h/zskiplist */
typedef struct zskiplist {
// 表头节点和表尾节点
struct zskiplistNode *header, *tail;
// 表中节点的数量
unsigned long length;
// 表中层数最大的节点的层数
int level;
} zskiplist;
/* ZSETs use a specialized version of Skiplists */
/* src/redis.h/zskiplistNode */
typedef struct zskiplistNode {
// 成员对象
robj *obj;
// 分值
double score;
// 后退指针
struct zskiplistNode *backward;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 跨度
unsigned int span;
} level[];
} zskiplistNode;
IV、 adlist
一个双向链表结构:
/*src/adlist.h/list*/
typedef struct list {
// 头指针
listNode *head;
// 尾指针
listNode *tail;
// 数据拷贝函数指针
void *(*dup)(void *ptr);
// 析构函数指针
void (*free)(void *ptr);
// 数据比较指针
int (*match)(void *ptr, void *key);
// 链表长度
unsigned long len;
} list;
V、ziplist
为了优化内存而实现的压缩链表,其实是一个数组,这样能快速的导入到CPU cache中:
/* 保存 ziplist 节点信息的结构 */
/*src/ziplist.c/zlentry*/
typedef struct zlentry {
// prevrawlen :前置节点的长度
// prevrawlensize :编码 prevrawlen 所需的字节大小
unsigned int prevrawlensize, prevrawlen;
// len :当前节点值的长度
// lensize :编码 len 所需的字节大小
unsigned int lensize, len;
// 当前节点 header 的大小
// 等于 prevrawlensize + lensize
unsigned int headersize;
// 当前节点值所使用的编码类型
unsigned char encoding;
// 指向当前节点的指针
unsigned char *p;
} zlentry;
VI、intset
表示整数集合:
/*src/intset.h/intset*/
typedef struct intset {
// 每个整数的类型
uint32_t encoding;
// intset 长度
uint32_t length;
// 整数数组
int8_t contents[];
} intset;
VII、sds
二进制安全的动态字符串:
/*src/sds.h/sds*/
typedef char *sds;
【参考】
[1] 《Redis设计与实现》
[2] 《Redis源码日志》