redis radix tree的簡單解釋

所有例子均出自源碼。

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。

  1. 當插入ANNIENTARE時,在一個節點的ANNI後邊發生了分歧,此時保留前四個字符作爲共有的前綴父節點,並生成一個非壓縮子節點表示前綴的分歧,如下。

     *               |B| -> "ALE" -> "SCO" -> []

     *     "ANNI" -> |-|

     *               |E| -> (... continue algo ...) "NTARE" -> []

  1. 當插入AGO的時候分歧在第一個字符後便產生,總體情況似乎後第一種情況相似,但由於該場景的分歧發生在第二字符,由此,在生成非壓縮子節點的同時,其根節點也變成了非壓縮節點。

 *            |N| -> "NIBALE" -> "SCO" -> []

     *     |A| -> |-|

     *            |G| -> (... continue algo ...) |O| -> []

  1. 當插入CIAO的時候,相對於上一中情況,從第一個字符便發生了分歧,根節點直接變成多成員的非壓縮節點。

     *     |A| -> "NNIBALE" -> "SCO" -> []

     *     |-|

     *     |C| -> (... continue algo ...) "IAO" -> []

  1. 當插入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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章