github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/rbtree/rbtree.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package rbtree
    13  
    14  type Node interface {
    15  	Parent() Node
    16  	SetParent(Node)
    17  	Left() Node
    18  	SetLeft(Node)
    19  	Right() Node
    20  	SetRight(Node)
    21  	IsRed() bool
    22  	SetRed(bool)
    23  	IsNil() bool
    24  }
    25  
    26  // This function rebalances and recolours trees to be valid RB trees. It needs to be called after each node that
    27  // was added to the tree.
    28  //
    29  // Deletions are currently not supported as this is done through the tombstone flag and from the POV of the RB-tree
    30  // tombstone-nodes are just normal nodes that get rebalanced the normal way.
    31  //
    32  // Throughout this file the following relationships between nodes are used:
    33  // GP = grandparent, P = parent, U = uncle, S = sibling, N = node that was just added
    34  //
    35  //	   GP
    36  //	 /   \
    37  //	U     P
    38  //	     / \
    39  //	    S   N
    40  func Rebalance(node Node) Node {
    41  	for {
    42  		parent := node.Parent()
    43  
    44  		// if parent is black or the current node is the root node (== parent is nil) there is nothing to do
    45  		if !parent.IsRed() {
    46  			return nil
    47  		}
    48  
    49  		grandparent := node.Parent().Parent()
    50  		var uncle Node
    51  		if parent == grandparent.Right() {
    52  			uncle = grandparent.Left()
    53  		} else {
    54  			uncle = grandparent.Right()
    55  		}
    56  
    57  		if uncle.IsRed() {
    58  			// if uncle is red, recoloring the tree up to the grandparent results in a valid RBtree.
    59  			// The color of the grandfather changes to red, so there might be more fixes needed. Therefore
    60  			// go up the tree and repeat.
    61  			recolourNodes(parent, grandparent, uncle)
    62  			node = grandparent
    63  		} else {
    64  			// if uncle is black, there are four possible cases:
    65  			//   parent is the right child grandparent:
    66  			//    1) node is right child of parent => left rotate around GP
    67  			//    2) node is left child of parent => right rotate around parent results in case 1
    68  			//   For cases 3 and 4 just replace left and right in the two cases above
    69  			//
    70  			// In all of these cases the grandfather stays black and there is no need for further fixes up the tree
    71  			var newRoot Node
    72  			if parent == grandparent.Right() {
    73  				if node == parent.Left() {
    74  					rightRotate(parent)
    75  					// node and parent switch places in the tree, update parent to recolour the current node
    76  					parent = node
    77  				}
    78  				newRoot = leftRotate(grandparent)
    79  			} else { // parent == grandparent.left
    80  				if node == parent.Right() {
    81  					leftRotate(parent)
    82  					parent = node
    83  				}
    84  				newRoot = rightRotate(grandparent)
    85  			}
    86  			recolourNodes(grandparent, parent)
    87  			return newRoot
    88  		}
    89  	}
    90  }
    91  
    92  func recolourNodes(nodes ...Node) {
    93  	for _, n := range nodes {
    94  		if !n.IsNil() {
    95  			if n.IsRed() {
    96  				n.SetRed(false)
    97  			} else {
    98  				n.SetRed(true)
    99  			}
   100  		}
   101  	}
   102  }
   103  
   104  // Rotate the tree left around the given node.
   105  //
   106  // After this rotation, the former right child (FC) will be the new parent and the former parent (FP) will
   107  // be the left node of the new parent. The left child of the former child is transferred to the former parent.
   108  //
   109  //	    FP                                FC
   110  //	 /      \         left rotate        /  \
   111  //	FP_R     FC          =>            FP   FC_R
   112  //	        / \                       / \
   113  //	     FC_L   FC_R               FP_R  FC_L
   114  //
   115  // In case FP was the root of the tree, FC will be the new root of the tree.
   116  func leftRotate(rotationNode Node) Node {
   117  	formerChild := rotationNode.Right()
   118  	rootRotate := rotationNode.Parent().IsNil()
   119  
   120  	// former child node becomes new parent unless the rotation is around the root node
   121  	if rootRotate {
   122  		formerChild.SetParent(nil)
   123  	} else {
   124  		if rotationNode.Parent().Left() == rotationNode {
   125  			rotationNode.Parent().SetLeft(formerChild)
   126  		} else {
   127  			rotationNode.Parent().SetRight(formerChild)
   128  		}
   129  		formerChild.SetParent(rotationNode.Parent())
   130  	}
   131  
   132  	rotationNode.SetParent(formerChild)
   133  
   134  	// Switch left child from former_child to rotation node
   135  	rotationNode.SetRight(formerChild.Left())
   136  	if formerChild.Left() != nil {
   137  		formerChild.Left().SetParent(rotationNode)
   138  	}
   139  	formerChild.SetLeft(rotationNode)
   140  
   141  	if rootRotate {
   142  		return formerChild
   143  	} else {
   144  		return nil
   145  	}
   146  }
   147  
   148  // Same as leftRotate, just switch left and right everywhere
   149  func rightRotate(rotationNode Node) Node {
   150  	formerChild := rotationNode.Left()
   151  	rootRotate := rotationNode.Parent().IsNil()
   152  
   153  	if rootRotate {
   154  		formerChild.SetParent(nil)
   155  	} else {
   156  		if rotationNode.Parent().Left() == rotationNode {
   157  			rotationNode.Parent().SetLeft(formerChild)
   158  		} else {
   159  			rotationNode.Parent().SetRight(formerChild)
   160  		}
   161  		formerChild.SetParent(rotationNode.Parent())
   162  	}
   163  	rotationNode.SetParent(formerChild)
   164  
   165  	rotationNode.SetLeft(formerChild.Right())
   166  	if formerChild.Right() != nil {
   167  		formerChild.Right().SetParent(rotationNode)
   168  	}
   169  	formerChild.SetRight(rotationNode)
   170  
   171  	if rootRotate {
   172  		return formerChild
   173  	} else {
   174  		return nil
   175  	}
   176  }