redis源码阅读之zipmap

6290阅读 0评论2019-02-09 stolennnxb
分类:NOSQL

这次讲讲zipmap,其实看过之前ziplist那篇文章http://blog.chinaunix.net/uid-31422160-id-5817681.html之后,看这个应该就会容易理解很多了,个人觉得zipmap之于dict,就相当于ziplist之于adlist。好了,闲话少说,先看注释

点击(此处)折叠或打开

  1. /* String -> String Map data structure optimized for size.
  2.  * This file implements a data structure mapping strings to other strings
  3.  * implementing an O(n) lookup data structure designed to be very memory
  4.  * efficient.
  5.  *
  6.  * The Redis Hash type uses this data structure for hashes composed of a small
  7.  * number of elements, to switch to a hash table once a given number of
  8.  * elements is reached.
  9.  *
  10.  * Given that many times Redis Hashes are used to represent objects composed
  11.  * of few fields, this is a very big win in terms of used memory.
  12.  */
注释里面也说的比较清楚了,当在redis当中使用hash的时候,如果元素个数在一个比较小的量级,其内部就会使用zipmap这种结构来存储,如果大过某个阈值就会转而使用dict来存储了。
接下来我们就来看看zipmap在内存中的结构

点击(此处)折叠或打开

  1. /* Memory layout of a zipmap, for the map "foo" => "bar", "hello" => "world":
  2.  *
  3.  * <zmlen><len>"foo"<len><free>"bar"<len>"hello"<len><free>"world"
  4.  */
其中各个字段的意义如下
字段 描述
zmlen 占一个字节,表示zipmap当前的元素个数,当zipmap中的元素个数大于或者等于254时,这个字节所表示的数就没有具体含义了,如果想知道当前zipmap当中具体的元素个数,就需要自己去遍历整个zipmap来获取了。
len
表示接下来的key/value所占的字节数,取值跟ziplist当中的entry有点类似,都是带编码的,只不过这边就两种;当第一个字节为0-253时,该值就直接表示len;若为254,则后面紧跟着的4个字节表示的一个无符号整形数为len的取值。
free 一般表示在接下来的value之后的空出没用的字节数,一般只占一个字节,因为如果空白太多的话,zipmap就会自己重新分配空间来保证其自身的小巧灵活的特性。

综上所述,之前例子当中的foo->bar, hello->world在zipmap当中最紧凑的表示方式如下

点击(此处)折叠或打开

  1. "\x02\x03foo\x03\x00bar\x05hello\x05\x00world\xff"

其中第一个字节表示共有两对key->value,第一对的key占3个字节,为foo,第一对的value占3个字节,其后空余字节为0,其值为bar;第二对的key占5个字节,为hello,第二对的value占5个字节,其后空余字节为0,其值为world;最后255表示zipmap的结尾

具体实现的话就是先定义宏来确定上面的具体规则

点击(此处)折叠或打开

  1. #define ZIPMAP_BIGLEN 254
  2. #define ZIPMAP_END 255

  3. /* The following defines the max value for the <free> field described in the
  4.  * comments above, that is, the max number of trailing bytes in a value. */
  5. #define ZIPMAP_VALUE_MAX_FREE 4

  6. /* The following macro returns the number of bytes needed to encode the length
  7.  * for the integer value _l, that is, 1 byte for lengths < ZIPMAP_BIGLEN and
  8.  * 5 bytes for all the other lengths. */
  9. #define ZIPMAP_LEN_BYTES(_l) (((_l) < ZIPMAP_BIGLEN) ? 1 : sizeof(unsigned int)+1)
之后的底层实现就是使用字符数组了,需要注意的就是取值时的大小端的转换问题,其他的就是字符数组的常规操作了~~~大家新年好鸭~~~
上一篇:redis源码阅读之quicklist
下一篇:redis源码阅读之intset