Redis5设计与源码分析读后感(二)简单动态字符串SDS
一、引言
学习之前先了解几个概念:
SDS定义:简单动态字符串,Redis的基本数据结构之一,用于储存字符串和整型数据。
二进制安全:C语言中用"\0"表示字符串结束,如果字符串本身就有这个字符,那么此字符串会被阶段,此时为非二进制安全;若通过某种机制保证读写字符串时不损害其内容,则称为二进制安全。
字节对齐:字节按照一定规则在空间上排列。(不按规则排列有些架构CPU进行访问时会引起错误或者影响读取效率)。
PS:如4字节对齐的意思是4字节为一个对齐单位,1字节对齐的意思就是连续存放。
柔性数组:伸缩性数组,大小待定的数组,结构体和地址连续,查找内存更快,不用额外的指针。
二、新旧版本间的字符串结构对比
5.0之前版本的SDS结构


5.0版本的SDS结构
sdshdr5


- flags:低3位表示类型,高5位表示长度
- buf:柔性数组,存放实际内容
sdshdr16
由于sdshdr8、sdshdr16、sdshdr32、sdshdr64结构类似,这里以sdshdr16为例子解析:


- len:表示buf中已占用字节数
- alloc:表示buf中已分配的字节数,不同于free,记录的是为buf分配的总长度
- flags:标识当前结构体的类型,低3位表示类型,高5位闲置预留
- buf:柔性数组,真正储存字符串的数据空间,存放实际内容
三、字符串结构特点
5.0之前版本的SDS结构
- 有单独的统计变量len和free,可以很方便地得到字符串长度。
- 内容存放在柔性数组中,SDS对上层暴露的是直接指向柔性数组buf的指针,兼容C语言处理字符串的各种函数。
- 有长度统计变量len,读写字符串不依赖“\0”终止符,保证了二进制安全。
5.0版本的SDS结构
- 字符串结构类型:短字符串【sdshdr5、sdshdr8】、长字符串【sdshdr16、sdshdr32】、更长字符串【sdshdr64】。
- 包含字段:len【长度】、alloc【已分配的总长度】、flags【字符串结构类型,注意sdshdr5和其它的区别】、buf【柔性数组,储存字符串内容】。
- _attribute_((_packed_)):结构体按1字节对齐,节省空间,且地址连续,操作效率飞起。

小结
- SDS暴露给上层的是指向柔性数组buf的指针。
- 读操作的时间复杂度多为O(1),直接读取成员变量;涉及修改的写操作,则可能会触发扩容。
四、常用的操作字符串函数
- sdsnewlen :创建字符串
- sdsfree :释放字符串【同时释放内存】
- sdsclear :重置统计值,但buf并没有真正清除【不释放内存,减少申请内存时的开销】
- sdscatsds :拼接字符串
创建字符串
创建字符串一般包含以下两点:
- 计算好不同类型的头部和初始长度
- 动态分配内存
需要注意的点:
- 创建空字符串时,SDS_TYPE_5 被强制转换为SDS_TYPE_8【应该是为了以后实例化的时候不用再去扩容而重新申请内存】
- 长度计算时有"+1"操作,是为了算上结束符"\0"
- 返回值是指向 sds 结构中的 buf 字段的指针
释放字符串
释放字符串的方法一般有2种:
- sdsfree :释放字符串【同时释放内存】
- sdsclear :重置统计值,但buf并没有真正清除【不释放内存,减少申请内存时的开销】
拼接字符串
拼接字符串比较好理解,主要需要注意的是拼接过程中的扩容策略,扩容策略一般有以下几种:
- 若sds中剩余的空闲长度avail大于新增内容的长度addlen,直接在柔性数组buf末尾追加即可,无需扩容。
- 若sds中剩余的空闲长度avail小于或等于新增内容的长度addlen:
- 新增后总长度len+addlen<1MB :按照新长度的2倍扩容
- 新增后总长度len+addlen>1MB :按照新长度+1MB扩容
- 最后根据新长度重新选取储存类型【判断是否修改flags】,并分配空间:
- 若无需更改,则只扩大柔性数组buf即可
- 若需要更改,则重新开辟内存,并将原来的buf柔性数组移动到新位置
扩容流程示例:

