redis源码之SDS
1:SDS介绍
我们在redis中执行命令
set key name
的时候,key和name都是字符串类型,而且字符串(string)在redis中是会经常用到的类型,那redis是如何保存字符串的呢?我们接下来往下看
众所周知,redis是c写的,在c中使用char来保存字符串,并且用\0作为字符串的结尾,但是redis不是这样保存的,redis是使用一种叫SDS的结构来保存字符串的。结构如下(redis3.2以前)
struct sdshdr{
int len;
int free;
char buf[];
}
那么问题来了,redis为什么 会用SDS的结构,而不直接用c语言的字符串,我们来看看他们的区别
1:计算字符串长度的区别
对于c来说,计算字符串的长度的方式就是遍历,遇到\0就停止,所以复杂对是O(n),而SDS直接保存了字符串的长度,复杂度是O(1)
2:保证二进制的安全
因为SDS并不是以\0为结尾的标志,自然就保证了二进制的安全
3:内存管理策略(预分配内存和惰性空间释放策略)
redis是一个高速的缓存数据库,需要频繁的对字符串进行操作,如果内存分配错误,会导致很严重的后果,就算内存分配没问题,频繁的内存分配也是非常耗费时间的,所以这些都是应该去避免的
惰性空间释放策略
在SDS中首先用到了惰性空间释放策略,惰性空间释放用于优化SDS的字符串缩短操作。
当要缩短SDS保存的字符串时,程序并不立即使用内存充分配来回收缩短后多出来的字节,而是使用表头的free成员将这些字节记录起来,并等待将来使用。
源码如下
void sdsclear(sds s) { //重置sds的buf空间,懒惰释放
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
sh->free += sh->len; //表头free成员+已使用空间的长度len = 新的free
sh->len = 0; //已使用空间变为0
sh->buf[0] = '\0'; //字符串置空
}
预分配内存
扩容策略是字符串在长度小于 1M 之前,扩容空间采用加倍策略,也就是保留 100% 的冗余空间。当长度超过1M 之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配 1M大小的冗余空间。
4:兼容c语言函数库 (字符串后面会自动加上\0)
3.2版本以后的SDS结构
前面的len和free以及char这种结构看起来很好,但是是存在一定的问题的
struct sdshdr{
int len;
int free;
char buf[];
}
len和free都是int类型,都是4byte也就是32bit,能表示42亿左右的范围,大大的造成了空间的浪费,所以在3.2以后对SDS有一定的更改,更改如下
typedef char *sds;
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
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[];
};
.........
sdshdr5表示的是用5个bit位来表示数据的长度,sdshdr8就是表示用8个bit位来表示数据的长度,以此类推
sdshdr5的内存分配如图

当需要存储的数据长度超过31,就需要用sdshdr8来表示
sdshdr8的内存分配如图

