Redis原始碼分析之SET流程

2021-10-07 02:52:54 字數 3580 閱讀 3303

本篇分析redis 如何處理set指令

客戶端解析使用者輸入、構造指令

redisformatsdscommandar**()

clisendcommand()

issuecommandrepeat()

repl()

例如使用者輸入set abcd 2,則構造的指令就是*3\r\n$3\r\nset\r\n$4\r\nabcd\r\n$1\r\n2\r\n*後面表示指令+引數的個數,$後面表示當前引數的長度,然後緊跟引數值。

伺服器端,無論使用者輸入的是set還是set xx px還是其他set引數,均有setcommand函式執行,setcommand函式簡單判斷否有nxpx等然後提取超時時間,接著呼叫setgenericcommand執行實際set操作。set指令儲存在字典裡面。

void

setcommand

(client *c)

elseif(

(a[0]==

'x'|| a[0]

=='x')&&

(a[1]==

'x'|| a[1]

=='x'

)&& a[2]

=='\0'&&!

(flags & obj_set_nx)

)elseif(

(a[0]==

'e'|| a[0]

=='e')&&

(a[1]==

'x'|| a[1]

=='x'

)&& a[2]

=='\0'&&!

(flags & obj_set_px)

&& next)

elseif(

(a[0]==

'p'|| a[0]

=='p')&&

(a[1]==

'x'|| a[1]

=='x'

)&& a[2]

=='\0'&&!

(flags & obj_set_ex)

&& next)

else

} c->ar**[2]

=tryobjectencoding

(c->ar**[2]

);setgenericcommand

(c,flags,c->ar**[1]

,c->ar**[2]

,expire,unit,

null

,null);

}

setgenericcommand函式

void

setgenericcommand

(client *c,

int flags, robj *key, robj *val, robj *expire,

int unit, robj *ok_reply, robj *abort_reply)

if(unit == unit_seconds) milliseconds *

=1000;}

/*key存在,返回失敗,這符合set nx語義

* key不存在,返回失敗,這符合set xx語義

*/if

((flags & obj_set_nx &&

lookupkeywrite

(c->db,key)

!=null)||

(flags & obj_set_xx &&

lookupkeywrite

(c->db,key)

==null))

/*這是核心set指令的操作*/

setkey

(c->db,key,val)

; server.dirty++

;/*如果key設定了超時,例如setex 或者set px,則將key加入到expires的hash鍊錶

*超時這是乙個單獨的dict,下文會單獨說明為什麼需要expires

*/if(expire)

setexpire

(c,c->db,key,

mstime()

+milliseconds)

;notifykeyspaceevent

(notify_string,

"set"

,key,c->db->id);if

(expire)

notifykeyspaceevent

(notify_generic,

"expire"

,key,c->db->id)

;addreply

(c, ok_reply ? ok_reply : shared.ok)

;}

void

setkey

(redisdb *db, robj *key, robj *val)

else

/*這裡對val的引用計數++,因為外層會無條件對va引用計數--,這裡保證val不會被釋放*/

incrrefcount

(val)

;/*將key從expires移除,因為有這麼一種可能性,就是先setex key 設定的超時時間,後來沒超時後,又設定了 set key不帶超時時間,

*此時就要從expires中刪除。

*這裡無論此次操作是不是需要設定超時,都會無條件刪除,因為外層setgenericcommand會加expired。

*/removeexpire

(db,key)

;signalmodifiedkey

(db,key)

;}

setkey的邏輯比較繞,按照正常理解,如果自己實現乙個set操作,首先應該就是查詢key,查到key則設定value,查不到就新建key,然後設定value。redis考慮了函式的封裝性以及解耦,犧牲了部分效能。

其次,對應有超時需求的key,均會加入乙份key到db->expires,他是單獨管理超時的hash鍊錶,為什麼需要單獨乙份?這是效能優化上的設計。假設你有100w個key,如果沒有db->expires,每當判斷老化時,需要在包含100w個db->dict裡面查詢所有,顯然這是不能接受的。有了db->expires,查詢得到老化的key,key沒有則不查詢db->dict,key有,則查詢db->expires連指定的key。

我們看下dbadd的情況,即key不存在,然後加key的情況。

void

dbadd

(redisdb *db, robj *key, robj *val)

set的操作,總的來說並不複雜,實際就是dictadd,新增到字典,即hash表。

STL原始碼分析set

include include using namespace std int main set iset ia,ia 5 cout size iset.size endl cout 3 count iset.count 3 endl iset.insert 3 cout size iset.siz...

Redis原始碼分析之unlock

override public void unlock if opstatus 第一步 發布解鎖訊息刪除key protected rfutureunlockinnerasync long threadid 呼叫lua指令碼,exists命令 若 key 存在返回 1 否則返回 0 publish ...

redis之string原始碼分析

string資料型別的物件編碼有兩種,分別是embstr和raw。兩種編碼的區別並不大,embstr相對於raw,記憶體空間連續。兩者的資料格式見下圖 redis的string資料之所以使用embstr和raw兩種編碼格式,是為了當乙個string物件的值比較小時,使用乙個連續的記憶體分割槽存放re...