99 lines
4.0 KiB
Go
99 lines
4.0 KiB
Go
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
|
// of this source code is governed by a BSD-style license that can be found in
|
|
// the LICENSE file.
|
|
|
|
package keyspan
|
|
|
|
import "github.com/cockroachdb/pebble/internal/base"
|
|
|
|
// TODO(jackson): Move snapshot visiblity outside of SeekGE/SeekLE and into the
|
|
// callsite. This should simplify the code some more.
|
|
|
|
// SeekGE seeks to the span that contains the target key or the first span past
|
|
// the target key. The snapshot parameter controls the visibility of keys (only
|
|
// spans older than the snapshot sequence number are visible).
|
|
func SeekGE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) Span {
|
|
// NB: We use SeekLT in order to land on the proper span for a search
|
|
// key that resides in the middle of a span. Consider the scenario:
|
|
//
|
|
// a---e
|
|
// e---i
|
|
//
|
|
// The spans are indexed by their start keys `a` and `e`. If the
|
|
// search key is `c` we want to land on the span [a,e). If we were to
|
|
// use SeekGE then the search key `c` would land on the span [e,i) and
|
|
// we'd have to backtrack. The one complexity here is what happens for the
|
|
// search key `e`. In that case SeekLT will land us on the span [a,e)
|
|
// and we'll have to move forward.
|
|
iterSpan := iter.SeekLT(key)
|
|
|
|
// Invariant: key > iterSpan.Start
|
|
|
|
if !iterSpan.Valid() || cmp(key, iterSpan.End) >= 0 {
|
|
// The current span lies entirely before the search key, or the iterator
|
|
// is exhausted. Advance the iterator to the next span which is
|
|
// guaranteed to lie at or past the search key.
|
|
iterSpan = iter.Next()
|
|
}
|
|
// The iterator is positioned at a valid iterSpan which is the first
|
|
// iterator position that satisfies the requirement that it contains or is
|
|
// past the target key. It may not be visible based on the snapshot. So now
|
|
// we only need to move forward and return the first span with visible keys.
|
|
iterSpan = iterSpan.Visible(snapshot)
|
|
for iterSpan.Valid() && iterSpan.Empty() {
|
|
iterSpan = iter.Next().Visible(snapshot)
|
|
}
|
|
return iterSpan
|
|
}
|
|
|
|
// SeekLE seeks to the span that contains or is before the target key. The
|
|
// snapshot parameter controls the visibility of keys (only spans older than the
|
|
// snapshot sequence number are visible).
|
|
func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) Span {
|
|
// NB: We use SeekLT in order to land on the proper span for a search
|
|
// key that resides in the middle of a span. Consider the scenario:
|
|
//
|
|
// a---e
|
|
// e---i
|
|
//
|
|
// The spans are indexed by their start keys `a` and `e`. If the
|
|
// search key is `c` we want to land on the span [a,e). If we were to
|
|
// use SeekGE then the search key `c` would land on the span [e,i) and
|
|
// we'd have to backtrack. The one complexity here is what happens for the
|
|
// search key `e`. In that case SeekLT will land us on the span [a,e)
|
|
// and we'll have to move forward.
|
|
iterSpan := iter.SeekLT(key)
|
|
|
|
if !iterSpan.Valid() {
|
|
// Advance the iterator once to see if the next span has a start key
|
|
// equal to key.
|
|
iterSpan = iter.Next()
|
|
if !iterSpan.Valid() || cmp(key, iterSpan.Start) < 0 {
|
|
// The iterator is exhausted or we've hit the next span.
|
|
return Span{}
|
|
}
|
|
} else {
|
|
// Invariant: key > iterSpan.Start
|
|
if cmp(key, iterSpan.End) >= 0 {
|
|
// The current span lies entirely before the search key. Check to see if
|
|
// the next span contains the search key. If it doesn't, we'll backup
|
|
// and return to our earlier candidate.
|
|
iterSpan = iter.Next()
|
|
if !iterSpan.Valid() || cmp(key, iterSpan.Start) < 0 {
|
|
// The next span is past our search key or there is no next span. Go
|
|
// back.
|
|
iterSpan = iter.Prev()
|
|
}
|
|
}
|
|
}
|
|
|
|
// We're positioned at a span that contains or is before the search key. It
|
|
// may not be visible based on the snapshot. So now we only need to move
|
|
// backward and return the first span with visible keys.
|
|
iterSpan = iterSpan.Visible(snapshot)
|
|
for iterSpan.Valid() && iterSpan.Empty() {
|
|
iterSpan = iter.Prev().Visible(snapshot)
|
|
}
|
|
return iterSpan
|
|
}
|