鍍金池/ 教程/ 大數(shù)據(jù)/ Redis 數(shù)據(jù)結(jié)構(gòu) redisOb
Redis 數(shù)據(jù)淘汰機(jī)制
積分排行榜
小剖 Memcache
Redis 數(shù)據(jù)結(jié)構(gòu) intset
分布式鎖
從哪里開始讀起,怎么讀
Redis 數(shù)據(jù)結(jié)構(gòu) dict
不在浮沙筑高臺
Redis 集群(上)
Redis 監(jiān)視器
源碼閱讀工具
Redis 日志和斷言
內(nèi)存數(shù)據(jù)管理
Redis 數(shù)據(jù)結(jié)構(gòu)綜述
源碼日志
Web 服務(wù)器存儲 session
消息中間件
Redis 與 Lua 腳本
什么樣的源代碼適合閱讀
Redis 數(shù)據(jù)結(jié)構(gòu) sds
Memcached slab 分配策略
訂閱發(fā)布機(jī)制
Redis 是如何提供服務(wù)的
Redis 事務(wù)機(jī)制
Redis 集群(下)
主從復(fù)制
Redis 應(yīng)用
RDB 持久化策略
Redis 數(shù)據(jù)遷移
Redis 事件驅(qū)動詳解
初探 Redis
Redis 與 Memcache
AOF 持久化策略
Redis 數(shù)據(jù)結(jié)構(gòu) redisOb
作者簡介
Redis 數(shù)據(jù)結(jié)構(gòu) ziplist
Redis 數(shù)據(jù)結(jié)構(gòu) skiplist
Redis 哨兵機(jī)制

Redis 數(shù)據(jù)結(jié)構(gòu) redisOb

redisObject 結(jié)構(gòu)簡介

redis 是 key-value 存儲系統(tǒng),其中 key 類型一般為字符串,而 value 類型則為 redis 對象(redis object)。Redis 對象可以綁定各種類型的數(shù)據(jù),譬如 string、list 和set。

typedef struct redisObject {
    // 剛剛好32 bits
    // 對象的類型,字符串/列表/集合/哈希表
    unsigned type:4;
    // 未使用的兩個位
    unsigned notused:2; /* Not used */
    // 編碼的方式,Redis 為了節(jié)省空間,提供多種方式來保存一個數(shù)據(jù)
    // 譬如:“123456789” 會被存儲為整數(shù)123456789
    unsigned encoding:4;
    // 當(dāng)內(nèi)存緊張,淘汰數(shù)據(jù)的時候用到
    unsigned lru:22; /* lru time (relative to server.lruclock) */
    // 引用計數(shù)
    int refcount;
    // 數(shù)據(jù)指針
    void *ptr;
} robj;

其中,void *ptr 已經(jīng)給了我們無限的遐想空間了。

redisObject 數(shù)據(jù)的屬性

redis.h 中定義了 struct redisObject,它是一個簡單優(yōu)秀的數(shù)據(jù)結(jié)構(gòu),因為在 redisObject 中數(shù)據(jù)屬性和數(shù)據(jù)分開來了,其中,數(shù)據(jù)屬性包括數(shù)據(jù)類型,存儲編碼方式,淘汰時鐘,引用計數(shù)。下面一一展開:

數(shù)據(jù)類型,標(biāo)記了 Redis 對象綁定的是什么類型的數(shù)據(jù),有下面幾種可能的值;

/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4

存儲編碼方式,一個數(shù)據(jù),可以以多種方式存儲。譬如,數(shù)據(jù)類型為 REDIS_SET 的數(shù)據(jù)編碼方式可能為 REDIS_ENCODING_HT,也可能為 REDIS_ENCODING_INTSET。

/* 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 */
#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 */

淘汰時鐘,Redis 對數(shù)據(jù)集占用內(nèi)存的大小有「實時」的計算,當(dāng)超出限額時,會淘汰超時的數(shù)據(jù)。

引用計數(shù),一個 Redis 對象可能被多個指針引用。當(dāng)需要增加或者減少引用的時候,必須調(diào)用相應(yīng)的函數(shù),程序員必須遵守這一準(zhǔn)則。

// 增加 Redis 對象引用
void incrRefCount(robj *o) {
    o->refcount++;
    }
    // 減少 Redis 對象引用。特別的,引用為零的時候會銷毀對象
void decrRefCount(robj *o) {
    if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
    // 如果取消的是最后一個引用,則釋放資源
    if (o->refcount == 1) {
    // 不同數(shù)據(jù)類型,銷毀操作不同
    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--;
  }
}

得益于 Redis 是單進(jìn)程單線程工作的,所以增加/減少引用的操作不必保證原子性,這在 memcache 中是做不到的(memcached 是多線程的工作模式,需要做到互斥)。structredisObject 把最后一個指針留給了真正的數(shù)據(jù)。