github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/rangedel/get.go (about) 1 // Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package rangedel 6 7 import "github.com/petermattis/pebble/internal/base" 8 9 // iterator is a subset of the pebble.internalIterator interface needed for 10 // range deletion iteration. 11 type iterator interface { 12 // SeekLT moves the iterator to the last key/value pair whose key is less 13 // than the given key. 14 SeekLT(key []byte) (*base.InternalKey, []byte) 15 16 // First moves the iterator the the first key/value pair. 17 First() (*base.InternalKey, []byte) 18 19 // Last moves the iterator the the last key/value pair. 20 Last() (*base.InternalKey, []byte) 21 22 // Next moves the iterator to the next key/value pair. 23 // It returns whether the iterator is exhausted. 24 Next() (*base.InternalKey, []byte) 25 26 // Prev moves the iterator to the previous key/value pair. 27 // It returns whether the iterator is exhausted. 28 Prev() (*base.InternalKey, []byte) 29 } 30 31 // Get returns the newest tombstone that contains the target key. If no 32 // tombstone contains the target key, an empty tombstone is returned. The 33 // snapshot parameter controls the visibility of tombstones (only tombstones 34 // older than the snapshot sequence number are visible). The iterator must 35 // contain fragmented tombstones: any overlapping tombstones must have the same 36 // start and end key. 37 func Get(cmp base.Compare, iter iterator, key []byte, snapshot uint64) Tombstone { 38 // NB: We use SeekLT in order to land on the proper tombstone for a search 39 // key that resides in the middle of a tombstone. Consider the scenario: 40 // 41 // a---e 42 // e---i 43 // 44 // The tombstones are indexed by their start keys `a` and `e`. If the 45 // search key is `c` we want to land on the tombstone [a,e). If we were to 46 // use SeekGE then the search key `c` would land on the tombstone [e,i) and 47 // we'd have to backtrack. The one complexity here is what happens for the 48 // search key `e`. In that case SeekLT will land us on the tombstone [a,e) 49 // and we'll have to move forward. 50 iterKey, iterValue := iter.SeekLT(key) 51 if iterKey == nil { 52 iterKey, iterValue = iter.Next() 53 if iterKey == nil { 54 // The iterator is empty. 55 return Tombstone{} 56 } 57 if cmp(key, iterKey.UserKey) < 0 { 58 // The search key lies before the first tombstone. 59 return Tombstone{} 60 } 61 } 62 63 // Invariant: key >= iter.Key().UserKey 64 65 if cmp(key, iterValue) < 0 { 66 // The current tombstone contains the search key, but SeekLT returns the 67 // oldest entry for a key, so backup until we hit the previous tombstone or 68 // an entry which is not visible. 69 for { 70 iterKey, iterValue = iter.Prev() 71 if iterKey == nil || cmp(key, iterValue) >= 0 || !iterKey.Visible(snapshot) { 72 iterKey, iterValue = iter.Next() 73 break 74 } 75 } 76 } else { 77 // The current tombstone lies before the search key. Advance the iterator 78 // as long as the search key lies past the end of the tombstone. See the 79 // comment at the start of this function about why this is necessary. 80 for { 81 iterKey, iterValue = iter.Next() 82 if iterKey == nil || cmp(key, iterKey.UserKey) < 0 { 83 // We've run out of tombstones or we've moved on to a tombstone which 84 // starts after our search key. 85 return Tombstone{} 86 } 87 if cmp(key, iterValue) < 0 { 88 break 89 } 90 } 91 } 92 93 for { 94 if start := iterKey; start.Visible(snapshot) { 95 // The tombstone is visible at our read sequence number. 96 return Tombstone{ 97 Start: *start, 98 End: iterValue, 99 } 100 } 101 iterKey, iterValue = iter.Next() 102 if iterKey == nil || cmp(key, iterKey.UserKey) < 0 { 103 // We've run out of tombstones or we've moved on to a tombstone which 104 // starts after our search key. 105 return Tombstone{} 106 } 107 } 108 }