1 nginx的基数树简单介绍

typedef struct ngx_radix_node_s  ngx_radix_node_t;
//基数树的节点
uintptr_t          value;//指向存储数据的指针
};


typedef struct {
ngx_pool_t        *pool;//内存池，负责分配内存
char              *start;//已分配内存中还未使用内存的首地址
size_t             size;//已分配内存内中还未使用内存的大小
} ngx_radix_tree_t;

2ngingx基数的基本操作函数

//创建基数树。preallocate是预分配节点的个数

//依据key值和掩码向基数树中插入value,返回值可能是NGX_OK,NGX_ERROR, NGX_BUSY

//依据key值和掩码删除节点（value的值）

//依据key值在基数树中查找返回value数据
uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);

ngx_radix_tree_t *
{

if (tree == NULL) {
return NULL;
}
tree->pool = pool;
tree->free = NULL;
tree->start = NULL;
tree->size = 0;

if (tree->root == NULL) {
return NULL;
}
//初始化root节点
tree->root->right = NULL;
tree->root->left = NULL;
tree->root->parent = NULL;

if (preallocate == 0) {
return tree;
}
/*prealloc=-1时,依据以下的情况创建基数树节点*/
if (preallocate == -1) {

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

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

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

inc = 0x80000000;
//加入preallocate=7,终于建的基数树的节点总个数为2^(preallocate+1)-1，每一层个数为2^(7-preallocate)
//循环例如以下：
//preallocate  =      7         6        5         4         3         2        1
//mask(最左8位)=      10000000  11000000 11100000  11110000  11111000  11111100 11111110
//inc          =     10000000  01000000 00100000  00010000  00001000  00000100 00000010
//添加节点个数    =      2         4        8         16        32        64       128
while (preallocate--) {

key = 0;

do {//依据inc的值加入节点
!= NGX_OK)
{
return NULL;
}

key += inc;//当preallocate=0时，是最后一层。构建的节点个数为2^preallocate

} while (key);

inc >>= 1;
}

return tree;
}

ngx_int_t
uintptr_t value)
{
uint32_t           bit;

bit = 0x80000000;//从最左位開始。推断key值

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

if (key & bit) {//等于1向右查找
next = node->right;

} else {//等于0向左查找
next = node->left;
}

if (next == NULL) {
break;
}

bit >>= 1;
node = next;
}

if (next) {//假设next不为空
return NGX_BUSY;//返回NGX_BUSY
}

node->value = value;//直接赋值
return NGX_OK;
}

//假设next为中间节点。且为空，继续查找且申请路径上为空的节点
//比方找key=1000111。在找到10001时next为空，那要就要申请三个节点分别存10001,100011,1000111,
//1000111最后一个节点为key要插入的节点
if (next == NULL) {
return NGX_ERROR;
}

//初始化节点
next->right = NULL;
next->left = NULL;
next->parent = node;

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

} else {
node->left = next;
}

bit >>= 1;
node = next;
}

node->value = value;//指向数据区

return NGX_OK;
}


1）假设删除的是叶子节点，直接从基数树中删除，并把这个节点放入free链表

ngx_int_t
{
uint32_t           bit;

bit = 0x80000000;
node = tree->root;
//依据key和掩码查找
while (node && (bit & mask)) {
if (key & bit) {
node = node->right;

} else {
node = node->left;
}

bit >>= 1;
}

if (node == NULL) {//没有找到
return NGX_ERROR;
}

//node不为叶节点直接把value置为空
if (node->right || node->left) {
return NGX_OK;
}

return NGX_ERROR;//value为空，返回error
}

//node为叶子节点，直接放到free区域
for ( ;; ) {//删除叶子节点
if (node->parent->right == node) {
node->parent->right = NULL;//

} else {
node->parent->left = NULL;
}

//把node链入free链表
node->right = tree->free;//放到free区域
tree->free = node;//free指向node
//假如删除node以后。父节点是叶子节点，就继续删除父节点，
//一直到node不是叶子节点
node = node->parent;

if (node->right || node->left) {//node不为叶子节点
break;
}

break;
}

