github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/binary_search_tree_map.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 "sort" 17 18 "github.com/weaviate/weaviate/adapters/repos/db/lsmkv/rbtree" 19 "github.com/weaviate/weaviate/entities/lsmkv" 20 ) 21 22 type binarySearchTreeMap struct { 23 root *binarySearchNodeMap 24 } 25 26 func (t *binarySearchTreeMap) insert(key []byte, pair MapPair) { 27 if t.root == nil { 28 t.root = &binarySearchNodeMap{ 29 key: key, 30 values: []MapPair{pair}, 31 colourIsRed: false, // root node is always black 32 } 33 return 34 } 35 36 if newRoot := t.root.insert(key, pair); newRoot != nil { 37 t.root = newRoot 38 } 39 t.root.colourIsRed = false // Can be flipped in the process of balancing, but root is always black 40 } 41 42 func (t *binarySearchTreeMap) get(key []byte) ([]MapPair, error) { 43 if t.root == nil { 44 return nil, lsmkv.NotFound 45 } 46 47 return t.root.get(key) 48 } 49 50 func (t *binarySearchTreeMap) flattenInOrder() []*binarySearchNodeMap { 51 if t.root == nil { 52 return nil 53 } 54 55 return t.root.flattenInOrder() 56 } 57 58 type binarySearchNodeMap struct { 59 key []byte 60 values []MapPair 61 left *binarySearchNodeMap 62 right *binarySearchNodeMap 63 parent *binarySearchNodeMap 64 colourIsRed bool 65 } 66 67 func (n *binarySearchNodeMap) Parent() rbtree.Node { 68 if n == nil { 69 return nil 70 } 71 return n.parent 72 } 73 74 func (n *binarySearchNodeMap) SetParent(parent rbtree.Node) { 75 if n == nil { 76 addNewSearchNodeMapReceiver(&n) 77 } 78 79 if parent == nil { 80 n.parent = nil 81 return 82 } 83 84 n.parent = parent.(*binarySearchNodeMap) 85 } 86 87 func (n *binarySearchNodeMap) Left() rbtree.Node { 88 if n == nil { 89 return nil 90 } 91 return n.left 92 } 93 94 func (n *binarySearchNodeMap) SetLeft(left rbtree.Node) { 95 if n == nil { 96 addNewSearchNodeMapReceiver(&n) 97 } 98 99 if left == nil { 100 n.left = nil 101 return 102 } 103 104 n.left = left.(*binarySearchNodeMap) 105 } 106 107 func (n *binarySearchNodeMap) Right() rbtree.Node { 108 if n == nil { 109 return nil 110 } 111 return n.right 112 } 113 114 func (n *binarySearchNodeMap) SetRight(right rbtree.Node) { 115 if n == nil { 116 addNewSearchNodeMapReceiver(&n) 117 } 118 119 if right == nil { 120 n.right = nil 121 return 122 } 123 124 n.right = right.(*binarySearchNodeMap) 125 } 126 127 func (n *binarySearchNodeMap) IsRed() bool { 128 if n == nil { 129 return false 130 } 131 return n.colourIsRed 132 } 133 134 func (n *binarySearchNodeMap) SetRed(isRed bool) { 135 n.colourIsRed = isRed 136 } 137 138 func (n *binarySearchNodeMap) IsNil() bool { 139 return n == nil 140 } 141 142 func addNewSearchNodeMapReceiver(nodePtr **binarySearchNodeMap) { 143 *nodePtr = &binarySearchNodeMap{} 144 } 145 146 func (n *binarySearchNodeMap) insert(key []byte, pair MapPair) *binarySearchNodeMap { 147 if bytes.Equal(key, n.key) { 148 n.values = append(n.values, pair) 149 return nil // tree root does not change when replacing node 150 } 151 152 if bytes.Compare(key, n.key) < 0 { 153 if n.left != nil { 154 return n.left.insert(key, pair) 155 } else { 156 n.left = &binarySearchNodeMap{ 157 key: key, 158 parent: n, 159 colourIsRed: true, 160 values: []MapPair{pair}, 161 } 162 return binarySearchNodeMapFromRB(rbtree.Rebalance(n.left)) 163 } 164 } else { 165 if n.right != nil { 166 return n.right.insert(key, pair) 167 } else { 168 n.right = &binarySearchNodeMap{ 169 key: key, 170 parent: n, 171 colourIsRed: true, 172 values: []MapPair{pair}, 173 } 174 return binarySearchNodeMapFromRB(rbtree.Rebalance(n.right)) 175 } 176 } 177 } 178 179 func (n *binarySearchNodeMap) get(key []byte) ([]MapPair, error) { 180 if bytes.Equal(n.key, key) { 181 return sortAndDedupValues(n.values), nil 182 } 183 184 if bytes.Compare(key, n.key) < 0 { 185 if n.left == nil { 186 return nil, lsmkv.NotFound 187 } 188 189 return n.left.get(key) 190 } else { 191 if n.right == nil { 192 return nil, lsmkv.NotFound 193 } 194 195 return n.right.get(key) 196 } 197 } 198 199 func (n *binarySearchNodeMap) flattenInOrder() []*binarySearchNodeMap { 200 var left []*binarySearchNodeMap 201 var right []*binarySearchNodeMap 202 203 if n.left != nil { 204 left = n.left.flattenInOrder() 205 } 206 207 if n.right != nil { 208 right = n.right.flattenInOrder() 209 } 210 211 // the values are sorted on read for performance reasons, the assumption is 212 // that while a memtable is open writes a much more common, thus we write map 213 // KVs unsorted and only sort/dedup them on read. 214 right = append([]*binarySearchNodeMap{{ 215 key: n.key, 216 values: sortAndDedupValues(n.values), 217 colourIsRed: n.colourIsRed, 218 }}, right...) 219 return append(left, right...) 220 } 221 222 // takes a list of MapPair and sorts it while keeping the original order. Then 223 // removes redundancies (from updates or deletes after previous inserts) using 224 // a simple deduplication process. 225 func sortAndDedupValues(in []MapPair) []MapPair { 226 out := make([]MapPair, len(in)) 227 copy(out, in) 228 229 // use SliceStable so that we keep the insert order on duplicates. This is 230 // important because otherwise we can't dedup them correctly if we don't know 231 // in which order they came in. 232 sort.SliceStable(out, func(a, b int) bool { 233 return bytes.Compare(out[a].Key, out[b].Key) < 0 234 }) 235 236 // now deduping is as simple as looking one key ahead - if it's the same key 237 // simply skip the current element. Meaning "out" will be a subset of 238 // (sorted) "in". 239 outIndex := 0 240 for inIndex, pair := range out { 241 // look ahead 242 if inIndex+1 < len(out) && bytes.Equal(out[inIndex+1].Key, pair.Key) { 243 continue 244 } 245 246 out[outIndex] = pair 247 outIndex++ 248 } 249 250 return out[:outIndex] 251 } 252 253 func binarySearchNodeMapFromRB(rbNode rbtree.Node) (bsNode *binarySearchNodeMap) { 254 if rbNode == nil { 255 bsNode = nil 256 return 257 } 258 bsNode = rbNode.(*binarySearchNodeMap) 259 return 260 }