src/core/ngx_rbtree.c - nginx source code

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. /*
  8. * The red-black tree code is based on the algorithm described in
  9. * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
  10. */


  11. static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
  12.     ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
  13. static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root,
  14.     ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);


  15. void
  16. ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
  17. {
  18.     ngx_rbtree_node_t  **root, *temp, *sentinel;

  19.     /* a binary tree insert */

  20.     root = &tree->root;
  21.     sentinel = tree->sentinel;

  22.     if (*root == sentinel) {
  23.         node->parent = NULL;
  24.         node->left = sentinel;
  25.         node->right = sentinel;
  26.         ngx_rbt_black(node);
  27.         *root = node;

  28.         return;
  29.     }

  30.     tree->insert(*root, node, sentinel);

  31.     /* re-balance tree */

  32.     while (node != *root && ngx_rbt_is_red(node->parent)) {

  33.         if (node->parent == node->parent->parent->left) {
  34.             temp = node->parent->parent->right;

  35.             if (ngx_rbt_is_red(temp)) {
  36.                 ngx_rbt_black(node->parent);
  37.                 ngx_rbt_black(temp);
  38.                 ngx_rbt_red(node->parent->parent);
  39.                 node = node->parent->parent;

  40.             } else {
  41.                 if (node == node->parent->right) {
  42.                     node = node->parent;
  43.                     ngx_rbtree_left_rotate(root, sentinel, node);
  44.                 }

  45.                 ngx_rbt_black(node->parent);
  46.                 ngx_rbt_red(node->parent->parent);
  47.                 ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
  48.             }

  49.         } else {
  50.             temp = node->parent->parent->left;

  51.             if (ngx_rbt_is_red(temp)) {
  52.                 ngx_rbt_black(node->parent);
  53.                 ngx_rbt_black(temp);
  54.                 ngx_rbt_red(node->parent->parent);
  55.                 node = node->parent->parent;

  56.             } else {
  57.                 if (node == node->parent->left) {
  58.                     node = node->parent;
  59.                     ngx_rbtree_right_rotate(root, sentinel, node);
  60.                 }

  61.                 ngx_rbt_black(node->parent);
  62.                 ngx_rbt_red(node->parent->parent);
  63.                 ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
  64.             }
  65.         }
  66.     }

  67.     ngx_rbt_black(*root);
  68. }


  69. void
  70. ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
  71.     ngx_rbtree_node_t *sentinel)
  72. {
  73.     ngx_rbtree_node_t  **p;

  74.     for ( ;; ) {

  75.         p = (node->key < temp->key) ? &temp->left : &temp->right;

  76.         if (*p == sentinel) {
  77.             break;
  78.         }

  79.         temp = *p;
  80.     }

  81.     *p = node;
  82.     node->parent = temp;
  83.     node->left = sentinel;
  84.     node->right = sentinel;
  85.     ngx_rbt_red(node);
  86. }


  87. void
  88. ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
  89.     ngx_rbtree_node_t *sentinel)
  90. {
  91.     ngx_rbtree_node_t  **p;

  92.     for ( ;; ) {

  93.         /*
  94.          * Timer values
  95.          * 1) are spread in small range, usually several minutes,
  96.          * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
  97.          * The comparison takes into account that overflow.
  98.          */

  99.         /*  node->key < temp->key */

  100.         p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
  101.             ? &temp->left : &temp->right;

  102.         if (*p == sentinel) {
  103.             break;
  104.         }

  105.         temp = *p;
  106.     }

  107.     *p = node;
  108.     node->parent = temp;
  109.     node->left = sentinel;
  110.     node->right = sentinel;
  111.     ngx_rbt_red(node);
  112. }


  113. void
  114. ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
  115. {
  116.     ngx_uint_t           red;
  117.     ngx_rbtree_node_t  **root, *sentinel, *subst, *temp, *w;

  118.     /* a binary tree delete */

  119.     root = &tree->root;
  120.     sentinel = tree->sentinel;

  121.     if (node->left == sentinel) {
  122.         temp = node->right;
  123.         subst = node;

  124.     } else if (node->right == sentinel) {
  125.         temp = node->left;
  126.         subst = node;

  127.     } else {
  128.         subst = ngx_rbtree_min(node->right, sentinel);
  129.         temp = subst->right;
  130.     }

  131.     if (subst == *root) {
  132.         *root = temp;
  133.         ngx_rbt_black(temp);

  134.         /* DEBUG stuff */
  135.         node->left = NULL;
  136.         node->right = NULL;
  137.         node->parent = NULL;
  138.         node->key = 0;

  139.         return;
  140.     }

  141.     red = ngx_rbt_is_red(subst);

  142.     if (subst == subst->parent->left) {
  143.         subst->parent->left = temp;

  144.     } else {
  145.         subst->parent->right = temp;
  146.     }

  147.     if (subst == node) {

  148.         temp->parent = subst->parent;

  149.     } else {

  150.         if (subst->parent == node) {
  151.             temp->parent = subst;

  152.         } else {
  153.             temp->parent = subst->parent;
  154.         }

  155.         subst->left = node->left;
  156.         subst->right = node->right;
  157.         subst->parent = node->parent;
  158.         ngx_rbt_copy_color(subst, node);

  159.         if (node == *root) {
  160.             *root = subst;

  161.         } else {
  162.             if (node == node->parent->left) {
  163.                 node->parent->left = subst;
  164.             } else {
  165.                 node->parent->right = subst;
  166.             }
  167.         }

  168.         if (subst->left != sentinel) {
  169.             subst->left->parent = subst;
  170.         }

  171.         if (subst->right != sentinel) {
  172.             subst->right->parent = subst;
  173.         }
  174.     }

  175.     /* DEBUG stuff */
  176.     node->left = NULL;
  177.     node->right = NULL;
  178.     node->parent = NULL;
  179.     node->key = 0;

  180.     if (red) {
  181.         return;
  182.     }

  183.     /* a delete fixup */

  184.     while (temp != *root && ngx_rbt_is_black(temp)) {

  185.         if (temp == temp->parent->left) {
  186.             w = temp->parent->right;

  187.             if (ngx_rbt_is_red(w)) {
  188.                 ngx_rbt_black(w);
  189.                 ngx_rbt_red(temp->parent);
  190.                 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
  191.                 w = temp->parent->right;
  192.             }

  193.             if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
  194.                 ngx_rbt_red(w);
  195.                 temp = temp->parent;

  196.             } else {
  197.                 if (ngx_rbt_is_black(w->right)) {
  198.                     ngx_rbt_black(w->left);
  199.                     ngx_rbt_red(w);
  200.                     ngx_rbtree_right_rotate(root, sentinel, w);
  201.                     w = temp->parent->right;
  202.                 }

  203.                 ngx_rbt_copy_color(w, temp->parent);
  204.                 ngx_rbt_black(temp->parent);
  205.                 ngx_rbt_black(w->right);
  206.                 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
  207.                 temp = *root;
  208.             }

  209.         } else {
  210.             w = temp->parent->left;

  211.             if (ngx_rbt_is_red(w)) {
  212.                 ngx_rbt_black(w);
  213.                 ngx_rbt_red(temp->parent);
  214.                 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
  215.                 w = temp->parent->left;
  216.             }

  217.             if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
  218.                 ngx_rbt_red(w);
  219.                 temp = temp->parent;

  220.             } else {
  221.                 if (ngx_rbt_is_black(w->left)) {
  222.                     ngx_rbt_black(w->right);
  223.                     ngx_rbt_red(w);
  224.                     ngx_rbtree_left_rotate(root, sentinel, w);
  225.                     w = temp->parent->left;
  226.                 }

  227.                 ngx_rbt_copy_color(w, temp->parent);
  228.                 ngx_rbt_black(temp->parent);
  229.                 ngx_rbt_black(w->left);
  230.                 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
  231.                 temp = *root;
  232.             }
  233.         }
  234.     }

  235.     ngx_rbt_black(temp);
  236. }


  237. static ngx_inline void
  238. ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
  239.     ngx_rbtree_node_t *node)
  240. {
  241.     ngx_rbtree_node_t  *temp;

  242.     temp = node->right;
  243.     node->right = temp->left;

  244.     if (temp->left != sentinel) {
  245.         temp->left->parent = node;
  246.     }

  247.     temp->parent = node->parent;

  248.     if (node == *root) {
  249.         *root = temp;

  250.     } else if (node == node->parent->left) {
  251.         node->parent->left = temp;

  252.     } else {
  253.         node->parent->right = temp;
  254.     }

  255.     temp->left = node;
  256.     node->parent = temp;
  257. }


  258. static ngx_inline void
  259. ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
  260.     ngx_rbtree_node_t *node)
  261. {
  262.     ngx_rbtree_node_t  *temp;

  263.     temp = node->left;
  264.     node->left = temp->right;

  265.     if (temp->right != sentinel) {
  266.         temp->right->parent = node;
  267.     }

  268.     temp->parent = node->parent;

  269.     if (node == *root) {
  270.         *root = temp;

  271.     } else if (node == node->parent->right) {
  272.         node->parent->right = temp;

  273.     } else {
  274.         node->parent->left = temp;
  275.     }

  276.     temp->right = node;
  277.     node->parent = temp;
  278. }


  279. ngx_rbtree_node_t *
  280. ngx_rbtree_next(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
  281. {
  282.     ngx_rbtree_node_t  *root, *sentinel, *parent;

  283.     sentinel = tree->sentinel;

  284.     if (node->right != sentinel) {
  285.         return ngx_rbtree_min(node->right, sentinel);
  286.     }

  287.     root = tree->root;

  288.     for ( ;; ) {
  289.         parent = node->parent;

  290.         if (node == root) {
  291.             return NULL;
  292.         }

  293.         if (node == parent->left) {
  294.             return parent;
  295.         }

  296.         node = parent;
  297.     }
  298. }