if (node->parent == NULL) {//node的parent为空
break;
}
}

return NGX_OK;
}

uintptr_t
{
uint32_t           bit;
uintptr_t          value;

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

while (node) {
value = node->value;
}

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

} else {
node = node->left;
}

bit >>= 1;//往下层查找
}

return value;
}

1）假设free链表不为空，直接从上面取下一个空暇节点

2）free链表为空，则申请一个节点

static void *
{
char  *p;

if (tree->free) {//假设free中有可利用的空间节点
p = (char *) tree->free;//指向第一个可利用的空间节点
tree->free = tree->free->right;//改动free
return p;
}

tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
if (tree->start == NULL) {
return NULL;
}

tree->size = ngx_pagesize;//改动空暇内存大小
}

//分配一个节点的空间
p = tree->start;

return p;
}

3測试样例

tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
gdb  p ngx_pagesize 居然是0，晕了非常久找到这个ngx_pagesize的定义，是个全局变量没有初始化。

http://blog.csdn.net/xiaoliangsky/article/details/39695591

/********************************************************
author: smtl
date: 2014-10-01--4:50
*********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ngx_core.h>
#include <ngx_config.h>
#include <ngx_conf_file.h>
#include <ngx_palloc.h>

////////////////////////////////////////////////////////////////////////////////////
//不加以下这两个定义编译会出错
volatile ngx_cycle_t  *ngx_cycle;

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
const char *fmt, ...)
{
}
////////////////////////////////////////////////////////////////////////////////////

int main()
{
/*基数树节点的数据集:ngx_int_t类型。仅仅是測试，实际上能够为不论什么类型*/
ngx_int_t data[64];
ngx_int_t i = 0;
for (i = 0; i < 64; ++i)
{
data[i] = rand()%10000;
}

/*创建内存池对象*/
ngx_pool_t* pool = ngx_create_pool(1024, NULL);
if (pool == NULL)
{
printf("create pool failed!\n");
exit(1);
}

//printf("xxxxx\n");
////////////////////////////////////////////////////////////////////////////////
//一定要初始化ngx_pagesize这个全局变量，调试了一个晚上
//不初始化，会出现段错误（核心已转储）。这也是全局变量的潜在危害：
//你不知道你的程序中是否用到这个全局变量，假设用到。这个全局变量初始化了没有
//在一些大的程序中，你根本无法高速知道这些，所以应尽量避免使用全局变量
ngx_pagesize = getpagesize();
printf("pagesize = %d\n", ngx_pagesize);
////////////////////////////////////////////////////////////////////////////////

//printf("xxxxxY\n");
if (tree == NULL)
{
exit(1);
}

/*插入data*/
ngx_uint_t deep = 5;//树的最大深度为4
ngx_uint_t inc  = 0x80000000;
ngx_uint_t key  = 0;
ngx_uint_t cunt = 0;//data数组的索引

while (deep--)
{
key    = 0;
do
{
{
printf("insert error\n");
exit(1);
}

key += inc;

++cunt;
if (cunt > 63)
{
cunt = 63;
}
}while(key);

inc >>= 1;
}

/*先序打印数据*/
printf("\n");

/*查找測试*/
ngx_uint_t tkey  = 0x58000000;
{
printf("find the value: %d with the key = %x\n", *value, tkey);
}
else
{
printf("not find the the value with the key = %x\n", tkey);
}

/*删除測试*/
{
printf("delete the the value with the key = %x is succeed\n", tkey);
}
else
{
printf("delete the the value with the key = %x is failed\n", tkey);
}

{
printf("find the value: %d with the key = %x\n", *value, tkey);
}
else
{
printf("not find the the value with the key = %x\n", tkey);
}

return 0;
}

{
if (root->left != NULL)
{
}

{
ngx_int_t* value = root->value;
printf("%d\n", *value);
}

if (root->right != NULL)
{
}