Redis基本数据类型:列表(list)
Redis内部使用两种结构实现list:
- 压缩列表(ziplist)
- 快速列表(quicklist)
1. 压缩列表(ziplist)
当列表存储的是整数或者很短的字符串时,Redis内部会优先使用ziplist。
使用这种结构时,redisObject.encoding = OBJ_ENCODING_ZIPLIST
ziplist是由三部分组成,header + entries + end
- ziplist header
ziplist head 是由两个unsigned int 和一个unsigned short组成,占用10Byte。其中第一个unsigned int存储ziplist占用的所有内存,第二个unsigned int存储列表尾部节点距离起始位置的偏移量,最后一个unsigned short记录的是节点数量,定义如下:
#define ZIPLIST_HEADER_SIZE (sizeof(uint32_t)2+sizeof(uint16_t))
#define ZIPLIST_BYTES(zl) (((uint32_t*)(zl)))
#define ZIPLIST_TAIL_OFFSET(zl) (((uint32_t)((zl)+sizeof(uint32_t))))
#define ZIPLIST_LENGTH(zl) (((uint16_t)((zl)+sizeof(uint32_t)*2)))
- ziplist entries
ziplist entries是一段连续的内存空间,所以我们可以把他当成数组来访问。
zlentry用于记录每个节点的信息,结构如下:
typedef struct zlentry {
unsigned int prevrawlensize;
unsigned int prevrawlen;
unsigned int lensize;
unsigned int len;
unsigned int headersize;
unsigned char encoding;
unsigned char *p;
} zlentry;
ziplist内部还定义了两个指针,一个指向第一个entry,一个指向最后一个entry,这样就把lpush和rpush的时间复杂度都降到了O(1),定义如下:
#define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE)
#define ZIPLIST_ENTRY_TAIL(zl) ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))
- ziplist end
ziplist end是一个固定的标示符255,占用1Byte
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
2. 快速列表(quicklist)
使用这种结构时,redisObject.encoding = OBJ_ENCODING_QUICKLIST
quicklist的定义如下:
typedef struct quicklist {
quicklistNode *head;
quicklistNode *tail;
unsigned long count;
unsigned long len;
int fill : 16;
unsigned int compress : 16;
} quicklist;
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz;
unsigned int count : 16;
unsigned int encoding : 2;
unsigned int container : 2;
unsigned int recompress : 1;
unsigned int attempted_compress : 1;
unsigned int extra : 10;
} quicklistNode;
quicklistNode采用的是双向链表进行索引,为了节省空间,每一个node里面存储的时一个ziplist(zl).当每个ziplist大小超过8K时,才会重新创建一个新的quicklistNode。
#define SIZE_SAFETY_LIMIT 8192
if (_quicklistNodeAllowInsert(…)) {
ziplistPush(…);
} else {
quicklistNode *node = quicklistCreateNode();
ziplistPust(…);
}
3. command
- BLPOP - Remove and get the first element in a list, or block until one is available
- BRPOP - Remove and get the last element in a list, or block until one is available
- BRPOPLPUSH - Pop a value from a list, push it to another list and return it; or block until one is available"
- LINDEX - Get an element from a list by its index
- LINSERT - Insert an element before or after another element in a list
- LLEN - Get the length of a list
- LPOP - Remove and get the first element in a list
- LPUSH - Prepend one or multiple values to a list
- LPUSHX - Prepend a value to a list, only if the list exists
- LRANGE - Get a range of elements from a list
- LREM - Remove elements from a list
- LSET - Set the value of an element in a list by its index
- LTRIM - Trim a list to the specified range
- RPOP - Remove and get the last element in a list
- RPOPLPUSH - Remove the last element in a list, prepend it to another list and return it
- RPUSH - Append one or multiple values to a list
- RPUSHX - Append a value to a list, only if the list exists
上一篇:Redis学习小计(4) - 基本数据类型:字符串(string)
下一篇:Redis学习小计(6) - 基本数据类型:哈希(hash)