github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/rangedel/seek.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 // invalidate the specified iterator by moving it past the last entry. 10 func invalidate(iter iterator) { 11 iter.Last() 12 iter.Next() 13 } 14 15 // SeekGE seeks to the newest tombstone that contains or is past the target 16 // key. The snapshot parameter controls the visibility of tombstones (only 17 // tombstones older than the snapshot sequence number are visible). The 18 // iterator must contain fragmented tombstones: any overlapping tombstones must 19 // have the same start and end key. 20 func SeekGE(cmp base.Compare, iter iterator, key []byte, snapshot uint64) Tombstone { 21 // NB: We use SeekLT in order to land on the proper tombstone for a search 22 // key that resides in the middle of a tombstone. Consider the scenario: 23 // 24 // a---e 25 // e---i 26 // 27 // The tombstones are indexed by their start keys `a` and `e`. If the 28 // search key is `c` we want to land on the tombstone [a,e). If we were to 29 // use SeekGE then the search key `c` would land on the tombstone [e,i) and 30 // we'd have to backtrack. The one complexity here is what happens for the 31 // search key `e`. In that case SeekLT will land us on the tombstone [a,e) 32 // and we'll have to move forward. 33 iterKey, iterValue := iter.SeekLT(key) 34 35 // Invariant: key < iter.Key().UserKey 36 37 if iterKey != nil && cmp(key, iterValue) < 0 { 38 // The current tombstones contains or is past the search key, but SeekLT 39 // returns the oldest entry for a key, so backup until we hit the previous 40 // tombstone or an entry which is not visible. 41 for savedKey := iterKey.UserKey; ; { 42 iterKey, iterValue = iter.Prev() 43 if iterKey == nil || cmp(savedKey, iterValue) >= 0 || !iterKey.Visible(snapshot) { 44 iterKey, iterValue = iter.Next() 45 break 46 } 47 } 48 } else { 49 // The current tombstone lies before the search key. Advance the iterator 50 // as long as the search key lies past the end of the tombstone. See the 51 // comment at the start of this function about why this is necessary. 52 for { 53 iterKey, iterValue = iter.Next() 54 if iterKey == nil { 55 // We've run out of tombstones. 56 return Tombstone{} 57 } 58 if cmp(key, iterValue) < 0 { 59 break 60 } 61 } 62 } 63 64 // Walk through the tombstones to find one the newest one that is visible 65 // (i.e. has a sequence number less than the snapshot sequence number). 66 for { 67 if start := iterKey; start.Visible(snapshot) { 68 // The tombstone is visible at our read sequence number. 69 return Tombstone{ 70 Start: *start, 71 End: iterValue, 72 } 73 } 74 iterKey, iterValue = iter.Next() 75 if iterKey == nil { 76 // We've run out of tombstones. 77 return Tombstone{} 78 } 79 } 80 } 81 82 // SeekLE seeks to the newest tombstone that contains or is before the target 83 // key. The snapshot parameter controls the visibility of tombstones (only 84 // tombstones older than the snapshot sequence number are visible). The 85 // iterator must contain fragmented tombstones: any overlapping tombstones must 86 // have the same start and end key. 87 func SeekLE(cmp base.Compare, iter iterator, key []byte, snapshot uint64) Tombstone { 88 // NB: We use SeekLT in order to land on the proper tombstone for a search 89 // key that resides in the middle of a tombstone. Consider the scenario: 90 // 91 // a---e 92 // e---i 93 // 94 // The tombstones are indexed by their start keys `a` and `e`. If the 95 // search key is `c` we want to land on the tombstone [a,e). If we were to 96 // use SeekGE then the search key `c` would land on the tombstone [e,i) and 97 // we'd have to backtrack. The one complexity here is what happens for the 98 // search key `e`. In that case SeekLT will land us on the tombstone [a,e) 99 // and we'll have to move forward. 100 iterKey, iterValue := iter.SeekLT(key) 101 if iterKey == nil { 102 iterKey, iterValue = iter.Next() 103 if iterKey == nil { 104 // The iterator is empty. 105 return Tombstone{} 106 } 107 if cmp(key, iterKey.UserKey) < 0 { 108 // The search key lies before the first tombstone. 109 // 110 // TODO(peter): why is this call to iter.Prev() here? 111 iterKey, iterValue = iter.Prev() 112 return Tombstone{} 113 } 114 // Advance the iterator until we find a visible version or we hit the next 115 // tombstone. 116 for { 117 if start := iterKey; start.Visible(snapshot) { 118 return Tombstone{ 119 Start: *start, 120 End: iterValue, 121 } 122 } 123 iterKey, iterValue = iter.Next() 124 if iterKey == nil { 125 // We've run out of tombstones. 126 return Tombstone{} 127 } 128 if cmp(key, iterKey.UserKey) < 0 { 129 // We've hit the next tombstone. 130 invalidate(iter) 131 return Tombstone{} 132 } 133 } 134 } 135 136 // Invariant: key >= iter.Key().UserKey 137 138 if cmp(key, iterValue) >= 0 { 139 // The current tombstone lies before the search key. Check to see if the 140 // next tombstone contains the search key. If it doesn't, we'll backup and 141 // use the current tombstone. 142 iterKey, iterValue = iter.Next() 143 if iterKey == nil || cmp(key, iterKey.UserKey) < 0 { 144 iterKey, iterValue = iter.Prev() 145 } else { 146 // Advance the iterator until we find a visible version or we hit the 147 // next tombstone. 148 for { 149 if start := iterKey; start.Visible(snapshot) { 150 return Tombstone{ 151 Start: *start, 152 End: iterValue, 153 } 154 } 155 iterKey, iterValue = iter.Next() 156 if iterKey == nil || cmp(key, iterKey.UserKey) < 0 { 157 iterKey, iterValue = iter.Prev() 158 break 159 } 160 } 161 } 162 } 163 164 // We're now positioned at a tombstone that contains or is before the search 165 // key and we're positioned at either the oldest of the versions or a visible 166 // version. Walk backwards through the tombstones to find the newest one that 167 // is visible (i.e. has a sequence number less than the snapshot sequence 168 // number). 169 for savedKey := iterKey.UserKey; ; { 170 valid := iterKey.Visible(snapshot) 171 iterKey, iterValue = iter.Prev() 172 if iterKey == nil { 173 break 174 } 175 if valid { 176 if !iterKey.Visible(snapshot) { 177 break 178 } 179 if cmp(savedKey, iterKey.UserKey) != 0 { 180 break 181 } 182 } 183 } 184 185 iterKey, iterValue = iter.Next() 186 start := iterKey 187 if cmp(key, start.UserKey) < 0 { 188 // The current tombstone is after our search key. 189 invalidate(iter) 190 return Tombstone{} 191 } 192 if !start.Visible(snapshot) { 193 // The current tombstone is not visible at our read sequence number. 194 invalidate(iter) 195 return Tombstone{} 196 } 197 // The tombstone is visible at our read sequence number. 198 return Tombstone{ 199 Start: *start, 200 End: iterValue, 201 } 202 }