redis:string类型的原理及实现

redis作为一个key-value数据库,string是其基本数据类型。

redis所有的keys都是字符串类型,同时字符串类型也是values的基本数据类型。以及其他更为复杂的数据类型——lists,sets,sorted sets,hashes——也是使用字符串来实现的。


redis string数据类型的实现包含在sds.c(sds,即为Simple Dynamic Strings,简单的动态字符串)中.C语言结构体sdshdr在sds.h中声明,它表示redis string类型:

struct sdshdr {
    long len;
    long free;
    char buf[];
};

字符数组buf储存实际的字符串;

len变量保存字符串的长度,从而获取字符串长度的时间复杂度为O(1);

free变量存放buf中可利用的空间;

len和free保存了buf字符数组的元信息。

  • 创建redis字符串

在sds.h中定义了一个叫做sds的新数据类型,其实就是一个字符串指针:

typedef char *sds;

在sds.c中定义了 sdsnewlen函数用来创建一个新的字符串:

sds sdsnewlen(const void *init, size_t initlen) {
    struct sdshdr *sh;

    sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
#ifdef SDS_ABORT_ON_OOM
    if (sh == NULL) sdsOomAbort();
#else
    if (sh == NULL) return NULL;
#endif
    sh->len = initlen;
    sh->free = 0;
    if (initlen) {
        if (init) memcpy(sh->buf, init, initlen);
        else memset(sh->buf,0,initlen);
    }
    sh->buf[initlen] = '\0';
    return (char*)sh->buf;
}

redis string是一个sdshdr类型的变量,但该函数返回一个字符串指针。

这是一个小技巧,在这解释一下:

假设,我们利用sdsnewlen创建一个字符串”redis“,

sdsnewlen("redis", 5);

该函数创建了一个struct sdshdr类型变量,并且为len,free和buf分配了内存空间:

struct sdshdr *sh;
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);

sdsnewlen创建成功后得到一个redis string,其结构如下:

-----------
|5|0|redis|
-----------
^   ^
sh  sh->buf

sdsnewlen将sh->buf返回给调用者。

那么,如果需要释放sh指向的redis string,需要怎么办呢?

你需要得到指向sh的指针,但是你得到的却是指向sh->buf的指针。

可以从sh->buf中得到指向sh的指针吗?

可以的。通过指针的运算。由上面的ASCII示意图可知,如果从sh->buf中减去两个long型大小之后就得到了指向sh的指针。两个long型大小恰好是struct sdshdr的大小。

看看 sdslen函数是怎样做的:

size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    return sh->len;
}
了解这个小技巧后你很容易理解sds.c中的其他函数。

redis string的实现隐藏在接口后面,这个接口只接受字符串指针。redis string的用户不需要关心它的具体实现,只要把它看作是字符串指针就可以了。


原文:http://redis.io/topics/internals-sds

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值