github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/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/zuoyebang/bitalostable/internal/base"
     8  
     9  // SeekGE seeks to the span that contains the target key or the first span past
    10  // the target key.
    11  func SeekGE(cmp base.Compare, iter FragmentIterator, key []byte) *Span {
    12  	// NB: We use SeekLT in order to land on the proper span for a search
    13  	// key that resides in the middle of a span. Consider the scenario:
    14  	//
    15  	//     a---e
    16  	//         e---i
    17  	//
    18  	// The spans are indexed by their start keys `a` and `e`. If the
    19  	// search key is `c` we want to land on the span [a,e). If we were to
    20  	// use SeekGE then the search key `c` would land on the span [e,i) and
    21  	// we'd have to backtrack. The one complexity here is what happens for the
    22  	// search key `e`. In that case SeekLT will land us on the span [a,e)
    23  	// and we'll have to move forward.
    24  	iterSpan := iter.SeekLT(key)
    25  
    26  	// Invariant: key > iterSpan.Start
    27  
    28  	if iterSpan == nil || cmp(key, iterSpan.End) >= 0 {
    29  		// The current span lies entirely before the search key, or the iterator
    30  		// is exhausted. Advance the iterator to the next span which is
    31  		// guaranteed to lie at or past the search key.
    32  		iterSpan = iter.Next()
    33  	}
    34  	return iterSpan
    35  }
    36  
    37  // SeekLE seeks to the span that contains or is before the target key.
    38  func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte) *Span {
    39  	// NB: We use SeekLT in order to land on the proper span for a search
    40  	// key that resides in the middle of a span. Consider the scenario:
    41  	//
    42  	//     a---e
    43  	//         e---i
    44  	//
    45  	// The spans are indexed by their start keys `a` and `e`. If the
    46  	// search key is `c` we want to land on the span [a,e). If we were to
    47  	// use SeekGE then the search key `c` would land on the span [e,i) and
    48  	// we'd have to backtrack. The one complexity here is what happens for the
    49  	// search key `e`. In that case SeekLT will land us on the span [a,e)
    50  	// and we'll have to move forward.
    51  	iterSpan := iter.SeekLT(key)
    52  
    53  	if iterSpan == nil {
    54  		// Advance the iterator once to see if the next span has a start key
    55  		// equal to key.
    56  		iterSpan = iter.Next()
    57  		if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
    58  			// The iterator is exhausted or we've hit the next span.
    59  			return nil
    60  		}
    61  	} else {
    62  		// Invariant: key > iterSpan.Start
    63  		if cmp(key, iterSpan.End) >= 0 {
    64  			// The current span lies entirely before the search key. Check to see if
    65  			// the next span contains the search key. If it doesn't, we'll backup
    66  			// and return to our earlier candidate.
    67  			iterSpan = iter.Next()
    68  			if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
    69  				// The next span is past our search key or there is no next span. Go
    70  				// back.
    71  				iterSpan = iter.Prev()
    72  			}
    73  		}
    74  	}
    75  	return iterSpan
    76  }