字符串内部结构
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[];
};
这buf
character 数组存储实际的字符串。
这len
field 存储buf
.这使得获取长度
的 Redis 字符串的 O(1)作。
这free
field 存储可供使用的其他字节数。
一起len
和free
field 可以被视为保存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
分配内存len
和free
字段以及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
.
你能得到指针吗sh
从sh->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 字符串视为字符指针。