Compare commits

...

3 Commits

Author SHA1 Message Date
Igor Sysoev 39ffa86c97 add radix tree skip node 2008-12-03 13:26:02 +00:00
Igor Sysoev 9072efe6b4 remove parent from radix tree node to add skip field 2008-12-03 13:23:07 +00:00
Igor Sysoev 132cd9e32e The special branch to archive an attempt to implement radix tree with skip.
On geo base with country level resolution the skips decrease number of nodes
for 1-2% only.
2008-12-03 13:16:33 +00:00
3 changed files with 162 additions and 60 deletions

View File

@ -8,6 +8,10 @@
#include <ngx_core.h>
static ngx_int_t ngx_radix32tree_delete_node(ngx_radix_tree_t *tree,
uint32_t key, uint32_t mask, ngx_radix_node_t **pnode, uint32_t bit);
void ngx_radix32tree_compress_node(ngx_radix_tree_t *tree,
ngx_radix_node_t *node);
static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
@ -26,6 +30,7 @@ ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
tree->free = NULL;
tree->start = NULL;
tree->size = 0;
tree->count = 0;
tree->root = ngx_radix_alloc(tree);
if (tree->root == NULL) {
@ -34,7 +39,7 @@ ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
tree->root->right = NULL;
tree->root->left = NULL;
tree->root->parent = NULL;
tree->root->skip = 0;
tree->root->value = NGX_RADIX_NO_VALUE;
if (preallocate == 0) {
@ -149,7 +154,7 @@ ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
next->right = NULL;
next->left = NULL;
next->parent = node;
next->skip = 0;
next->value = NGX_RADIX_NO_VALUE;
if (key & bit) {
@ -172,93 +177,179 @@ ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
ngx_int_t
ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
{
uint32_t bit;
return ngx_radix32tree_delete_node(tree, key, mask, &tree->root,
0x80000000);
}
static ngx_int_t
ngx_radix32tree_delete_node(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
ngx_radix_node_t **pnode, uint32_t bit)
{
ngx_radix_node_t *node;
bit = 0x80000000;
node = tree->root;
while (node && (bit & mask)) {
if (key & bit) {
node = node->right;
} else {
node = node->left;
}
bit >>= 1;
}
node = *pnode;
if (node == NULL) {
return NGX_ERROR;
}
if (node->right || node->left) {
if (node->value != NGX_RADIX_NO_VALUE) {
node->value = NGX_RADIX_NO_VALUE;
return NGX_OK;
if ((bit & mask) == 0) {
if (node->right || node->left) {
if (node->value != NGX_RADIX_NO_VALUE) {
node->value = NGX_RADIX_NO_VALUE;
return NGX_OK;
}
return NGX_ERROR;
} else {
node->right = tree->free;
tree->free = node;
tree->count--;
*pnode = NULL;
}
return NGX_OK;
}
if (ngx_radix32tree_delete_node(tree, key, mask,
(key & bit) ? &node->right : &node->left,
bit >> 1)
!= NGX_OK)
{
return NGX_ERROR;
}
for ( ;; ) {
if (node->parent->right == node) {
node->parent->right = NULL;
} else {
node->parent->left = NULL;
}
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;
}
if (node->right || node->left) {
return NGX_OK;
}
if (node->value != NGX_RADIX_NO_VALUE) {
return NGX_OK;
}
node->right = tree->free;
tree->free = node;
tree->count--;
*pnode = NULL;
return NGX_OK;
}
void
ngx_radix32tree_compress(ngx_radix_tree_t *tree)
{
if (tree->root) {
ngx_radix32tree_compress_node(tree, tree->root);
}
}
void
ngx_radix32tree_compress_node(ngx_radix_tree_t *tree, ngx_radix_node_t *node)
{
uintptr_t skip;
ngx_radix_node_t *n;
if (node->right) {
skip = 0;
for (n = node->right;
n->right && n->left == NULL && n->value == NGX_RADIX_NO_VALUE;
n = node->right)
{
node->right = n->right;
n->right = tree->free;
tree->free = n;
tree->count--;
skip++;
}
node->right->skip = skip;
ngx_radix32tree_compress_node(tree, node->right);
}
if (node->left) {
skip = 0;
for (n = node->left;
n->left && n->right == NULL && n->value == NGX_RADIX_NO_VALUE;
n = node->left)
{
node->left = n->left;
n->right = tree->free;
tree->free = n;
tree->count--;
skip++;
}
node->left->skip = skip;
ngx_radix32tree_compress_node(tree, node->left);
}
}
uintptr_t
ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
{
uint32_t bit;
uintptr_t value;
uint32_t bit, test;
uintptr_t value, skip;
ngx_radix_node_t *node;
bit = 0x80000000;
value = NGX_RADIX_NO_VALUE;
node = tree->root;
while (node) {
if (node == NULL) {
return NGX_RADIX_NO_VALUE;
}
bit = 0x80000000;
for ( ;; ) {
if (node->value != NGX_RADIX_NO_VALUE) {
value = node->value;
}
if (key & bit) {
node = node->right;
test = 0;
} else {
node = node->left;
test = bit >> 1;
}
if (node == NULL) {
return value;
}
bit >>= 1;
}
return value;
for (skip = node->skip; skip; skip--) {
if ((key & bit) == test) {
return value;
}
bit >>= 1;
test >>= 1;
}
}
}
@ -270,6 +361,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree)
if (tree->free) {
p = (char *) tree->free;
tree->free = tree->free->right;
tree->count++;
return p;
}
@ -285,6 +377,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree)
p = tree->start;
tree->start += sizeof(ngx_radix_node_t);
tree->size -= sizeof(ngx_radix_node_t);
tree->count++;
return p;
}

View File

@ -19,7 +19,7 @@ typedef struct ngx_radix_node_s ngx_radix_node_t;
struct ngx_radix_node_s {
ngx_radix_node_t *right;
ngx_radix_node_t *left;
ngx_radix_node_t *parent;
uintptr_t skip;
uintptr_t value;
};
@ -30,6 +30,7 @@ typedef struct {
ngx_radix_node_t *free;
char *start;
size_t size;
ngx_uint_t count;
} ngx_radix_tree_t;
@ -39,6 +40,7 @@ ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
uint32_t key, uint32_t mask, uintptr_t value);
ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
uint32_t key, uint32_t mask);
void ngx_radix32tree_compress(ngx_radix_tree_t *tree);
uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);

View File

@ -171,7 +171,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
char *rv;
size_t len;
ngx_str_t *value, name;
ngx_uint_t i;
ngx_uint_t i, count;
ngx_conf_t save;
ngx_pool_t *pool;
ngx_array_t *a;
@ -268,16 +268,23 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) {
return rv;
if (ngx_radix32tree_find(ctx.tree, 0) == NGX_RADIX_NO_VALUE) {
if (ngx_radix32tree_insert(ctx.tree, 0, 0,
(uintptr_t) &ngx_http_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
}
}
if (ngx_radix32tree_insert(ctx.tree, 0, 0,
(uintptr_t) &ngx_http_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
}
count = ctx.tree->count;
ngx_radix32tree_compress(ctx.tree);
ngx_log_error(NGX_LOG_NOTICE, cf->log, 0,
"\"%V\" geo tree has been compressed as %ui/%ui",
&name, ctx.tree->count, count);
}
return rv;