所有例子均出自源碼。
Radix tree壓縮前綴樹,是redis在5.0新加入的用來存儲key的數據結構。
前綴樹的節點結構如下。
typedef struct raxNode {
uint32_t iskey:1; /* Does this node contain a key? */
uint32_t isnull:1; /* Associated value is NULL (don't store it). */
uint32_t iscompr:1; /* Node is compressed. */
uint32_t size:29; /* Number of children, or compressed string len. */
unsigned char data[];
} raxNode;
簡單來看一個radix樹中的節點共分爲五部分,前三者分別是三個標誌量,iskey代表從根節點到該節點的父節點是否是一個key,注意,這裏的iskey代表的是根節點到父節點位置的字符串,並不包含iskey所在的節點。Isnull代表當前key所包含的value是否爲null。Iscompr代表當前節點是否是壓縮節點。
在前綴樹中,分爲壓縮節點和非壓縮節點。
在一棵具體的樹中,具體是這樣構成的。
* ["foo"] ""
* |
* [t b] "foo"
* / \
* "foot" ("er") ("ar") "foob"
* / \
* "footer" [] [] "foobar"
其中,樹中的節點結構會有以下兩種情況。
* [header iscompr=0][abc][a-ptr][b-ptr][c-ptr](value-ptr?)
* [header iscompr=1][xyz][z-ptr](value-ptr?)
在上面的結構中第一個便是非壓縮節點,第二個則是壓縮節點。
在這顆樹裏,第二層便是非壓縮節點,其他都是壓縮節點,具體的非壓縮節點出現在前綴相同但是下一個字符出現分歧的地方。而壓縮節點是一段正常的字符串,但如果這是一個key,將會在子節點的iskey子段中表示出來。
size在壓縮節點中表示該節點的字符串長度,壓縮節點的大小必定大於等於2,在非壓縮節點中表示在父節點的前綴下分歧的數量。
data則是具體的字符信息。
在radix樹的插入中,源碼中的註釋給出了各種情況的解釋。
* "ANNIBALE" -> "SCO" -> []
以上是當前樹的初始情況,共存在兩個key,一個是ANNIBALE,和ANNIBALESCO。
- 當插入ANNIENTARE時,在一個節點的ANNI後邊發生了分歧,此時保留前四個字符作爲共有的前綴父節點,並生成一個非壓縮子節點表示前綴的分歧,如下。
* |B| -> "ALE" -> "SCO" -> []
* "ANNI" -> |-|
* |E| -> (... continue algo ...) "NTARE" -> []
- 當插入AGO的時候分歧在第一個字符後便產生,總體情況似乎後第一種情況相似,但由於該場景的分歧發生在第二字符,由此,在生成非壓縮子節點的同時,其根節點也變成了非壓縮節點。
* |N| -> "NIBALE" -> "SCO" -> []
* |A| -> |-|
* |G| -> (... continue algo ...) |O| -> []
- 當插入CIAO的時候,相對於上一中情況,從第一個字符便發生了分歧,根節點直接變成多成員的非壓縮節點。
* |A| -> "NNIBALE" -> "SCO" -> []
* |-|
* |C| -> (... continue algo ...) "IAO" -> []
- 當插入ANNI的時候,由於其字符完全匹配當前已經存在的前綴節點,只需要在當前的壓縮節點中進行拆分出其存在即可。
* "ANNI" -> "BALE" -> "SCO" -> []
以上是radix樹插入時各種可能會出現的情況。
當刪除時,源碼也給出了各種情況的解釋。
* "FOO" -> "BAR" -> [] (2)
* (1)
以上是當前樹的情況,存在兩個鍵值對,FOO->1,FOOBAR->2。
當需要刪除FOO這個key的時候,其實只需要把父節點和子節點合併即可,保留子節點的value。
* "FOOBAR" -> [] (2)
還有一種情況如下。
* |B| -> "AR" -> [] (1)
* "FOO" -> |-|
* |T| -> "ER" -> [] (2)
以上存在兩個key,FOOBAR->1,FOOTER->2。
當刪除FOOTER這個key的時候,結果如下。
* "FOO" -> |B| -> "AR" -> [] (1)
此時可以考慮進行壓縮,壓縮結果如下。
* "FOOBAR" -> [] (1)