Redis系列——8.SDS

01

前言

从今天开始我们就要学习redis的源码了,想想还有点小激动呢。

前方高能预警,非战斗人员迅速撤离。

但是咱怎么能怂呢,撤离啥啊,说干就干,死磕源码,这代码也是人写的,他还能整出什么幺蛾子。

又一个但是来了,redis底层是用C语言写的,如果对C语言一窍不通,那还是算了,前方等待的是一座大山。墙裂推荐去了解一下C.emmmm,幸好我会C,哈哈哈,毕竟他是开启偶代码之路的小哥哥。

好啦,不扯淡了,说说正经事。

02

介绍

Redis没有直接使用C语言传统的字符串来表示(以空字符串结尾的字符数组),而是自己构造了一种名为简单动态字符串SDS。

之前看的String类型的数据结构底层就是用SDS实现的。

SDSHDR(SDS的表头结构如下):

举个栗子:

我们之前设置一个名为str1的字符串,值为redis,其实他在内存上的结构大致如下:

len为5,表示这个sds长度为5个字节。

free为2,表示这个sds还有2个字节未使用的空间。

buf为char[]的数组,分配了(len+1+free)个字节的长度,前len个字节保存redis这5个字符串,接下来1个字节保存了'\0',剩下的free个字节未使用。

03

优点

1.二进制安全。

因为传统的C语言字符串符合ASCII编码,而他的特点是遇零则止,所以当读一个字符串的时候,只要遇到'\0',就认为到达了末尾。这个问题就来了,如果保存的是图片或视频等二进制文件,就会被强行截断,那么数据就不完整了。

那现在不能通过遇零则止来判断是否这个字符串读完了,但是现在可以通过len与buf[]数组的长度比较,如果len+1等于buf的长度,就说明这个字符串读完了。

2.获取字符串长度的操作,其时间复杂度为O(1)。

原来传统的C字符串获得长度的做法是遍历字符串的长度,如果遇零就返回,其时间复杂度为O(n)。

而SDS表头的len成员就保存了字符串的长度,其时间复杂度为O(1)。

3.杜绝缓存区溢出。

因为SDS表头的free成员记录着buf字符数据中未使用的数量,所以,在进行append命令的时候,先判断free是否够用,如果够用,就直接添加字符,如果不够用,就先进行内存扩展,再进行添加字符串。

04

内存分配原则和惰性释放

前面说的内存会扩展,但是呢,不是随便扩展的。就像奥特曼要小怪兽,一个闪光就行,但是要是终极大boss,就要好好打了,注意策略,很有可能会场外求救呢。

如果SDS表头len成员小于1MB(1024X1024),就分配和len长度相同的未使用空间。

如果SDS表头len成员大于等于1MB(1024X1024),就分配1MB的未使用空间。

空说无凭,翠花,上代码。

这边说的是内存扩展,如果新的字符串比旧的字符串要短很多,那么他是不是要回收呢?

先看重置代码,很明显,程序并没有回收多出来的长度,而是使用free来将这些字符串记录起来,等到将来使用。

此上就是SDS的源码,如果要看他具体每个操作的步骤,就要看具体的文件了sds.c和sds.h。

emmmm,偶反正是不行了。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190206G0M5F400?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券