读<<Redis设计与实现>>与redis(5.0)源码__ziplist
ziplist构成
zlbytes- ztail- zllen- entrys-…- zlend uint32_t uint32_t uint16_t zlentry uint8_t
因为zlend使用固定值
ZIP_END = 255作为结束标志(0xFF作为uint8的最大值,与prevlen单字节长度0xFE进行区别,同时是最后面的两个数作为标志(这个懂的吧)).
zlentry
这个结构体只是用来接收存放信息的,只是为了方便操作,而并不是其在ziplist中的真正编码方式
实际是:
previous_entry_length-> encoding -> content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 typedef struct zlentry {
// 前一个entry的字长
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.*/
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. */
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. */
// 值
unsigned char *p; /* Pointer to the very start of the entry, that
is, this points to prev-entry-len field. */
} zlentry;
previous_entry_length
读取第一个字节是否为0xfe区分是1个字长还是5个字长(为什么是0xfe,因为0xff被用作结束标志)
- 1字节长,小于0xfe(244)
- 5字节长,第一字节是 0xfe,后面四个字节是实际长度
encoding
根据第一字节前2位,判断是整数还是字符串
- 前2位是00,01,10.这时候是字符串
- 00bbbbbb,后面6位表示content长度,(<=2^6-1 = 63)
- 01bbbbbb xxxxxxxx,用后6位以及后面一个字节表示content长度,共14位(<=16383)
- 10______ aaaaaaaa bbbbbbbb cccccccc dddddddd,5字节长,后4个字节表示长度(<=2^32-1)
- 前2为是11.这时候是整数
- 11 00 0000,content长2,表示int16_t类型
- 11 01 0000,int32_t
- 11 10 0000,int64_t
- 11 11 0000,24位有符号整数
- 11 11 1110,8位有符号整数
- 11 11 xxxx,介于0-12的整数值,直接存在xxxx中