<返回更多

redis sds 介绍

2020-01-09    
加入收藏

redis sds 介绍

 

字符串是redis中最为常见的存储数据存储类型,其底层实现是简单的动态字符串sds(simple dynamic string),可以修改的字符串。

sds 介绍

sds本质上是 char *,因为有了表头sdshdr结构的存在,所以sds比传统c字符串在某些方面更加优秀,并且能够兼容传统C字符串。

sds采用预分配存储空间的方式来减少内存的频繁分配,惰性空间释放的策略来优化sds的缩短操作,降低内存重新分配的概率。

redis 的字符串实现在sds.h sds.c 中。

typedef char *sds;/* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */struct __attribute__ ((__packed__)) sdshdr5 {    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */    char buf[];};

上述代码来自sds.h

sds 数据存储结构

我们摘取其中一个sdshdr32的数据结构来分析redis中sdsh的数据存储结构

struct __attribute__ ((__packed__)) sdshdr32 {    uint32_t len; /* used */    uint32_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};

sdsnew(const char *init) 会根据init数据的长度去分配内存,分配内存的大小为s_malloc(hdrlen+initlen+1) 其中 hdrlen 为sdshdr* 的结构体的大小,initlen为传入的init 变量的数据大小或者为sdsnewlen(const void *init, size_t initlen) 传入的initlen 的大小。

sdsnewlen 方法会根据initlen 的数值去通过sdsReqType去确定type的类型,然后根据返回的type数值再通过sdsHdrSize(type)获得hdrlen。 具体代码实现可参见sds.c文件。

当sds s = sdsnew()之后,其中s的位置并不是内存的起始位置, sh = s_malloc(hdrlen+initlen+1), 而是偏移了sh + hdrlen 后的位置 s = (char*)sh+hdrlen。

sds 有一个关键的宏SDS_HDR 定义如下

#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))

其中SDS_HDR 能够将s 的指针位置减去 sdshdr##T的大小,从而将指针位置指向sdsnew内存分配的起始位置dh,进而去通过sh去操作sdshdr##T的成员变量。其中T取值为(5,8,16,32,64)

    -----------------------------    | len | alloc | flags | buf |    -----------------------------

如上,其中buf位置真正存储了字符数据, 前面十三个位置分别存储了buf相关的sds信息。

整个sds的内存是连续的,统一开辟的。在大多数操作中,buf内的字符串实体才是操作对象。统一开辟内存能通过buf头指针进行寻址,拿到整个struct的指针,而且通过buf的头指针减1直接就能获取flags的值, flags = s[-1]。

更详细的sds的分配可参见sds.c中sdsnewlen的实现部分。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>