形象化设计模式实战? ? ? ? ? ? ?HELLO!架构? ? ? ? ? ? ? ? ? ? ?redis命令源码解析
?
用过Redis的应该对其哈希命令不陌生,在探索其实现之前,先得了解Redis的一个内部映射数据结构——压缩列表。
?
找到ziplist.c文件,在代码注释中:
?* The general layout of the ziplist is as follows:
?* <zlbytes><zltail><zllen><entry><entry><zlend>
?
?
//注意这三个定义,新建时会使用。
#define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl))) //32位unsigned int,4个字节
#define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint32_t))))
#define ZIPLIST_LENGTH(zl) (*((uint16_t*)((zl)+sizeof(uint32_t)*2))) //16位unsigned int,2个字节
/* Create a new empty ziplist.
*
* 创建并返回一个新的 ziplist
*
* T = O(1)
*/
unsigned char *ziplistNew(void) {
// ZIPLIST_HEADER_SIZE 是 ziplist 表头的大小
// 1 字节是表末端 ZIP_END 的大小
unsigned int bytes = ZIPLIST_HEADER_SIZE+1;
// 为表头和表末端分配空间
unsigned char *zl = zmalloc(bytes);
// 初始化<zlbytes>,整个ziplist 占用的内存字节数,对ziplist 进行内存重分配,或者计算末端时使用。
ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
// 初始化<zltail>,到达ziplist 表尾节点的偏移量。通过这个偏移量,可以在不遍历整个ziplist 的前提下,弹出表尾节点。
ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
// 新的list还没有entry,所以为0
ZIPLIST_LENGTH(zl) = 0;
// 初始化<zlend>,用于标记ziplist的末端
zl[bytes-1] = ZIP_END;
return zl;
}
?
成功后,ziplist结构如图所示:
?
?
+-----------------------+---------------+-----------+-------------+
?
| pre_entry_length | encoding | length | content |
?
+-----------------------+----------------+-----------+-------------+
/* Decode the number of bytes required to store the length of the previous
* element, from the perspective of the entry pointed to by ‘ptr‘.
*
* 解码 ptr 指针,
* 取出编码前置节点长度所需的字节数,并将它保存到 prevlensize 变量中。
*
* T = O(1)
*/
#define ZIP_DECODE_PREVLENSIZE(ptr, prevlensize) do { if ((ptr)[0] < ZIP_BIGLEN) { (prevlensize) = 1; } else { (prevlensize) = 5; } } while(0);
ZIP_BIGLEN为254。/* Extract the encoding from the byte pointed by ‘ptr‘ and set it into
* ‘encoding‘.
*
* 从 ptr 中取出节点值的编码类型,并将它保存到 encoding 变量中。
*
* T = O(1)
*/
#define ZIP_ENTRY_ENCODING(ptr, encoding) do { (encoding) = (ptr[0]); if ((encoding) < ZIP_STR_MASK) (encoding) &= ZIP_STR_MASK; } while(0)
ZIP_STR_MASK为0xc0,二进制就是11000000,与11000000取&,只能四种结果:11000000,1000000,01000000,00000000,这就是之前说encoding类型的由来。/* Decode the length encoded in ‘ptr‘. The ‘encoding‘ variable will hold the
* entries encoding, the ‘lensize‘ variable will hold the number of bytes
* required to encode the entries length, and the ‘len‘ variable will hold the
* entries length.
*
* 解码 ptr 指针,取出列表节点的相关信息,并将它们保存在以下变量中:
*
* - encoding 保存节点值的编码类型。
*
* - lensize 保存编码节点长度所需的字节数。
*
* - len 保存节点的长度。
*
* T = O(1)
*/
#define ZIP_DECODE_LENGTH(ptr, encoding, lensize, len) do { /* 取出值的编码类型 */ ZIP_ENTRY_ENCODING((ptr), (encoding)); /* 字符串编码 */ if ((encoding) < ZIP_STR_MASK) { if ((encoding) == ZIP_STR_06B) { (lensize) = 1; (len) = (ptr)[0] & 0x3f; } else if ((encoding) == ZIP_STR_14B) { (lensize) = 2; (len) = (((ptr)[0] & 0x3f) << 8) | (ptr)[1]; } else if (encoding == ZIP_STR_32B) { (lensize) = 5; (len) = ((ptr)[1] << 24) | ((ptr)[2] << 16) | ((ptr)[3] << 8) | ((ptr)[4]); } else { assert(NULL); } /* 整数编码 */ } else { (lensize) = 1; (len) = zipIntSize(encoding); } } while(0);
</pre><pre name="code" class="cpp">/* ?* 字符串编码类型 ?*/ #define ZIP_STR_06B (0 << 6) #define ZIP_STR_14B (1 << 6) #define ZIP_STR_32B (2 << 6)ZIP_STR_06B就是00000000,ZIP_STR_14B就是01000000,ZIP_STR_32B就是10000000,
?
原文:http://lobert.iteye.com/blog/2152131