形象化设计模式实战? ? ? ? ? ? ?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