五、小问答
Q:SDS如何兼容C语言字符串?
A:SDS对象的buf是柔性数组,且直接返回上层,而且是直接指向内容的指针,所以兼容C语言函数。
Q:如何保证二进制安全?
A:读取内容时,SDS会通过len来限制读取长度,不依赖于"\0"终止符,所以保证了二进制安全。
Q:sdshdr5的特殊之处?
A:
- 只负责储存小于32字节的字符串
- 类型和长度放到同一个属性中,节省内存
- 创建空字符串时,sdshdr5会被sdshdr8替代
Q:SDS是如何扩容的?
A:SDS在涉及字符串修改处会调用 sdsMakeRoomFor 函数进行检查,根据不同情况动态扩容,此操作对于上层调用方透明,即无感知。
Redis5设计与源码分析读后感(二)简单动态字符串SDS的更多相关文章
- Redis5设计与源码分析读后感(一)认识Redis
一.初识redis 定义 Redis是一个开源的Key-Value数据库,通常被称为数据结构服务器,其值可以是多种常见的数据格式,且读写性能极高,且所有操作都是原子性的. 高性能的主要原因 1.基于内 ...
- Redis5设计与源码分析读后感(四)压缩列表
一.引言 上一节我们总结了跳跃表的知识,我们知道了有序数组可以用跳跃表实现,也可以用压缩列表来实现,这一篇文章我们来总结一下压缩列表相关的知识. 二.压缩列表简介 定义:压缩列表 ziplist 本质 ...
- Redis5设计与源码分析读后感(三)跳跃表
一.引言 有序集合在日常开发中相当常见,比如做排名等相关的功能,肯定要用到排序的功能,那么常见底层实现有很多种: 数组 :不便于元素的插入和删除 链表 :查询效率低,需要遍历所有元素 平衡树OR红黑树 ...
- Redis源码解析:01简单动态字符串SDS
Redis没有直接使用C字符串(以'\0'结尾的字符数组),而是构建了一种名为简单动态字符串( simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默认字符 ...
- Spring AOP源码分析(二)动态A0P自定义标签
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 之前讲过Spring中的自定义注解,如果声明了自定义的注解,那么就一定 ...
- DataTable源码分析(二)
DataTable源码分析(二) ===================== DataTable函数分析 ---------------- DataTable作为整个插件的入口,完成了整个表格的数据初 ...
- 一个普通的 Zepto 源码分析(二) - ajax 模块
一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...
- Zepto源码分析(二)奇淫技巧总结
Zepto源码分析(一)核心代码分析 Zepto源码分析(二)奇淫技巧总结 目录 * 前言 * 短路操作符 * 参数重载(参数个数重载) * 参数重载(参数类型重载) * CSS操作 * 获取属性值的 ...
- Koa源码分析(二) -- co的实现
Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...
随机推荐
- MapReduce框架原理
MapReduce框架原理 3.1 InputFormat数据输入 3.1.1 切片与MapTask并行度决定机制 1.问题引出 MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个J ...
- python numpy常用的数学和统计函数
numpy模块的核心就是基于数组的运算,相比于列表和其他数据结构,数组的运算效率是最高的.在统计分析和挖掘过程中,经常会使用到numpy模块的函数,以下是常用的数学函数和统计函数: 常数p就是圆周率 ...
- 从开源协议到谷歌禁用华为、Docker实体清单事件
平时我们在日常开发生活都在大量和开源软件打着交道,例如安卓.Linux.Github.Docker等,而其中开源协议比如MIT.Apache也是耳熟能详,但是真正对开源协议的了解相信对大部分人来说都 ...
- 四维dp,传纸条,方格取数
四维dp例题 四维dp便是维护4个状态的dp方式 拿题来说吧. 1. 洛谷P1004 方格取数 #include<iostream> #include<cstdio> usin ...
- Linux 部署java web 项目,验证码图片不显示文字问题
系统上线后,在获取验证码接口时,获取的验证码图片上没有对应的验证码数字,经过验证后,是由于Linux缺少字体造成的. 正常我们也可以将window的字体直接上传到linux服务器上,window的字体 ...
- Autoit 使用
一.Autoit 上传文件. 1.常用语法 - WinActivate("title") 聚焦到指定活动窗口 - ControlFocus ( "titl ...
- ssm框架(Spring Springmvc Mybatis框架)整合及案例增删改查
三大框架介绍 ssm框架是由Spring springmvc和Mybatis共同组成的框架.Spring和Springmvc都是spring公司开发的,因此他们之间不需要整合.也可以说是无缝整合.my ...
- Unity中利用柏林噪声(perlinnoise)制作摇摆效果
perlinnoise是unity中Mathf下的一个函数,需要两个float参数x和y进行采样,返回一个0-1的float型. 项目里经常要随机摇摆某些东西,比如摄像机,某个随机运动的目标等等,都可 ...
- 【接口自动化】selenium库也有大用场(获取cookie)
相信有些童鞋在做接口.或者说接口自动化测试的过程中会遇到这样的场景:测试的接口,必须是需要登录后才能发起请求成功的. 那么怎么解决呢? 本着团队协作的精神,我们就去让开发同学开个后门,给你个" ...
- SpringCloud 服务负载均衡和调用 Ribbon、OpenFeign
1.Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的-套客户端―负载均衡的工具. 简单的说,Ribbon是Netlix发布的开源项目,主要功能是提供客户端的 ...