資料結構
typedef struct sdstr
sds是字串物件的底層實現之一
sds的特性
賦值操作會統計字串的長度然後將字串存入buff裡面,同時設定長度和使用的長度
例如 "hello"這個字串的儲存結構如下
修改的時候會比較麻煩,分為兩種情況
一是由段字串變長:例如:由"hello"變為"hello,redis".
這個時候系統會檢查原本的sds字串是否有空餘空間,剩餘空間為0,會分配等同於修改後字串長度的剩餘空間給sds,這個時候字串的free屬性會變為11,然後執行sdscat(),這個時候buff會變為['h','e','l','l','o',',','r','e','d','i','s','\0'],然後將字串長度len修改為11
最終結構如下
ps:當長度小於1m是翻倍擴容,超過1m時是以1m為標準定量擴容
二是由長字串變短
例如:由"hello,redis"變為"redis",這個時候會釋放多餘空間,同時把free值設為多出來的空間,以便下次使用方便
修改後的結構大概如下
需要釋放的時候可以手動呼叫函式來釋放空間
為什麼要使用sds?
sds可以杜絕緩衝區溢位的問題,獲取字串長度複雜度為常數
二進位制安全,sds使用len屬性來判斷字串的結束
減少字串修改時的記憶體重分配次數
資料結構
//鍊錶節點
typedef struct listnodelistnode;
//鍊錶
typedef struct list
鍊錶是列表物件的底層實現之一
鍊錶在redis中主要負責的是儲存和維護某一類物件,所常用到的操主要有遍歷,修改等
鍊錶在redis中使用極為廣泛,redis的事務,發布與訂閱,伺服器中維護的redisclient資訊等都是用鍊錶結構進行的儲存
資料結構
//雜湊表
typedef struct dictht dictht;
//雜湊節點
typedef struct dictentry v;
struct dictentry *next;
}dictentry;
//字典
typedef struct dictdict;
字典是資料庫的底層實現
解決鍵衝突
redis使用鏈位址法(separate chaining)來解決鍵衝突,當兩個鍵的index值相同時,會把第二個鍵放到第乙個鍵的前面,查詢時對這個index的雜湊節點鍊錶進行遍歷
rehash:
當雜湊表的負載因子(load factor)大於設定值時(平時為1,在bgrewriteaof時為5),雜湊表會進行rehash操作
rehash採用漸進式的方式進行執行,具體流程就是把ht[0]裡面的資料重新進行雜湊計算放到ht[1],此時的雜湊查詢操作兩個表同時提供服務,寫入操作則只有ht[1]提供,這樣ht[0]處於只減不增的狀態,最終當ht[0]裡面的所有資料都被轉移到ht[1]時,rehashidx被設為-1,表明rehash結束,刪除ht[0],並將ht[1]設為ht[0],同時重新分配新的ht[1]
ps:負載因子 = used /size;
資料結構
//跳躍表節點
typedef struct zskiplistnode level;
} zskiplistnode;
//跳躍表
typedef struct zskiplist zskiplist;
跳躍表是有序集合的底層實現之一
跳躍表中的頭結點不計算在length長度之內,跳躍表的節點排序按照分值從小到大排序
每次建立新節點的時候,redis會根據冪次定律隨機生成乙個1-32的層數作為level陣列的大小,每個節點都有指向表尾方向的前進指標和之前表頭方向的後退指標,這兩個指標可以讓程式方便的遍歷所有節點,層的跨度用於記錄兩點之間的距離,跨度可以用來計算rank值.節點的分值是乙個double值,節點的物件是乙個指標,指向乙個儲存著sds字串的字串物件(下一節講redis物件)
資料結構
typedef struct intset intset;
顧名思義整數集合是用來儲存整數值的抽象資料結構
集合中不會出現重複元素
contents陣列中儲存的整數值有小到大排列
length等於contents的長度
雖然contents的定義是int8_t 但實際上contents的值型別由encoding決定
公升級當乙個新元素超過原來整數集合encoding定義的值的型別時,會進行公升級,公升級結果會使集合的encoding變成所有陣列中元素的值最大的資料型別,並且不支援降級
例如:有乙個整數集合[1,2,3],本身的編碼為int8,現在增加乙個300的數字進該集合,會導致集合的編碼公升級為int16,這個時候列表的大小由8x3=24 變為 16x4=64,即便int8可以儲存前三個值,但是為了簡單起見,仍然會為集合中每乙個元素分配同樣的空間
壓縮列表被用作列表鍵和雜湊鍵的底層實現
壓縮列表屬於特殊的結構,是一種資料儲存的方式,目的是為了節約記憶體,是一種採用特殊編碼的連續記憶體塊組成的順序型(sequential)資料結構.
大致結構如下:
zlbytes
zltail
zllen
entry1
entry2
...zlend
每個壓縮列表由如下三部分組成
previous_entry_length
encoding
content
前一節點的長度
記錄content的型別和長度
節點的值
如果前乙個節點長度小於254位元組,previous_entry_length會使用1位元組空間儲存這個長度,如果大於254位元組,將使用5位元組長度儲存這個值,這個機制會引起"連鎖更新"
連鎖更新: 假設現有連續的三個壓縮列表節點l1,l2,l3,長度分別為 253,253,253,現在往第乙個節點前新增乙個長度超過254的節點,這個時候l1要給previous_entry_length分配5個位元組來儲存長度,所以列表本身長度會變為257,這將導致l2也需要5位元組儲存l1的長度,l3也會產生同樣的變化,這樣由乙個列表操作引起的一系列更新操作成為連鎖更新
redis基本資料結構 1
redis的作者為了方便自己的使用,在redis中定義了動態字串sds,鍊錶,字典dict,跳躍表skiplist,整數集合intset和壓縮列表ziplist這六種資料結構。下文,我簡要地介紹一下幾種資料結構的定義。sds的全稱叫 dynamic string,它的定義和注釋如下 struct s...
redis基本資料結構概述
redis 有 5 種基礎資料結構,分別為 string 字串 list 列表 hash 雜湊 set 集合 和 zset 有序集合 以下圖示並不代表記憶體連續,僅僅只是邏輯表述。因為redis的key值為字串,當我們使用字串型別作為value時,我們是在將乙個字串對映另乙個字串。member是不可...
redis基本資料結構之ZSet
zset資料結構類似於set結構,只是zset結構中,每個元素都會有乙個分值,然後所有元素按照分值的大小進行排列,相當於是乙個進行了排序的鍊錶。如果zset是乙個鍊錶,而且內部元素是有序的,在進行元素插入和刪除,以及查詢的時候,就必須要遍歷鍊錶才行,時間複雜度就達到了o n 這個在以單執行緒處理的r...