字符串内部结构
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 存储可供使用的其他字节数。
一起len和freefield 可以被视为保存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 字符串视为字符指针。