github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/binary_search_tree.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 lsmkv 13 14 import ( 15 "bytes" 16 17 "github.com/weaviate/weaviate/adapters/repos/db/lsmkv/rbtree" 18 "github.com/weaviate/weaviate/entities/lsmkv" 19 ) 20 21 type binarySearchTree struct { 22 root *binarySearchNode 23 } 24 25 // returns net additions of insert in bytes, and previous secondary keys 26 func (t *binarySearchTree) insert(key, value []byte, secondaryKeys [][]byte) (int, [][]byte) { 27 if t.root == nil { 28 t.root = &binarySearchNode{ 29 key: key, 30 value: value, 31 secondaryKeys: secondaryKeys, 32 colourIsRed: false, // root node is always black 33 } 34 return len(key) + len(value), nil 35 } 36 37 addition, newRoot, previousSecondaryKeys := t.root.insert(key, value, secondaryKeys) 38 if newRoot != nil { 39 t.root = newRoot 40 } 41 t.root.colourIsRed = false // Can be flipped in the process of balancing, but root is always black 42 43 return addition, previousSecondaryKeys 44 } 45 46 func (t *binarySearchTree) get(key []byte) ([]byte, error) { 47 if t.root == nil { 48 return nil, lsmkv.NotFound 49 } 50 51 return t.root.get(key) 52 } 53 54 func (t *binarySearchTree) setTombstone(key []byte, secondaryKeys [][]byte) { 55 if t.root == nil { 56 // we need to actively insert a node with a tombstone, even if this node is 57 // not present because we still need to propagate the delete into the disk 58 // segments. It could refer to an entity which was created in a previous 59 // segment and is thus unknown to this memtable 60 t.root = &binarySearchNode{ 61 key: key, 62 value: nil, 63 tombstone: true, 64 secondaryKeys: secondaryKeys, 65 colourIsRed: false, // root node is always black 66 } 67 return 68 } 69 70 newRoot := t.root.setTombstone(key, secondaryKeys) 71 if newRoot != nil { 72 t.root = newRoot 73 } 74 t.root.colourIsRed = false // Can be flipped in the process of balancing, but root is always black 75 } 76 77 func (t *binarySearchTree) flattenInOrder() []*binarySearchNode { 78 if t.root == nil { 79 return nil 80 } 81 82 return t.root.flattenInOrder() 83 } 84 85 type countStats struct { 86 upsertKeys [][]byte 87 tombstonedKeys [][]byte 88 } 89 90 func (c *countStats) hasUpsert(needle []byte) bool { 91 if c == nil { 92 return false 93 } 94 95 for _, hay := range c.upsertKeys { 96 if bytes.Equal(needle, hay) { 97 return true 98 } 99 } 100 101 return false 102 } 103 104 func (c *countStats) hasTombstone(needle []byte) bool { 105 if c == nil { 106 return false 107 } 108 109 for _, hay := range c.tombstonedKeys { 110 if bytes.Equal(needle, hay) { 111 return true 112 } 113 } 114 115 return false 116 } 117 118 func (t *binarySearchTree) countStats() *countStats { 119 stats := &countStats{} 120 if t.root == nil { 121 return stats 122 } 123 124 t.root.countStats(stats) 125 return stats 126 } 127 128 type binarySearchNode struct { 129 key []byte 130 value []byte 131 secondaryKeys [][]byte 132 left *binarySearchNode 133 right *binarySearchNode 134 parent *binarySearchNode 135 tombstone bool 136 colourIsRed bool 137 } 138 139 func (n *binarySearchNode) Parent() rbtree.Node { 140 if n == nil { 141 return nil 142 } 143 return n.parent 144 } 145 146 func (n *binarySearchNode) SetParent(parent rbtree.Node) { 147 if n == nil { 148 addNewSearchNodeReceiver(&n) 149 } 150 151 if parent == nil { 152 n.parent = nil 153 return 154 } 155 156 n.parent = parent.(*binarySearchNode) 157 } 158 159 func (n *binarySearchNode) Left() rbtree.Node { 160 if n == nil { 161 return nil 162 } 163 return n.left 164 } 165 166 func (n *binarySearchNode) SetLeft(left rbtree.Node) { 167 if n == nil { 168 addNewSearchNodeReceiver(&n) 169 } 170 171 if left == nil { 172 n.left = nil 173 return 174 } 175 176 n.left = left.(*binarySearchNode) 177 } 178 179 func (n *binarySearchNode) Right() rbtree.Node { 180 if n == nil { 181 return nil 182 } 183 return n.right 184 } 185 186 func (n *binarySearchNode) SetRight(right rbtree.Node) { 187 if n == nil { 188 addNewSearchNodeReceiver(&n) 189 } 190 191 if right == nil { 192 n.right = nil 193 return 194 } 195 196 n.right = right.(*binarySearchNode) 197 } 198 199 func (n *binarySearchNode) IsRed() bool { 200 if n == nil { 201 return false 202 } 203 return n.colourIsRed 204 } 205 206 func (n *binarySearchNode) SetRed(isRed bool) { 207 n.colourIsRed = isRed 208 } 209 210 func (n *binarySearchNode) IsNil() bool { 211 return n == nil 212 } 213 214 func addNewSearchNodeReceiver(nodePtr **binarySearchNode) { 215 *nodePtr = &binarySearchNode{} 216 } 217 218 // returns net additions of insert in bytes 219 func (n *binarySearchNode) insert(key, value []byte, secondaryKeys [][]byte) (netAdditions int, newRoot *binarySearchNode, previousSecondaryKeys [][]byte) { 220 if bytes.Equal(key, n.key) { 221 // since the key already exists, we only need to take the difference 222 // between the existing value and the new one to determine net change 223 netAdditions = len(n.value) - len(value) 224 if netAdditions < 0 { 225 netAdditions *= -1 226 } 227 228 // assign new value to node 229 n.value = value 230 231 // reset tombstone in case it had one 232 n.tombstone = false 233 previousSecondaryKeys = n.secondaryKeys 234 n.secondaryKeys = secondaryKeys 235 236 newRoot = nil // tree root does not change when replacing node 237 return 238 } 239 240 if bytes.Compare(key, n.key) < 0 { 241 if n.left != nil { 242 netAdditions, newRoot, previousSecondaryKeys = n.left.insert(key, value, secondaryKeys) 243 return 244 } else { 245 n.left = &binarySearchNode{ 246 key: key, 247 value: value, 248 secondaryKeys: secondaryKeys, 249 parent: n, 250 colourIsRed: true, // new nodes are always red, except root node which is handled in the tree itself 251 } 252 newRoot = binarySearchNodeFromRB(rbtree.Rebalance(n.left)) 253 netAdditions = len(key) + len(value) 254 return 255 } 256 } else { 257 if n.right != nil { 258 netAdditions, newRoot, previousSecondaryKeys = n.right.insert(key, value, secondaryKeys) 259 return 260 } else { 261 n.right = &binarySearchNode{ 262 key: key, 263 value: value, 264 secondaryKeys: secondaryKeys, 265 parent: n, 266 colourIsRed: true, 267 } 268 netAdditions = len(key) + len(value) 269 newRoot = binarySearchNodeFromRB(rbtree.Rebalance(n.right)) 270 return 271 } 272 } 273 } 274 275 func (n *binarySearchNode) get(key []byte) ([]byte, error) { 276 if bytes.Equal(n.key, key) { 277 if !n.tombstone { 278 return n.value, nil 279 } else { 280 return nil, lsmkv.Deleted 281 } 282 } 283 284 if bytes.Compare(key, n.key) < 0 { 285 if n.left == nil { 286 return nil, lsmkv.NotFound 287 } 288 289 return n.left.get(key) 290 } else { 291 if n.right == nil { 292 return nil, lsmkv.NotFound 293 } 294 295 return n.right.get(key) 296 } 297 } 298 299 func (n *binarySearchNode) setTombstone(key []byte, secondaryKeys [][]byte) *binarySearchNode { 300 if bytes.Equal(n.key, key) { 301 n.value = nil 302 n.tombstone = true 303 n.secondaryKeys = secondaryKeys 304 return nil 305 } 306 307 if bytes.Compare(key, n.key) < 0 { 308 if n.left == nil { 309 n.left = &binarySearchNode{ 310 key: key, 311 value: nil, 312 tombstone: true, 313 secondaryKeys: secondaryKeys, 314 parent: n, 315 colourIsRed: true, 316 } 317 return binarySearchNodeFromRB(rbtree.Rebalance(n.left)) 318 319 } 320 return n.left.setTombstone(key, secondaryKeys) 321 } else { 322 if n.right == nil { 323 n.right = &binarySearchNode{ 324 key: key, 325 value: nil, 326 tombstone: true, 327 secondaryKeys: secondaryKeys, 328 parent: n, 329 colourIsRed: true, 330 } 331 return binarySearchNodeFromRB(rbtree.Rebalance(n.right)) 332 } 333 return n.right.setTombstone(key, secondaryKeys) 334 } 335 } 336 337 func (n *binarySearchNode) flattenInOrder() []*binarySearchNode { 338 var left []*binarySearchNode 339 var right []*binarySearchNode 340 341 if n.left != nil { 342 left = n.left.flattenInOrder() 343 } 344 345 if n.right != nil { 346 right = n.right.flattenInOrder() 347 } 348 349 right = append([]*binarySearchNode{n}, right...) 350 return append(left, right...) 351 } 352 353 // This is not very allocation friendly, since we basically need to allocate 354 // once for each element in the memtable. However, these results can 355 // potentially be cached, as we don't care about the intermediary results, just 356 // the net additions. 357 func (n *binarySearchNode) countStats(stats *countStats) { 358 if n.tombstone { 359 stats.tombstonedKeys = append(stats.tombstonedKeys, n.key) 360 } else { 361 stats.upsertKeys = append(stats.upsertKeys, n.key) 362 } 363 364 if n.left != nil { 365 n.left.countStats(stats) 366 } 367 368 if n.right != nil { 369 n.right.countStats(stats) 370 } 371 } 372 373 func binarySearchNodeFromRB(rbNode rbtree.Node) (bsNode *binarySearchNode) { 374 if rbNode == nil { 375 bsNode = nil 376 return 377 } 378 bsNode = rbNode.(*binarySearchNode) 379 return 380 }