在 Redis 的命令中, 用於對鍵 (key) 進行處理的命令佔了很大一部分, 而對於鍵所保存的值的類型, 鍵能執行的命令又各不相同.redis
好比說, LPUSH
和 LLEN
只能用於列表鍵, 而 SADD
和 SRANDMEMBER
只能用於集合鍵, 等等.數據庫
另一些命令, 好比 DEL
、 TTL
和 TYPE
, 能夠用於任何類型的鍵, 可是, 要正確實現這些命令, 必須爲不一樣類型的鍵設置不一樣的處理方式: 好比說, 刪除一個列表鍵和刪除一個字符串鍵的操做過程就不太同樣.數據結構
以上的描述說明, Redis 必須讓每一個鍵都帶有類型信息, 使得程序能夠檢查鍵的類型, 併爲它選擇合適的處理方式.函數
好比說, 集合類型就能夠由字典和整數集合兩種不一樣的數據結構實現, 可是, 當用戶執行 ZADD 命令時, 他/她應該沒必要關心集合使用的是什麼編碼, 只要 Redis 能按照 ZADD
命令的指示, 將新元素添加到集合就能夠了。編碼
這說明, 操做數據類型的命令除了要對鍵的類型進行檢查以外, 還須要根據數據類型的不一樣編碼進行多態處理.spa
爲了解決以上問題, Redis 構建了本身的類型系統, 這個系統的主要功能包括:指針
redisObject 是 Redis 類型系統的核心, 數據庫中的每一個鍵、值, 以及 Redis 自己處理的參數, 都表示爲這種數據類型.code
/* * Redis 對象 */ typedef struct redisObject { // 類型 unsigned type:4; // 對齊位 unsigned notused:2; // 編碼方式 unsigned encoding:4; // LRU 時間(相對於 server.lruclock) unsigned lru:22; // 引用計數 int refcount; // 指向對象的值 void *ptr; } robj;
type、 encoding 和 ptr 是最重要的三個屬性.server
type
記錄了對象所保存的值的類型, 它的值多是如下常量的其中一個.對象
/* * 對象類型 */ #define REDIS_STRING 0 // 字符串 #define REDIS_LIST 1 // 列表 #define REDIS_SET 2 // 集合 #define REDIS_ZSET 3 // 有序集 #define REDIS_HASH 4 // 哈希表
encoding
記錄了對象所保存的值的編碼, 它的值多是如下常量的其中一個.
/* * 對象編碼 */ #define REDIS_ENCODING_RAW 0 // 編碼爲字符串 #define REDIS_ENCODING_INT 1 // 編碼爲整數 #define REDIS_ENCODING_HT 2 // 編碼爲哈希表 #define REDIS_ENCODING_ZIPMAP 3 // 編碼爲 zipmap #define REDIS_ENCODING_LINKEDLIST 4 // 編碼爲雙端鏈表 #define REDIS_ENCODING_ZIPLIST 5 // 編碼爲壓縮列表 #define REDIS_ENCODING_INTSET 6 // 編碼爲整數集合 #define REDIS_ENCODING_SKIPLIST 7 // 編碼爲跳躍表
也就是經過 encoding
來對鍵進行不一樣的操做.
ptr
是一個指針, 指向實際保存值的數據結構, 這個數據結構由 type
屬性和 encoding
屬性決定.
舉個例子, 若是一個 redisObject 的 type 屬性爲 REDIS_LIST, encoding 屬性爲 REDIS_ENCODING_LINKEDLIST
, 那麼這個對象就是一個 Redis 列表, 它的值保存在一個雙端鏈表內, 而 ptr 指針就指向這個雙端鏈表;
另外一方面, 若是一個 redisObject 的 type 屬性爲 REDIS_HASH
, encoding 屬性爲 REDIS_ENCODING_ZIPMAP
, 那麼這個對象就是一個 Redis 哈希表, 它的值保存在一個 zipmap 裏, 而 ptr 指針就指向這個 zipmap.
下圖展現了 redisObject 、Redis 全部數據類型、以及 Redis 全部編碼方式(底層實現)三者之間的關係:
有了 redisObject 結構的存在, 在執行處理數據類型的命令時, 進行類型檢查和對編碼進行多態操做就簡單得多了.
當執行一個處理數據類型的命令時, Redis 執行如下步驟:
做爲例子,如下展現了對鍵 key 執行 LPOP 命令的完整過程:
值得注意的是:
我下載了兩個版本的 Redis, 5.0.5 和 3.0.7.
其中 5.0.5 存在 server.h 中, 3.0.7 存在 redis.h 中.
可使find ./ -name "*" | xargs grep "redisObject"
搜索如下.