redis字典dict——Part1:數(shù)據(jù)結(jié)構(gòu)

dict是一個(gè)用于維護(hù)key和value映射關(guān)系的數(shù)據(jù)結(jié)構(gòu)烦却,與很多語言中的Map或dictionary類似矾芙。redis實(shí)現(xiàn)了自己的dict實(shí)現(xiàn)菱鸥。redis數(shù)據(jù)庫底層主要使用字典dict來實(shí)現(xiàn)的铆帽,對(duì)redis數(shù)據(jù)庫db的增刪改查都是基于字典進(jìn)行操作的胞枕。這只是它在Redis中的一個(gè)用途而已压真,它在Redis中被使用的地方還有很多娩嚼。比如,一個(gè)Redis hash結(jié)構(gòu)滴肿,當(dāng)它的field較多時(shí)岳悟,便會(huì)采用dict來存儲(chǔ)。再比如泼差,Redis配合使用dict和skiplist來共同維護(hù)一個(gè)sorted set贵少。下面這篇文章先簡(jiǎn)單介紹redis的dict結(jié)構(gòu)體實(shí)現(xiàn)。

字典實(shí)體節(jié)點(diǎn)

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
   // 指向下個(gè)表節(jié)點(diǎn)堆缘,形成鏈表滔灶,解決鏈表沖突
    struct dictEntry *next;
} dictEntry;

dictEntry是redis存儲(chǔ)數(shù)據(jù)的真正實(shí)體,其結(jié)構(gòu)中包含k, v和指向鏈表下一項(xiàng)的next指針吼肥。

  • k是void指針录平,這意味著它可以指向任何類型。
  • v是個(gè)union缀皱,當(dāng)它的值是uint64_t斗这、int64_t或double類型時(shí),就不再需要額外的存儲(chǔ)啤斗,這有利于減少內(nèi)存碎片表箭。當(dāng)然,v也可以是void指針钮莲,以便能存儲(chǔ)任何類型的數(shù)據(jù)免钻。
  • next指向下個(gè)表節(jié)點(diǎn)彼水,形成鏈表,解決hash沖突

字典表結(jié)構(gòu)體

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
    // hash表數(shù)組
    dictEntry **table;
    // hash表大小
    unsigned long size;
    // hash表大小掩碼极舔,用于計(jì)算索引值猿涨,大小等于size-1
    unsigned long sizemask;
    // hash表已有節(jié)點(diǎn)數(shù)量
    unsigned long used;
} dictht;

dictType結(jié)構(gòu)包含若干函數(shù)指針,用于dict的調(diào)用者對(duì)涉及key和value的各種操作進(jìn)行自定義姆怪。這些操作包含:

  • hashFunction叛赚,對(duì)key進(jìn)行哈希值計(jì)算的哈希算法。
  • keyDup和valDup稽揭,分別定義key和value的拷貝函數(shù)俺附,用于在需要的時(shí)候?qū)ey和value進(jìn)行深拷貝,而不僅僅是傳遞對(duì)象指針溪掀。
  • keyCompare事镣,定義兩個(gè)key的比較操作,在根據(jù)key進(jìn)行查找時(shí)會(huì)用到揪胃。
  • keyDestructor和valDestructor璃哟,分別定義對(duì)key和value的析構(gòu)函數(shù)。

dictht結(jié)構(gòu)喊递,它定義一個(gè)哈希表的結(jié)構(gòu)随闪,由如下若干項(xiàng)組成:

  • table: 一個(gè)dictEntry指針數(shù)組。key的哈希值最終映射到這個(gè)數(shù)組的某個(gè)位置上(對(duì)應(yīng)一個(gè)bucket)骚勘。如果多個(gè)key映射到同一個(gè)位置铐伴,就發(fā)生了沖突,那么就拉出一個(gè)dictEntry鏈表俏讹。
  • size:標(biāo)識(shí)dictEntry指針數(shù)組的長(zhǎng)度当宴。它總是2的指數(shù)。
  • sizemask:用于將哈希值映射到table的位置索引泽疆。它的值等于(size-1)户矢,比如7, 15, 31, 63,等等殉疼,也就是用二進(jìn)制表示的各個(gè)bit全1的數(shù)字梯浪。每個(gè)key先經(jīng)過hashFunction計(jì)算得到一個(gè)哈希值,然后計(jì)算(哈希值 & sizemask)得到在table上的位置株依。相當(dāng)于計(jì)算取余(哈希值 % size)驱证。
  • used:記錄dict中現(xiàn)有的數(shù)據(jù)個(gè)數(shù)。它與size的比值就是裝載因子(load factor)恋腕。這個(gè)比值越大抹锄,哈希值沖突概率越高。

字典

