github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/keyspan/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 keyspan
     6  
     7  import "github.com/cockroachdb/pebble/internal/base"
     8  
     9  // SeekLE seeks to the span that contains or is before the target key.
    10  func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte) *Span {
    11  	// NB: We use SeekLT in order to land on the proper span for a search
    12  	// key that resides in the middle of a span. Consider the scenario:
    13  	//
    14  	//     a---e
    15  	//         e---i
    16  	//
    17  	// The spans are indexed by their start keys `a` and `e`. If the
    18  	// search key is `c` we want to land on the span [a,e). If we were to
    19  	// use SeekGE then the search key `c` would land on the span [e,i) and
    20  	// we'd have to backtrack. The one complexity here is what happens for the
    21  	// search key `e`. In that case SeekLT will land us on the span [a,e)
    22  	// and we'll have to move forward.
    23  	iterSpan := iter.SeekLT(key)
    24  
    25  	if iterSpan == nil {
    26  		// Advance the iterator once to see if the next span has a start key
    27  		// equal to key.
    28  		iterSpan = iter.Next()
    29  		if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
    30  			// The iterator is exhausted or we've hit the next span.
    31  			return nil
    32  		}
    33  	} else {
    34  		// Invariant: key > iterSpan.Start
    35  		if cmp(key, iterSpan.End) >= 0 {
    36  			// The current span lies entirely before the search key. Check to see if
    37  			// the next span contains the search key. If it doesn't, we'll backup
    38  			// and return to our earlier candidate.
    39  			iterSpan = iter.Next()
    40  			if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
    41  				// The next span is past our search key or there is no next span. Go
    42  				// back.
    43  				iterSpan = iter.Prev()
    44  			}
    45  		}
    46  	}
    47  	return iterSpan
    48  }