github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/cursor_memtable_replace.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/entities/lsmkv" 18 ) 19 20 type memtableCursor struct { 21 data []*binarySearchNode 22 current int 23 lock func() 24 unlock func() 25 } 26 27 func (m *Memtable) newCursor() innerCursorReplace { 28 // This cursor is a really primitive approach, it actually requires 29 // flattening the entire memtable - even if the cursor were to point to the 30 // very last element. However, given that the memtable will on average be 31 // only half it's max capacity and even that is relatively small, we might 32 // get away with the full-flattening and a linear search. Let's not optimize 33 // prematurely. 34 35 m.RLock() 36 defer m.RUnlock() 37 38 data := m.key.flattenInOrder() 39 40 return &memtableCursor{ 41 data: data, 42 lock: m.RLock, 43 unlock: m.RUnlock, 44 } 45 } 46 47 func (c *memtableCursor) first() ([]byte, []byte, error) { 48 c.lock() 49 defer c.unlock() 50 51 if len(c.data) == 0 { 52 return nil, nil, lsmkv.NotFound 53 } 54 55 c.current = 0 56 57 if c.data[c.current].tombstone { 58 return c.data[c.current].key, nil, lsmkv.Deleted 59 } 60 return c.data[c.current].key, c.data[c.current].value, nil 61 } 62 63 func (c *memtableCursor) seek(key []byte) ([]byte, []byte, error) { 64 c.lock() 65 defer c.unlock() 66 67 pos := c.posLargerThanEqual(key) 68 if pos == -1 { 69 return nil, nil, lsmkv.NotFound 70 } 71 72 c.current = pos 73 if c.data[c.current].tombstone { 74 return c.data[c.current].key, nil, lsmkv.Deleted 75 } 76 return c.data[pos].key, c.data[pos].value, nil 77 } 78 79 func (c *memtableCursor) posLargerThanEqual(key []byte) int { 80 for i, node := range c.data { 81 if bytes.Compare(node.key, key) >= 0 { 82 return i 83 } 84 } 85 86 return -1 87 } 88 89 func (c *memtableCursor) next() ([]byte, []byte, error) { 90 c.lock() 91 defer c.unlock() 92 93 c.current++ 94 if c.current >= len(c.data) { 95 return nil, nil, lsmkv.NotFound 96 } 97 98 if c.data[c.current].tombstone { 99 return c.data[c.current].key, nil, lsmkv.Deleted 100 } 101 return c.data[c.current].key, c.data[c.current].value, nil 102 }