changeset 2369:12e8e0045096 radix_with_skip

add radix tree skip node
author Igor Sysoev <igor@sysoev.ru>
date Wed, 03 Dec 2008 13:26:02 +0000
parents 62be1c4edfba
children e14debe728b0
files src/core/ngx_radix_tree.c src/core/ngx_radix_tree.h src/http/modules/ngx_http_geo_module.c
diffstat 3 files changed, 113 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_radix_tree.c
+++ b/src/core/ngx_radix_tree.c
@@ -10,6 +10,8 @@
 
 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);
 
 
@@ -28,6 +30,7 @@ ngx_radix_tree_create(ngx_pool_t *pool, 
     tree->free = NULL;
     tree->start = NULL;
     tree->size = 0;
+    tree->count = 0;
 
     tree->root = ngx_radix_alloc(tree);
     if (tree->root == NULL) {
@@ -205,6 +208,7 @@ ngx_radix32tree_delete_node(ngx_radix_tr
         } else {
             node->right = tree->free;
             tree->free = node;
+            tree->count--;
 
             *pnode = NULL;
         }
@@ -230,6 +234,7 @@ ngx_radix32tree_delete_node(ngx_radix_tr
 
     node->right = tree->free;
     tree->free = node;
+    tree->count--;
 
     *pnode = NULL;
 
@@ -237,33 +242,114 @@ ngx_radix32tree_delete_node(ngx_radix_tr
 }
 
 
+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;
-    }
+
+        for (skip = node->skip; skip; skip--) {
 
-    return value;
+            if ((key & bit) == test) {
+                return value;
+            }
+
+            bit >>= 1;
+            test >>= 1;
+        }
+    }
 }
 
 
@@ -275,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;
     }
 
@@ -290,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;
 }
--- a/src/core/ngx_radix_tree.h
+++ b/src/core/ngx_radix_tree.h
@@ -19,7 +19,7 @@ typedef struct ngx_radix_node_s  ngx_rad
 struct ngx_radix_node_s {
     ngx_radix_node_t  *right;
     ngx_radix_node_t  *left;
-    ngx_uint_t         skip;
+    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_rad
     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);
 
 
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -171,7 +171,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
     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_c
         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;