2004-05-25 23:28:46 +08:00
|
|
|
|
2004-09-28 16:34:51 +08:00
|
|
|
/*
|
2004-09-30 00:00:49 +08:00
|
|
|
* Copyright (C) Igor Sysoev
|
2012-01-18 23:07:43 +08:00
|
|
|
* Copyright (C) Nginx, Inc.
|
2004-09-28 16:34:51 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2004-05-25 23:28:46 +08:00
|
|
|
#include <ngx_config.h>
|
|
|
|
#include <ngx_core.h>
|
|
|
|
|
|
|
|
|
2005-02-04 03:33:37 +08:00
|
|
|
static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
ngx_radix_tree_t *
|
2005-02-16 21:40:36 +08:00
|
|
|
ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
|
2004-05-25 23:28:46 +08:00
|
|
|
{
|
2005-02-09 22:31:07 +08:00
|
|
|
uint32_t key, mask, inc;
|
2004-05-25 23:28:46 +08:00
|
|
|
ngx_radix_tree_t *tree;
|
|
|
|
|
2005-03-19 20:38:37 +08:00
|
|
|
tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
|
|
|
|
if (tree == NULL) {
|
2004-05-25 23:28:46 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tree->pool = pool;
|
|
|
|
tree->free = NULL;
|
2004-05-26 23:30:12 +08:00
|
|
|
tree->start = NULL;
|
2004-05-25 23:28:46 +08:00
|
|
|
tree->size = 0;
|
|
|
|
|
2005-03-19 20:38:37 +08:00
|
|
|
tree->root = ngx_radix_alloc(tree);
|
|
|
|
if (tree->root == NULL) {
|
2004-05-27 03:33:53 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tree->root->right = NULL;
|
|
|
|
tree->root->left = NULL;
|
|
|
|
tree->root->parent = NULL;
|
2005-02-04 03:33:37 +08:00
|
|
|
tree->root->value = NGX_RADIX_NO_VALUE;
|
2004-05-27 03:33:53 +08:00
|
|
|
|
2005-02-16 21:40:36 +08:00
|
|
|
if (preallocate == 0) {
|
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
/*
|
2008-12-03 00:50:56 +08:00
|
|
|
* 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
|
2005-02-16 21:40:36 +08:00
|
|
|
* takes continuous 4K, 7 - 8K, 8 - 16K, etc. There is no sense to
|
|
|
|
* to preallocate more than one page, because further preallocation
|
2008-12-03 00:50:56 +08:00
|
|
|
* distributes the only bit per page. Instead, a random insertion
|
2005-02-16 21:40:36 +08:00
|
|
|
* 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)
|
2005-02-09 22:31:07 +08:00
|
|
|
*/
|
|
|
|
|
2005-02-16 21:40:36 +08:00
|
|
|
if (preallocate == -1) {
|
|
|
|
switch (ngx_pagesize / sizeof(ngx_radix_tree_t)) {
|
|
|
|
|
|
|
|
/* amd64 */
|
|
|
|
case 128:
|
|
|
|
preallocate = 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* i386, sparc64 */
|
|
|
|
case 256:
|
|
|
|
preallocate = 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* sparc64 in 32-bit mode */
|
|
|
|
default:
|
|
|
|
preallocate = 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
mask = 0;
|
|
|
|
inc = 0x80000000;
|
|
|
|
|
|
|
|
while (preallocate--) {
|
|
|
|
|
|
|
|
key = 0;
|
|
|
|
mask >>= 1;
|
|
|
|
mask |= 0x80000000;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
|
2007-03-06 20:18:45 +08:00
|
|
|
!= NGX_OK)
|
2005-02-09 22:31:07 +08:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
key += inc;
|
|
|
|
|
|
|
|
} while (key);
|
|
|
|
|
|
|
|
inc >>= 1;
|
|
|
|
}
|
|
|
|
|
2004-05-25 23:28:46 +08:00
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
ngx_int_t
|
|
|
|
ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
|
|
|
|
uintptr_t value)
|
2004-05-25 23:28:46 +08:00
|
|
|
{
|
|
|
|
uint32_t bit;
|
2004-05-27 03:33:53 +08:00
|
|
|
ngx_radix_node_t *node, *next;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
bit = 0x80000000;
|
2005-02-04 03:33:37 +08:00
|
|
|
|
2004-05-25 23:28:46 +08:00
|
|
|
node = tree->root;
|
2005-02-04 03:33:37 +08:00
|
|
|
next = tree->root;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
while (bit & mask) {
|
2004-05-25 23:28:46 +08:00
|
|
|
if (key & bit) {
|
2004-05-27 03:33:53 +08:00
|
|
|
next = node->right;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
} else {
|
2004-05-27 03:33:53 +08:00
|
|
|
next = node->left;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
if (next == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-02-04 03:33:37 +08:00
|
|
|
bit >>= 1;
|
2004-05-27 03:33:53 +08:00
|
|
|
node = next;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
if (next) {
|
2005-02-04 03:33:37 +08:00
|
|
|
if (node->value != NGX_RADIX_NO_VALUE) {
|
2004-05-25 23:28:46 +08:00
|
|
|
return NGX_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
node->value = value;
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (bit & mask) {
|
2005-03-19 20:38:37 +08:00
|
|
|
next = ngx_radix_alloc(tree);
|
|
|
|
if (next == NULL) {
|
2004-05-25 23:28:46 +08:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
next->right = NULL;
|
|
|
|
next->left = NULL;
|
|
|
|
next->parent = node;
|
2005-02-04 03:33:37 +08:00
|
|
|
next->value = NGX_RADIX_NO_VALUE;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
if (key & bit) {
|
2004-05-27 03:33:53 +08:00
|
|
|
node->right = next;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
} else {
|
2004-05-27 03:33:53 +08:00
|
|
|
node->left = next;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bit >>= 1;
|
2004-05-27 03:33:53 +08:00
|
|
|
node = next;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
2005-02-04 03:33:37 +08:00
|
|
|
node->value = value;
|
|
|
|
|
2004-05-25 23:28:46 +08:00
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
ngx_int_t
|
|
|
|
ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
|
2004-05-25 23:28:46 +08:00
|
|
|
{
|
|
|
|
uint32_t bit;
|
2004-05-27 03:33:53 +08:00
|
|
|
ngx_radix_node_t *node;
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
bit = 0x80000000;
|
|
|
|
node = tree->root;
|
|
|
|
|
|
|
|
while (node && (bit & mask)) {
|
|
|
|
if (key & bit) {
|
|
|
|
node = node->right;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
node = node->left;
|
|
|
|
}
|
|
|
|
|
|
|
|
bit >>= 1;
|
|
|
|
}
|
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
if (node == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
2004-05-26 23:30:12 +08:00
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
if (node->right || node->left) {
|
2005-02-04 03:33:37 +08:00
|
|
|
if (node->value != NGX_RADIX_NO_VALUE) {
|
|
|
|
node->value = NGX_RADIX_NO_VALUE;
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_ERROR;
|
2004-05-27 03:33:53 +08:00
|
|
|
}
|
2004-05-26 23:30:12 +08:00
|
|
|
|
2004-05-27 03:33:53 +08:00
|
|
|
for ( ;; ) {
|
|
|
|
if (node->parent->right == node) {
|
|
|
|
node->parent->right = NULL;
|
2005-10-19 20:33:58 +08:00
|
|
|
|
2004-05-26 23:30:12 +08:00
|
|
|
} else {
|
2004-05-27 03:33:53 +08:00
|
|
|
node->parent->left = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
node->right = tree->free;
|
|
|
|
tree->free = node;
|
|
|
|
|
|
|
|
node = node->parent;
|
|
|
|
|
2005-10-19 20:33:58 +08:00
|
|
|
if (node->right || node->left) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->value != NGX_RADIX_NO_VALUE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->parent == NULL) {
|
2004-05-27 03:33:53 +08:00
|
|
|
break;
|
2004-05-26 23:30:12 +08:00
|
|
|
}
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
2004-05-27 03:33:53 +08:00
|
|
|
|
|
|
|
return NGX_OK;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
uintptr_t
|
|
|
|
ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
|
2004-05-25 23:28:46 +08:00
|
|
|
{
|
|
|
|
uint32_t bit;
|
|
|
|
uintptr_t value;
|
|
|
|
ngx_radix_node_t *node;
|
|
|
|
|
|
|
|
bit = 0x80000000;
|
2005-02-04 03:33:37 +08:00
|
|
|
value = NGX_RADIX_NO_VALUE;
|
2004-05-25 23:28:46 +08:00
|
|
|
node = tree->root;
|
|
|
|
|
|
|
|
while (node) {
|
2005-02-04 03:33:37 +08:00
|
|
|
if (node->value != NGX_RADIX_NO_VALUE) {
|
2004-05-25 23:28:46 +08:00
|
|
|
value = node->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key & bit) {
|
|
|
|
node = node->right;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
node = node->left;
|
|
|
|
}
|
|
|
|
|
|
|
|
bit >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-09 22:31:07 +08:00
|
|
|
static void *
|
|
|
|
ngx_radix_alloc(ngx_radix_tree_t *tree)
|
2004-05-25 23:28:46 +08:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
2004-05-26 23:30:12 +08:00
|
|
|
if (tree->free) {
|
|
|
|
p = (char *) tree->free;
|
|
|
|
tree->free = tree->free->right;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2005-02-04 03:33:37 +08:00
|
|
|
if (tree->size < sizeof(ngx_radix_node_t)) {
|
2008-09-01 21:52:55 +08:00
|
|
|
tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
|
2005-03-19 20:38:37 +08:00
|
|
|
if (tree->start == NULL) {
|
2004-05-25 23:28:46 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-06-11 02:36:57 +08:00
|
|
|
tree->size = ngx_pagesize;
|
2004-05-25 23:28:46 +08:00
|
|
|
}
|
|
|
|
|
2004-05-26 23:30:12 +08:00
|
|
|
p = tree->start;
|
2005-02-04 03:33:37 +08:00
|
|
|
tree->start += sizeof(ngx_radix_node_t);
|
|
|
|
tree->size -= sizeof(ngx_radix_node_t);
|
2004-05-25 23:28:46 +08:00
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|