其余的sdshdr16以上的都是以此类推,判断方式源码如下
static inline char sdsReqType(size_t string_size) {
if (string_size < 1<<5) //2^5-1
return SDS_TYPE_5;
if (string_size < 1<<8) //2^8-1
return SDS_TYPE_8;
if (string_size < 1<<16) //2^16-1
return SDS_TYPE_16;
#if (LONG_MAX == LLONG_MAX)
if (string_size < 1ll<<32) //2^32-1
return SDS_TYPE_32;
return SDS_TYPE_64;
#else
return SDS_TYPE_32;
#endif
}
关注我的技术公众号,每周都有优质技术文章推送。
微信扫一扫下方二维码即可关注:
redis源码之SDS的更多相关文章
- Redis源码阅读-sds字符串源码阅读
redis使用sds代替char *字符串, 其定义如下: typedef char *sds; struct sdshdr { unsigned int len; unsigned int free ...
- Redis源码阅读笔记(1)——简单动态字符串sds实现原理
首先,sds即simple dynamic string,redis实现这个的时候使用了一个技巧,并且C99将其收录为标准,即柔性数组成员(flexible array member),参考资料见这里 ...
- [Redis源码阅读]sds字符串实现
初衷 从开始工作就开始使用Redis,也有一段时间了,但都只是停留在使用阶段,没有往更深的角度探索,每次想读源码都止步在阅读书籍上,因为看完书很快又忘了,这次逼自己先读代码.因为个人觉得写作需要阅读文 ...
- redis源码分析(一)-sds实现
redis支持多种数据类型,sds(simple dynamic string)是最基本的一种,redis中的字符串类型大多使用sds保存,它支持动态的扩展与压缩,并提供许多工具函数.这篇文章将分析s ...
- Redis源码阅读一:简单动态字符串SDS
源码阅读基于Redis4.0.9 SDS介绍 redis 127.0.0.1:6379> SET dbname redis OK redis 127.0.0.1:6379> GET dbn ...
- Redis源码分析(sds)
源码版本:redis-4.0.1 源码位置:https://github.com/antirez/sds 一.SDS简介 sds (Simple Dynamic String),Simple的意思是简 ...
- Redis 源码简洁剖析 02 - SDS 字符串
C 语言的字符串函数 C 语言 string 函数,在 C 语言中可以使用 char* 字符数组实现字符串,C 语言标准库 string.h 中也定义了多种字符串操作函数. 字符串使用广泛,需要满足: ...
- Redis源码研究--字典
计划每天花1小时学习Redis 源码.在博客上做个记录. --------6月18日----------- redis的字典dict主要涉及几个数据结构, dictEntry:具体的k-v链表结点 d ...
- redis源码笔记(一) —— 从redis的启动到command的分发
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/redis1 本博客同步在http://www.cnblog ...
随机推荐
- Javascript 基础知识整理
Javascript的作用 表单验证,减轻服务器压力 添加页面动画效果 动态更改页面内容 Ajax网络请求(异步加载数据) -它属于前端的核心,主要用来控制和重新调整DOM,通过修改DOM结构,从而达 ...
- 使用session实现网站N天免登陆()
问题描述: 一些网站的N天之内免登陆实现方式. 方式一: 首先想到的是使用cookie保存用户登录信息,设置有效期,在用户下次访问时免去登录环节,直接通过cookie获取用户信息. 方式二: 方式二: ...
- spark-submit提交spark任务的具体参数配置说明
spark-submit提交spark任务的具体参数配置说明 1.spark提交任务常见的两种模式 2.提交任务时的几个重要参数 3.参数说明 3.1 executor_cores*num_execu ...
- 天融信Top-app LB负载均衡SQL注入0day
POST /acc/clsf/report/datasource.php HTTP/1.1 Host: Connection: close Accept: text/javascript, text/ ...
- scala的隐式转换学习总结(详细)
一,隐式转换函数 1, 格式, implicit def 函数名(参数):返回值类型={ //函数体 //返回值 } 2,例子: //导入对应的规则类,以免出现警告 scala> import ...
- 4. Linux工作目录切换和文本文件编辑命令
1.pwd:显示用户当前所处的工作目录 举例:[root@Centos ~]# pwd /root 2.cd:切换工作路径 "cd -"命令返回到上一次所处的目录 " ...
- Spring MVC 处理一个请求的流程分析
Spring MVC是Spring系列框架中使用频率最高的部分.不管是Spring Boot还是传统的Spring项目,只要是Web项目都会使用到Spring MVC部分.因此程序员一定要熟练掌握MV ...
- AYIT-2020 609暑假集训第一周周赛题 A - A计划
可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验.魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老.年迈的国王正是心急如焚,告招天下 ...
- CF-311B Cats Transport(斜率优化DP)
题目链接 题目描述 小S是农场主,他养了 \(M\)只猫,雇了 \(P\) 位饲养员. 农场中有一条笔直的路,路边有 \(N\) 座山,从 \(1\) 到 \(N\)编号. 第 \(i\) 座山与第 ...
- hdu2430Beans(单调队列)
Mr. Pote's shop sells beans now. He has N bags of beans in his warehouse, and he has numbered them ...
