按照网上别人的建议,从数据结构相关的代码看起,reids version:3.2.0-rc3,涉及:
文件 | 内容 |
`sds.h` 和 `sds.c` | Redis 的动态字符串实现。 |
`adlist.h` 和 `adlist.c` | Redis 的双端链表实现。 |
dict.h 和 dict.c | Redis 的字典实现。 |
`server.h` 中的 `zskiplist` 结构和 `zskiplistNode` 结构, 以及 t_zset.c 中所有以 zsl 开头的函数,比如 zslCreate 、 zslInsert 、 zslDeleteNode ,等等。 | Redis 的跳跃表实现。 |
hyperloglog.c 中的 hllhdr 结构, 以及所有以 hll 开头的函数。 | Redis 的 HyperLogLog 实现。 |
其中sds部分简单的看了下,在C原有的字符串基础上做了封装,主要的好处有这么几点:
1. 二进制安全,sds中允许存在’\0’作为一个正常的char了。同时会自动在字符串末尾增加一个’\0’,这样也就能支持部分c原有的一些函数
2. sds中保存了string的长度、free,当长度不足以保存的时候,自动进行扩容。这样就避免了溢出的风险,同时也不用频繁的分配内存
3. 根据字符串长度,定义了从TYPE5到TYPE64不同位长的类型来保存数据
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
这段代码是什么鬼还没看懂……
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
根据字符串长度选择对应的类型保存len和alloc,对内存的使用果然是很抠门啊。