Redis设计与实现(一)简单动态字符串
Redis没有使用C中自带的String,而是自己构建了一个字符串类,名为Simple Dynamic String。缩写为SDS,下文的SDS就是指此玩意。SDS是redis中默认的字符串使用。而Redis是基于C实现的,C内部的自带的String被它作用于log的记录。也就是一个简单的字符串字面量。当Redis在数据库中新建一个对象的时候(set msg "nb"),KV中的Key是一个SDS,而Value则是Redis自身实现的SDS对象。当redis中使用RPUSH msg "1" "2"这种情况下 key依然是一个SDS,但是value则为一个列表对象,列表里面存储着2个SDS。
除了用来保存里面的字符串值对象,SDS也会被用来做缓存区,例如AOF中的缓存区,客户端状态中的输入缓冲区。
那么SDS是什么呢?我们写代码的人应该能感知出来,这个玩意应该就是对基础数据的封装,然后加入了自己需要的特性。
源码中SDS是一个对象,里面有三个成员变量,int len用来记录已经使用的长度。也就是字符串的长度,int free表示数组中还剩余的空间。char [] buf表示容器用来存储字符串。
还是很好理解的吧,SDS遵守了C中以空字符结尾的特点,所以最后一位并没有被算入长度中。所以输出的时候完成可以使用c中自带的print来进行。printf("%s",s->buf)。
自己使用SDS的好处也很明显,就是利用了哨兵的思想,这样的话知道一个字符串的长度的时间复杂度就可以从O(N)直接变成O(1)。
另外一个好处就是,不会造成缓存的溢出,这一点Java程序员可能感受不到,理解就是一个操作在执行的时候,因为C是用空字符里进行切割的,例如5+5的字符串组合,如何5变成了6的长度,那么就会溢出到下一个字符串,造成了污染。而SDS存储了长度,就会在每一次修改的时候,进行时候的check。保证这种情况不会出现。
最后一个特点就是使用SDS可以防止空间的重复操作,什么意思,就是字符串变大变小都需要在C里面对空间进行释放。而SDS这种情况就可以通过"空间预分配",通俗点就是每次多给一点空间,"惰性空间分配",在给字符串锁缩短的时候也会保留多出的空间。这样的话就不需要进行重复的数组重分配了。
SDS同时可以保存C中字符串无法保存的一些数据,因为C中的字符串是不可以有空的,不然会被认为是结尾,这样的话很多的图片什么的都无法进行保存了,但是SDS是通过长度来进行判断的,所有可以保证的一点就是你存入的数据我都会完整的给你。
至于为什么SDS也是空结尾,这是为了也可以对C中的String做到一点的重用,也可以使用C中的部分函数。