src/core/ngx_rbtree.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. /*
  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 = (ngx_rbtree_node_t **) &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 = (ngx_rbtree_node_t **) &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.         if (subst->left != sentinel) {
  130.             temp = subst->left;
  131.         } else {
  132.             temp = subst->right;
  133.         }
  134.     }

  135.     if (subst == *root) {
  136.         *root = temp;
  137.         ngx_rbt_black(temp);

  138.         /* DEBUG stuff */
  139.         node->left = NULL;
  140.         node->right = NULL;
  141.         node->parent = NULL;
  142.         node->key = 0;

  143.         return;
  144.     }

  145.     red = ngx_rbt_is_red(subst);

  146.     if (subst == subst->parent->left) {
  147.         subst->parent->left = temp;

  148.     } else {
  149.         subst->parent->right = temp;
  150.     }

  151.     if (subst == node) {

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

  153.     } else {

  154.         if (subst->parent == node) {
  155.             temp->parent = subst;

  156.         } else {
  157.             temp->parent = subst->parent;
  158.         }

  159.         subst->left = node->left;
  160.         subst->right = node->right;
  161.         subst->parent = node->parent;
  162.         ngx_rbt_copy_color(subst, node);

  163.         if (node == *root) {
  164.             *root = subst;

  165.         } else {
  166.             if (node == node->parent->left) {
  167.                 node->parent->left = subst;
  168.             } else {
  169.                 node->parent->right = subst;
  170.             }
  171.         }

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

  175.         if (subst->right != sentinel) {
  176.             subst->right->parent = subst;
  177.         }
  178.     }

  179.     /* DEBUG stuff */
  180.     node->left = NULL;
  181.     node->right = NULL;
  182.     node->parent = NULL;
  183.     node->key = 0;

  184.     if (red) {
  185.         return;
  186.     }

  187.     /* a delete fixup */

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

  189.         if (temp == temp->parent->left) {
  190.             w = temp->parent->right;

  191.             if (ngx_rbt_is_red(w)) {
  192.                 ngx_rbt_black(w);
  193.                 ngx_rbt_red(temp->parent);
  194.                 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
  195.                 w = temp->parent->right;
  196.             }

  197.             if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
  198.                 ngx_rbt_red(w);
  199.                 temp = temp->parent;

  200.             } else {
  201.                 if (ngx_rbt_is_black(w->right)) {
  202.                     ngx_rbt_black(w->left);
  203.                     ngx_rbt_red(w);
  204.                     ngx_rbtree_right_rotate(root, sentinel, w);
  205.                     w = temp->parent->right;
  206.                 }

  207.                 ngx_rbt_copy_color(w, temp->parent);
  208.                 ngx_rbt_black(temp->parent);
  209.                 ngx_rbt_black(w->right);
  210.                 ngx_rbtree_left_rotate(root, sentinel, temp->parent);
  211.                 temp = *root;
  212.             }

  213.         } else {
  214.             w = temp->parent->left;

  215.             if (ngx_rbt_is_red(w)) {
  216.                 ngx_rbt_black(w);
  217.                 ngx_rbt_red(temp->parent);
  218.                 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
  219.                 w = temp->parent->left;
  220.             }

  221.             if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
  222.                 ngx_rbt_red(w);
  223.                 temp = temp->parent;

  224.             } else {
  225.                 if (ngx_rbt_is_black(w->left)) {
  226.                     ngx_rbt_black(w->right);
  227.                     ngx_rbt_red(w);
  228.                     ngx_rbtree_left_rotate(root, sentinel, w);
  229.                     w = temp->parent->left;
  230.                 }

  231.                 ngx_rbt_copy_color(w, temp->parent);
  232.                 ngx_rbt_black(temp->parent);
  233.                 ngx_rbt_black(w->left);
  234.                 ngx_rbtree_right_rotate(root, sentinel, temp->parent);
  235.                 temp = *root;
  236.             }
  237.         }
  238.     }

  239.     ngx_rbt_black(temp);
  240. }


  241. static ngx_inline void
  242. ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
  243.     ngx_rbtree_node_t *node)
  244. {
  245.     ngx_rbtree_node_t  *temp;

  246.     temp = node->right;
  247.     node->right = temp->left;

  248.     if (temp->left != sentinel) {
  249.         temp->left->parent = node;
  250.     }

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

  252.     if (node == *root) {
  253.         *root = temp;

  254.     } else if (node == node->parent->left) {
  255.         node->parent->left = temp;

  256.     } else {
  257.         node->parent->right = temp;
  258.     }

  259.     temp->left = node;
  260.     node->parent = temp;
  261. }


  262. static ngx_inline void
  263. ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
  264.     ngx_rbtree_node_t *node)
  265. {
  266.     ngx_rbtree_node_t  *temp;

  267.     temp = node->left;
  268.     node->left = temp->right;

  269.     if (temp->right != sentinel) {
  270.         temp->right->parent = node;
  271.     }

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

  273.     if (node == *root) {
  274.         *root = temp;

  275.     } else if (node == node->parent->right) {
  276.         node->parent->right = temp;

  277.     } else {
  278.         node->parent->left = temp;
  279.     }

  280.     temp->right = node;
  281.     node->parent = temp;
  282. }