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 }