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  }