typedef struct dict {
    // 類型特定函數(shù)
    dictType *type;
    // 私有數(shù)據(jù)
    void *privdata;
    // 包含兩個(gè)dictht的數(shù)組,一般使用ht[0]伙单,rehash才會(huì)使用的ht[1]
    dictht ht[2];
    // rehash索引
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

dict的結(jié)構(gòu)由如下若干項(xiàng)組成:

  • 一個(gè)指向dictType結(jié)構(gòu)的指針(type)获高。它通過自定義的方式使得dict的key和value能夠存儲(chǔ)任何類型的數(shù)據(jù)。
  • 一個(gè)私有數(shù)據(jù)指針(privdata)吻育。由調(diào)用者在創(chuàng)建dict的時(shí)候傳進(jìn)來念秧。type與privdata針對(duì)不同類型的鍵值對(duì),實(shí)現(xiàn)多態(tài)布疼。
  • 兩個(gè)哈希表(ht[2])摊趾。只有在重哈希的過程中,ht[0]和ht[1]才都有效游两。而在平常情況下砾层,只有ht[0]有效,ht[1]里面沒有任何數(shù)據(jù)贱案。上圖表示的就是重哈希進(jìn)行到中間某一步時(shí)的情況肛炮。
  • 當(dāng)前重哈希索引(rehashidx)。如果rehashidx = -1宝踪,表示當(dāng)前沒有在重哈希過程中侨糟;否則,表示當(dāng)前正在進(jìn)行重哈希瘩燥,且它的值記錄了當(dāng)前重哈希進(jìn)行到哪一步了秕重。
  • 當(dāng)前正在進(jìn)行遍歷的iterator的個(gè)數(shù)。

下圖可以清晰展示redis的dict的數(shù)據(jù)結(jié)構(gòu)


沒有進(jìn)行rehash的字典.png

參考:

http://zhangtielei.com/posts/blog-redis-dict.html
《redis設(shè)計(jì)與實(shí)現(xiàn)》第二版

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颤芬,一起剝皮案震驚了整個(gè)濱河市悲幅,隨后出現(xiàn)的幾起案子套鹅,更是在濱河造成了極大的恐慌站蝠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卓鹿,死亡現(xiàn)場(chǎng)離奇詭異菱魔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吟孙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門澜倦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杰妓,你說我怎么就攤上這事藻治。” “怎么了巷挥?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵桩卵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)雏节,這世上最難降的妖魔是什么胜嗓? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮钩乍,結(jié)果婚禮上辞州,老公的妹妹穿的比我還像新娘。我一直安慰自己寥粹,他們只是感情好变过,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涝涤,像睡著了一般牵啦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妄痪,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天哈雏,我揣著相機(jī)與錄音,去河邊找鬼衫生。 笑死裳瘪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罪针。 我是一名探鬼主播彭羹,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼泪酱!你這毒婦竟也來了派殷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤墓阀,失蹤者是張志新(化名)和其女友劉穎毡惜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斯撮,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡经伙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勿锅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帕膜。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溢十,靈堂內(nèi)的尸體忽然破棺而出垮刹,到底是詐尸還是另有隱情,我是刑警寧澤张弛,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布荒典,位于F島的核電站宗挥,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏种蝶。R本人自食惡果不足惜契耿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望螃征。 院中可真熱鬧搪桂,春花似錦、人聲如沸盯滚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽魄藕。三九已至内列,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間背率,已是汗流浹背话瞧。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寝姿,地道東北人交排。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饵筑,于是被迫代替她去往敵國(guó)和親埃篓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:可能是目前最詳細(xì)的Redis內(nèi)存模型及應(yīng)用解讀 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一根资,通過在內(nèi)存中讀寫數(shù)據(jù)...
    meng_philip123閱讀 1,440評(píng)論 1 22
  • 轉(zhuǎn)載:可能是目前最詳細(xì)的Redis內(nèi)存模型及應(yīng)用解讀 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一架专,通過在內(nèi)存中讀寫數(shù)據(jù)...
    jwnba24閱讀 623評(píng)論 0 4
  • 前言 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一,通過在內(nèi)存中讀寫數(shù)據(jù)玄帕,大大提高了讀寫速度部脚,可以說Redis是實(shí)現(xiàn)網(wǎng)站...
    小陳阿飛閱讀 805評(píng)論 0 1
  • Redis 是一個(gè)鍵值對(duì)數(shù)據(jù)庫(key-value DB),數(shù)據(jù)庫的值可以是字符串桨仿、集合睛低、列表等多種類型的對(duì)象,而...
    吳昂_ff2d閱讀 3,195評(píng)論 0 5
  • 【書香陪伴Day89】玩的小球:站(stand)服傍、坐(sit)。 繼續(xù)看低幼繪本:《好朋友》骂铁。小浣熊在搭房子吹零,小猴...
    心靈一隅閱讀 108評(píng)論 0 0