Redis中的数据结构之简单动态字符串

Posted 被噶的韭菜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis中的数据结构之简单动态字符串相关的知识,希望对你有一定的参考价值。

上一篇我们讲到了Redis中简单动态字符串与c语言中字符串相比的一个优势,也就是获取字符串长度时的时间复杂度有了大幅度降低,满足了Redis在效率方面的要求。

今天来说一下,SDS是如何满足Redis对字符串在安全性方面的要求。

除了获取字符串长度的复杂度高之外,C语言中字符串不记录自身长度带来的另一个问题是容易造成缓冲区溢出(buffer overflow),例如 <string.h>/strcat函数可以将 src字符串中的内容拼接到 dest字符串末尾。

 
   
   
 
  1. char* strcat(char* dest,const char* src)

举个例子,假如一段程序,在内存中有两个紧紧相邻的c语言字符串 s1s2Redis, MongoDB,如图所示

如果一个程序员决定使用 strcat函数来修改 s1的内容为 RedisCluster

 
   
   
 
  1. strcat(s1, "Cluster");

但他忘了在执行 strcat之前为 s1分配足够的空间(众所周知,在c语言与c++中需要程序员自己手工对内存进行管理),那么就会导致 Cluster溢出到 s2的位置,如下图:

Redis中的数据结构之简单动态字符串(二)

而在SDS中,通过一个巧妙的方法避免了这种情况的发生,也就是利用SDS结构体中的 free属性(在最新版的Redis中,SDS的结构体中已经移除了free属性,转而使用alloc来代替,不过两个属性的含义有所不同,但在SDS中起到的作用基本一致,这个有机会再说哈)。那么SDS是怎么使用 free属性来杜绝缓冲区溢出的呢?

举个例子:SDS的API中也有一个用于执行拼接操作的 sdscat函数,类似于c语言中的 strcat,当SDS中 sdscat需要拼接字符串的时候,会先检查SDS的空间是否满足所需的要求,如果不满足的话,Redis会自动将SDS的空间扩展到所需大小,然后再执行拼接操作,所以使用SDS既不必像c语言中手动修改空间大小,也不会出现前面所说的c语言中字符串的缓冲区问题。( 注:这里只是举了一个拼接字符串的例子,其他的有关SDSAPI在修改SDS的时候也会做上面的操作

例如有以下SDS:

我们执行:

 
   
   
 
  1. sdscat(s,"Cluster");

拼接完的SDS如下图所示:

注意:上图所示的SDS,sdscat不仅对SDS进行了拼接操作,还为SDS分配了13字节的未使用空间,并且拼接之后的字符串正好也是13字节长,这种现象既不是巧合,也不是bug(工业界以及大规模使用的Redis怎么会有bug!?),这和SDS的空间分配策略有关系,空间分配策略又是Redis一个很巧妙的设计,所以,我们下一篇再讲吧!

以上是关于Redis中的数据结构之简单动态字符串的主要内容,如果未能解决你的问题,请参考以下文章

图解Redis之数据结构篇——简单动态字符串SDS

Redis数据结构之简单动态字符串SDS

Redis数据结构之简单动态字符串

Redis数据结构之简单动态字符串

redis设计与实现之SDS简单动态字符串

redis数据结构之动态字符串(SDS)