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