您的位置:首页 > 数据库 > Redis

redis:string类型的原理及实现

2011-12-01 13:34 567 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: