字符串内部结构

Redis 字符串的原始实现指南

Redis 堆栈 Redis 社区版

注意:本文档由 Redis 的创建者 Salvatore Sanfilippo 在 Redis 开发初期(约 2010 年)编写。虚拟内存从 Redis 2.6 开始已被弃用,因此本文档 这里只是为了历史兴趣。

Redis 字符串的实现包含在sds.c (sds代表 Simple Dynamic Strings)。该实现可作为独立库使用 在 https://github.com/antirez/sds

C 结构sdshdr声明于sds.h表示 Redis 字符串:

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

bufcharacter 数组存储实际的字符串。

lenfield 存储buf.这使得获取长度 的 Redis 字符串的 O(1)作。

freefield 存储可供使用的其他字节数。

一起lenfreefield 可以被视为保存buf字符数组。

创建 Redis 字符串

名为sds定义在sds.h要成为字符指针的同义词:

typedef char *sds;

sdsnewlen函数定义在sds.c创建一个新的 Redis 字符串:

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 字符串是struct sdshdr.但sdsnewlen返回一个字符指针!!

这是一个技巧,需要一些解释。

假设我使用sdsnewlen如下所示:

sdsnewlen("redis", 5);

这将创建一个类型为struct sdshdr分配内存lenfree字段以及buf字符数组。

sh = zmalloc(sizeof(struct sdshdr)+initlen+1); // initlen is length of init argument.

sdsnewlen成功创建 Redis 字符串,结果如下:

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

sdsnewlen返回sh->buf给调用方。

如果需要释放 Redis 字符串,该怎么办sh?

您需要指针sh但你只有指针sh->buf.

你能得到指针吗shsh->buf?

是的。指针算术。请注意,从上面的 ASCII 图中可以看出,如果你减去 两长端的大小从sh->buf您得到指针sh.

sizeof两个 long 恰好是 的大小struct sdshdr.

sdslen功能,并查看 this trick 中的作方法:

size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    return sh->len;
}

了解了这个技巧,你可以轻松地浏览sds.c.

Redis 字符串实现隐藏在仅接受字符指针的接口后面。Redis 字符串的用户无需关心它是如何实现的,可以将 Redis 字符串视为字符指针。

为本页评分
返回顶部 ↑