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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值