nginx中基数树代码注释

基数树结构体

typedef struct {
    ngx_radix_node_t  *root;  
    ngx_pool_t        *pool;
    ngx_radix_node_t  *free;  /* 释放节点的链表 */
    char              *start; /* 已分配内存未使用空间的起始地址 */
    size_t             size; /* 已分配内存未使用空间大小 */
} ngx_radix_tree_t;

节点结构体

struct ngx_radix_node_s {
    ngx_radix_node_t  *right;
    ngx_radix_node_t  *left;
    ngx_radix_node_t  *parent;
    uintptr_t          value; /* 节点实际所指对象的地址 */
};

分配节点函数


/* 返回新分配的节点地址 */
static ngx_radix_node_t *
ngx_radix_alloc(ngx_radix_tree_t *tree)
{
    ngx_radix_node_t  *p;

    if (tree->free) { /* 如果free链表不为空,直接从free链表中取出节点 */
        p = tree->free;
        tree->free = tree->free->right;
        return p;
    }
    /* 已分配内存不足,重新申请内存 */
    if (tree->size < sizeof(ngx_radix_node_t)) {
        tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
        if (tree->start == NULL) {
            return NULL;
        }

        tree->size = ngx_pagesize;
    }
    /* 已分配内存足够 */
    p = (ngx_radix_node_t *) tree->start;
    tree->start += sizeof(ngx_radix_node_t);
    tree->size -= sizeof(ngx_radix_node_t);

    return p;
}

创建基数树并预分配节点


/*
 *  pool 内存池
 *  preallocate 预分配基数树高度-1
 *  
 */
ngx_radix_tree_t *
ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
{
    uint32_t           key, mask, inc;
    ngx_radix_tree_t  *tree;

    tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
    if (tree == NULL) {
        return NULL;
    }

    tree->pool = pool;
    tree->free = NULL;
    tree->start = NULL;
    tree->size = 0;

    tree->root = ngx_radix_alloc(tree);
    if (tree->root == NULL) {
        return NULL;
    }

    tree->root->right = NULL;
    tree->root->left = NULL;
    tree->root->parent = NULL;
    tree->root->value = NGX_RADIX_NO_VALUE;

    if (preallocate == 0) {
        return tree;
    }

    /*
     * Preallocation of first nodes : 0, 1, 00, 01, 10, 11, 000, 001, etc.
     * increases TLB hits even if for first lookup iterations.
     * On 32-bit platforms the 7 preallocated bits takes continuous 4K,
     * 8 - 8K, 9 - 16K, etc.  On 64-bit platforms the 6 preallocated bits
     * takes continuous 4K, 7 - 8K, 8 - 16K, etc.  There is no sense to
     * to preallocate more than one page, because further preallocation
     * distributes the only bit per page.  Instead, a random insertion
     * may distribute several bits per page.
     *
     * Thus, by default we preallocate maximum
     *     6 bits on amd64 (64-bit platform and 4K pages)
     *     7 bits on i386 (32-bit platform and 4K pages)
     *     7 bits on sparc64 in 64-bit mode (8K pages)
     *     8 bits on sparc64 in 32-bit mode (8K pages)
     */

    /* 如果参数是-1,将会分配内存页大小的节点数 */
    if (preallocate == -1) {
        switch (ngx_pagesize / sizeof(ngx_radix_node_t)) {

        /* amd64 */
        case 128:
            preallocate = 6;
            break;

        /* i386, sparc64 */
        case 256:
            preallocate = 7;
            break;

        /* sparc64 in 32-bit mode */
        default: /* 512 */
            preallocate = 8;
        }
    }

    mask = 0;
    inc = 0x80000000; /* 1000 0000 0000 0000 0000 0000 0000 0000 */

    while (preallocate--) {

        key = 0;
        mask >>= 1;
        mask |= 0x80000000;
        /* 按照层来插入节点,这样就不需要考虑会遇到NULL情况 */
        /* 第一次:0 1 */
        /* 第二次:00 01 10 11 */
        /* 总共会插入2^1+2^2+2^3+...+2^preallocate个预分配的节点 */
        do {
            if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
                != NGX_OK)
            {
                return NULL;
            }

            key += inc;

        } while (key);

        inc >>= 1;
    }

    return tree;
}

