所有例子均出自源码。
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)