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  }