mirror of
https://github.com/MariaDB/server.git
synced 2025-12-03 05:41:09 +03:00
Merge all of ticket 567 into trunk git-svn-id: file:///svn/tokudb@3134 c7de825b-a66e-492c-adef-691d508d4ae1
764 lines
20 KiB
C
764 lines
20 KiB
C
/*
|
|
Redblack balanced tree algorithm
|
|
Copyright (C) Damian Ivereigh 2000
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version. See the file COPYING for details.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/* Implement the red/black tree structure. It is designed to emulate
|
|
** the standard tsearch() stuff. i.e. the calling conventions are
|
|
** exactly the same
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <tokuredblack.h>
|
|
#include <assert.h>
|
|
|
|
/* Dummy (sentinel) node, so that we can make X->left->up = X
|
|
** We then use this instead of NULL to mean the top or bottom
|
|
** end of the rb tree. It is a black node.
|
|
**
|
|
** Initialization of the last field in this initializer is left implicit
|
|
** because it could be of any type. We count on the compiler to zero it.
|
|
*/
|
|
static struct toku_rbt_node toku_rbt__null;
|
|
static struct toku_rbt_node* RBNULL = &toku_rbt__null;
|
|
|
|
|
|
static struct toku_rbt_node *toku_rbt__alloc(struct toku_rbt_tree *rbinfo) {return (struct toku_rbt_node *) rbinfo->rb_malloc(sizeof(struct toku_rbt_node));}
|
|
static void toku_rbt__free(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *x) {rbinfo->rb_free(x);}
|
|
|
|
/* These functions are always needed */
|
|
static void toku_rbt__left_rotate(struct toku_rbt_node **, struct toku_rbt_node *);
|
|
static void toku_rbt__right_rotate(struct toku_rbt_node **, struct toku_rbt_node *);
|
|
static struct toku_rbt_node *toku_rbt__successor(const struct toku_rbt_node *);
|
|
static struct toku_rbt_node *toku_rbt__predecessor(const struct toku_rbt_node *);
|
|
static struct toku_rbt_node *toku_rbt__traverse(int, const toku_range * , struct toku_rbt_tree *);
|
|
|
|
/* These functions may not be needed */
|
|
static struct toku_rbt_node* toku_rbt__insert(
|
|
const toku_range* key,
|
|
struct toku_rbt_tree* rbinfo,
|
|
struct toku_rbt_node* parent
|
|
);
|
|
|
|
static struct toku_rbt_node *toku_rbt__lookup(int, const toku_interval * , struct toku_rbt_tree *, struct toku_rbt_node**);
|
|
|
|
static void toku_rbt__destroy(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *);
|
|
|
|
static void toku_rbt__delete(struct toku_rbt_tree* rbinfo, struct toku_rbt_node **, struct toku_rbt_node *);
|
|
static void toku_rbt__delete_fix(struct toku_rbt_node **, struct toku_rbt_node *);
|
|
|
|
/*
|
|
** OK here we go, the balanced tree stuff. The algorithm is the
|
|
** fairly standard red/black taken from "Introduction to Algorithms"
|
|
** by Cormen, Leiserson & Rivest. Maybe one of these days I will
|
|
** fully understand all this stuff.
|
|
**
|
|
** Basically a red/black balanced tree has the following properties:-
|
|
** 1) Every node is either red or black (colour is RED or BLACK)
|
|
** 2) A leaf (RBNULL pointer) is considered black
|
|
** 3) If a node is red then its children are black
|
|
** 4) Every path from a node to a leaf contains the same no
|
|
** of black nodes
|
|
**
|
|
** 3) & 4) above guarantee that the longest path (alternating
|
|
** red and black nodes) is only twice as long as the shortest
|
|
** path (all black nodes). Thus the tree remains fairly balanced.
|
|
*/
|
|
|
|
/*
|
|
* Initialise a tree. Identifies the comparison routine and any config
|
|
* data that must be sent to it when called.
|
|
* Returns a pointer to the top of the tree.
|
|
*/
|
|
int toku_rbt_init (
|
|
int (*cmp)(const toku_point*, const toku_point*),
|
|
struct toku_rbt_tree** ptree,
|
|
void* (*user_malloc) (size_t),
|
|
void (*user_free) (void*),
|
|
void* (*user_realloc)(void*, size_t)
|
|
)
|
|
{
|
|
struct toku_rbt_tree* temptree = NULL;
|
|
int r = ENOSYS;
|
|
|
|
static int toku_rbt__null_is_initialized = 0;
|
|
if (!toku_rbt__null_is_initialized) {
|
|
toku_rbt__null_is_initialized = 1;
|
|
toku_rbt__null.up = &toku_rbt__null;
|
|
toku_rbt__null.left = &toku_rbt__null;
|
|
toku_rbt__null.right = &toku_rbt__null;
|
|
toku_rbt__null.colour = BLACK;
|
|
/* Key is initialized since the toku_rbt__null is static. */
|
|
}
|
|
|
|
if (!cmp || !ptree || !user_malloc || !user_free || !user_realloc) {
|
|
r = EINVAL; goto cleanup; }
|
|
temptree=(struct toku_rbt_tree *) user_malloc(sizeof(struct toku_rbt_tree));
|
|
if (!temptree) { r = ENOMEM; goto cleanup; }
|
|
|
|
temptree->rb_cmp=cmp;
|
|
temptree->rb_root=RBNULL;
|
|
temptree->rb_malloc = user_malloc;
|
|
temptree->rb_free = user_free;
|
|
temptree->rb_realloc = user_realloc;
|
|
|
|
|
|
*ptree = temptree;
|
|
r = 0;
|
|
cleanup:
|
|
return r;
|
|
}
|
|
|
|
void toku_rbt_clear(struct toku_rbt_tree *rbinfo) {
|
|
assert(rbinfo);
|
|
if (rbinfo->rb_root!=RBNULL) { toku_rbt__destroy(rbinfo, rbinfo->rb_root); }
|
|
rbinfo->rb_root = RBNULL;
|
|
}
|
|
|
|
void toku_rbt_destroy(struct toku_rbt_tree *rbinfo) {
|
|
toku_rbt_clear(rbinfo);
|
|
rbinfo->rb_free(rbinfo);
|
|
}
|
|
|
|
int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbinfo) {
|
|
int r = ENOSYS;
|
|
|
|
if (!rbinfo || !node || node == RBNULL) { r = EINVAL; goto cleanup; }
|
|
toku_rbt__delete(rbinfo, &rbinfo->rb_root, node);
|
|
r = 0;
|
|
cleanup:
|
|
return r;
|
|
}
|
|
|
|
int toku_rbt_lookup(
|
|
int mode,
|
|
const toku_interval* key,
|
|
struct toku_rbt_tree* rbinfo,
|
|
struct toku_rbt_node** pinsert_finger,
|
|
struct toku_rbt_node** pelement_finger,
|
|
toku_range** pdata
|
|
)
|
|
{
|
|
int r = ENOSYS;
|
|
|
|
if (!rbinfo || !rbinfo->rb_root || !pdata ||
|
|
!pinsert_finger || !pelement_finger ||
|
|
(
|
|
(mode == RB_LUFIRST || mode == RB_LULAST) != (key == NULL)
|
|
)) {
|
|
r = EINVAL; goto cleanup; }
|
|
|
|
*pelement_finger = toku_rbt__lookup(mode, key, rbinfo, pinsert_finger);
|
|
*pdata = *pelement_finger == RBNULL ? NULL : RB_GET((*pelement_finger), key);
|
|
r = 0;
|
|
cleanup:
|
|
return r;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
/* Search for and if not found and insert is true, will add a new
|
|
** node in. Returns a pointer to the new node, or the node found
|
|
*/
|
|
static struct toku_rbt_node *
|
|
toku_rbt__traverse(int insert, const toku_range *key, struct toku_rbt_tree *rbinfo)
|
|
{
|
|
struct toku_rbt_node *x,*y;
|
|
int cmp;
|
|
int found=0;
|
|
int cmpmods();
|
|
|
|
y=RBNULL; /* points to the parent of x */
|
|
x=rbinfo->rb_root;
|
|
|
|
/* walk x down the tree */
|
|
while(x!=RBNULL && found==0)
|
|
{
|
|
y=x;
|
|
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
|
|
cmp=rbinfo->rb_cmp(key->ends.left, x->key.ends.left);
|
|
|
|
if (cmp<0)
|
|
x=x->left;
|
|
else if (cmp>0)
|
|
x=x->right;
|
|
else
|
|
found=1;
|
|
}
|
|
|
|
if (found || !insert)
|
|
return(x);
|
|
|
|
return toku_rbt__insert(key, rbinfo, y);
|
|
}
|
|
|
|
static struct toku_rbt_node* toku_rbt__insert(
|
|
const toku_range* key,
|
|
struct toku_rbt_tree* rbinfo,
|
|
struct toku_rbt_node* parent
|
|
) {
|
|
struct toku_rbt_node* x;
|
|
struct toku_rbt_node* y = parent;
|
|
struct toku_rbt_node* z;
|
|
int cmp;
|
|
|
|
if (parent == NULL) {
|
|
/* This means we have NOT actually located the right spot.
|
|
Locate it with traverse and then insert. */
|
|
return toku_rbt__traverse(1, key, rbinfo);
|
|
}
|
|
|
|
if ((z=toku_rbt__alloc(rbinfo))==NULL)
|
|
{
|
|
/* Whoops, no memory */
|
|
return(RBNULL);
|
|
}
|
|
|
|
RB_SET(z, key, key);
|
|
z->up=y;
|
|
if (y==RBNULL)
|
|
{
|
|
rbinfo->rb_root=z;
|
|
}
|
|
else
|
|
{
|
|
cmp=rbinfo->rb_cmp(z->key.ends.left, y->key.ends.left);
|
|
if (cmp<0)
|
|
y->left=z;
|
|
else
|
|
y->right=z;
|
|
}
|
|
|
|
z->left=RBNULL;
|
|
z->right=RBNULL;
|
|
|
|
/* colour this new node red */
|
|
z->colour=RED;
|
|
|
|
/* Having added a red node, we must now walk back up the tree balancing
|
|
** it, by a series of rotations and changing of colours
|
|
*/
|
|
x=z;
|
|
|
|
/* While we are not at the top and our parent node is red
|
|
** N.B. Since the root node is garanteed black, then we
|
|
** are also going to stop if we are the child of the root
|
|
*/
|
|
|
|
while(x != rbinfo->rb_root && (x->up->colour == RED))
|
|
{
|
|
/* if our parent is on the left side of our grandparent */
|
|
if (x->up == x->up->up->left)
|
|
{
|
|
/* get the right side of our grandparent (uncle?) */
|
|
y=x->up->up->right;
|
|
if (y->colour == RED)
|
|
{
|
|
/* make our parent black */
|
|
x->up->colour = BLACK;
|
|
/* make our uncle black */
|
|
y->colour = BLACK;
|
|
/* make our grandparent red */
|
|
x->up->up->colour = RED;
|
|
|
|
/* now consider our grandparent */
|
|
x=x->up->up;
|
|
}
|
|
else
|
|
{
|
|
/* if we are on the right side of our parent */
|
|
if (x == x->up->right)
|
|
{
|
|
/* Move up to our parent */
|
|
x=x->up;
|
|
toku_rbt__left_rotate(&rbinfo->rb_root, x);
|
|
}
|
|
|
|
/* make our parent black */
|
|
x->up->colour = BLACK;
|
|
/* make our grandparent red */
|
|
x->up->up->colour = RED;
|
|
/* right rotate our grandparent */
|
|
toku_rbt__right_rotate(&rbinfo->rb_root, x->up->up);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* everything here is the same as above, but
|
|
** exchanging left for right
|
|
*/
|
|
|
|
y=x->up->up->left;
|
|
if (y->colour == RED)
|
|
{
|
|
x->up->colour = BLACK;
|
|
y->colour = BLACK;
|
|
x->up->up->colour = RED;
|
|
|
|
x=x->up->up;
|
|
}
|
|
else
|
|
{
|
|
if (x == x->up->left)
|
|
{
|
|
x=x->up;
|
|
toku_rbt__right_rotate(&rbinfo->rb_root, x);
|
|
}
|
|
|
|
x->up->colour = BLACK;
|
|
x->up->up->colour = RED;
|
|
toku_rbt__left_rotate(&rbinfo->rb_root, x->up->up);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set the root node black */
|
|
(rbinfo->rb_root)->colour = BLACK;
|
|
|
|
return(z);
|
|
}
|
|
|
|
/* Search for a key according to mode (see redblack.h)
|
|
*/
|
|
static struct toku_rbt_node *
|
|
toku_rbt__lookup(int mode, const toku_interval *key, struct toku_rbt_tree *rbinfo, struct toku_rbt_node** pinsert_finger)
|
|
{
|
|
struct toku_rbt_node *x,*y;
|
|
int cmp = 0;
|
|
int found=0;
|
|
|
|
y=RBNULL; /* points to the parent of x */
|
|
x=rbinfo->rb_root;
|
|
|
|
if (mode==RB_LUFIRST)
|
|
{
|
|
/* Keep going left until we hit a NULL */
|
|
while(x!=RBNULL)
|
|
{
|
|
y=x;
|
|
x=x->left;
|
|
}
|
|
|
|
return(y);
|
|
}
|
|
else if (mode==RB_LULAST)
|
|
{
|
|
/* Keep going right until we hit a NULL */
|
|
while(x!=RBNULL)
|
|
{
|
|
y=x;
|
|
x=x->right;
|
|
}
|
|
|
|
return(y);
|
|
}
|
|
|
|
/* walk x down the tree */
|
|
while(x!=RBNULL && found==0)
|
|
{
|
|
y=x;
|
|
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
|
|
cmp=rbinfo->rb_cmp(key->left, x->key.ends.left);
|
|
|
|
|
|
if (cmp<0)
|
|
x=x->left;
|
|
else if (cmp>0)
|
|
x=x->right;
|
|
else
|
|
found=1;
|
|
}
|
|
if (pinsert_finger) *pinsert_finger = y;
|
|
|
|
if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ))
|
|
return(x);
|
|
|
|
if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV))
|
|
return(RBNULL);
|
|
|
|
if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT))
|
|
{
|
|
if (cmp>0)
|
|
return(toku_rbt__successor(y));
|
|
else
|
|
return(y);
|
|
}
|
|
|
|
if (mode==RB_LULTEQ || (!found && mode==RB_LULESS))
|
|
{
|
|
if (cmp<0)
|
|
return(toku_rbt__predecessor(y));
|
|
else
|
|
return(y);
|
|
}
|
|
|
|
if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT))
|
|
return(toku_rbt__successor(x));
|
|
|
|
if (mode==RB_LUPREV || (found && mode==RB_LULESS))
|
|
return(toku_rbt__predecessor(x));
|
|
|
|
/* Shouldn't get here */
|
|
return(RBNULL);
|
|
}
|
|
|
|
/*
|
|
* Destroy all the elements blow us in the tree
|
|
* only useful as part of a complete tree destroy.
|
|
*/
|
|
static void
|
|
toku_rbt__destroy(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *x)
|
|
{
|
|
if (x!=RBNULL)
|
|
{
|
|
if (x->left!=RBNULL)
|
|
toku_rbt__destroy(rbinfo, x->left);
|
|
if (x->right!=RBNULL)
|
|
toku_rbt__destroy(rbinfo, x->right);
|
|
toku_rbt__free(rbinfo,x);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Rotate our tree thus:-
|
|
**
|
|
** X rb_left_rotate(X)---> Y
|
|
** / \ / \
|
|
** A Y <---rb_right_rotate(Y) X C
|
|
** / \ / \
|
|
** B C A B
|
|
**
|
|
** N.B. This does not change the ordering.
|
|
**
|
|
** We assume that neither X or Y is NULL
|
|
*/
|
|
|
|
static void
|
|
toku_rbt__left_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *x)
|
|
{
|
|
struct toku_rbt_node *y;
|
|
|
|
assert(x!=RBNULL);
|
|
assert(x->right!=RBNULL);
|
|
|
|
y=x->right; /* set Y */
|
|
|
|
/* Turn Y's left subtree into X's right subtree (move B)*/
|
|
x->right = y->left;
|
|
|
|
/* If B is not null, set it's parent to be X */
|
|
if (y->left != RBNULL)
|
|
y->left->up = x;
|
|
|
|
/* Set Y's parent to be what X's parent was */
|
|
y->up = x->up;
|
|
|
|
/* if X was the root */
|
|
if (x->up == RBNULL)
|
|
{
|
|
*rootp=y;
|
|
}
|
|
else
|
|
{
|
|
/* Set X's parent's left or right pointer to be Y */
|
|
if (x == x->up->left)
|
|
{
|
|
x->up->left=y;
|
|
}
|
|
else
|
|
{
|
|
x->up->right=y;
|
|
}
|
|
}
|
|
|
|
/* Put X on Y's left */
|
|
y->left=x;
|
|
|
|
/* Set X's parent to be Y */
|
|
x->up = y;
|
|
}
|
|
|
|
static void
|
|
toku_rbt__right_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *y)
|
|
{
|
|
struct toku_rbt_node *x;
|
|
|
|
assert(y!=RBNULL);
|
|
assert(y->left!=RBNULL);
|
|
|
|
x=y->left; /* set X */
|
|
|
|
/* Turn X's right subtree into Y's left subtree (move B) */
|
|
y->left = x->right;
|
|
|
|
/* If B is not null, set it's parent to be Y */
|
|
if (x->right != RBNULL)
|
|
x->right->up = y;
|
|
|
|
/* Set X's parent to be what Y's parent was */
|
|
x->up = y->up;
|
|
|
|
/* if Y was the root */
|
|
if (y->up == RBNULL)
|
|
{
|
|
*rootp=x;
|
|
}
|
|
else
|
|
{
|
|
/* Set Y's parent's left or right pointer to be X */
|
|
if (y == y->up->left)
|
|
{
|
|
y->up->left=x;
|
|
}
|
|
else
|
|
{
|
|
y->up->right=x;
|
|
}
|
|
}
|
|
|
|
/* Put Y on X's right */
|
|
x->right=y;
|
|
|
|
/* Set Y's parent to be X */
|
|
y->up = x;
|
|
}
|
|
|
|
/* Return a pointer to the smallest key greater than x
|
|
*/
|
|
static struct toku_rbt_node *
|
|
toku_rbt__successor(const struct toku_rbt_node *x)
|
|
{
|
|
struct toku_rbt_node *y;
|
|
|
|
if (x->right!=RBNULL)
|
|
{
|
|
/* If right is not NULL then go right one and
|
|
** then keep going left until we find a node with
|
|
** no left pointer.
|
|
*/
|
|
for (y=x->right; y->left!=RBNULL; y=y->left);
|
|
}
|
|
else
|
|
{
|
|
/* Go up the tree until we get to a node that is on the
|
|
** left of its parent (or the root) and then return the
|
|
** parent.
|
|
*/
|
|
y=x->up;
|
|
while(y!=RBNULL && x==y->right)
|
|
{
|
|
x=y;
|
|
y=y->up;
|
|
}
|
|
}
|
|
return(y);
|
|
}
|
|
|
|
/* Return a pointer to the largest key smaller than x
|
|
*/
|
|
static struct toku_rbt_node *
|
|
toku_rbt__predecessor(const struct toku_rbt_node *x)
|
|
{
|
|
struct toku_rbt_node *y;
|
|
|
|
if (x->left!=RBNULL)
|
|
{
|
|
/* If left is not NULL then go left one and
|
|
** then keep going right until we find a node with
|
|
** no right pointer.
|
|
*/
|
|
for (y=x->left; y->right!=RBNULL; y=y->right);
|
|
}
|
|
else
|
|
{
|
|
/* Go up the tree until we get to a node that is on the
|
|
** right of its parent (or the root) and then return the
|
|
** parent.
|
|
*/
|
|
y=x->up;
|
|
while(y!=RBNULL && x==y->left)
|
|
{
|
|
x=y;
|
|
y=y->up;
|
|
}
|
|
}
|
|
return(y);
|
|
}
|
|
|
|
int toku_rbt_finger_predecessor(struct toku_rbt_node** pfinger,
|
|
toku_range** ppred_data) {
|
|
int r = ENOSYS;
|
|
|
|
if (!pfinger || !*pfinger ||
|
|
*pfinger == RBNULL || !ppred_data) { r = EINVAL; goto cleanup; }
|
|
*pfinger = toku_rbt__predecessor(*pfinger);
|
|
*ppred_data = (toku_range*)
|
|
((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key));
|
|
r = 0;
|
|
cleanup:
|
|
return r;
|
|
}
|
|
|
|
int toku_rbt_finger_successor(struct toku_rbt_node** pfinger,
|
|
toku_range** psucc_data) {
|
|
int r = ENOSYS;
|
|
|
|
if (!pfinger || !*pfinger || !psucc_data) { r = EINVAL; goto cleanup; }
|
|
if (*pfinger == RBNULL) { r = EDOM; goto cleanup; }
|
|
*pfinger = toku_rbt__successor(*pfinger);
|
|
*psucc_data = (toku_range*)
|
|
((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key));
|
|
r = 0;
|
|
cleanup:
|
|
return r;
|
|
}
|
|
|
|
int toku_rbt_finger_insert(
|
|
const toku_range* key,
|
|
struct toku_rbt_tree* rbinfo,
|
|
struct toku_rbt_node* parent
|
|
) {
|
|
if (!key || !rbinfo || !parent) return EINVAL;
|
|
toku_rbt__insert(key, rbinfo, parent);
|
|
return 0;
|
|
}
|
|
|
|
/* Delete the node z, and free up the space
|
|
*/
|
|
static void
|
|
toku_rbt__delete(struct toku_rbt_tree* rbinfo, struct toku_rbt_node **rootp, struct toku_rbt_node *z)
|
|
{
|
|
struct toku_rbt_node *x, *y;
|
|
|
|
if (z->left == RBNULL || z->right == RBNULL)
|
|
y=z;
|
|
else
|
|
y=toku_rbt__successor(z);
|
|
|
|
if (y->left != RBNULL)
|
|
x=y->left;
|
|
else
|
|
x=y->right;
|
|
|
|
x->up = y->up;
|
|
|
|
if (y->up == RBNULL)
|
|
{
|
|
*rootp=x;
|
|
}
|
|
else
|
|
{
|
|
if (y==y->up->left)
|
|
y->up->left = x;
|
|
else
|
|
y->up->right = x;
|
|
}
|
|
|
|
if (y!=z)
|
|
{
|
|
RB_SET(z, key, RB_GET(y, key));
|
|
}
|
|
|
|
if (y->colour == BLACK)
|
|
toku_rbt__delete_fix(rootp, x);
|
|
|
|
toku_rbt__free(rbinfo,y);
|
|
}
|
|
|
|
/* Restore the reb-black properties after a delete */
|
|
static void
|
|
toku_rbt__delete_fix(struct toku_rbt_node **rootp, struct toku_rbt_node *x)
|
|
{
|
|
struct toku_rbt_node *w;
|
|
|
|
while (x!=*rootp && x->colour==BLACK)
|
|
{
|
|
if (x==x->up->left)
|
|
{
|
|
w=x->up->right;
|
|
if (w->colour==RED)
|
|
{
|
|
w->colour=BLACK;
|
|
x->up->colour=RED;
|
|
toku_rbt__left_rotate(rootp, x->up);
|
|
w=x->up->right;
|
|
}
|
|
|
|
if (w->left->colour==BLACK && w->right->colour==BLACK)
|
|
{
|
|
w->colour=RED;
|
|
x=x->up;
|
|
}
|
|
else
|
|
{
|
|
if (w->right->colour == BLACK)
|
|
{
|
|
w->left->colour=BLACK;
|
|
w->colour=RED;
|
|
toku_rbt__right_rotate(rootp, w);
|
|
w=x->up->right;
|
|
}
|
|
|
|
|
|
w->colour=x->up->colour;
|
|
x->up->colour = BLACK;
|
|
w->right->colour = BLACK;
|
|
toku_rbt__left_rotate(rootp, x->up);
|
|
x=*rootp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
w=x->up->left;
|
|
if (w->colour==RED)
|
|
{
|
|
w->colour=BLACK;
|
|
x->up->colour=RED;
|
|
toku_rbt__right_rotate(rootp, x->up);
|
|
w=x->up->left;
|
|
}
|
|
|
|
if (w->right->colour==BLACK && w->left->colour==BLACK)
|
|
{
|
|
w->colour=RED;
|
|
x=x->up;
|
|
}
|
|
else
|
|
{
|
|
if (w->left->colour == BLACK)
|
|
{
|
|
w->right->colour=BLACK;
|
|
w->colour=RED;
|
|
toku_rbt__left_rotate(rootp, w);
|
|
w=x->up->left;
|
|
}
|
|
|
|
w->colour=x->up->colour;
|
|
x->up->colour = BLACK;
|
|
w->left->colour = BLACK;
|
|
toku_rbt__right_rotate(rootp, x->up);
|
|
x=*rootp;
|
|
}
|
|
}
|
|
}
|
|
|
|
x->colour=BLACK;
|
|
}
|