本文主要說(shuō)明Redis key-value結(jié)構(gòu)中封裝五種value的
redisObject
結(jié)構(gòu)辩尊。
I洛勉、上帝視角
redisObject
結(jié)構(gòu)主要說(shuō)明value對(duì)象的底層編碼方式遮斥,以及實(shí)際指向等內(nèi)容:
/*src/redis.h/redisObject */
typedef struct redisObject {
// 剛剛好32 bits
// 對(duì)象的類(lèi)型茬底,字符串/列表/集合/哈希表
unsigned type:4;
// 未使用的兩個(gè)位
unsigned notused:2; /* Not used */
// 編碼的方式征绎,Redis 為了節(jié)省空間占键,提供多種方式來(lái)保存一個(gè)數(shù)據(jù)
// 譬如:“123456789” 會(huì)被存儲(chǔ)為整數(shù)123456789
unsigned encoding:4;
// 當(dāng)內(nèi)存緊張昔善,淘汰數(shù)據(jù)的時(shí)候用到
unsigned lru:22; /* lru time (relative to server.lruclock) */
// 引用計(jì)數(shù)
int refcount;
// 數(shù)據(jù)指針,指向真正的數(shù)據(jù)
void *ptr;
} robj;
下面對(duì)以上屬性進(jìn)行一一說(shuō)明畔乙。
II君仆、type屬性
redisObject
數(shù)據(jù)結(jié)構(gòu)將對(duì)象屬性與對(duì)象的數(shù)據(jù)分開(kāi),這樣做有良好的特性牲距,可以先根據(jù)屬性進(jìn)行檢查判斷等操作返咱,這些都不需要直接訪問(wèn)數(shù)據(jù)本身。
其中type屬相標(biāo)記了value對(duì)象的數(shù)據(jù)類(lèi)型:
/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
III牍鞠、encoding屬性
Redis為優(yōu)化內(nèi)存咖摹,對(duì)每種type類(lèi)型都至少會(huì)有兩種底層實(shí)現(xiàn)方式,如zset就可以是ziplist與skiplist难述。
redisObject
結(jié)構(gòu)中的encoding屬性就標(biāo)記了對(duì)象使用的是那種底層數(shù)據(jù)結(jié)構(gòu):
/* 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 REDIS_ENCODING_RAW 0 /* Raw representation */
#define REDIS_ENCODING_INT 1 /* Encoded as integer */
#define REDIS_ENCODING_HT 2 /* Encoded as hash table */
#define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap萤晴,已經(jīng)淘汰 */
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6 /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
IV、refcount屬性
Redis中為了更好的優(yōu)化內(nèi)存空間胁后,對(duì)數(shù)字字符串進(jìn)行了共享內(nèi)存的操作店读,并以引用計(jì)數(shù)方式進(jìn)行管理。
下面的函數(shù)為增加引用及減少應(yīng)用的操作:
// 增加 Redis 對(duì)象引用
void incrRefCount(robj *o) {
o->refcount++;
}
// 減少 Redis 對(duì)象引用攀芯。需要判斷是否需要進(jìn)行析構(gòu)
void decrRefCount(robj *o) {
if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
// 如果取消的是最后一個(gè)引用屯断,則釋放資源
if (o->refcount == 1) {
// 不同數(shù)據(jù)類(lèi)型,銷(xiāo)毀操作不同
switch(o->type) {
case REDIS_STRING: freeStringObject(o); break;
case REDIS_LIST: freeListObject(o); break;
case REDIS_SET: freeSetObject(o); break;
case REDIS_ZSET: freeZsetObject(o); break;
case REDIS_HASH: freeHashObject(o); break;
default: redisPanic("Unknown object type"); break;
}
zfree(o);
} else {
o->refcount--;
}
}
對(duì)于這里的引用計(jì)數(shù)來(lái)說(shuō),因?yàn)镽edis是單線程工作模式的裹纳,所以引用計(jì)數(shù)的增加和減少不比保證原子性择葡。
V、lru屬性
Redis對(duì)數(shù)據(jù)集占用內(nèi)存的大小由周期性的計(jì)算剃氧,當(dāng)超出限制時(shí)敏储,會(huì)淘汰超時(shí)的數(shù)據(jù)。即淘汰的標(biāo)準(zhǔn)為:oversize & overtime朋鞍。
【參考】
[1] 《Redis設(shè)計(jì)與實(shí)現(xiàn)》
[2] 《Redis源碼日志》