標籤:style color io strong ar for 資料 cti sp
資料庫操作
1) REDIS是全部由KEY和VALUE值構成,對資料庫的增刪改查操作都是基於在通過key 映射到雜湊槽 然後通過雜湊槽進行單向鏈式遍曆 尋找到value和具體的key。
同樣 在查看大師寫的源碼時可以說是一種很好借鑒:
這裡所有的操作已經主體源碼引用都是zai redis/src/db.c下進行的:
查
robj *lookupKey(redisDb *db, robj *key) {
dictEntry *de = dictFind(db->dict,key->ptr);
if (de) {
robj *val = dictGetVal(de);
/* Update the access time for the ageing algorithm.
* Don‘t do it if we have a saving child, as this will trigger
* a copy on write madness. */
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
val->lru = server.lruclock;
return val;
} else {
return NULL;
}
}
lookforKey: 根據key 來尋找value
robj 是redis提出的一個抽象對象類【當然是用C寫的 但是這是一層抽象層】含有一系列redis所需要的參數資料,在這裡 通過dictFind尋找之後就可以得到dicEntry 【就是dic最基本的元素/含有key value指標】 就會構造出一個robj需要的值。
中間的rdb_child_pid和aof_child_pid是伺服器做持久化緩衝的2種進位,redis通過cow策略來做,如果有正在做持久化的一個動作,就會去設定lru變數 這個等到後面持久化等部分會詳細介紹。
在這裡: 有一個細節點: void *val 是dicEntry一個變數,怎麼robj *val 就可以得到dicGetVal(de)呢 而且還能順利的得到val的lru值呢?
因為所有寫操作 都是通過robj對象寫進去的 只不過在dicEntry定義void*類型。
這個操作是最基本的 不管做增刪改查 都需要調用lookforKey
robj *lookupKeyRead(redisDb *db, robj *key) {
robj *val;
expireIfNeeded(db,key);
val = lookupKey(db,key);
if (val == NULL)
server.stat_keyspace_misses++;
else
server.stat_keyspace_hits++;
return val;
}
redis是一個支援索引值存在長度的資料庫,所以呢 在寫和讀的上層操作時 都需要做一個expireIfNeed的操作。這個操作就是看看Key到期了沒 這個Key的時間熱度 在後面的部分也詳細做分析
stat_keyspace_misss 就是統計整個伺服器的Key不存在的總數量,這些資料給server做出相應的決策 在後面同樣要進行分析server一系列的資料
robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {
robj *o = lookupKeyRead(c->db, key);
if (!o) addReply(c,reply);
return o;
}
這裡是REDISClient做抽象的 如果robj 不是NULL,那麼都會給用戶端返回一個結果 這個結果都是統一用addReply函數來實現寫
void dbAdd(redisDb *db, robj *key, robj *val) {
sds copy = sdsdup(key->ptr);
int retval = dictAdd(db->dict, copy, val);
redisAssertWithInfo(NULL,key,retval == REDIS_OK);
}
這個函數就是添加操作。調用dic裡的添加函數,可以看出redis所有的redis都是一個字串構成, sds 是char*。所以這裡存的copy就是一個指向字串的指標。
注意點: 這裡的Key是複製一份到copy中的,為什麼這麼做,如果主調程式刪除了Key空間,但是我按照功能來講:redis是一個儲存Key和value的結構,不管主調程式是否釋放空間,我都應該存在 只有當使用者發出刪除命令或者達到時間限制命令才會釋放key空間。這裡的sdsdup是一個複製一個字串的過程。
處理修改KEY
- /*-----------------------------------------------------------------------------
- * Hooks for key space changes.
- *
- * Every time a key in the database is modified the function
- * signalModifiedKey() is called.
- *
- * Every time a DB is flushed the function signalFlushDb() is called.
- *----------------------------------------------------------------------------*/
- void signalModifiedKey(redisDb *db, robj *key) {
- touchWatchedKey(db,key);
- }
- void signalFlushedDb(int dbid) {
- touchWatchedKeysOnFlush(dbid);
- }
這裡先來看key 每當key被改變時,都會調用touchWatchedKey(db,key). 在redis每次做改 為什麼會調用這個function呢?
以及touchWatchedKey的具體含義在哪裡?
在事務部分可以看到 每當上層修改操作進行改這個key時 都會調用touchWatchedKey() 如果Key沒有touched 進行正常的增刪改
如果有的話,主調函數進行正常的增刪改,只不過會做相應的redisClient的DIR改寫
redis DB操作