Redis的数据类型(三)SDS篇

SDS是redis的String类型的底层数据结构,属于自定义的数据结构,即基于C的 string 聚合的一个结构。

SDS是redis有较大改动的一个数据结构,接下来就以这两个版本进行讲解。

一、3.2版本前的SDS

struct sdshdr {
    //用于记录buf数组中使用的字节的数目,和SDS存储的字符串的长度相等
    int len;
    //用于记录buf数组中没有使用的字节的数目 
    int free;
    //字节数组,用于储存字符串
    char buf[]; //buf的大小等于len+free+1,其中多余的1个字节是用来存储’\0’的
};

C与SDS的字符数组的最后一个元素总是空字符 '\0',即表示停止符号 。

1. SDS与C中的string结构的区别

  1. 获取字符串长度,C中没有存放长度信息,所以需遍历才能知道字符串长度O(n);SDS则是直接存放着长度信息O(1)

  2. 字符串变更的变化

    1. C对字符串的更变都需改变char[]数组的空间大小,即先新建一个,在将旧值copy过来。

    2. 对 SDS 进行修改之后,会有预分配空间与惰性释放机制。

      1. 如果 当len的值小于1M,则会分配free与len相同的空间。例:len长度修改后是10字节,那么也会分配10字节的空间给free,所以字节的总长度就是 10(len) + 10(free) + 1(存储\0)。

      2. 当len的值大于1M,则固定分配1M空间给free。

      3. 缩短SDS进行惰性释放,程序不会立即释放多余的空间,会将这些空间保留下来,以备将来使用。下图就是执行sdstrim的变化

  3. C字符串编码是ASCII码,末尾以\0结束,即空字符串,因为这个缺陷,导致图片、音视频中的文件存有空字符串,会让C以为程序结束,限制C只能存文本数据;SDS是二进制存储数据,可以存储任意数据。

  4. SDS总会在buf[]数组分配空间时,多分配一个字节来存储空字符(’\0’),便于重用C中的函数。

注:在《redisObject篇》文章中提到过,如果sds是embstr,那么字符串存储的长度不能超过44字节,数据类型使用的是sdshdr8,sdshdr8占用的空间:1(len)+1(alloc)+1(flags)+1(buf[])= 4byte,不过这是3.2版本后的。3.2版本前长度不能超过39字节,因为sdshdr占用空间:4(len)+ 4(free)+1(buf[])= 9byte

 二、3.2及以后的sds

先来看看数据结构上的变化

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; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
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[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

len表示已被使用的长度,alloc表示总长度,flags表示低3位存储类型,高5位预留,buf[]还是存内容。所以可以得出 sds 剩余可用长度, free = alloc - len

Redis 将 SDS 划分为 5 种类型,而且使用时会根据字符串的长度,使用不同的数据结构进行存储。

sdshdr5:长度小于 1 字节;sdshdr8:长度 1 字节;sdshdr16:长度 2 字节;sdshdr32:长度 4 字节;sdshdr64:长度 8 字节。

其中数据中的特性与3.2之前相比有2点上有变化,其他都一致

1. 扩容规则

  1. sds长度修改后 小于 1M,则 alloc = len * 2, 两倍扩容

  2. sds长度修改后 大于 1M, 则 alloc += 1M, 每次扩容 1M

2. 缩容:SDS 的空间从 alloc 缩容到 len 长度,即 alloc - len = 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值