Redis字典

哈希表

typedef struct dictht{
    dictEntry ** table;     //哈希表數(shù)組
    unsigned long size;     //哈希表大小
    unsigned long sizemask; //哈希表大小掩碼,用于計算索引值席里,總是等于size-1
    unsigned long used;     //該哈希表已有節(jié)點的數(shù)量
}dictht;

其中主要是table用于存放數(shù)據(jù)奖磁,其是一個dictEntry指針數(shù)組

哈希表節(jié)點

typedef struct dictEntry{
    void *key;      //鍵
    union{
        void *val;
        uint64_tu64;
        int64_ts64;
    }v;             //值
    struct dictEntry *next;
}dictEntry;

字典的實現(xiàn)

typedef struct dictEntry{
    dictType *type;     //類型特定函數(shù)
    void *privdata;     //私有數(shù)據(jù)
    dictht ht[2];       //哈希表
    int rehashidx;      //rehash索引咖为,當(dāng)rehash不在進行時,值為-1
}dict;
  • 其中的type屬性和privdata屬性是針對不同類型的鍵值對封恰,為創(chuàng)建多態(tài)字典而設(shè)置的诺舔。
typedef struct dictEntry{
    unsigned int (*hashFunction)(const void *key);                              //計算哈希值的函數(shù)
    void *(*keyDup)(void *privdata,const void *key);                            //復(fù)制鍵的函數(shù)
    void *(*valDup)(void *privdata,const void *obj);                            //復(fù)制值的函數(shù)
    int (*keyCompare)(void *privdata,const void *key1,const void *key2);        //對比鍵的函數(shù)
    void *(*keyDestructor)(void *privdata,const void *key);                     //銷毀鍵的函數(shù)
    void *(*valDestructor)(void *privdata,const void *obj);                     //銷毀值的函數(shù)
}
  • ht是個長度為2的數(shù)組备畦,一般情況下懂盐,字典只使用ht[0]莉恼,ht[1]只在rehash時使用
  • rehashidx也跟rehash有關(guān),記錄了rehash的進度尿背。如果當(dāng)前沒有進行rehash捶惜,則值為-1

哈希算法

當(dāng)有新的鍵值要插入字典時,程序會對鍵進行hash值計算鹤竭,然后計算其索引值臀稚,其步驟如下

  • 計算hash:hash=dict->type->hashFunction(key);
  • 計算索引:indix=hash & dict->ht[x].sizemask;
    redis使用的是MurmurHash2來計算鍵的哈希值

解決鍵的沖突

redis采用鏈地址法來解決鍵的沖突啡直,即每個哈希表節(jié)點有一個next指針酒觅,多個哈希表節(jié)點可以使用next指針構(gòu)成一個單鏈表,被分配到同一個索引的多個節(jié)點就可以使用這個單鏈表連接起來舷丹,以解決鍵的沖突颜凯。

rehash(重新散列)

rehash是對哈希表進行相應(yīng)的擴展和收縮仗扬,即哈希表重新分配內(nèi)存的過程,以維持哈希表的負(fù)載因子在一個合理的范圍
redis對字典的哈希表rehash步驟如下

  1. 為字典的ht[1]哈希表分配空間彼城,其分配的大小取決于執(zhí)行的操作以及ht[0]當(dāng)前包含的鍵值對的數(shù)量(ht[0].used的值)
  • 當(dāng)是擴展操作募壕,則ht[1]的大小為第一個大于等于ht[0].used*2的2^n(2的n次冪)
  • 當(dāng)執(zhí)行的時收縮操作舱馅,則ht[1]的大小為第一個大于等于ht[0].used的2^n
  1. 將保存在ht[0]中的所有鍵值對rehash到ht[1]上面
  2. 當(dāng)ht[0]包含的所有鍵值對遷移到ht[1]之后(ht[0]變?yōu)榭毡恚┐停尫舎t[0],將ht[1]設(shè)置為ht[0]干毅,并在ht[1]新創(chuàng)鍵一個空哈希表溶锭,為下次rehash做準(zhǔn)備

哈希表的負(fù)載因子

負(fù)載因子=哈希表已保存節(jié)點數(shù)量/哈希表大小
load_factor=ht[0].used/ht[0].size

哈希表的擴展與收縮

擴展

  1. 當(dāng)服務(wù)器目前沒有執(zhí)行BGSAVE或者BGREWRITEAOF命令趴捅,且哈希表的負(fù)載因子大于等于1
  2. 服務(wù)器目前正在執(zhí)行BGSAVE或者BGREWRITEAOF命令,并且哈希表的負(fù)載因子大于等于5
  • 在執(zhí)行BGSAVE或者BGREWRITEAOF命令過程中,redis需要創(chuàng)建當(dāng)前服務(wù)器進程的子進程综芥,而大多數(shù)操作系統(tǒng)采用寫時復(fù)制技術(shù)來優(yōu)化子進程的使用效率膀藐,所以在子進程存在期間红省,服務(wù)器會提高執(zhí)行擴展操作所需要的負(fù)載因子吧恃,從而避免在子進程存在期間進行哈希表擴展的操作,這可以避免不必要的內(nèi)存寫入痕寓,最大限度節(jié)約內(nèi)存

收縮

  1. 當(dāng)負(fù)載因子小于0.1時呻率,程序?qū)1磉M行收縮操作

漸進式rehash

rehash并不是由一次性礼仗,集中式完成的藐守,而是分多次卢厂,漸進式地完成的
步驟:

  1. 為ht[1]分配空間
  2. 在字典中維持一個索引計數(shù)器變量rehashidx乾蓬,并設(shè)置為0,表示rehash正式開始
  3. rehash期間,每次對字典執(zhí)行添加慎恒,刪除任内,查找,更新操作時融柬,程序除了執(zhí)行指定操作外死嗦,也會同時將ht[0]哈希表在rehashidx索引上的所有鍵值對rehash到ht[1](避免集中式rehash帶來龐大的計算量),當(dāng)rehash完成粒氧,rehashidx屬性值增加一
  4. 最終在某個時間點上越除,ht[0]上的所有鍵值對都被rehash到ht[1]上,這時程序?qū)ehashidx設(shè)置為-1,表示rehash操作已經(jīng)完成

本文來自redis設(shè)計與實現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摘盆,一起剝皮案震驚了整個濱河市翼雀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孩擂,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件米苹,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機掩缓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門舍哄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丧靡,“玉大人饭庞,你說我怎么就攤上這事×酰” “怎么了拆座?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵躏碳,是天一觀的道長肄渗。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮衙伶,結(jié)果婚禮上慌随,老公的妹妹穿的比我還像新娘蹋艺。我一直安慰自己,他們只是感情好涛救,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天嫌拣,我揣著相機與錄音插掂,去河邊找鬼燎竖。 笑死,一個胖子當(dāng)著我的面吹牛凳鬓,可吹牛的內(nèi)容都是我干的垦梆。 我是一名探鬼主播辽慕,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼欠气,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淋袖?” 一聲冷哼從身側(cè)響起适贸,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谒获,失蹤者是張志新(化名)和其女友劉穎批狱,沒想到半個月后赔硫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年嘹朗,在試婚紗的時候發(fā)現(xiàn)自己被綠了溜歪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡沛豌,死狀恐怖趋箩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情加派,我是刑警寧澤叫确,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站芍锦,受9級特大地震影響竹勉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娄琉,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一次乓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧车胡,春花似錦檬输、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至主卫,卻和暖如春逃默,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背簇搅。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工完域, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘩将。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓吟税,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姿现。 傳聞我的和親對象是個殘疾皇子肠仪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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