Redis中字典 Dictionary 的實現

2021-09-24 13:55:51 字數 2846 閱讀 6210

字典

字典,又稱為符號表(symbol table)、關聯表(associative array)或對映(map),是一種用於儲存鍵值對(key-value pair)的抽象資料結構。

在字典裡面,乙個鍵(key)可以和乙個值(value)進行關聯(將鍵對映為值)

字典中的每個鍵都是獨一無二的,程式可以在字典中根據鍵查詢與之關聯的值,或者通過鍵更新值,又或者根據鍵來刪除整個鍵值對。

redis所使用的c語言裡面沒有內建這種資料結構,所以redis構建了自己的字典實現。

字典在redis中的應用廣泛,比如redis的資料庫就是使用字典來作為底層實現的,對資料庫的增刪改查操作也都是構建在字典的操作上的。

幾個例子,當我們執行命令

在資料庫中建立了乙個鍵為msg,值為 hello world的鍵值對,這個鍵值對就是儲存在代表資料庫的字典裡面的。

除了用來表示資料庫之外,字典還是hash鍵的底層實現之一,當乙個hash鍵包含的鍵值對比較多,又或者鍵值對中的元素是比較長的字串時,redis就會使用字典作為雜湊鍵的底層實現。

字典的實現

redis的字典使用雜湊表作為底層實現,乙個雜湊表裡面可以有多個雜湊表節點,而每個雜湊表節點就儲存了字典中的乙個鍵值對。

1.1 雜湊表

redis字典所使用的雜湊表由dict.h/dictht結構定義

typedef struct dictht

table屬性是乙個陣列,陣列中每個元素都是乙個指向dict.h/dictentry結構的指標,每個dictentry結構儲存著乙個鍵值對。size屬性記錄了雜湊表的大小,也即是table陣列的大小,而used屬性則記錄了hash表目前已有節點的數量。sizemask屬性的值總是等於size-1,這個屬性和雜湊值一起決定乙個鍵應該被放到table陣列的那個索引上面。

1.2 雜湊表節點

雜湊表節點使用dictentry結構表示,每個dictentry結構都儲存著乙個鍵值對:

typedef struct dictentry v

struct dictentry *next;

}dictentry;

key屬性儲存著鍵值對中的鍵,而v屬性則儲存著鍵值對中的值,其中鍵值對的值可以是乙個指標,或者乙個整數。

next屬性是指向下乙個雜湊表節點,這個指標可以將多個雜湊值相同的鍵值對鏈結在一起,以此來解決鍵衝突問題。

1.3 字典

redis中的字典由dict.h/dict結構表示:

typedef struct dict

type屬性和privdata屬性是針對不同型別的鍵值對,為建立多型字典而設定的。

type屬性是乙個指向dicttype結構的指標,每個dicttype結構儲存了一簇用於操作特定型別鍵值對的函式,redis會為不同用途的字典設定不同型別的特定函式。

而private屬性則儲存了需要傳給那些型別特定函式的可選引數

typedef struct dicttype

ht屬性是乙個包含兩個項的陣列,陣列中的每個項都是乙個dictht雜湊表,一邊情況下,字典除了只使用ht[0]雜湊表,ht[1]雜湊表只會在對ht[0]雜湊表進行rehash是使用。

除了ht[1]之外,另乙個和rehash有關的屬性是rehashidx,它記錄了rehash目前的進度,如果目前沒有在進行rehash,那麼他的值應該為-1。

雜湊演算法

當要將乙個新的鍵新增到字典裡面時,程式先根據鍵值對的鍵計算出雜湊值和索引值,然後再更加索引值,將包含新鍵值對的雜湊表節點放到雜湊表陣列的指定索引上面。

hash = dict->type->hashfunction(key);

index= hash&dict->ht[x].sizemask;

解決鍵衝突

當有兩個或以上數量的鍵被分配到了雜湊表陣列的同乙個索引上面時,我們稱這些鍵發生了衝突,拉鍊法解決衝突。具體的解決方法可以參考hashmap的實現原理。這裡就不具體贅述了。著重講解下面的rehash和漸進式hash。

rehash

隨著操作的不斷增加,雜湊表儲存的鍵值對會逐漸的增多或者減少,為了讓雜湊表的負載儲存在乙個合理的範圍之內,當雜湊表儲存的鍵值對數量太多或者太少時,程式對hash表的大小進行動態的擴充套件或者收縮。

拓展和收縮雜湊表的工作可以通過執行rehash操作來完成,redis的字典的rehash過程如下:

1)為字典的ht[1]雜湊表分配空間,這個雜湊表空間大小取決於要執行的操作,以及ht[0]當前包含的鍵值對數量(也即是ht[0].used屬性的值)

2) 將保持在ht[0]中所有鍵值對rehash到ht[1]上面,rehash指的是重新計算hash值和索引值,然後將鍵值對放置到ht[1]雜湊表指定位置上。

3)當ht[0]包含的所有鍵值對都遷移到ht[1]之後,釋放ht[0],當ht[1]設定為ht[0],並在ht[1]新建立空白雜湊表,為下一次hash做準備。

下面舉個例子,架設程式要對圖4-8所示字典的ht[0]進行拓展操作,那麼程式將執行以下步驟:

XLua 在Lua中遍歷C 的Dictionary

前些日子在處理一段客戶端資料時遇到這樣乙個問題,嘗試了各種的迴圈遍歷,結果都是不行,後來發現這段資料是c 的dictionary。我們在lua中可以通過獲取迭代器的方式來遍歷c 的dictionary。廢話不多說,直接上 local playerinfo cs.sg.playerdata.insta...

Redis基礎3(redis字典操作)

importredis conn redis.redis host 192.168.131.129 port 6379,password 123456 存值 conn.hset k4 name 123 conn.hset k4 age 66 取值 取單個值 val conn.hget k4 name...

Redis 字典的實現 2

1.redis 字典 hash演算法 根據key計算hash值 hash dict type hashfunction key 根據sizemask屬性和雜湊值,計算出索引,ht x 可以是ht 0 或ht 1 index hash dict ht x sizemask redis使用murmurh...