src/core/ngx_radix_tree.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree);


  8. ngx_radix_tree_t *
  9. ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
  10. {
  11.     uint32_t           key, mask, inc;
  12.     ngx_radix_tree_t  *tree;

  13.     tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
  14.     if (tree == NULL) {
  15.         return NULL;
  16.     }

  17.     tree->pool = pool;
  18.     tree->free = NULL;
  19.     tree->start = NULL;
  20.     tree->size = 0;

  21.     tree->root = ngx_radix_alloc(tree);
  22.     if (tree->root == NULL) {
  23.         return NULL;
  24.     }

  25.     tree->root->right = NULL;
  26.     tree->root->left = NULL;
  27.     tree->root->parent = NULL;
  28.     tree->root->value = NGX_RADIX_NO_VALUE;

  29.     if (preallocate == 0) {
  30.         return tree;
  31.     }

  32.     /*
  33.      * Preallocation of first nodes : 0, 1, 00, 01, 10, 11, 000, 001, etc.
  34.      * increases TLB hits even if for first lookup iterations.
  35.      * On 32-bit platforms the 7 preallocated bits takes continuous 4K,
  36.      * 8 - 8K, 9 - 16K, etc.  On 64-bit platforms the 6 preallocated bits
  37.      * takes continuous 4K, 7 - 8K, 8 - 16K, etc.  There is no sense to
  38.      * to preallocate more than one page, because further preallocation
  39.      * distributes the only bit per page.  Instead, a random insertion
  40.      * may distribute several bits per page.
  41.      *
  42.      * Thus, by default we preallocate maximum
  43.      *     6 bits on amd64 (64-bit platform and 4K pages)
  44.      *     7 bits on i386 (32-bit platform and 4K pages)
  45.      *     7 bits on sparc64 in 64-bit mode (8K pages)
  46.      *     8 bits on sparc64 in 32-bit mode (8K pages)
  47.      */

  48.     if (preallocate == -1) {
  49.         switch (ngx_pagesize / sizeof(ngx_radix_node_t)) {

  50.         /* amd64 */
  51.         case 128:
  52.             preallocate = 6;
  53.             break;

  54.         /* i386, sparc64 */
  55.         case 256:
  56.             preallocate = 7;
  57.             break;

  58.         /* sparc64 in 32-bit mode */
  59.         default:
  60.             preallocate = 8;
  61.         }
  62.     }

  63.     mask = 0;
  64.     inc = 0x80000000;

  65.     while (preallocate--) {

  66.         key = 0;
  67.         mask >>= 1;
  68.         mask |= 0x80000000;

  69.         do {
  70.             if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
  71.                 != NGX_OK)
  72.             {
  73.                 return NULL;
  74.             }

  75.             key += inc;

  76.         } while (key);

  77.         inc >>= 1;
  78.     }

  79.     return tree;
  80. }


  81. ngx_int_t
  82. ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
  83.     uintptr_t value)
  84. {
  85.     uint32_t           bit;
  86.     ngx_radix_node_t  *node, *next;

  87.     bit = 0x80000000;

  88.     node = tree->root;
  89.     next = tree->root;

  90.     while (bit & mask) {
  91.         if (key & bit) {
  92.             next = node->right;

  93.         } else {
  94.             next = node->left;
  95.         }

  96.         if (next == NULL) {
  97.             break;
  98.         }

  99.         bit >>= 1;
  100.         node = next;
  101.     }

  102.     if (next) {
  103.         if (node->value != NGX_RADIX_NO_VALUE) {
  104.             return NGX_BUSY;
  105.         }

  106.         node->value = value;
  107.         return NGX_OK;
  108.     }

  109.     while (bit & mask) {
  110.         next = ngx_radix_alloc(tree);
  111.         if (next == NULL) {
  112.             return NGX_ERROR;
  113.         }

  114.         next->right = NULL;
  115.         next->left = NULL;
  116.         next->parent = node;
  117.         next->value = NGX_RADIX_NO_VALUE;

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

  120.         } else {
  121.             node->left = next;
  122.         }

  123.         bit >>= 1;
  124.         node = next;
  125.     }

  126.     node->value = value;

  127.     return NGX_OK;
  128. }


  129. ngx_int_t
  130. ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
  131. {
  132.     uint32_t           bit;
  133.     ngx_radix_node_t  *node;

  134.     bit = 0x80000000;
  135.     node = tree->root;

  136.     while (node && (bit & mask)) {
  137.         if (key & bit) {
  138.             node = node->right;

  139.         } else {
  140.             node = node->left;
  141.         }

  142.         bit >>= 1;
  143.     }

  144.     if (node == NULL) {
  145.         return NGX_ERROR;
  146.     }

  147.     if (node->right || node->left) {
  148.         if (node->value != NGX_RADIX_NO_VALUE) {
  149.             node->value = NGX_RADIX_NO_VALUE;
  150.             return NGX_OK;
  151.         }

  152.         return NGX_ERROR;
  153.     }

  154.     for ( ;; ) {
  155.         if (node->parent->right == node) {
  156.             node->parent->right = NULL;

  157.         } else {
  158.             node->parent->left = NULL;
  159.         }

  160.         node->right = tree->free;
  161.         tree->free = node;

  162.         node = node->parent;

  163.         if (node->right || node->left) {
  164.             break;
  165.         }

  166.         if (node->value != NGX_RADIX_NO_VALUE) {
  167.             break;
  168.         }

  169.         if (node->parent == NULL) {
  170.             break;
  171.         }
  172.     }

  173.     return NGX_OK;
  174. }


  175. uintptr_t
  176. ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
  177. {
  178.     uint32_t           bit;
  179.     uintptr_t          value;
  180.     ngx_radix_node_t  *node;

  181.     bit = 0x80000000;
  182.     value = NGX_RADIX_NO_VALUE;
  183.     node = tree->root;

  184.     while (node) {
  185.         if (node->value != NGX_RADIX_NO_VALUE) {
  186.             value = node->value;
  187.         }

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

  190.         } else {
  191.             node = node->left;
  192.         }

  193.         bit >>= 1;
  194.     }

  195.     return value;
  196. }


  197. #if (NGX_HAVE_INET6)

  198. ngx_int_t
  199. ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
  200.     uintptr_t value)
  201. {
  202.     u_char             bit;
  203.     ngx_uint_t         i;
  204.     ngx_radix_node_t  *node, *next;

  205.     i = 0;
  206.     bit = 0x80;

  207.     node = tree->root;
  208.     next = tree->root;

  209.     while (bit & mask[i]) {
  210.         if (key[i] & bit) {
  211.             next = node->right;

  212.         } else {
  213.             next = node->left;
  214.         }

  215.         if (next == NULL) {
  216.             break;
  217.         }

  218.         bit >>= 1;
  219.         node = next;

  220.         if (bit == 0) {
  221.             if (++i == 16) {
  222.                 break;
  223.             }

  224.             bit = 0x80;
  225.         }
  226.     }

  227.     if (next) {
  228.         if (node->value != NGX_RADIX_NO_VALUE) {
  229.             return NGX_BUSY;
  230.         }

  231.         node->value = value;
  232.         return NGX_OK;
  233.     }

  234.     while (bit & mask[i]) {
  235.         next = ngx_radix_alloc(tree);
  236.         if (next == NULL) {
  237.             return NGX_ERROR;
  238.         }

  239.         next->right = NULL;
  240.         next->left = NULL;
  241.         next->parent = node;
  242.         next->value = NGX_RADIX_NO_VALUE;

  243.         if (key[i] & bit) {
  244.             node->right = next;

  245.         } else {
  246.             node->left = next;
  247.         }

  248.         bit >>= 1;
  249.         node = next;

  250.         if (bit == 0) {
  251.             if (++i == 16) {
  252.                 break;
  253.             }

  254.             bit = 0x80;
  255.         }
  256.     }

  257.     node->value = value;

  258.     return NGX_OK;
  259. }


  260. ngx_int_t
  261. ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
  262. {
  263.     u_char             bit;
  264.     ngx_uint_t         i;
  265.     ngx_radix_node_t  *node;

  266.     i = 0;
  267.     bit = 0x80;
  268.     node = tree->root;

  269.     while (node && (bit & mask[i])) {
  270.         if (key[i] & bit) {
  271.             node = node->right;

  272.         } else {
  273.             node = node->left;
  274.         }

  275.         bit >>= 1;

  276.         if (bit == 0) {
  277.             if (++i == 16) {
  278.                 break;
  279.             }

  280.             bit = 0x80;
  281.         }
  282.     }

  283.     if (node == NULL) {
  284.         return NGX_ERROR;
  285.     }

  286.     if (node->right || node->left) {
  287.         if (node->value != NGX_RADIX_NO_VALUE) {
  288.             node->value = NGX_RADIX_NO_VALUE;
  289.             return NGX_OK;
  290.         }

  291.         return NGX_ERROR;
  292.     }

  293.     for ( ;; ) {
  294.         if (node->parent->right == node) {
  295.             node->parent->right = NULL;

  296.         } else {
  297.             node->parent->left = NULL;
  298.         }

  299.         node->right = tree->free;
  300.         tree->free = node;

  301.         node = node->parent;

  302.         if (node->right || node->left) {
  303.             break;
  304.         }

  305.         if (node->value != NGX_RADIX_NO_VALUE) {
  306.             break;
  307.         }

  308.         if (node->parent == NULL) {
  309.             break;
  310.         }
  311.     }

  312.     return NGX_OK;
  313. }


  314. uintptr_t
  315. ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
  316. {
  317.     u_char             bit;
  318.     uintptr_t          value;
  319.     ngx_uint_t         i;
  320.     ngx_radix_node_t  *node;

  321.     i = 0;
  322.     bit = 0x80;
  323.     value = NGX_RADIX_NO_VALUE;
  324.     node = tree->root;

  325.     while (node) {
  326.         if (node->value != NGX_RADIX_NO_VALUE) {
  327.             value = node->value;
  328.         }

  329.         if (key[i] & bit) {
  330.             node = node->right;

  331.         } else {
  332.             node = node->left;
  333.         }

  334.         bit >>= 1;

  335.         if (bit == 0) {
  336.             i++;
  337.             bit = 0x80;
  338.         }
  339.     }

  340.     return value;
  341. }

  342. #endif


  343. static ngx_radix_node_t *
  344. ngx_radix_alloc(ngx_radix_tree_t *tree)
  345. {
  346.     ngx_radix_node_t  *p;

  347.     if (tree->free) {
  348.         p = tree->free;
  349.         tree->free = tree->free->right;
  350.         return p;
  351.     }

  352.     if (tree->size < sizeof(ngx_radix_node_t)) {
  353.         tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
  354.         if (tree->start == NULL) {
  355.             return NULL;
  356.         }

  357.         tree->size = ngx_pagesize;
  358.     }

  359.     p = (ngx_radix_node_t *) tree->start;
  360.     tree->start += sizeof(ngx_radix_node_t);
  361.     tree->size -= sizeof(ngx_radix_node_t);

  362.     return p;
  363. }