redis6.0.5之ziplist阅读笔记--压缩列表(ziplist)之代码解读宏定义部分
压缩列表是一段按照一定格式连续化的内存空间,这种格式化的方法就是它的数据结构
***********************************************************************
#define ZIP_END 255 /* Special "end of ziplist" entry. */ 用来表示压缩列表的结尾元素
#define ZIP_BIG_PREVLEN 254
/* Max number of bytes of the previous entry, for the "prevlen" field prefixing each entry,
to be represented with just a single byte. Otherwise it is represented as FF AA BB CC DD,
where AA BB CC DD are a 4 bytes unsigned integer representing the previous entry len. */
前一个实体元素的字节数的最大值,用于每个实体的前缀prevlen字段,用一个字节来表示.
否则需要表示成如下样子 FE(原文的FF应该为笔误) AA BB CC DD,AA BB CC DD 是4个字节的无符号整数代表前面实体的长度。
/* Different encoding/length possibilities */ 各种编码和长度
#define ZIP_STR_MASK 0xc0 1100用来做与操作,可以获取前面两位比特的值,用来判断字符串类型
#define ZIP_INT_MASK 0x30 0011用来做与操作,可以获取前面3,4位比特的值,用来判断整数类型
#define ZIP_STR_06B (0 << 6) //0
#define ZIP_STR_14B (1 << 6) //64 = 1000 0000
#define ZIP_STR_32B (2 << 6) //128 = 1 0000 0000
字符串类型
#define ZIP_INT_16B (0xc0 | 0<<4) // 1100 0000 | 0000 0000 = 1100 0000
#define ZIP_INT_32B (0xc0 | 1<<4) // 1100 0000 | 0001 0000 = 1101 0000
#define ZIP_INT_64B (0xc0 | 2<<4) // 1100 0000 | 0010 0000 = 1110 0000
#define ZIP_INT_24B (0xc0 | 3<<4) // 1100 0000 | 0011 0000 = 1111 0000
#define ZIP_INT_8B 0xfe // 1111 1110
不同整数的类型
/* 4 bit integer immediate encoding |1111xxxx| with xxxx between * 0001 and 1101. */
4位编码从0001 and 1101
#define ZIP_INT_IMM_MASK 0x0f /* Mask to extract the 4 bits value. To add one is needed to reconstruct the value. */
用来抽取第四位比特的掩码,然后加1重构值
#define ZIP_INT_IMM_MIN 0xf1 /* 11110001 */ 最小值
#define ZIP_INT_IMM_MAX 0xfd /* 11111101 */ 最大值
#define INT24_MAX 0x7fffff
#define INT24_MIN (-INT24_MAX - 1)
/* Macro to determine if the entry is a string. String entries never start
* with "11" as most significant bits of the first byte. */
用来判断是否是字符串的宏定义,字符串实体从不用第一个字节的最高前两位11来表示。
(开头11是整数的表示方法)
#define ZIP_IS_STR(enc) (((enc) & ZIP_STR_MASK) < ZIP_STR_MASK)
/* Utility macros.*/
/* Return total bytes a ziplist is composed of. */
返回压缩列表的总长度
#define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl)))
/* Return the offset of the last item inside the ziplist. */
返回压缩列偏移量的值
#define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint32_t))))
/* Return the length of a ziplist, or UINT16_MAX if the length cannot be determined without scanning the whole ziplist. */
返回压缩列表元素个数,或者最大的16位无符号数,如果没有扫描整个压缩序列长度就不能被确定的情况下。
#define ZIPLIST_LENGTH(zl) (*((uint16_t*)((zl)+sizeof(uint32_t)*2)))
/* The size of a ziplist header: two 32 bit integers for the total bytes count and last item offset.
* One 16 bit integer for the number of items field. */
压缩列表的头部长度,两个32位整数,总的压缩列表的长度和最后一个实体元素的偏移量.
外加一个16位的整数表示实体元素的个数
#define ZIPLIST_HEADER_SIZE (sizeof(uint32_t)*2+sizeof(uint16_t))
/* Size of the "end of ziplist" entry. Just one byte. */
压缩列表结尾标识符,是一个字节
#define ZIPLIST_END_SIZE (sizeof(uint8_t))
/* Return the pointer to the first entry of a ziplist. */
返回指向压缩列表第一个实体元素的指针
#define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE)
/* Return the pointer to the last entry of a ziplist, using the last entry offset inside the ziplist header. */
返回指向压缩列表的最后一个元素的指针,使用在压缩列表中最后一个元素实体的偏移量
#define ZIPLIST_ENTRY_TAIL(zl) ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))
/* Return the pointer to the last byte of a ziplist, which is, the end of ziplist FF entry. */
返回指向压缩列表最后一个字节的指针,即压缩列表结尾的实体元素FF
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
/* Increment the number of items field in the ziplist header. Note that this
* macro should never overflow the unsigned 16 bit integer, since entries are
* always pushed one at a time. When UINT16_MAX is reached we want the count
* to stay there to signal that a full scan is needed to get the number of
* items inside the ziplist. */
在压缩列表头部增加元素数量。注意这个宏不会超过16位无符号整数,因为实体每次都是压入一个实体。
到达UINT16_MAX的时候,我们让计数保持在哪里表示一个遍历扫描才能确定压缩列表中实体总的数量
#define ZIPLIST_INCR_LENGTH(zl,incr) { \
if (ZIPLIST_LENGTH(zl) < UINT16_MAX) \
ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \
}
/* We use this function to receive information about a ziplist entry.
* Note that this is not how the data is actually encoded, is just what we
* get filled by a function in order to operate more easily. */
我们使用这个函数去获取一个压缩列表实体的信息.
注意到这并不是数据真正的编码方式,只是让我们通过这个函数方便获操作更加容易。
(所以下面这个结构体是方便操作压缩列表,而不是压缩列表的格式)
typedef struct zlentry {
unsigned int prevrawlensize; /* Bytes used to encode the previous entry len*/ 用来编码前一个实体长度的字节
unsigned int prevrawlen; /* Previous entry len. */ 前一个实体的长度
unsigned int lensize; /* Bytes used to encode this entry type/len. 用来编码实体自己长度的字节
For example strings have a 1, 2 or 5 bytes header. Integers always use a single byte.*/
举例如下,字符串拥有1,2或者5个字节的头部。整数只有一个字节
unsigned int len; /* Bytes used to represent the actual entry.For strings this is just the string length
while for integers it is 1, 2, 3, 4, 8 or 0 (for 4 bit immediate) depending on the number range. */
用来表示实际实体的字节。对于字符串来说就是字符串的长度,对于整数来说,它就是1,2,3,4,8或者0(对于4比特的情况)
取决于数字的范围.
unsigned int headersize; /* prevrawlensize + lensize. */ 实体头部字节数
unsigned char encoding; /* Set to ZIP_STR_* or ZIP_INT_* depending on
the entry encoding. However for 4 bits immediate integers this can assume a range of values and must be range-checked. */
编码格式设置为ZIP_STR_* 或者 ZIP_INT_*。然而对于4比特的整数来说,这个假定是一个范围内的值,而且必须进行范围检测
unsigned char *p; /* Pointer to the very start of the entry, that is, this points to prev-entry-len field. */
指向实体元素开始的地方,那就是指向实体的prevlen字段
} zlentry;
//清空一个zlentry的结构体实体
#define ZIPLIST_ENTRY_ZERO(zle) { \
(zle)->prevrawlensize = (zle)->prevrawlen = 0; \ 前一个实体的长度
(zle)->lensize = (zle)->len = (zle)->headersize = 0; \ 自己的长度
(zle)->encoding = 0; \ 自己的编码
(zle)->p = NULL; \具体内容
}
/* Extract the encoding from the byte pointed by 'ptr' and set it into 'encoding' field of the zlentry structure. */
通过指针ptr指向的字节抽取编码方式,并且将编码方式设置到实体元素结构的encoding字段中
#define ZIP_ENTRY_ENCODING(ptr, encoding) do { \
(encoding) = (ptr[0]); \
if ((encoding) < ZIP_STR_MASK) (encoding) &= ZIP_STR_MASK; \
} while(0)
***********************************************************************
/* Return bytes needed to store integer encoded by 'encoding'. */
通过encoding字段返回整数需要保存的编码字节数
unsigned int zipIntSize(unsigned char encoding) {
switch(encoding) {
case ZIP_INT_8B: return 1;
case ZIP_INT_16B: return 2;
case ZIP_INT_24B: return 3;
case ZIP_INT_32B: return 4;
case ZIP_INT_64B: return 8;
}
#define ZIP_INT_IMM_MIN 0xf1 /* 11110001 */ 最小值
#define ZIP_INT_IMM_MAX 0xfd /* 11111101 */ 最大值
if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX)
return 0; /* 4 bit immediate */
panic("Invalid integer encoding 0x%02X", encoding);
return 0;
}
***********************************************************************
/* Write the encoidng header of the entry in 'p'. If p is NULL it just returns
* the amount of bytes required to encode such a length. Arguments:
将实体头部的编码方式写入到指针指向的区域。如果p是空的,那么直接返回需要编码的字节长度。参数:
* 'encoding' is the encoding we are using for the entry. It could be
* ZIP_INT_* or ZIP_STR_* or between ZIP_INT_IMM_MIN and ZIP_INT_IMM_MAX
* for single-byte small immediate integers.
参数encoding是我们对实体使用的编码方式。它是ZIP_INT_* 或者 ZIP_STR_*或者
介于ZIP_INT_IMM_MIN 和 ZIP_INT_IMM_MAX之间单字节表示的小整数
* 'rawlen' is only used for ZIP_STR_* encodings and is the length of the
* srting that this entry represents.
参数rawlen只是为ZIP_STR_*的类型编码,同时也是这个实体元素的字符串长度表示
* The function returns the number of bytes used by the encoding/length
* header stored in 'p'. */
这个函数返回保存在p中的长度编码字节数
unsigned int zipStoreEntryEncoding(unsigned char *p, unsigned char encoding, unsigned int rawlen) {
unsigned char len = 1, buf[5];
if (ZIP_IS_STR(encoding)) { 是字符串,需要根据长度确定具体的编码类型
/* Although encoding is given it may not be set for strings,
* so we determine it here using the raw length. */
if (rawlen <= 0x3f) { 在6比特范围内,就是63个字节
if (!p) return len; 长度只有一个字节,默认的1
buf[0] = ZIP_STR_06B | rawlen; 具体长度
} else if (rawlen <= 0x3fff) { 在14比特范围内,16383字节
len += 1; 需要两个字节表示
if (!p) return len;
buf[0] = ZIP_STR_14B | ((rawlen >> 8) & 0x3f); 0100 0000 | 保证前面两位是01
buf[1] = rawlen & 0xff; 后8比特
} else {
len += 4; 需要5个字节长度保存
if (!p) return len;
buf[0] = ZIP_STR_32B; 10000000最高一个字节
buf[1] = (rawlen >> 24) & 0xff;
buf[2] = (rawlen >> 16) & 0xff;
buf[3] = (rawlen >> 8) & 0xff;
buf[4] = rawlen & 0xff;
}
} else {
/* Implies integer encoding, so length is always 1. */
整数编码长度,字节数总是1
if (!p) return len;
buf[0] = encoding;
}
/* Store this length at p. */
memcpy(p,buf,len);
return len;
}
***********************************************************************
/* Decode the entry encoding type and data length (string length for strings,
* number of bytes used for the integer for integer entries) encoded in 'ptr'.
* The 'encoding' variable will hold the entry encoding, the 'lensize'
* variable will hold the number of bytes required to encode the entry
* length, and the 'len' variable will hold the entry length. */
解码在ptr中的实体编码类型和数据长度(字符串长度,整数实体中整数的字节数)。
encoding变量保存实体的编码,lensize变量保存编码实体长度需要的字节数,
len变量保存实体本身的长度
#define ZIP_DECODE_LENGTH(ptr, encoding, lensize, len) do { \
ZIP_ENTRY_ENCODING((ptr), (encoding)); \
if ((encoding) < ZIP_STR_MASK) { 是字符串类型 \
if ((encoding) == ZIP_STR_06B) { 1个字节,表示63字节内的字符串 \
(lensize) = 1; \
(len) = (ptr)[0] & 0x3f; \
} else if ((encoding) == ZIP_STR_14B) { 2个字节,表示16383字节 \
(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 { \
panic("Invalid string encoding 0x%02X", (encoding)); \
} \
} else { \
(lensize) = 1; \
(len) = zipIntSize(encoding); \
} \
} while(0);
***********************************************************************
/* Encode the length of the previous entry and write it to "p". This only
* uses the larger encoding (required in __ziplistCascadeUpdate). */
对前一个实体长度进行编码,并且写入p指向的内存。
这个函数只在大编码使用(在 __ziplistCascadeUpdate 中调用 )
int zipStorePrevEntryLengthLarge(unsigned char *p, unsigned int len) {
if (p != NULL) {
p[0] = ZIP_BIG_PREVLEN;
标志大数编码,这种情况下,前一个实体的长度超过了253
memcpy(p+1,&len,sizeof(len));
memrev32ifbe(p+1);
}
return 1+sizeof(len); 返回实际的 对前面实体长度的编码 的 长度
1个字节是标志FE 后面的是是实际长度
}
***********************************************************************
/* Encode the length of the previous entry and write it to "p". Return the
* number of bytes needed to encode this length if "p" is NULL. */
对前一个实体长度进行编码,并且写入p指向的内存。
如果p为空返回编码长度需要的字节数
unsigned int zipStorePrevEntryLength(unsigned char *p, unsigned int len) {
if (p == NULL) { 指针为空,无需操作,直接返回长度即可
return (len < ZIP_BIG_PREVLEN) ? 1 : sizeof(len)+1;
} else {
if (len < ZIP_BIG_PREVLEN) {
p[0] = len;
return 1;
} else { 超过了单个字节能表示的最大长度
return zipStorePrevEntryLengthLarge(p,len);
}
}
}
***********************************************************************
/* Return the number of bytes used to encode the length of the previous
* entry. The length is returned by setting the var 'prevlensize'. */
返回前一个实体长度编码的字节数。长度通过设置变量prevlensize返回
#define ZIP_DECODE_PREVLENSIZE(ptr, prevlensize) do { \
if ((ptr)[0] < ZIP_BIG_PREVLEN) { \
(prevlensize) = 1; \
} else { \
(prevlensize) = 5; 1个标志字节FE + 4个实际长度字节 \
} \
} while(0);
***********************************************************************
/* Return the length of the previous element, and the number of bytes that
* are used in order to encode the previous element length.
* 'ptr' must point to the prevlen prefix of an entry (that encodes the
* length of the previous entry in order to navigate the elements backward).
* The length of the previous entry is stored in 'prevlen', the number of
* bytes needed to encode the previous entry length are stored in
* 'prevlensize'. */
返回前一个元素的长度和用来编码前一个元素长度的字节数。
变量ptr必须指向一个实体的前缀prevlen(即编码前一个实体的长度是为了反向查找(查找或者操作)元素)
前一个实体的长度被保存在变量prevlen中,编码前一个实体长度的字节数被保存在变量prevlensize中
#define ZIP_DECODE_PREVLEN(ptr, prevlensize, prevlen) do { \
ZIP_DECODE_PREVLENSIZE(ptr, prevlensize); \
if ((prevlensize) == 1) { \
(prevlen) = (ptr)[0]; \
} else if ((prevlensize) == 5) { \
assert(sizeof((prevlen)) == 4); \
memcpy(&(prevlen), ((char*)(ptr)) + 1, 4); \
memrev32ifbe(&prevlen); \
} \
} while(0);
***********************************************************************