@@ -178,7 +178,7 @@ func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileRetur
178178 return noFileLoaded
179179 }
180180 if indicator != fileAlreadyLoaded {
181- l .iter , l .err = l .newIter (l . files . Current () , & l .tableOpts )
181+ l .iter , l .err = l .newIter (file , & l .tableOpts )
182182 indicator = newFileLoaded
183183 }
184184 if l .err != nil {
@@ -190,33 +190,42 @@ func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileRetur
190190// SeekGE implements keyspan.FragmentIterator.
191191func (l * LevelIter ) SeekGE (key []byte ) * Span {
192192 l .dir = + 1
193+ l .straddle = Span {}
194+ l .straddleDir = 0
193195 l .err = nil // clear cached iteration error
194196
195197 f := l .findFileGE (key )
196198 if f != nil && l .keyType == manifest .KeyTypeRange && l .cmp (key , f .SmallestRangeKey .UserKey ) < 0 {
197- // Return a straddling key instead of loading the file.
198- l .iterFile = f
199- l .iter = nil
200- l .straddleDir = + 1
201- // The synthetic span that we are creating starts at the seeked key. This
202- // is an optimization as it prevents us from loading the adjacent file's
203- // bounds, at the expense of this iterator appearing "inconsistent" to its
204- // callers i.e.:
205- //
206- // SeekGE(bb) -> {bb-c, empty}
207- // Next() -> {c-d, RANGEKEYSET}
208- // Prev() -> {a-c, empty}
209- //
210- // Seeing as the inconsistency will only be around empty spans, which are
211- // expected to be elided by one of the higher-level iterators (either
212- // top-level Iterator or the defragmenting iter), the entire iterator should
213- // still appear consistent to the user.
214- l .straddle = Span {
215- Start : key ,
216- End : f .SmallestRangeKey .UserKey ,
217- Keys : nil ,
199+ prevFile := l .files .Prev ()
200+ if prevFile != nil {
201+ // We could unconditionally return an empty span between the seek key and
202+ // f.SmallestRangeKey, however if this span is to the left of all range
203+ // keys on this level, it could lead to inconsistent behaviour in relative
204+ // positioning operations. Consider this example, with a b-c range key:
205+ //
206+ // SeekGE(a) -> a-b:{}
207+ // Next() -> b-c{(#5,RANGEKEYSET,@4,foo)}
208+ // Prev() -> nil
209+ //
210+ // Iterators higher up in the iterator stack rely on this sort of relative
211+ // positioning consistency.
212+ //
213+ // TODO(bilal): Investigate ways to be able to return straddle spans in
214+ // cases similar to the above, while still retaining correctness.
215+ l .files .Next ()
216+ // Return a straddling key instead of loading the file.
217+ l .iterFile = f
218+ if err := l .Close (); err != nil {
219+ return nil
220+ }
221+ l .straddleDir = + 1
222+ l .straddle = Span {
223+ Start : prevFile .LargestRangeKey .UserKey ,
224+ End : f .SmallestRangeKey .UserKey ,
225+ Keys : nil ,
226+ }
227+ return & l .straddle
218228 }
219- return & l .straddle
220229 }
221230 loadFileIndicator := l .loadFile (f , + 1 )
222231 if loadFileIndicator == noFileLoaded {
@@ -231,33 +240,42 @@ func (l *LevelIter) SeekGE(key []byte) *Span {
231240// SeekLT implements keyspan.FragmentIterator.
232241func (l * LevelIter ) SeekLT (key []byte ) * Span {
233242 l .dir = - 1
243+ l .straddle = Span {}
244+ l .straddleDir = 0
234245 l .err = nil // clear cached iteration error
235246
236247 f := l .findFileLT (key )
237248 if f != nil && l .keyType == manifest .KeyTypeRange && l .cmp (f .LargestRangeKey .UserKey , key ) < 0 {
238- // Return a straddling key instead of loading the file.
239- l .iterFile = f
240- l .iter = nil
241- l .straddleDir = - 1
242- // The synthetic span that we are creating ends at the seeked key. This
243- // is an optimization as it prevents us from loading the adjacent file's
244- // bounds, at the expense of this iterator appearing "inconsistent" to its
245- // callers i.e.:
246- //
247- // SeekLT(dd) -> {d-dd, empty}
248- // Prev() -> {c-d, RANGEKEYSET}
249- // Next() -> {d-e, empty}
250- //
251- // Seeing as the inconsistency will only be around empty spans, which are
252- // expected to be elided by one of the higher-level iterators (either
253- // top-level Iterator or the defragmenting iter), the entire iterator should
254- // still appear consistent to the user.
255- l .straddle = Span {
256- Start : f .LargestRangeKey .UserKey ,
257- End : key ,
258- Keys : nil ,
249+ nextFile := l .files .Next ()
250+ if nextFile != nil {
251+ // We could unconditionally return an empty span between f.LargestRangeKey
252+ // and the seek key, however if this span is to the right of all range keys
253+ // on this level, it could lead to inconsistent behaviour in relative
254+ // positioning operations. Consider this example, with a b-c range key:
255+ //
256+ // SeekLT(d) -> c-d:{}
257+ // Prev() -> b-c{(#5,RANGEKEYSET,@4,foo)}
258+ // Next() -> nil
259+ //
260+ // Iterators higher up in the iterator stack rely on this sort of relative
261+ // positioning consistency.
262+ //
263+ // TODO(bilal): Investigate ways to be able to return straddle spans in
264+ // cases similar to the above, while still retaining correctness.
265+ l .files .Prev ()
266+ // Return a straddling key instead of loading the file.
267+ l .iterFile = f
268+ if err := l .Close (); err != nil {
269+ return nil
270+ }
271+ l .straddleDir = - 1
272+ l .straddle = Span {
273+ Start : f .LargestRangeKey .UserKey ,
274+ End : nextFile .SmallestRangeKey .UserKey ,
275+ Keys : nil ,
276+ }
277+ return & l .straddle
259278 }
260- return & l .straddle
261279 }
262280 if l .loadFile (l .findFileLT (key ), - 1 ) == noFileLoaded {
263281 return nil
@@ -271,6 +289,8 @@ func (l *LevelIter) SeekLT(key []byte) *Span {
271289// First implements keyspan.FragmentIterator.
272290func (l * LevelIter ) First () * Span {
273291 l .dir = + 1
292+ l .straddle = Span {}
293+ l .straddleDir = 0
274294 l .err = nil // clear cached iteration error
275295
276296 if l .loadFile (l .files .First (), + 1 ) == noFileLoaded {
@@ -285,6 +305,8 @@ func (l *LevelIter) First() *Span {
285305// Last implements keyspan.FragmentIterator.
286306func (l * LevelIter ) Last () * Span {
287307 l .dir = - 1
308+ l .straddle = Span {}
309+ l .straddleDir = 0
288310 l .err = nil // clear cached iteration error
289311
290312 if l .loadFile (l .files .Last (), - 1 ) == noFileLoaded {
@@ -298,10 +320,14 @@ func (l *LevelIter) Last() *Span {
298320
299321// Next implements keyspan.FragmentIterator.
300322func (l * LevelIter ) Next () * Span {
301- l .dir = + 1
302- if l .err != nil || (l .iter == nil && l .iterFile == nil ) {
323+ if l .err != nil || (l .iter == nil && l .iterFile == nil && l .dir > 0 ) {
303324 return nil
304325 }
326+ if l .iter == nil && l .iterFile == nil {
327+ // l.dir <= 0
328+ return l .First ()
329+ }
330+ l .dir = + 1
305331
306332 if l .iter != nil {
307333 if span := l .iter .Next (); span != nil {
@@ -313,10 +339,14 @@ func (l *LevelIter) Next() *Span {
313339
314340// Prev implements keyspan.FragmentIterator.
315341func (l * LevelIter ) Prev () * Span {
316- l .dir = - 1
317- if l .err != nil || (l .iter == nil && l .iterFile == nil ) {
342+ if l .err != nil || (l .iter == nil && l .iterFile == nil && l .dir < 0 ) {
318343 return nil
319344 }
345+ if l .iter == nil && l .iterFile == nil {
346+ // l.dir >= 0
347+ return l .Last ()
348+ }
349+ l .dir = - 1
320350
321351 if l .iter != nil {
322352 if span := l .iter .Prev (); span != nil {
@@ -355,7 +385,7 @@ func (l *LevelIter) skipEmptyFileForward() *Span {
355385 Start : startKey ,
356386 End : endKey ,
357387 }
358- l .straddleDir = l . dir
388+ l .straddleDir = + 1
359389 return & l .straddle
360390 }
361391 } else if l .straddleDir < 0 {
@@ -416,7 +446,7 @@ func (l *LevelIter) skipEmptyFileBackward() *Span {
416446 Start : startKey ,
417447 End : endKey ,
418448 }
419- l .straddleDir = l . dir
449+ l .straddleDir = - 1
420450 return & l .straddle
421451 }
422452 } else if l .straddleDir > 0 {
0 commit comments