文章目录
前言
从本篇文章开始会持续更新有关"redis数据结构源码"的分析。[分析的源码是redis7.2.2版本的,有时候会结合之前的版本]。由于能力有限,有些地方可能有些错误,还望指正。
在分析"intset"的源码的发现。在7.2.2版本,数据类型"set"的底层编码多了一种"listpack",但是之前的版本并没有。本着严谨的态度重新查看了源码以及配置文件,并作出相应的修改。主要修改的地方就是各个版本的数据类型和底层编码的对应图以及编码之间的阈值。
Type && Encoding
redis的每种数据结构都被封装在"redisObject"中,先来看一下"redisObject"长什么样子。
struct redisObject {
unsigned type:4;//表示数据结构的类型,占4bits
unsigned encoding:4;//数据结构底层使用的编码,占4bits
unsigned lru:LRU_BITS; //用于LRU或者LFU内存淘汰算法,占24bits
int refcount;//引用计数,占4bytes,引用计数变为0对象被销毁,内存被回收
void *ptr;//指向具体的数据,占8bytes
};
接下来看一下"type"都有哪些[以下是五种基本的数据结构]
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
接下来看一下数据结构对应的"encoding"
redis在3.2版本时引入了"quicklist"[也就是linkedlist+ziplist]
redis在5.0版本引入"listpack"
- 虽然5.0版本引入了"listpack"解决了"ziplist"级联更新的问题,但是hash和zset结构使用的仍然是ziplist。listpack目前只使用在新增加的Stream数据结构中。
redis在7版本将"ziplist"替换为"listpack"
接下来分析"sds"的源码
sds
首先看一下sds的结构
redis-7.2.2\src\sds.h
typedef char * sds;//sds的本质就是char*指向一块连续的内存
sds分为“sdshdr5”、“sdshdr8”、“sdshdr16”、“sdshdr32”、“sdshdr64”五种结构。其中"sdshdr5"从未使用过。
/* Note: sdshdr5 is never used, we just access the flags byte directly.However is here to document the layout of type 5 SDS strings. */
//sdshdr5从未被使用过,只是用它来直接访问flags字节
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; //1byte
uint8_t alloc;//1byte,不包括头部和终止符
unsigned char flags; /* 3 lsb of type, 5 unused bits 1byte*/
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used 2byte*/
uint16_t alloc; /* excluding the header and null terminator 2byte*/
unsigned char flags; /* 3 lsb of type, 5 unused bits 1byte*/
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used 4byte*/
uint32_t alloc; /* excluding the header and null terminator 4byte*/
unsigned char flags; /* 3 lsb of type, 5 unused bits 1byte*/
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used 8byte*/
uint64_t alloc; /* excluding the header and null terminator 8byte*/
unsigned char flags; /* 3 lsb of type, 5 unused bits 1byte*/
char buf[];
};
以上几种结构的布局很相似都是包含"len\alloc\flags\buf"不同的是记录“len\alloc”的字节数不相同。
其中flags的类型如下
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
encoding
sds底层有三种编码方式
redis-7.2.2\src\server.h
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
接下来依次看一下编码方式的选择
createStringObject
[redis-7.2.2\src\object.c]
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char