插入节点


/* key 带插入关键字
   mask 掩码
   value 实际数据结构体首地址
   按照掩码的1的个数一直往树底走,直到叶节点并给叶节点分配对象
   */
ngx_int_t
 ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
    uintptr_t value)
{
    uint32_t           bit;
    ngx_radix_node_t  *node, *next;

    bit = 0x80000000; /* 从左至右 */ 

    node = tree->root;
    next = tree->root;

    /* 找到插入路径上的节点,如果为空,表示路径需要插入额外更多的节点,
        掩码中的1的个数表示路径中的指针数*/
    while (bit & mask) { /* 掩码一定要左边是连续的1 */
        if (key & bit) { /* 1 */
            next = node->right;

        } else { /* 0 */
            next = node->left;
        }

        if (next == NULL) {
            break;
        }

        bit >>= 1;
        node = next;
    }

    if (next) {
        /* 节点已经存在 */
        if (node->value != NGX_RADIX_NO_VALUE) {
            return NGX_BUSY;
        }

        node->value = value;
        return NGX_OK;
    }

    /* 需要分配额外的节点在root到key的路径上面 */
    while (bit & mask) {
        next = ngx_radix_alloc(tree);
        if (next == NULL) {
            return NGX_ERROR;
        }

        next->right = NULL;
        next->left = NULL;
        next->parent = node;
        next->value = NGX_RADIX_NO_VALUE;

        if (key & bit) {
            node->right = next;

        } else {
            node->left = next;
        }

        bit >>= 1;
        node = next;
    }

    node->value = value;

    return NGX_OK;
}

删除节点



ngx_int_t
ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
{
    uint32_t           bit;
    ngx_radix_node_t  *node;

    bit = 0x80000000;
    node = tree->root; /* node的key == key */

    while (node && (bit & mask)) {
        if (key & bit) {
            node = node->right;

        } else {
            node = node->left;
        }

        bit >>= 1;
    }

    if (node == NULL) {
        return NGX_ERROR;
    }
    /* 这种情况是由于掩码对于插入node时的掩码1的位数更多 */
    if (node->right || node->left) {
        if (node->value != NGX_RADIX_NO_VALUE) {
            node->value = NGX_RADIX_NO_VALUE;
            return NGX_OK;
        }

        return NGX_ERROR; /* 此节点已经标记为删除的节点了 */
    }

    /* node是叶节点,并将root到node的路径上的删除node后依然是叶节点的节点都删除 */
    for ( ;; ) {
        if (node->parent->right == node) {
            node->parent->right = NULL;

        } else {
            node->parent->left = NULL;
        }
        /* 并将node添加到基数树的删除节点单链表中 */
        node->right = tree->free;
        tree->free = node;

        node = node->parent; /* 如果这个节点也是叶节点且没有对象指针将会从书中删除 */

        if (node->right || node->left) {
            break;
        }

        if (node->value != NGX_RADIX_NO_VALUE) {
            break;
        }

        if (node->parent == NULL) {
            break;
        }
    }

    return NGX_OK;
}

查找关键字是否存在,并返回节点指向的对象地址


/* 返回关键字为key的value指针,这里的查找直到该节点是叶节点或者只有一棵子树,且没有唯一子树这个分支 */
uintptr_t
ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
{
    uint32_t           bit;
    uintptr_t          value;
    ngx_radix_node_t  *node;

    bit = 0x80000000;
    value = NGX_RADIX_NO_VALUE;
    node = tree->root;

    while (node) {
        if (node->value != NGX_RADIX_NO_VALUE) {
            value = node->value;
        }

        if (key & bit) {
            node = node->right;

        } else {
            node = node->left;
        }

        bit >>= 1;
    }

    return value;
}

猜你喜欢

转载自blog.csdn.net/w1157984197/article/details/81218476