Redis 5.0数据结构之SDS简单动态字符串实现源码详解

概述

Redis基于C语言实现,但Redis并没有采用C语言中传统的字符串表示,而是特别构建了一种叫做简单动态字符串(simple dynamic string)的数据结构,简称SDS,SDS是Redis中默认的字符串表示。

C字符串只在无须对字符串值修改的场景下作为字面量使用,如日志打印,而在字符串值可能被修改的场景下,均使用SDS表示字符串值。

SDS的实现代码均在sds.h和sds.c中。

本文使用的源码版本为Redis5.0,SDS的数据结构在Redis 3.2中有较大的改动,3.2版本以前的SDS数据结构定义相较简单,源码如下:

struct sdshdr {
   
    unsigned int len;   //表示buf[]数组中已使用的长度
    unsigned int free;  //表示buf[]数组中未使用的长度
    char buf[];         //用于存储字符串的字节数组buf[]
};

本文只讨论新版本Redis的SDS数据结构、初始化和扩容等。

SDS数据结构

SDS结构源码

SDS的数据结构在sds.h文件内定义,总共定义了五种类型的SDS,源码如下:

// 五种SDS类型分别对应五种不同的初始长度 其中sdshdr5没有投入过使用

struct __attribute__((__packed__)) sdshdr5 {
   
  unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
  char buf[];
};
struct __attribute__((__packed__)) sdshdr8 {
   
  //buf数组中已被使用的长度
  uint8_t len;         /* used */
  //buf数组的总长度
  uint8_t alloc;       /* excluding the header and null terminator */
  // sds类型标识
  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[];
};

数据结构属性说明

五种SDS类型大同小异,主要区别体现在有效位不同,SDS结构体定义总共有以下四个字段:

  • buf[]:buf数组是一个字符数组,但在设计上被看作字节数组,后文会解释,用于保存字符串。
  • len:表示buf数组中当前已被使用的长度。
  • alloc:表示分配给buf数组的总长度,实际的值为buf[]的总长度减一,因为与C语言传统字符串一样,最后一个字节都保存了空字符’\0’,该位不实际保存字符串。
  • flags:表示SDS是哪种类型的,因为只有五种类型的SDS,所以实际只有三位有效位,flag从sdshrd5到sdshdr64的取值分别为0~4。

其中uint8_t实际对应的数据类型就是unsigned char,表示当前SDS有八位有效位,uint16_t
对应的就是unsigned short,其他类型同理。

SDS结构图示

在这里插入图片描述

SDS的初始化流程

此部分展示代码均定义在sds.c文件中。

创建SDS时首先调用sdsnew()函数,sdsnew()函数源码如下:

sds sdsnew(const char *init) {
   
    size_t initlen = (init == NULL) ? 0 : strlen(init);
    return sdsnewlen(init, initlen);
}

函数的入参为初始化字符串,首先函数计算了传入字符串的长度,随后将初始字符串和该字符串长度作为参数传递,调用sdsnewlen()函数。

sdsnewlen()函数源码如下:

sds sdsnewlen(const void *init, size_t initlen) {
   
	//首先定义了两个指针 其中sh指向整个sds的首地址 s指向buf[]的首地址
    void 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7rulyL1ar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值