1.对象结构体robj
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
熟悉redis的都知道。redis是一个k-v型的数据库。其中key只能是字符串。但value可以是字符串,列表,集合,有序集合的哈希。
这五种类型在redis中被称为对象结构体robi。
server.h/506:
/* The actual Redis Object */
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
以上五种代表的是type。
并且,针对某一类的对象,redis有可能采取不同的底层存储策略。
server.h/651:
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The ‘encoding’ field of the object
* is set to one of this fields for this object. */
#define OBJ_ENCODING_RAW 0 /* Raw representation */ 数据结构:SDS。可存储的类型:字符串。
#define OBJ_ENCODING_INT 1 /* Encoded as integer */ 数据结构:整数。可存储的类型:字符串。
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */ 数据类型:字典。可存储的类型:集合,hash,有序集合。
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ 压缩字典
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */未使用。
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ 压缩列表。hash,zset
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */ 整数集合。set
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ 跳表。zset
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */ SDS。字符串
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */ 快速列表。list
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */ stream。stream
以上的11种,代表了当前对象底层存储采用的数据结构。即encoding。
第一:对象在不同的情况下可能采取不同的数据结构存储。比如上的OBJ_ENCODING_INTSET 6和OBJ_ENCODING_HT 2。如果一个set中全是整型,那么就会用前者存储。如果在sadd是存了非整型,那么就会变为后者。
第二:同一对象,会采用不同的数据类型存储吗。从上面的举例不难看出,会的。并且实际占用的空间不会太多,因为存的都是指针。
举例:
typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset;
zset实际上字典和跳表都有存储。
第三:SDS的OBJ_ENCODING_RAW和OBJ_ENCODING_EMBSTR有什么区别。
OBJ_ENCODING_EMBSTR主要是为了方便存储。如果robj存储的数据能用long类型表示,数据直接存储在ptr。不然的话,你存放一个sds,既要申请robj,又要申请sds,并且内存还不连续。效率是十分慢的。
然后整个数据在内存中对齐是这么的:
上面是robj,下面是sds。
lru存储的是和淘汰策略有关的数据。
搞16位存储的是该对象上次的访问时间。低8位存储的是该对象的访问次数。
原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/273748.html