nginx/src/core/ngx_radix_tree.c
Igor Sysoev aa8286101a nginx-0.1.18-RELEASE import
*) Workaround: the default values of the devpoll_events and the
       devpoll_changes directives changed from 512 to 32 to be compatible
       with Solaris 10.

    *) Bugfix: the proxy_set_x_var and fastcgi_set_var directives were not
       inherited.

    *) Bugfix: in the redirect rewrite directive the arguments were
       concatenated with URI by the "&" rather than the "?".

    *) Bugfix: the lines without trailing ";" in the file being included by
       the ngx_http_geo_module were silently ignored.

    *) Feature: the ngx_http_stub_status_module.

    *) Bugfix: the unknown log format in the access_log directive caused
       the segmentation fault.

    *) Feature: the new "document_root" parameter of the fastcgi_params
       directive.

    *) Feature: the fastcgi_redirect_errors directive.

    *) Feature: the new "break" modifier of the "rewrite" directive allows
       to stop the rewrite/location cycle and sets the current
       configuration to the request.
2005-02-09 14:31:07 +00:00

249 lines
4.5 KiB
C

/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
ngx_radix_tree_t *
ngx_radix_tree_create(ngx_pool_t *pool, ngx_uint_t preallocate)
{
uint32_t key, mask, inc;
ngx_radix_tree_t *tree;
if (!(tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t)))) {
return NULL;
}
tree->pool = pool;
tree->free = NULL;
tree->start = NULL;
tree->size = 0;
if (!(tree->root = ngx_radix_alloc(tree))) {
return NULL;
}
tree->root->right = NULL;
tree->root->left = NULL;
tree->root->parent = NULL;
tree->root->value = NGX_RADIX_NO_VALUE;
/*
* We preallocate the first nodes: 0, 1, 00, 01, 10, 11, 000, 001, etc.,
* to increase the TLB hits even if for the first lookup iterations.
* On the 32-bit platforms the 7 preallocated bits takes continuous 4K,
* 8 - 8K, 9 - 16K, etc.
*/
mask = 0;
inc = 0x80000000;
while (preallocate--) {
key = 0;
mask >>= 1;
mask |= 0x80000000;
do {
if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
!= NGX_OK)
{
return NULL;
}
key += inc;
} while (key);
inc >>= 1;
}
return tree;
}
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;
while (bit & mask) {
if (key & bit) {
next = node->right;
} else {
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;
}
while (bit & mask) {
if (!(next = ngx_radix_alloc(tree))) {
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;
while (node && (bit & mask)) {
if (key & bit) {
node = node->right;
} else {
node = node->left;
}
bit >>= 1;
}
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;
}
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
|| node->value != NGX_RADIX_NO_VALUE
|| node->parent == NULL)
{
break;
}
}
return NGX_OK;
}
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;
}
static void *
ngx_radix_alloc(ngx_radix_tree_t *tree)
{
char *p;
if (tree->free) {
p = (char *) tree->free;
tree->free = tree->free->right;
return p;
}
if (tree->size < sizeof(ngx_radix_node_t)) {
if (!(tree->start = ngx_palloc(tree->pool, ngx_pagesize))) {
return NULL;
}
tree->size = ngx_pagesize;
}
p = tree->start;
tree->start += sizeof(ngx_radix_node_t);
tree->size -= sizeof(ngx_radix_node_t);
return p;
}