本章將對 Redis 數(shù)據(jù)庫的構(gòu)造和實現(xiàn)進行討論。
除了說明數(shù)據(jù)庫是如何儲存數(shù)據(jù)對象之外,本章還會討論鍵的過期信息是如何保存,而 Redis 又是如何刪除過期鍵的。
Redis 中的每個數(shù)據(jù)庫,都由一個 redis.h/redisDb
結(jié)構(gòu)表示:
typedef struct redisDb {
// 保存著數(shù)據(jù)庫以整數(shù)表示的號碼
int id;
// 保存著數(shù)據(jù)庫中的所有鍵值對數(shù)據(jù)
// 這個屬性也被稱為鍵空間(key space)
dict *dict;
// 保存著鍵的過期信息
dict *expires;
// 實現(xiàn)列表阻塞原語,如 BLPOP
// 在列表類型一章有詳細的討論
dict *blocking_keys;
dict *ready_keys;
// 用于實現(xiàn) WATCH 命令
// 在事務(wù)章節(jié)有詳細的討論
dict *watched_keys;
} redisDb;
下文將詳細討論 id
、 dict
和 expires
三個屬性,以及針對這三個屬性所執(zhí)行的數(shù)據(jù)庫操作。
redisDb
結(jié)構(gòu)的 id
域保存著數(shù)據(jù)庫的號碼。
這個號碼很容易讓人將它和切換數(shù)據(jù)庫的 SELECT 命令聯(lián)系在一起,但是,實際上,id
屬性并不是用來實現(xiàn) SELECT 命令,而是給 Redis 內(nèi)部程序使用的。
當 Redis 服務(wù)器初始化時,它會創(chuàng)建出 redis.h/REDIS_DEFAULT_DBNUM
個數(shù)據(jù)庫,并將所有數(shù)據(jù)庫保存到 redis.h/redisServer.db
數(shù)組中,每個數(shù)據(jù)庫的 id
為從 0
到 REDIS_DEFAULT_DBNUM - 1
的值。
當執(zhí)行 SELECT number
命令時,程序直接使用 redisServer.db[number]
來切換數(shù)據(jù)庫。
但是,一些內(nèi)部程序,比如 AOF 程序、復(fù)制程序和 RDB 程序,需要知道當前數(shù)據(jù)庫的號碼,如果沒有 id
域的話,程序就只能在當前使用的數(shù)據(jù)庫的指針,和 redisServer.db
數(shù)組中所有數(shù)據(jù)庫的指針進行對比,以此來弄清楚自己正在使用的是那個數(shù)據(jù)庫。
以下偽代碼描述了這個對比過程:
def PSEUDO_GET_CURRENT_DB_NUMBER(current_db_pointer):
i = 0
for db_pointer in redisServer.db:
if db_pointer == current_db_pointer:
break
i += 1
return i
有了 id
域的話,程序就可以通過讀取 id
域來了解自己正在使用的是哪個數(shù)據(jù)庫,這樣就不用對比指針那么麻煩了。
因為 Redis 是一個鍵值對數(shù)據(jù)庫(key-value pairs database),所以它的數(shù)據(jù)庫本身也是一個字典(俗稱 key space):
在 redisDb
結(jié)構(gòu)的 dict
屬性中,保存著數(shù)據(jù)庫的所有鍵值對數(shù)據(jù)。
下圖展示了一個包含 number
、 book
、 message
三個鍵的數(shù)據(jù)庫 ——其中 number
鍵是一個列表,列表中包含三個整數(shù)值;book
鍵是一個哈希表,表中包含三個鍵值對;而 message
鍵則指向另一個字符串:
更多建議: