0

Upgrade versions of vendored libs

This commit is contained in:
eleksir
2022-11-04 16:20:16 +03:00
parent d9de157ad8
commit 76a660ebed
931 changed files with 215108 additions and 23070 deletions

View File

@@ -0,0 +1,265 @@
// Copyright 2022 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): Consider removing this type and adding bounds enforcement
// directly to the MergingIter. This type is probably too lightweight to warrant
// its own type, but for now we implement it separately for expediency.
// boundedIterPos records the position of the BoundedIter relative to the
// underlying iterator's position. It's used to avoid Next/Prev-ing the iterator
// if there can't possibly be another span within bounds, because the current
// span overlaps the bound.
//
// Imagine bounds [a,c) and an iterator that seeks to a span [b,d). The span
// [b,d) overlaps some portion of the iterator bounds, so the iterator must
// return it. If the iterator is subsequently Nexted, Next can tell that the
// iterator is exhausted without advancing the underlying iterator because the
// current span's end bound of d is ≥ the upper bound of c. In this case, the
// bounded iterator returns nil and records i.pos as posAtUpperLimit to remember
// that the underlying iterator position does not match the current BoundedIter
// position.
type boundedIterPos int8
const (
posAtLowerLimit boundedIterPos = -1
posAtIterSpan boundedIterPos = 0
posAtUpperLimit boundedIterPos = +1
)
// BoundedIter implements FragmentIterator and enforces bounds.
//
// Like the point InternalIterator interface, the bounded iterator's forward
// positioning routines (SeekGE, First, and Next) only check the upper bound.
// The reverse positioning routines (SeekLT, Last, and Prev) only check the
// lower bound. It is up to the caller to ensure that the forward positioning
// routines respect the lower bound and the reverse positioning routines respect
// the upper bound (i.e. calling SeekGE instead of First if there is a lower
// bound, and SeekLT instead of Last if there is an upper bound).
//
// When the hasPrefix parameter indicates that the iterator is in prefix
// iteration mode, BoundedIter elides any spans that do not overlap with the
// prefix's keyspace. In prefix iteration mode, reverse iteration is disallowed,
// except for an initial SeekLT with a seek key greater than or equal to the
// prefix. In prefix iteration mode, the first seek must position the iterator
// at or immediately before the first fragment covering a key greater than or
// equal to the prefix.
type BoundedIter struct {
iter FragmentIterator
iterSpan *Span
cmp base.Compare
split base.Split
lower []byte
upper []byte
hasPrefix *bool
prefix *[]byte
pos boundedIterPos
}
// Init initializes the bounded iterator.
//
// In addition to the iterator bounds, Init takes pointers to a boolean
// indicating whether the iterator is in prefix iteration mode and the prefix
// key if it is. This is used to exclude spans that are outside the iteration
// prefix.
func (i *BoundedIter) Init(
cmp base.Compare,
split base.Split,
iter FragmentIterator,
lower, upper []byte,
hasPrefix *bool,
prefix *[]byte,
) {
*i = BoundedIter{
iter: iter,
cmp: cmp,
split: split,
lower: lower,
upper: upper,
hasPrefix: hasPrefix,
prefix: prefix,
}
}
var _ FragmentIterator = (*BoundedIter)(nil)
// Seek calls.
//
// Seek calls check iterator bounds in the direction of the seek. Additionally,
// if the iterator is in prefix iteration mode, seek calls check both start and
// end bounds against the prefix's bounds. We check both bounds for defense in
// depth. This optimization has been a source of various bugs due to various
// other prefix iteration optimizations that can result in seek keys that don't
// respect the prefix bounds.
// SeekGE implements FragmentIterator.
func (i *BoundedIter) SeekGE(key []byte) *Span {
s := i.iter.SeekGE(key)
s = i.checkPrefixSpanStart(s)
s = i.checkPrefixSpanEnd(s)
return i.checkForwardBound(s)
}
// SeekLT implements FragmentIterator.
func (i *BoundedIter) SeekLT(key []byte) *Span {
s := i.iter.SeekLT(key)
s = i.checkPrefixSpanStart(s)
s = i.checkPrefixSpanEnd(s)
return i.checkBackwardBound(s)
}
// First implements FragmentIterator.
func (i *BoundedIter) First() *Span {
s := i.iter.First()
s = i.checkPrefixSpanStart(s)
return i.checkForwardBound(s)
}
// Last implements FragmentIterator.
func (i *BoundedIter) Last() *Span {
s := i.iter.Last()
s = i.checkPrefixSpanEnd(s)
return i.checkBackwardBound(s)
}
// Next implements FragmentIterator.
func (i *BoundedIter) Next() *Span {
switch i.pos {
case posAtLowerLimit:
// The BoundedIter had previously returned nil, because it knew from
// i.iterSpan's bounds that there was no previous span. To Next, we only
// need to return the current iter span and reset i.pos to reflect that
// we're no longer positioned at the limit.
i.pos = posAtIterSpan
return i.iterSpan
case posAtIterSpan:
// If the span at the underlying iterator position extends to or beyond the
// upper bound, we can avoid advancing because the next span is necessarily
// out of bounds.
if i.iterSpan != nil && i.upper != nil && i.cmp(i.iterSpan.End, i.upper) >= 0 {
i.pos = posAtUpperLimit
return nil
}
// Similarly, if the span extends to the next prefix and we're in prefix
// iteration mode, we can avoid advancing.
if i.iterSpan != nil && *i.hasPrefix {
ei := i.split(i.iterSpan.End)
if i.cmp(i.iterSpan.End[:ei], *i.prefix) > 0 {
i.pos = posAtUpperLimit
return nil
}
}
return i.checkForwardBound(i.checkPrefixSpanStart(i.iter.Next()))
case posAtUpperLimit:
// Already exhausted.
return nil
default:
panic("unreachable")
}
}
// Prev implements FragmentIterator.
func (i *BoundedIter) Prev() *Span {
switch i.pos {
case posAtLowerLimit:
// Already exhausted.
return nil
case posAtIterSpan:
// If the span at the underlying iterator position extends to or beyond
// the lower bound, we can avoid advancing because the previous span is
// necessarily out of bounds.
if i.iterSpan != nil && i.lower != nil && i.cmp(i.iterSpan.Start, i.lower) <= 0 {
i.pos = posAtLowerLimit
return nil
}
// Similarly, if the span extends to or beyond the current prefix and
// we're in prefix iteration mode, we can avoid advancing.
if i.iterSpan != nil && *i.hasPrefix {
si := i.split(i.iterSpan.Start)
if i.cmp(i.iterSpan.Start[:si], *i.prefix) < 0 {
i.pos = posAtLowerLimit
return nil
}
}
return i.checkBackwardBound(i.checkPrefixSpanEnd(i.iter.Prev()))
case posAtUpperLimit:
// The BoundedIter had previously returned nil, because it knew from
// i.iterSpan's bounds that there was no next span. To Prev, we only
// need to return the current iter span and reset i.pos to reflect that
// we're no longer positioned at the limit.
i.pos = posAtIterSpan
return i.iterSpan
default:
panic("unreachable")
}
}
// Error implements FragmentIterator.
func (i *BoundedIter) Error() error {
return i.iter.Error()
}
// Close implements FragmentIterator.
func (i *BoundedIter) Close() error {
return i.iter.Close()
}
// SetBounds modifies the FragmentIterator's bounds.
func (i *BoundedIter) SetBounds(lower, upper []byte) {
i.lower, i.upper = lower, upper
}
func (i *BoundedIter) checkPrefixSpanStart(span *Span) *Span {
// Compare to the prefix's bounds, if in prefix iteration mode.
if span != nil && *i.hasPrefix {
si := i.split(span.Start)
if i.cmp(span.Start[:si], *i.prefix) > 0 {
// This span starts at a prefix that sorts after our current prefix.
span = nil
}
}
return span
}
// checkForwardBound enforces the upper bound, returning nil if the provided
// span is wholly outside the upper bound. It also updates i.pos and i.iterSpan
// to reflect the new iterator position.
func (i *BoundedIter) checkForwardBound(span *Span) *Span {
// Compare to the upper bound.
if span != nil && i.upper != nil && i.cmp(span.Start, i.upper) >= 0 {
span = nil
}
i.iterSpan = span
if i.pos != posAtIterSpan {
i.pos = posAtIterSpan
}
return span
}
func (i *BoundedIter) checkPrefixSpanEnd(span *Span) *Span {
// Compare to the prefix's bounds, if in prefix iteration mode.
if span != nil && *i.hasPrefix && i.cmp(span.End, *i.prefix) <= 0 {
// This span ends before the current prefix.
span = nil
}
return span
}
// checkBackward enforces the lower bound, returning nil if the provided span is
// wholly outside the lower bound. It also updates i.pos and i.iterSpan to
// reflect the new iterator position.
func (i *BoundedIter) checkBackwardBound(span *Span) *Span {
// Compare to the lower bound.
if span != nil && i.lower != nil && i.cmp(span.End, i.lower) <= 0 {
span = nil
}
i.iterSpan = span
if i.pos != posAtIterSpan {
i.pos = posAtIterSpan
}
return span
}

View File

@@ -21,26 +21,30 @@ const bufferReuseMaxCapacity = 10 << 10 // 10 KB
type DefragmentMethod interface {
// ShouldDefragment takes two abutting spans and returns whether the two
// spans should be combined into a single, defragmented Span.
ShouldDefragment(cmp base.Compare, left, right *Span) bool
ShouldDefragment(equal base.Equal, left, right *Span) bool
}
// The DefragmentMethodFunc type is an adapter to allow the use of ordinary
// functions as DefragmentMethods. If f is a function with the appropriate
// signature, DefragmentMethodFunc(f) is a DefragmentMethod that calls f.
type DefragmentMethodFunc func(cmp base.Compare, left, right *Span) bool
type DefragmentMethodFunc func(equal base.Equal, left, right *Span) bool
// ShouldDefragment calls f(cmp, left, right).
func (f DefragmentMethodFunc) ShouldDefragment(cmp base.Compare, left, right *Span) bool {
return f(cmp, left, right)
// ShouldDefragment calls f(equal, left, right).
func (f DefragmentMethodFunc) ShouldDefragment(equal base.Equal, left, right *Span) bool {
return f(equal, left, right)
}
// DefragmentInternal configures a DefragmentingIter to defragment spans
// only if they have identical keys.
// only if they have identical keys. It requires spans' keys to be sorted in
// trailer descending order.
//
// This defragmenting method is intended for use in compactions that may see
// internal range keys fragments that may now be joined, because the state that
// required their fragmentation has been dropped.
var DefragmentInternal DefragmentMethod = DefragmentMethodFunc(func(cmp base.Compare, a, b *Span) bool {
var DefragmentInternal DefragmentMethod = DefragmentMethodFunc(func(equal base.Equal, a, b *Span) bool {
if a.KeysOrder != ByTrailerDesc || b.KeysOrder != ByTrailerDesc {
panic("pebble: span keys unexpectedly not in trailer descending order")
}
if len(a.Keys) != len(b.Keys) {
return false
}
@@ -48,7 +52,7 @@ var DefragmentInternal DefragmentMethod = DefragmentMethodFunc(func(cmp base.Com
if a.Keys[i].Trailer != b.Keys[i].Trailer {
return false
}
if cmp(a.Keys[i].Suffix, b.Keys[i].Suffix) != 0 {
if !equal(a.Keys[i].Suffix, b.Keys[i].Suffix) {
return false
}
if !bytes.Equal(a.Keys[i].Value, b.Keys[i].Value) {
@@ -114,7 +118,8 @@ const (
// defragments in the iteration direction, ensuring it's found a whole
// defragmented span.
type DefragmentingIter struct {
cmp base.Compare
comparer *base.Comparer
equal base.Equal
iter FragmentIterator
iterSpan *Span
iterPos iterPos
@@ -149,13 +154,14 @@ var _ FragmentIterator = (*DefragmentingIter)(nil)
// Init initializes the defragmenting iter using the provided defragment
// method.
func (i *DefragmentingIter) Init(
cmp base.Compare, iter FragmentIterator, equal DefragmentMethod, reducer DefragmentReducer,
comparer *base.Comparer, iter FragmentIterator, equal DefragmentMethod, reducer DefragmentReducer,
) {
*i = DefragmentingIter{
cmp: cmp,
iter: iter,
method: equal,
reduce: reducer,
comparer: comparer,
equal: comparer.Equal,
iter: iter,
method: equal,
reduce: reducer,
}
}
@@ -176,11 +182,14 @@ func (i *DefragmentingIter) SeekGE(key []byte) *Span {
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
} else if i.iterSpan.Empty() {
i.iterPos = iterPosCurr
return i.iterSpan
}
// Save the current span and peek backwards.
i.saveCurrent()
i.iterSpan = i.iter.Prev()
if i.iterSpan != nil && i.cmp(i.curr.Start, i.iterSpan.End) == 0 && i.checkEqual(i.iterSpan, &i.curr) {
if i.iterSpan != nil && i.equal(i.curr.Start, i.iterSpan.End) && i.checkEqual(i.iterSpan, &i.curr) {
// A continuation. The span we originally landed on and defragmented
// backwards has a true Start key < key. To obey the FragmentIterator
// contract, we must not return this defragmented span. Defragment
@@ -206,6 +215,9 @@ func (i *DefragmentingIter) SeekLT(key []byte) *Span {
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
} else if i.iterSpan.Empty() {
i.iterPos = iterPosCurr
return i.iterSpan
}
// Defragment forward to find the end of the defragmented span.
i.defragmentForward()
@@ -355,7 +367,7 @@ func (i *DefragmentingIter) Prev() *Span {
// DefragmentMethod and ensures both spans are NOT empty; not defragmenting empty
// spans is an optimization that lets us load fewer sstable blocks.
func (i *DefragmentingIter) checkEqual(left, right *Span) bool {
return (!left.Empty() && !right.Empty()) && i.method.ShouldDefragment(i.cmp, i.iterSpan, &i.curr)
return (!left.Empty() && !right.Empty()) && i.method.ShouldDefragment(i.equal, i.iterSpan, &i.curr)
}
// defragmentForward defragments spans in the forward direction, starting from
@@ -374,7 +386,7 @@ func (i *DefragmentingIter) defragmentForward() *Span {
i.iterPos = iterPosNext
i.iterSpan = i.iter.Next()
for i.iterSpan != nil {
if i.cmp(i.curr.End, i.iterSpan.Start) != 0 {
if !i.equal(i.curr.End, i.iterSpan.Start) {
// Not a continuation.
break
}
@@ -407,7 +419,7 @@ func (i *DefragmentingIter) defragmentBackward() *Span {
i.iterPos = iterPosPrev
i.iterSpan = i.iter.Prev()
for i.iterSpan != nil {
if i.cmp(i.curr.Start, i.iterSpan.End) != 0 {
if !i.equal(i.curr.Start, i.iterSpan.End) {
// Not a continuation.
break
}
@@ -438,8 +450,9 @@ func (i *DefragmentingIter) saveCurrent() {
return
}
i.curr = Span{
Start: i.saveBytes(i.iterSpan.Start),
End: i.saveBytes(i.iterSpan.End),
Start: i.saveBytes(i.iterSpan.Start),
End: i.saveBytes(i.iterSpan.End),
KeysOrder: i.iterSpan.KeysOrder,
}
for j := range i.iterSpan.Keys {
i.keysBuf = append(i.keysBuf, Key{

View File

@@ -183,9 +183,13 @@ func (f *Fragmenter) checkInvariants(buf []Span) {
// deletion and range key blocks, so these keys are stable. Because of this key
// stability, typically callers only need to perform a shallow clone of the Span
// before Add-ing it to the fragmenter.
//
// Add requires the provided span's keys are sorted in Trailer descending order.
func (f *Fragmenter) Add(s Span) {
if f.finished {
panic("pebble: span fragmenter already finished")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span keys unexpectedly not in trailer descending order")
}
if f.flushedKey != nil {
switch c := f.Cmp(s.Start, f.flushedKey); {

View File

@@ -35,14 +35,6 @@ type SpanMask interface {
SkipPoint(userKey []byte) bool
}
type maskState int8
const (
maskStale maskState = iota
maskCleared
maskCurrent
)
// InterleavingIter combines an iterator over point keys with an iterator over
// key spans.
//
@@ -101,7 +93,8 @@ const (
// All spans containing keys are exposed during iteration.
type InterleavingIter struct {
cmp base.Compare
pointIter base.InternalIteratorWithStats
comparer *base.Comparer
pointIter base.InternalIterator
keyspanIter FragmentIterator
mask SpanMask
@@ -111,9 +104,13 @@ type InterleavingIter struct {
// to truncate a span. The byte slices backing a SeekGE/SeekPrefixGE search
// keys can come directly from the end user, so they're copied into keyBuf
// to ensure key stability.
keyBuf []byte
pointKey *base.InternalKey
pointVal []byte
keyBuf []byte
// nextPrefixBuf is used during SeekPrefixGE calls to store the truncated
// upper bound of the returned spans. SeekPrefixGE truncates the returned
// spans to an upper bound of the seeked prefix's immediate successor.
nextPrefixBuf []byte
pointKey *base.InternalKey
pointVal base.LazyValue
// span holds the span at the keyspanIter's current position. If the span is
// wholly contained within the iterator bounds, this span is directly
// returned to the iterator consumer through Span(). If either bound needed
@@ -158,32 +155,15 @@ type InterleavingIter struct {
// span's start bound marker to the search key. It's returned to false on
// the next repositioning of the keyspan iterator.
spanMarkerTruncated bool
// maskState holds a tri-state enum describing the state of the state
// machine managing invocations to i.mask.SpanChanged. When i.span is
// updated, `maskState` is set to the starting state `maskStale` to reflect
// that the mask has not been informed of the new span. From `maskStale`,
// the state transitions to `maskCleared` if the next returned key does not
// fall within i.span's bounds. The state transitions to `maskCurrent` if
// the next returned key does fall within i.span's bounds.
//
// return key outside [s,e)
// keyspan.Iter.{Next,Prev}
// _________________________________
// \/ |
// _____________ |
// | maskStale | |
// |_____________| |
// return key / \ return key |
// outside [s,e) / \ within [s,e) |
// \/ \/ |
// ________________________ __________________________ |
// | SpanChanged(nil) | | SpanChanged(i.span) | __|
// | maskState = maskCleared| | maskState = maskCurrent |
// |________________________| |__________________________|
// |__________________________^
// return key within [s,e)
//
maskState maskState
// maskSpanChangedCalled records whether or not the last call to
// SpanMask.SpanChanged provided the current span (i.span) or not.
maskSpanChangedCalled bool
// prefix records whether the iteator is in prefix mode. During prefix mode,
// Pebble will truncate spans to the next prefix. If the iterator
// subsequently leaves prefix mode, the existing span cached in i.span must
// be invalidated because its bounds do not reflect the original span's true
// bounds.
prefix bool
// dir indicates the direction of iteration: forward (+1) or backward (-1)
dir int8
}
@@ -197,14 +177,15 @@ var _ base.InternalIterator = &InterleavingIter{}
// The point iterator must already have the provided bounds. Init does not
// propagate the bounds down the iterator stack.
func (i *InterleavingIter) Init(
cmp base.Compare,
pointIter base.InternalIteratorWithStats,
comparer *base.Comparer,
pointIter base.InternalIterator,
keyspanIter FragmentIterator,
mask SpanMask,
lowerBound, upperBound []byte,
) {
*i = InterleavingIter{
cmp: cmp,
cmp: comparer.Compare,
comparer: comparer,
pointIter: pointIter,
keyspanIter: keyspanIter,
mask: mask,
@@ -224,16 +205,18 @@ func (i *InterleavingIter) Init(
// It allows for seeding the iterator with the current position of the point
// iterator.
func (i *InterleavingIter) InitSeekGE(
key []byte, pointKey *base.InternalKey, pointValue []byte,
) (*base.InternalKey, []byte) {
prefix, key []byte, pointKey *base.InternalKey, pointValue base.LazyValue,
) (*base.InternalKey, base.LazyValue) {
i.dir = +1
i.clearMask()
i.prefix = prefix != nil
i.pointKey, i.pointVal = pointKey, pointValue
i.pointKeyInterleaved = false
// NB: This keyspanSeekGE call will truncate the span to the seek key if
// necessary. This truncation is important for cases where a switch to
// combined iteration is made during a user-initiated SeekGE.
i.keyspanSeekGE(key)
return i.interleaveForward(key)
i.keyspanSeekGE(key, prefix)
return i.interleaveForward(key, prefix)
}
// InitSeekLT may be called after Init but before any positioning method.
@@ -247,9 +230,10 @@ func (i *InterleavingIter) InitSeekGE(
// It allows for seeding the iterator with the current position of the point
// iterator.
func (i *InterleavingIter) InitSeekLT(
key []byte, pointKey *base.InternalKey, pointValue []byte,
) (*base.InternalKey, []byte) {
key []byte, pointKey *base.InternalKey, pointValue base.LazyValue,
) (*base.InternalKey, base.LazyValue) {
i.dir = -1
i.clearMask()
i.pointKey, i.pointVal = pointKey, pointValue
i.pointKeyInterleaved = false
i.keyspanSeekLT(key)
@@ -265,14 +249,30 @@ func (i *InterleavingIter) InitSeekLT(
// the span returned by Span.
//
// NB: In accordance with the base.InternalIterator contract:
// i.lower ≤ key
func (i *InterleavingIter) SeekGE(key []byte, flags base.SeekGEFlags) (*base.InternalKey, []byte) {
i.maybeUpdateMask(false /* covered */)
//
// i.lower ≤ key
func (i *InterleavingIter) SeekGE(
key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, base.LazyValue) {
i.clearMask()
i.disablePrefixMode()
i.pointKey, i.pointVal = i.pointIter.SeekGE(key, flags)
i.pointKeyInterleaved = false
i.keyspanSeekGE(key)
// We need to seek the keyspan iterator too. If the keyspan iterator was
// already positioned at a span, we might be able to avoid the seek if the
// seek key falls within the existing span's bounds.
if i.span != nil && i.cmp(key, i.span.End) < 0 && i.cmp(key, i.span.Start) >= 0 {
// We're seeking within the existing span's bounds. We still might need
// truncate the span to the iterator's bounds.
i.checkForwardBound(nil /* prefix */)
i.savedKeyspan()
} else {
i.keyspanSeekGE(key, nil /* prefix */)
}
i.dir = +1
return i.interleaveForward(key)
return i.interleaveForward(key, nil /* prefix */)
}
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
@@ -284,43 +284,113 @@ func (i *InterleavingIter) SeekGE(key []byte, flags base.SeekGEFlags) (*base.Int
// to the span returned by Span.
//
// NB: In accordance with the base.InternalIterator contract:
// i.lower ≤ key
//
// i.lower ≤ key
func (i *InterleavingIter) SeekPrefixGE(
prefix, key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, []byte) {
i.maybeUpdateMask(false /* covered */)
) (*base.InternalKey, base.LazyValue) {
i.clearMask()
i.pointKey, i.pointVal = i.pointIter.SeekPrefixGE(prefix, key, flags)
i.pointKeyInterleaved = false
i.keyspanSeekGE(key)
i.prefix = true
// We need to seek the keyspan iterator too. If the keyspan iterator was
// already positioned at a span, we might be able to avoid the seek if the
// entire seek prefix key falls within the existing span's bounds.
//
// During a SeekPrefixGE, Pebble defragments range keys within the bounds of
// the prefix. For example, a SeekPrefixGE('c', 'c@8') must defragment the
// any overlapping range keys within the bounds of [c,c\00).
//
// If range keys are fragmented within a prefix (eg, because a version
// within a prefix was chosen as an sstable boundary), then it's possible
// the seek key falls into the current i.span, but the current i.span does
// not wholly cover the seek prefix.
//
// For example, a SeekPrefixGE('d@5') may only defragment a range key to
// the bounds of [c@2,e). A subsequent SeekPrefixGE('c@0') must re-seek the
// keyspan iterator, because although 'c@0' is contained within [c@2,e), the
// full span of the prefix is not.
//
// Similarly, a SeekPrefixGE('a@3') may only defragment a range key to the
// bounds [a,c@8). A subsequent SeekPrefixGE('c@10') must re-seek the
// keyspan iterator, because although 'c@10' is contained within [a,c@8),
// the full span of the prefix is not.
seekKeyspanIter := true
if i.span != nil && i.cmp(prefix, i.span.Start) >= 0 {
if ei := i.comparer.Split(i.span.End); i.cmp(prefix, i.span.End[:ei]) < 0 {
// We're seeking within the existing span's bounds. We still might need
// truncate the span to the iterator's bounds.
i.checkForwardBound(prefix)
i.savedKeyspan()
seekKeyspanIter = false
}
}
if seekKeyspanIter {
i.keyspanSeekGE(key, prefix)
}
i.dir = +1
return i.interleaveForward(key)
return i.interleaveForward(key, prefix)
}
// SeekLT implements (base.InternalIterator).SeekLT.
func (i *InterleavingIter) SeekLT(key []byte, flags base.SeekLTFlags) (*base.InternalKey, []byte) {
i.maybeUpdateMask(false /* covered */)
func (i *InterleavingIter) SeekLT(
key []byte, flags base.SeekLTFlags,
) (*base.InternalKey, base.LazyValue) {
i.clearMask()
i.disablePrefixMode()
i.pointKey, i.pointVal = i.pointIter.SeekLT(key, flags)
i.pointKeyInterleaved = false
i.keyspanSeekLT(key)
// We need to seek the keyspan iterator too. If the keyspan iterator was
// already positioned at a span, we might be able to avoid the seek if the
// seek key falls within the existing span's bounds.
if i.span != nil && i.cmp(key, i.span.Start) > 0 && i.cmp(key, i.span.End) < 0 {
// We're seeking within the existing span's bounds. We still might need
// truncate the span to the iterator's bounds.
i.checkBackwardBound()
// The span's start key is still not guaranteed to be less than key,
// because of the bounds enforcement. Consider the following example:
//
// Bounds are set to [d,e). The user performs a SeekLT(d). The
// FragmentIterator.SeekLT lands on a span [b,f). This span has a start
// key less than d, as expected. Above, checkBackwardBound truncates the
// span to match the iterator's current bounds, modifying the span to
// [d,e), which does not overlap the search space of [-∞, d).
//
// This problem is a consequence of the SeekLT's exclusive search key
// and the fact that we don't perform bounds truncation at every leaf
// iterator.
if i.span != nil && i.truncated && i.cmp(i.truncatedSpan.Start, key) >= 0 {
i.span = nil
}
i.savedKeyspan()
} else {
i.keyspanSeekLT(key)
}
i.dir = -1
return i.interleaveBackward()
}
// First implements (base.InternalIterator).First.
func (i *InterleavingIter) First() (*base.InternalKey, []byte) {
i.maybeUpdateMask(false /* covered */)
func (i *InterleavingIter) First() (*base.InternalKey, base.LazyValue) {
i.clearMask()
i.disablePrefixMode()
i.pointKey, i.pointVal = i.pointIter.First()
i.pointKeyInterleaved = false
i.span = i.keyspanIter.First()
i.checkForwardBound()
i.checkForwardBound(nil /* prefix */)
i.savedKeyspan()
i.dir = +1
return i.interleaveForward(i.lower)
return i.interleaveForward(i.lower, nil /* prefix */)
}
// Last implements (base.InternalIterator).Last.
func (i *InterleavingIter) Last() (*base.InternalKey, []byte) {
i.maybeUpdateMask(false /* covered */)
func (i *InterleavingIter) Last() (*base.InternalKey, base.LazyValue) {
i.clearMask()
i.disablePrefixMode()
i.pointKey, i.pointVal = i.pointIter.Last()
i.pointKeyInterleaved = false
i.span = i.keyspanIter.Last()
@@ -331,11 +401,18 @@ func (i *InterleavingIter) Last() (*base.InternalKey, []byte) {
}
// Next implements (base.InternalIterator).Next.
func (i *InterleavingIter) Next() (*base.InternalKey, []byte) {
func (i *InterleavingIter) Next() (*base.InternalKey, base.LazyValue) {
if i.dir == -1 {
// Switching directions.
i.dir = +1
if i.mask != nil {
// Clear the mask while we reposition the point iterator. While
// switching directions, we may move the point iterator outside of
// i.span's bounds.
i.clearMask()
}
// The existing point key (denoted below with *) is either the last
// key we returned (the current iterator position):
// points: x (y*) z
@@ -358,7 +435,7 @@ func (i *InterleavingIter) Next() (*base.InternalKey, []byte) {
// There was no span in the reverse direction, but there may be
// a span in the forward direction.
i.span = i.keyspanIter.Next()
i.checkForwardBound()
i.checkForwardBound(nil /* prefix */)
i.savedKeyspan()
} else {
// Regardless of the current iterator state, we mark any existing
@@ -396,18 +473,25 @@ func (i *InterleavingIter) Next() (*base.InternalKey, []byte) {
if i.keyspanInterleaved && i.pointKey != nil && i.span != nil &&
i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
i.span = i.keyspanIter.Next()
i.checkForwardBound()
i.checkForwardBound(nil /* prefix */)
i.savedKeyspan()
}
return i.interleaveForward(i.lower)
return i.interleaveForward(i.lower, nil /* prefix */)
}
// Prev implements (base.InternalIterator).Prev.
func (i *InterleavingIter) Prev() (*base.InternalKey, []byte) {
func (i *InterleavingIter) Prev() (*base.InternalKey, base.LazyValue) {
if i.dir == +1 {
// Switching directions.
i.dir = -1
if i.mask != nil {
// Clear the mask while we reposition the point iterator. While
// switching directions, we may move the point iterator outside of
// i.span's bounds.
i.clearMask()
}
if i.keyspanInterleaved {
// The current span's start key has already been interleaved in the
// forward direction. The start key may have been interleaved a
@@ -490,7 +574,9 @@ func (i *InterleavingIter) Prev() (*base.InternalKey, []byte) {
return i.interleaveBackward()
}
func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalKey, []byte) {
func (i *InterleavingIter) interleaveForward(
lowerBound []byte, prefix []byte,
) (*base.InternalKey, base.LazyValue) {
// This loop determines whether a point key or a span marker key should be
// interleaved on each iteration. If masking is disabled and the span is
// nonempty, this loop executes for exactly one iteration. If masking is
@@ -536,7 +622,7 @@ func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalK
// advancing past the current point key.
if i.keyspanInterleaved {
i.span = i.keyspanIter.Next()
i.checkForwardBound()
i.checkForwardBound(prefix)
i.savedKeyspan()
if i.span == nil {
return i.yieldNil()
@@ -558,7 +644,7 @@ func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalK
// keyspanInterleaved would likely trip up the invariant check
// above.
i.span = i.keyspanIter.Next()
i.checkForwardBound()
i.checkForwardBound(prefix)
i.savedKeyspan()
} else {
i.keyspanInterleaved = true
@@ -600,7 +686,7 @@ func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalK
// reestablish it before the next iteration.
if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
i.span = i.keyspanIter.Next()
i.checkForwardBound()
i.checkForwardBound(prefix)
i.savedKeyspan()
}
continue
@@ -614,7 +700,7 @@ func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalK
}
}
func (i *InterleavingIter) interleaveBackward() (*base.InternalKey, []byte) {
func (i *InterleavingIter) interleaveBackward() (*base.InternalKey, base.LazyValue) {
// This loop determines whether a point key or a span's start key should be
// interleaved on each iteration. If masking is disabled and the span is
// nonempty, this loop executes for exactly one iteration. If masking is
@@ -697,7 +783,7 @@ func (i *InterleavingIter) interleaveBackward() (*base.InternalKey, []byte) {
// keyspanSeekGE seeks the keyspan iterator to the first span covering k ≥ key.
// Note that this differs from the FragmentIterator.SeekGE semantics, which
// seek to the first span with a start key ≥ key.
func (i *InterleavingIter) keyspanSeekGE(key []byte) {
func (i *InterleavingIter) keyspanSeekGE(key []byte, prefix []byte) {
// Seek using SeekLT to look for a span that starts before key, with an end
// boundary extending beyond key.
i.span = i.keyspanIter.SeekLT(key)
@@ -706,7 +792,7 @@ func (i *InterleavingIter) keyspanSeekGE(key []byte) {
// found ends before key. Next to the first key with a start ≥ key.
i.span = i.keyspanIter.Next()
}
i.checkForwardBound()
i.checkForwardBound(prefix)
i.savedKeyspan()
}
@@ -733,7 +819,7 @@ func (i *InterleavingIter) keyspanSeekLT(key []byte) {
i.savedKeyspan()
}
func (i *InterleavingIter) checkForwardBound() {
func (i *InterleavingIter) checkForwardBound(prefix []byte) {
i.truncated = false
i.truncatedSpan = Span{}
if i.span == nil {
@@ -765,7 +851,23 @@ func (i *InterleavingIter) checkForwardBound() {
}
i.truncatedSpan.End = i.upper
}
if i.truncated && i.cmp(i.truncatedSpan.Start, i.truncatedSpan.End) == 0 {
// If this is a part of a SeekPrefixGE call, we may also need to truncate to
// the prefix's bounds.
if prefix != nil {
if !i.truncated {
i.truncated = true
i.truncatedSpan = *i.span
}
if i.cmp(prefix, i.truncatedSpan.Start) > 0 {
i.truncatedSpan.Start = prefix
}
i.nextPrefixBuf = i.comparer.ImmediateSuccessor(i.nextPrefixBuf[:0], prefix)
if i.truncated && i.cmp(i.nextPrefixBuf, i.truncatedSpan.End) < 0 {
i.truncatedSpan.End = i.nextPrefixBuf
}
}
if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) {
i.span = nil
}
}
@@ -802,25 +904,27 @@ func (i *InterleavingIter) checkBackwardBound() {
}
i.truncatedSpan.End = i.upper
}
if i.truncated && i.cmp(i.truncatedSpan.Start, i.truncatedSpan.End) == 0 {
if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) {
i.span = nil
}
}
func (i *InterleavingIter) yieldNil() (*base.InternalKey, []byte) {
func (i *InterleavingIter) yieldNil() (*base.InternalKey, base.LazyValue) {
i.spanCoversKey = false
i.maybeUpdateMask(false /* covered */)
return i.verify(nil, nil)
i.clearMask()
return i.verify(nil, base.LazyValue{})
}
func (i *InterleavingIter) yieldPointKey(covered bool) (*base.InternalKey, []byte) {
func (i *InterleavingIter) yieldPointKey(covered bool) (*base.InternalKey, base.LazyValue) {
i.pointKeyInterleaved = true
i.spanCoversKey = covered
i.maybeUpdateMask(covered)
return i.verify(i.pointKey, i.pointVal)
}
func (i *InterleavingIter) yieldSyntheticSpanMarker(lowerBound []byte) (*base.InternalKey, []byte) {
func (i *InterleavingIter) yieldSyntheticSpanMarker(
lowerBound []byte,
) (*base.InternalKey, base.LazyValue) {
i.spanMarker.UserKey = i.startKey()
i.spanMarker.Trailer = base.MakeTrailer(base.InternalKeySeqNumMax, i.span.Keys[0].Kind())
i.keyspanInterleaved = true
@@ -836,7 +940,7 @@ func (i *InterleavingIter) yieldSyntheticSpanMarker(lowerBound []byte) (*base.In
// bound for truncating a span. The span a-z will be truncated to [k,
// z). If i.upper == k, we'd mistakenly try to return a span [k, k), an
// invariant violation.
if i.cmp(lowerBound, i.upper) == 0 {
if i.comparer.Equal(lowerBound, i.upper) {
return i.yieldNil()
}
@@ -856,10 +960,21 @@ func (i *InterleavingIter) yieldSyntheticSpanMarker(lowerBound []byte) (*base.In
i.spanMarkerTruncated = true
}
i.maybeUpdateMask(true /* covered */)
return i.verify(&i.spanMarker, nil)
return i.verify(&i.spanMarker, base.LazyValue{})
}
func (i *InterleavingIter) verify(k *base.InternalKey, v []byte) (*base.InternalKey, []byte) {
func (i *InterleavingIter) disablePrefixMode() {
if i.prefix {
i.prefix = false
// Clear the existing span. It may not hold the true end bound of the
// underlying span.
i.span = nil
}
}
func (i *InterleavingIter) verify(
k *base.InternalKey, v base.LazyValue,
) (*base.InternalKey, base.LazyValue) {
// Wrap the entire function body in the invariants build tag, so that
// production builds elide this entire function.
if invariants.Enabled {
@@ -893,38 +1008,32 @@ func (i *InterleavingIter) verify(k *base.InternalKey, v []byte) (*base.Internal
func (i *InterleavingIter) savedKeyspan() {
i.keyspanInterleaved = false
i.spanMarkerTruncated = false
if i.maskState == maskCurrent {
// There's a span set as current. If the keyspan iterator was
// exhausted or moved to an empty keyspan, the current mask will need to be
// cleared. If the keyspan iterator was moved to a new keyspan, then we'll need
// to set the new mask once we step into the new keyspan's bounds.
//
// Either way, we need to reset to to `maskStale`.
i.maskState = maskStale
}
i.maskSpanChangedCalled = false
}
// maybeUpdateMask updates the current mask, if a mask is configured and
// the mask hasn't been updated with the current keyspan yet.
func (i *InterleavingIter) maybeUpdateMask(covered bool) {
if i.mask == nil {
return
if i.mask != nil {
if !covered || i.span.Empty() {
i.clearMask()
} else if !i.maskSpanChangedCalled {
if i.truncated {
i.mask.SpanChanged(&i.truncatedSpan)
} else {
i.mask.SpanChanged(i.span)
}
i.maskSpanChangedCalled = true
}
}
}
// Although covered=true, the covering span might be empty. Empty span's
// don't mask.
covered = covered && !i.span.Empty()
if covered && i.maskState != maskCurrent {
// We're currently positioned within the bounds of i.span, and we
// haven't updated the mask to this span yet. Update it now.
i.mask.SpanChanged(i.span)
i.maskState = maskCurrent
} else if !covered && i.maskState != maskCleared {
// We're not positioned beneath i.span, so we shouldn't set the mask to
// i.span. However, we've never cleared the previous mask.
// clearMask clears the current mask, if a mask is configured and no mask should
// be active.
func (i *InterleavingIter) clearMask() {
if i.mask != nil {
i.maskSpanChangedCalled = false
i.mask.SpanChanged(nil)
i.maskState = maskCleared
}
}
@@ -955,6 +1064,16 @@ func (i *InterleavingIter) Span() *Span {
func (i *InterleavingIter) SetBounds(lower, upper []byte) {
i.lower, i.upper = lower, upper
i.pointIter.SetBounds(lower, upper)
i.Invalidate()
}
// Invalidate invalidates the interleaving iterator's current position, clearing
// its state. This prevents optimizations such as reusing the current span on
// seek.
func (i *InterleavingIter) Invalidate() {
i.span = nil
i.pointKey = nil
i.pointVal = base.LazyValue{}
}
// Error implements (base.InternalIterator).Error.
@@ -974,18 +1093,6 @@ func (i *InterleavingIter) String() string {
return fmt.Sprintf("keyspan-interleaving(%q)", i.pointIter.String())
}
var _ base.InternalIteratorWithStats = &InterleavingIter{}
// Stats implements InternalIteratorWithStats.
func (i *InterleavingIter) Stats() base.InternalIteratorStats {
return i.pointIter.Stats()
}
// ResetStats implements InternalIteratorWithStats.
func (i *InterleavingIter) ResetStats() {
i.pointIter.ResetStats()
}
func firstError(err0, err1 error) error {
if err0 != nil {
return err0

View File

@@ -38,57 +38,57 @@ func (i *InternalIteratorShim) Span() *Span {
// SeekGE implements (base.InternalIterator).SeekGE.
func (i *InternalIteratorShim) SeekGE(
key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, []byte) {
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
func (i *InternalIteratorShim) SeekPrefixGE(
prefix, key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, []byte) {
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekLT implements (base.InternalIterator).SeekLT.
func (i *InternalIteratorShim) SeekLT(
key []byte, flags base.SeekLTFlags,
) (*base.InternalKey, []byte) {
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// First implements (base.InternalIterator).First.
func (i *InternalIteratorShim) First() (*base.InternalKey, []byte) {
func (i *InternalIteratorShim) First() (*base.InternalKey, base.LazyValue) {
i.span = i.miter.First()
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if i.span == nil {
return nil, nil
return nil, base.LazyValue{}
}
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
return &i.iterKey, i.span.End
return &i.iterKey, base.MakeInPlaceValue(i.span.End)
}
// Last implements (base.InternalIterator).Last.
func (i *InternalIteratorShim) Last() (*base.InternalKey, []byte) {
func (i *InternalIteratorShim) Last() (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// Next implements (base.InternalIterator).Next.
func (i *InternalIteratorShim) Next() (*base.InternalKey, []byte) {
func (i *InternalIteratorShim) Next() (*base.InternalKey, base.LazyValue) {
i.span = i.miter.Next()
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if i.span == nil {
return nil, nil
return nil, base.LazyValue{}
}
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
return &i.iterKey, i.span.End
return &i.iterKey, base.MakeInPlaceValue(i.span.End)
}
// Prev implements (base.InternalIterator).Prev.
func (i *InternalIteratorShim) Prev() (*base.InternalKey, []byte) {
func (i *InternalIteratorShim) Prev() (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}

View File

@@ -52,7 +52,11 @@ func visibleTransform(snapshot uint64) Transformer {
dst.Start, dst.End = s.Start, s.End
dst.Keys = dst.Keys[:0]
for _, k := range s.Keys {
if base.Visible(k.SeqNum(), snapshot) {
// NB: The InternalKeySeqNumMax value is used for the batch snapshot
// because a batch's visible span keys are filtered when they're
// fragmented. There's no requirement to enforce visibility at
// iteration time.
if base.Visible(k.SeqNum(), snapshot, base.InternalKeySeqNumMax) {
dst.Keys = append(dst.Keys, k)
}
}
@@ -68,6 +72,10 @@ func visibleTransform(snapshot uint64) Transformer {
// overlapping keys are surfaced in a single Span. Key spans from one child
// iterator may overlap key spans from another child iterator arbitrarily.
//
// The spans combined by MergingIter will return spans with keys sorted by
// trailer descending. If the MergingIter is configured with a Transformer, it's
// permitted to modify the ordering of the spans' keys returned by MergingIter.
//
// Algorithm
//
// The merging iterator wraps child iterators, merging and fragmenting spans
@@ -210,9 +218,9 @@ type MergingIter struct {
// buf is a buffer used to save [start, end) boundary keys.
buf []byte
// keys holds all of the keys across all levels that overlap the key span
// [start, end), sorted by sequence number and kind descending. This slice
// is reconstituted in synthesizeKeys from each mergingIterLevel's keys
// every time the [start, end) bounds change.
// [start, end), sorted by Trailer descending. This slice is reconstituted
// in synthesizeKeys from each mergingIterLevel's keys every time the
// [start, end) bounds change.
//
// Each element points into a child iterator's memory, so the keys may not
// be directly modified.
@@ -809,15 +817,22 @@ func (m *MergingIter) synthesizeKeys(dir int8) (bool, *Span) {
found = true
}
}
// TODO(jackson): We should be able to remove this sort and instead
// guarantee that we'll return keys in the order of the levels they're from.
// With careful iterator construction, this would guarantee that they're
// sorted by trailer descending for the range key iteration use case.
sort.Sort(&m.keys)
// Apply the configured transform. See visibleTransform.
s := Span{
Start: m.start,
End: m.end,
Keys: m.keys,
Start: m.start,
End: m.end,
Keys: m.keys,
KeysOrder: ByTrailerDesc,
}
if err := m.transformer.Transform(m.cmp, s, &m.span); err != nil {
// NB: m.heap.cmp is a base.Compare, whereas m.cmp is a method on
// MergingIter.
if err := m.transformer.Transform(m.heap.cmp, s, &m.span); err != nil {
m.err = err
return false, nil
}

View File

@@ -31,16 +31,30 @@ type Span struct {
// non-nil, or both nil if representing an invalid Span.
Start, End []byte
// Keys holds the set of keys applied over the [Start, End) user key range.
// Keys is sorted by (SeqNum, Kind) descending. If SeqNum and Kind are
// equal, the order of Keys is undefined. Keys may be empty, even if Start
// and End are non-nil.
// Keys is sorted by (SeqNum, Kind) descending, unless otherwise specified
// by the context. If SeqNum and Kind are equal, the order of Keys is
// undefined. Keys may be empty, even if Start and End are non-nil.
//
// Keys are a decoded representation of the internal keys stored in batches
// or sstable blocks. A single internal key in a range key block may produce
// several decoded Keys.
Keys []Key
Keys []Key
KeysOrder KeysOrder
}
// KeysOrder describes the ordering of Keys within a Span.
type KeysOrder int8
const (
// ByTrailerDesc indicates a Span's keys are sorted by Trailer descending.
// This is the default ordering, and the ordering used during physical
// storage.
ByTrailerDesc KeysOrder = iota
// BySuffixAsc indicates a Span's keys are sorted by Suffix ascending. This
// ordering is used during user iteration of range keys.
BySuffixAsc
)
// Key represents a single key applied over a span of user keys. A Key is
// contained by a Span which specifies the span of user keys over which the Key
// is applied.
@@ -69,9 +83,9 @@ func (k Key) Kind() base.InternalKeyKind {
// Equal returns true if this Key is equal to the given key. Two keys are said
// to be equal if the two Keys have equal trailers, suffix and value. Suffix
// comparison uses the provided base.Compare func. Value comparison is bytewise.
func (k Key) Equal(cmp base.Compare, b Key) bool {
func (k Key) Equal(equal base.Equal, b Key) bool {
return k.Trailer == b.Trailer &&
cmp(k.Suffix, b.Suffix) == 0 &&
equal(k.Suffix, b.Suffix) &&
bytes.Equal(k.Value, b.Value)
}
@@ -90,10 +104,13 @@ func (s *Span) Empty() bool {
}
// SmallestKey returns the smallest internal key defined by the span's keys.
// It panics if the span contains no keys.
// It requires the Span's keys be in ByTrailerDesc order. It panics if the span
// contains no keys or its keys are sorted in a different order.
func (s *Span) SmallestKey() base.InternalKey {
if len(s.Keys) == 0 {
panic("pebble: Span contains no keys")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
// The first key has the highest (sequence number,kind) tuple.
return base.InternalKey{
@@ -108,10 +125,13 @@ func (s *Span) SmallestKey() base.InternalKey {
// with the maximal sequence number, ensuring all InternalKeys with the same
// user key sort after the sentinel key.
//
// It panics if the span contains no keys.
// It requires the Span's keys be in ByTrailerDesc order. It panics if the span
// contains no keys or its keys are sorted in a different order.
func (s *Span) LargestKey() base.InternalKey {
if len(s.Keys) == 0 {
panic("pebble: Span contains no keys")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
// The last key has the lowest (sequence number,kind) tuple.
kind := s.Keys[len(s.Keys)-1].Kind()
@@ -119,19 +139,26 @@ func (s *Span) LargestKey() base.InternalKey {
}
// SmallestSeqNum returns the smallest sequence number of a key contained within
// the span. It panics if the span contains no keys.
// the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
// the span contains no keys or its keys are sorted in a different order.
func (s *Span) SmallestSeqNum() uint64 {
if len(s.Keys) == 0 {
panic("pebble: Span contains no keys")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
return s.Keys[len(s.Keys)-1].SeqNum()
}
// LargestSeqNum returns the largest sequence number of a key contained within
// the span. It panics if the span contains no keys.
// the span. It requires the Span's keys be in ByTrailerDesc order. It panics if
// the span contains no keys or its keys are sorted in a different order.
func (s *Span) LargestSeqNum() uint64 {
if len(s.Keys) == 0 {
panic("pebble: Span contains no keys")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
return s.Keys[0].SeqNum()
}
@@ -140,11 +167,16 @@ func (s *Span) LargestSeqNum() uint64 {
// that avoid the need to construct a new Span.
// Visible returns a span with the subset of keys visible at the provided
// sequence number.
// sequence number. It requires the Span's keys be in ByTrailerDesc order. It
// panics if the span's keys are sorted in a different order.
//
// Visible may incur an allocation, so callers should prefer targeted,
// non-allocating methods when possible.
func (s Span) Visible(snapshot uint64) Span {
if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
ret := Span{Start: s.Start, End: s.End}
if len(s.Keys) == 0 {
return ret
@@ -214,7 +246,13 @@ func (s Span) Visible(snapshot uint64) Span {
// VisibleAt returns true if the span contains a key visible at the provided
// snapshot. Keys with sequence numbers with the batch bit set are treated as
// always visible.
//
// VisibleAt requires the Span's keys be in ByTrailerDesc order. It panics if
// the span's keys are sorted in a different order.
func (s *Span) VisibleAt(snapshot uint64) bool {
if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
if len(s.Keys) == 0 {
return false
} else if first := s.Keys[0].SeqNum(); first&base.InternalKeySeqNumBatch != 0 {
@@ -235,9 +273,10 @@ func (s *Span) VisibleAt(snapshot uint64) bool {
// None of the key byte slices are cloned (see Span.DeepClone).
func (s *Span) ShallowClone() Span {
c := Span{
Start: s.Start,
End: s.End,
Keys: make([]Key, len(s.Keys)),
Start: s.Start,
End: s.End,
Keys: make([]Key, len(s.Keys)),
KeysOrder: s.KeysOrder,
}
copy(c.Keys, s.Keys)
return c
@@ -248,9 +287,10 @@ func (s *Span) ShallowClone() Span {
// because it is allocation heavy.
func (s *Span) DeepClone() Span {
c := Span{
Start: make([]byte, len(s.Start)),
End: make([]byte, len(s.End)),
Keys: make([]Key, len(s.Keys)),
Start: make([]byte, len(s.Start)),
End: make([]byte, len(s.End)),
Keys: make([]Key, len(s.Keys)),
KeysOrder: s.KeysOrder,
}
copy(c.Start, s.Start)
copy(c.End, s.End)
@@ -274,7 +314,13 @@ func (s *Span) Contains(cmp base.Compare, key []byte) bool {
}
// Covers returns true if the span covers keys at seqNum.
//
// Covers requires the Span's keys be in ByTrailerDesc order. It panics if the
// span's keys are sorted in a different order.
func (s Span) Covers(seqNum uint64) bool {
if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
return !s.Empty() && s.Keys[0].SeqNum() > seqNum
}
@@ -284,7 +330,13 @@ func (s Span) Covers(seqNum uint64) bool {
//
// Keys with sequence numbers with the batch bit set are treated as always
// visible.
//
// CoversAt requires the Span's keys be in ByTrailerDesc order. It panics if the
// span's keys are sorted in a different order.
func (s *Span) CoversAt(snapshot, seqNum uint64) bool {
if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
// NB: A key is visible at `snapshot` if its sequence number is strictly
// less than `snapshot`. See base.Visible.
for i := range s.Keys {
@@ -336,8 +388,8 @@ func (s prettySpan) Format(fs fmt.State, c rune) {
fmt.Fprintf(fs, "}")
}
// SortKeys sorts a keys slice by trailer.
func SortKeys(keys *[]Key) {
// SortKeysByTrailer sorts a keys slice by trailer.
func SortKeysByTrailer(keys *[]Key) {
// NB: keys is a pointer to a slice instead of a slice to avoid `sorted`
// escaping to the heap.
sorted := (*keysBySeqNumKind)(keys)