redis数据结构---sds

        看过了《redis设计与实现》,了解了redis设计的基本原理。但是三个月之后发现,遗忘了很多,只好重新温习。只是,这次是从redis源码的角度学习的,当然过程中会翻阅《redis设计与实现》这本书,毕竟需要一个框架指导。按照redis源码的阅读顺序,按照从基本到复杂、从redis使用的基本数据结构开始。本文就介绍redis中使用的最常见的数据结构之一---sds(simple dynamic string),当然是从源码的角度进行解释的。大致的原理,读者可以参考《redis设计与实现》第一章。

        redis源码中,关于sds的代码分布在sds.h和sds.c两个文件夹中。本文主要配合源码介绍redis代码中关于sds实现的重要思想。

        sds是基于c语言中的char*实现的,存储的字符串都是char*类型的。这从sds的定义可以看得出来( typedef char* sds;),这可以让redis直接使用c语言的字符串的很多函数,而不必自己实现一些在c语言中已有的函数。

        但是,redis中实现的sds与一般的c语言的字符串又不一样。sds除了存放字符串本身的数据之外,sds还分别存放着字符串相关的信息,如字符串的长度、未使用的空间的长度,同时针对不同的字符串的长度采用五种不同的说明字符串信息的头结构,最大化节约内存;sds使用空间预分配和惰性空间释放策略,减少内存中空间分配的次数,提高该数据库的性能。下面针对redis中使用的五种不同的字符串头结构及其空间预分配和惰性空间释放策略进行介绍。

一、字符串的五种头结构

  //sdshdr5与其他几个header结构体不同,不包含alloc字段,而是用flags的高5位来存储。因此不能为字符串分配空余空间。如果字符串需要动态增长,那么他>  就必然要分配内存才行。所以说,这种类型的sds字符串更适合存储静态的短字符串(长度小于32)
  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[];
  };

        上面列出的五种struct就是redis中的sds使用的五种管理字符串的结构头,现在分别对其中的成员变量做解释。

        uint(8,16,32,64)_t:是已经占用的字节数,就是buf中存放的字符串的长度,不包括结尾的'\0'。

        uint(8,16,32,64)_t:是一共分配的空间的大小,包括使用的和未使用的大小,不包括结尾的'\0'。

### SDS 数据结构概述 SDS (Simple Dynamic String) 是 Redis 中使用的底层动态字符串数据结构。它不仅能够高效地处理字符串操作,还具有动态扩展的能力,从而优化了内存管理效率[^1]。 #### 结构定义与演变 在 Redis 3.2 版本之前,SDS 只有一种固定的数据结构形式;而在 Redis 3.2 版本之后,为了进一步节省内存并提高灵活性,其设计演变为五种不同类型的结构。具体选择哪种结构取决于存储内容的长度以及实际需求。 以下是 SDS 的基本组成要素: - **buf**: 字符数组,用于保存实际的字符数据。 - **len**: 表示当前已占用的空间大小(即有效字节数)。 - **alloc**: 记录分配给 buf 数组的最大容量。 当需要增加或减少字符串中的字符数量时,Redis 能够自动调整 `buf` 的尺寸以适应新的需求[^2]。 #### 动态扩容机制 作为一种支持动态增长特性的容器类型,每当向其中追加新数据而超出原有界限时,系统便会触发重新分配过程——这通常意味着创建更大的缓冲区并将旧有的内容复制过去。值得注意的是,在执行此类操作期间可能会涉及额外开销,但由于采用了预估策略(例如每次扩增一定比例而非单纯按需),因此整体表现依然较为平稳。 ```c // 示例代码展示如何初始化一个简单的sds对象 #include "sds.h" int main() { sds str = sdsempty(); // 创建一个新的空sds实例 str = sdscatprintf(str, "%d bottles of beer on the wall", 99); printf("%s\n", str); return 0; } ``` 上述片段展示了利用 C 编程语言构建基础版别的方法,并通过函数调用来完成特定任务比如拼接字符串等动作。 #### 应用场景分析 由于具备良好的性能特征加上易于维护的优点,使得该技术广泛应用于各种场合之中: 1. **键值对数据库内部表示**:作为核心组件之一参与构成其他复杂数据类型的基础单元; 2. **网络通信协议解析/生成工具包的一部分**:帮助快速组装或者拆分消息体字段; 3. **文件I/O流处理器模块集成选项**:提供便捷途径来进行大块文本资料加载卸载工作流程简化方案等等[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值