一、引言

  学习之前先了解几个概念:  

  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的更多相关文章

  1. Redis5设计与源码分析读后感(一)认识Redis

    一.初识redis 定义 Redis是一个开源的Key-Value数据库,通常被称为数据结构服务器,其值可以是多种常见的数据格式,且读写性能极高,且所有操作都是原子性的. 高性能的主要原因 1.基于内 ...

  2. Redis5设计与源码分析读后感(四)压缩列表

    一.引言 上一节我们总结了跳跃表的知识,我们知道了有序数组可以用跳跃表实现,也可以用压缩列表来实现,这一篇文章我们来总结一下压缩列表相关的知识. 二.压缩列表简介 定义:压缩列表 ziplist 本质 ...

  3. Redis5设计与源码分析读后感(三)跳跃表

    一.引言 有序集合在日常开发中相当常见,比如做排名等相关的功能,肯定要用到排序的功能,那么常见底层实现有很多种: 数组 :不便于元素的插入和删除 链表 :查询效率低,需要遍历所有元素 平衡树OR红黑树 ...

  4. Redis源码解析:01简单动态字符串SDS

    Redis没有直接使用C字符串(以'\0'结尾的字符数组),而是构建了一种名为简单动态字符串( simple  dynamic  string, SDS)的抽象类型,并将SDS用作Redis的默认字符 ...

  5. Spring AOP源码分析(二)动态A0P自定义标签

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 之前讲过Spring中的自定义注解,如果声明了自定义的注解,那么就一定 ...

  6. DataTable源码分析(二)

    DataTable源码分析(二) ===================== DataTable函数分析 ---------------- DataTable作为整个插件的入口,完成了整个表格的数据初 ...

  7. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

  8. Zepto源码分析(二)奇淫技巧总结

    Zepto源码分析(一)核心代码分析 Zepto源码分析(二)奇淫技巧总结 目录 * 前言 * 短路操作符 * 参数重载(参数个数重载) * 参数重载(参数类型重载) * CSS操作 * 获取属性值的 ...

  9. Koa源码分析(二) -- co的实现

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...

随机推荐

  1. 第7章 Spark SQL 的运行原理(了解)

    第7章 Spark SQL 的运行原理(了解) 7.1 Spark SQL运行架构 Spark SQL对SQL语句的处理和关系型数据库类似,即词法/语法解析.绑定.优化.执行.Spark SQL会先将 ...

  2. chromium 源码下载地址

    下载链接:https://gsdview.appspot.com/chromium-browser-official/

  3. springboot2整合activiti7具体步骤

    写在前面 需要提前了解的内容有 springboot.springSecurity.activiti基本使用 关于activiti Activiti项目是一项新的基于Apache许可的开源BPM平台, ...

  4. 第2篇scrum

    第2篇scrum 一.站立式会议 1.1会议照片 想得美 1.2项目进展 团队成员 昨日完成任务 今日计划任务 感想 吴茂平 完善用户系统 改进评论数据表,增加评论,删除评论,查询评论 今天也是元气满 ...

  5. 【译】Database Profiling with Visual Studio

    你是否在排查运行缓慢的 web 应用程序时怀疑是数据库层造成的?以前排查数据库层需要特定的工具,现在可以使用 Visual Studio 的 Performance Explorer 中的数据库分析工 ...

  6. Flink-1.10中的StreamingFileSink相关特性

    一切新知识的学习,都离不开官网得相关阅读,那么StreamingFileSink的官网介绍呢? https://ci.apache.org/projects/flink/flink-docs-rele ...

  7. phoenix PQS的kerberos相关配置

    thin 客户端的实例代码 jdbc:phoenix:thin:url=<scheme>://<server-hostname>:<port>;authentica ...

  8. MD笔记

    1.力场中的例子电荷是有效电荷(clayff),有别于化学式中的电荷. 2.游离状态的阳离子(如层间阳离子)的电荷不能变动:而Al-O八面体.Si-O四面体中的离子(Al.Si等)电荷可以微调. 3. ...

  9. ssm-springboot实现修排名再顺序排的主要代码

    排序改为2,结果如下: package com.zhetang.controller; import com.core.vo.JsonResult; import com.utils.PageResu ...

  10. Navicat12 for Mysql激活

    1      下载 注册机和Navicat网盘下载地址 链接:https://pan.baidu.com/s/1AFpQIlHCXVHc8OuBZ9PAlA  提取码:xvi2 2      安装 2 ...