以下涉及到的源码均为redis5.0-rc3版本的代码【点击查看官方源码】
zipmap
- zipmap是为优化string映射到其他string这种结构而生的,故名思意其能节约内存。
- zipmap是redis中hash结构的底层涉及之一。当hash存储的元素数量少的情况下,底层使用zipmap结构,一旦元素数量达到一个限定值的时候就会自动切换成哈希表。
- 由于zipmap的特性,hash结构在存储的数据少的情况下,在内存使用方面又相当大的优势。
数据结构
在源码中例子可见,对于一个map中的值有 “foo” => “bar”, “hello” => “world”,那么其结构如下所示:
1 | <zmlen><len>"foo"<len><free>"bar"<len>"hello"<len><free>"world" |
其中各部分的含义如下:
- zmlen
占用一个字节长度,保存zipmap结构的当前长度,但是只针对zipmap的长度小于254时,如果大于等于254,那么仍然需要遍历整理结构才能得知长度值。 - len
表示后面紧跟着的一个字符串的长度,可以说key的长度,也可以是value的长度。len会被编码为一个单值或者一个5个字节的值,如果第一个字节值在0-253之间,那么len代表一个单值;如果是254,那么接下来的4个字节是一个无符号整型;如果是255,那么它是一个表示hash’结束点的信号。
- free
代表后面的字符串未使用的字节空间,往往是由于对一个键的值做修改导致。如原键值对映射为foo->bar,后续变为foo->ba,那么就会出现就会出现2哥字节的空闲空间,此时并不会去释放掉,而是供后续使用,如果后续再变为foo->baa,那么就不需要重新分配空间了。 但是free字段始终保持着一个特定字节长度(在zipmap.c文件中定义:“#define ZIPMAP_VALUE_MAX_FREE 4”),如果空闲的字节数多了,zipmap会释放其它的空闲空间来保证zipmap的占用空间尽量的小。
介绍了个字段的含义,那么就可以知道上面的例子的占用内存情况了,如下所示:
1 | "\x02\x03foo\x03\x00bar\x05hello\x05\x00world\xff" |
API
zipmap.h头文件中定义了如下api:
1 | //创建zipmap结构 |
zipmap的源码很简单,也不难理解,下面就只介绍一下zipmapSet函数的源码,其他的有兴趣的可以自行点击本文首部的链接去下载源码查看。
1 | /*如果key不存在,则创建;在update不为NULL的前提下 *,如果key存在则update指针的值为1,否则为0*/ |