Upgrade versions of vendored libs

This commit is contained in:
eleksir
2022-11-04 16:29:14 +03:00
parent fba732cc24
commit a7ae372459
941 changed files with 219674 additions and 23611 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

@@ -18,15 +18,33 @@ const bufferReuseMaxCapacity = 10 << 10 // 10 KB
// DefragmentMethod configures the defragmentation performed by the
// DefragmentingIter.
type DefragmentMethod func(base.Compare, Span, Span) bool
type DefragmentMethod interface {
// ShouldDefragment takes two abutting spans and returns whether the two
// spans should be combined into a single, defragmented Span.
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(equal base.Equal, left, right *Span) bool
// 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 = 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
}
@@ -34,7 +52,7 @@ var DefragmentInternal DefragmentMethod = func(cmp base.Compare, a, b Span) bool
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) {
@@ -42,7 +60,7 @@ var DefragmentInternal DefragmentMethod = func(cmp base.Compare, a, b Span) bool
}
}
return true
}
})
// DefragmentReducer merges the current and next Key slices, returning a new Key
// slice.
@@ -100,9 +118,10 @@ 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
iterSpan *Span
iterPos iterPos
// curr holds the span at the current iterator position. currBuf is a buffer
@@ -119,10 +138,10 @@ type DefragmentingIter struct {
keysBuf []Key
keyBuf []byte
// equal is a comparison function for two spans. equal is called when two
// method is a comparison function for two spans. method is called when two
// spans are abutting to determine whether they may be defragmented.
// equal does not itself check for adjacency for the two spans.
equal DefragmentMethod
// method does not itself check for adjacency for the two spans.
method DefragmentMethod
// reduce is the reducer function used to collect Keys across all spans that
// constitute a defragmented span.
@@ -135,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,
equal: equal,
reduce: reducer,
comparer: comparer,
equal: comparer.Equal,
iter: iter,
method: equal,
reduce: reducer,
}
}
@@ -157,16 +177,19 @@ func (i *DefragmentingIter) Close() error {
// SeekGE seeks the iterator to the first span with a start key greater than or
// equal to key and returns it.
func (i *DefragmentingIter) SeekGE(key []byte) Span {
func (i *DefragmentingIter) SeekGE(key []byte) *Span {
i.iterSpan = i.iter.SeekGE(key)
if !i.iterSpan.Valid() {
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.saveCurrent()
i.iterSpan = i.iter.Prev()
if 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
@@ -187,8 +210,15 @@ func (i *DefragmentingIter) SeekGE(key []byte) Span {
// SeekLT seeks the iterator to the last span with a start key less than
// key and returns it.
func (i *DefragmentingIter) SeekLT(key []byte) Span {
func (i *DefragmentingIter) SeekLT(key []byte) *Span {
i.iterSpan = i.iter.SeekLT(key)
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()
if i.iterPos == iterPosNext {
@@ -200,19 +230,27 @@ func (i *DefragmentingIter) SeekLT(key []byte) Span {
}
// First seeks the iterator to the first span and returns it.
func (i *DefragmentingIter) First() Span {
func (i *DefragmentingIter) First() *Span {
i.iterSpan = i.iter.First()
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
return i.defragmentForward()
}
// Last seeks the iterator to the last span and returns it.
func (i *DefragmentingIter) Last() Span {
func (i *DefragmentingIter) Last() *Span {
i.iterSpan = i.iter.Last()
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
return i.defragmentBackward()
}
// Next advances to the next span and returns it.
func (i *DefragmentingIter) Next() Span {
func (i *DefragmentingIter) Next() *Span {
switch i.iterPos {
case iterPosPrev:
// Switching directions; The iterator is currently positioned over the
@@ -228,7 +266,7 @@ func (i *DefragmentingIter) Next() Span {
// Next once to move onto y, defragment forward to land on the first z
// position.
i.iterSpan = i.iter.Next()
if !i.iterSpan.Valid() {
if invariants.Enabled && i.iterSpan == nil {
panic("pebble: invariant violation: no next span while switching directions")
}
// We're now positioned on the first span that was defragmented into the
@@ -236,6 +274,10 @@ func (i *DefragmentingIter) Next() Span {
// position's constitutent fragments. In the above example, this would
// land on the first 'z'.
i.defragmentForward()
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
// Now that we're positioned over the first of the next set of
// fragments, defragment forward.
@@ -243,14 +285,21 @@ func (i *DefragmentingIter) Next() Span {
case iterPosCurr:
// iterPosCurr is only used when the iter is exhausted or when the iterator
// is at an empty span.
if invariants.Enabled && i.iterSpan.Valid() && !i.iterSpan.Empty() {
if invariants.Enabled && i.iterSpan != nil && !i.iterSpan.Empty() {
panic("pebble: invariant violation: iterPosCurr with valid iterSpan")
}
i.iterSpan = i.iter.Next()
if i.iterSpan == nil {
return nil
}
return i.defragmentForward()
case iterPosNext:
// Already at the next span.
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
return i.defragmentForward()
default:
panic("unreachable")
@@ -258,19 +307,26 @@ func (i *DefragmentingIter) Next() Span {
}
// Prev steps back to the previous span and returns it.
func (i *DefragmentingIter) Prev() Span {
func (i *DefragmentingIter) Prev() *Span {
switch i.iterPos {
case iterPosPrev:
// Already at the previous span.
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
return i.defragmentBackward()
case iterPosCurr:
// iterPosCurr is only used when the iter is exhausted or when the iterator
// is at an empty span.
if invariants.Enabled && i.iterSpan.Valid() && !i.iterSpan.Empty() {
if invariants.Enabled && i.iterSpan != nil && !i.iterSpan.Empty() {
panic("pebble: invariant violation: iterPosCurr with valid iterSpan")
}
i.iterSpan = i.iter.Prev()
if i.iterSpan == nil {
return nil
}
return i.defragmentBackward()
case iterPosNext:
// Switching directions; The iterator is currently positioned over the
@@ -286,7 +342,7 @@ func (i *DefragmentingIter) Prev() Span {
// Prev once to move onto y, defragment backward to land on the last x
// position.
i.iterSpan = i.iter.Prev()
if !i.iterSpan.Valid() {
if invariants.Enabled && i.iterSpan == nil {
panic("pebble: invariant violation: no previous span while switching directions")
}
// We're now positioned on the last span that was defragmented into the
@@ -297,6 +353,10 @@ func (i *DefragmentingIter) Prev() Span {
// Now that we're positioned over the last of the prev set of
// fragments, defragment backward.
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
}
return i.defragmentBackward()
default:
panic("unreachable")
@@ -306,17 +366,14 @@ func (i *DefragmentingIter) Prev() Span {
// checkEqual checks the two spans for logical equivalence. It uses the passed-in
// 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 i.equal(i.cmp, i.iterSpan, i.curr) && !(left.Empty() && right.Empty())
func (i *DefragmentingIter) checkEqual(left, right *Span) bool {
return (!left.Empty() && !right.Empty()) && i.method.ShouldDefragment(i.equal, i.iterSpan, &i.curr)
}
// defragmentForward defragments spans in the forward direction, starting from
// i.iter's current position.
func (i *DefragmentingIter) defragmentForward() Span {
if !i.iterSpan.Valid() {
i.iterPos = iterPosCurr
return i.iterSpan
}
// i.iter's current position. The span at the current position must be non-nil,
// but may be Empty().
func (i *DefragmentingIter) defragmentForward() *Span {
if i.iterSpan.Empty() {
// An empty span will never be equal to another span; see checkEqual for
// why. To avoid loading non-empty range keys further ahead by calling Next,
@@ -324,16 +381,16 @@ func (i *DefragmentingIter) defragmentForward() Span {
i.iterPos = iterPosCurr
return i.iterSpan
}
i.saveCurrent(i.iterSpan)
i.saveCurrent()
i.iterPos = iterPosNext
i.iterSpan = i.iter.Next()
for i.iterSpan.Valid() {
if i.cmp(i.curr.End, i.iterSpan.Start) != 0 {
for i.iterSpan != nil {
if !i.equal(i.curr.End, i.iterSpan.Start) {
// Not a continuation.
break
}
if !i.checkEqual(i.iterSpan, i.curr) {
if !i.checkEqual(i.iterSpan, &i.curr) {
// Not a continuation.
break
}
@@ -343,16 +400,13 @@ func (i *DefragmentingIter) defragmentForward() Span {
i.iterSpan = i.iter.Next()
}
i.curr.Keys = i.keysBuf
return i.curr
return &i.curr
}
// defragmentBackward defragments spans in the backward direction, starting from
// i.iter's current position.
func (i *DefragmentingIter) defragmentBackward() Span {
if !i.iterSpan.Valid() {
i.iterPos = iterPosCurr
return i.iterSpan
}
// i.iter's current position. The span at the current position must be non-nil,
// but may be Empty().
func (i *DefragmentingIter) defragmentBackward() *Span {
if i.iterSpan.Empty() {
// An empty span will never be equal to another span; see checkEqual for
// why. To avoid loading non-empty range keys further ahead by calling Next,
@@ -360,16 +414,16 @@ func (i *DefragmentingIter) defragmentBackward() Span {
i.iterPos = iterPosCurr
return i.iterSpan
}
i.saveCurrent(i.iterSpan)
i.saveCurrent()
i.iterPos = iterPosPrev
i.iterSpan = i.iter.Prev()
for i.iterSpan.Valid() {
if i.cmp(i.curr.Start, i.iterSpan.End) != 0 {
for i.iterSpan != nil {
if !i.equal(i.curr.Start, i.iterSpan.End) {
// Not a continuation.
break
}
if !i.checkEqual(i.iterSpan, i.curr) {
if !i.checkEqual(i.iterSpan, &i.curr) {
// Not a continuation.
break
}
@@ -379,10 +433,10 @@ func (i *DefragmentingIter) defragmentBackward() Span {
i.iterSpan = i.iter.Prev()
}
i.curr.Keys = i.keysBuf
return i.curr
return &i.curr
}
func (i *DefragmentingIter) saveCurrent(span Span) {
func (i *DefragmentingIter) saveCurrent() {
i.currBuf = i.currBuf[:0]
i.keysBuf = i.keysBuf[:0]
i.keyBuf = i.keyBuf[:0]
@@ -392,15 +446,19 @@ func (i *DefragmentingIter) saveCurrent(span Span) {
if cap(i.keyBuf) > bufferReuseMaxCapacity {
i.keyBuf = nil
}
i.curr = Span{
Start: i.saveBytes(span.Start),
End: i.saveBytes(span.End),
if i.iterSpan == nil {
return
}
for j := range span.Keys {
i.curr = Span{
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{
Trailer: span.Keys[j].Trailer,
Suffix: i.saveBytes(span.Keys[j].Suffix),
Value: i.saveBytes(span.Keys[j].Value),
Trailer: i.iterSpan.Keys[j].Trailer,
Suffix: i.saveBytes(i.iterSpan.Keys[j].Suffix),
Value: i.saveBytes(i.iterSpan.Keys[j].Value),
})
}
i.curr.Keys = i.keysBuf

View File

@@ -10,7 +10,7 @@ package keyspan
// the output Span, for example, to elice certain keys, or update the Span's
// bounds if so desired. The output Span's Keys slice may be reused to reduce
// allocations.
type FilterFunc func(in Span, out *Span) (keep bool)
type FilterFunc func(in *Span, out *Span) (keep bool)
// filteringIter is a FragmentIterator that uses a FilterFunc to select which
// Spans from the input iterator are returned in the output.
@@ -37,32 +37,32 @@ func Filter(iter FragmentIterator, filter FilterFunc) FragmentIterator {
}
// SeekGE implements FragmentIterator.
func (i *filteringIter) SeekGE(key []byte) Span {
func (i *filteringIter) SeekGE(key []byte) *Span {
return i.filter(i.iter.SeekGE(key), +1)
}
// SeekLT implements FragmentIterator.
func (i *filteringIter) SeekLT(key []byte) Span {
func (i *filteringIter) SeekLT(key []byte) *Span {
return i.filter(i.iter.SeekLT(key), -1)
}
// First implements FragmentIterator.
func (i *filteringIter) First() Span {
func (i *filteringIter) First() *Span {
return i.filter(i.iter.First(), +1)
}
// Last implements FragmentIterator.
func (i *filteringIter) Last() Span {
func (i *filteringIter) Last() *Span {
return i.filter(i.iter.Last(), -1)
}
// Next implements FragmentIterator.
func (i *filteringIter) Next() Span {
func (i *filteringIter) Next() *Span {
return i.filter(i.iter.Next(), +1)
}
// Prev implements FragmentIterator.
func (i *filteringIter) Prev() Span {
func (i *filteringIter) Prev() *Span {
return i.filter(i.iter.Prev(), -1)
}
@@ -80,18 +80,18 @@ func (i *filteringIter) Close() error {
// given Span. If the current Span is to be skipped, the iterator continues
// iterating in the given direction until it lands on a Span that should be
// returned, or the iterator becomes invalid.
func (i *filteringIter) filter(span Span, dir int8) Span {
func (i *filteringIter) filter(span *Span, dir int8) *Span {
if i.filterFn == nil {
return span
}
for i.Error() == nil && span.Valid() {
for i.Error() == nil && span != nil {
if keep := i.filterFn(span, &i.span); keep {
return i.span
return &i.span
}
if dir == +1 {
span = i.Next()
span = i.iter.Next()
} else {
span = i.Prev()
span = i.iter.Prev()
}
}
return span

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); {
@@ -248,7 +252,7 @@ func (f *Fragmenter) Covers(key base.InternalKey, snapshot uint64) bool {
// NB: A range deletion tombstone does not delete a point operation
// at the same sequence number, and broadly a span is not considered
// to cover a point operation at the same sequence number.
if s.Visible(snapshot).Covers(seqNum) {
if s.CoversAt(snapshot, seqNum) {
return true
}
}

View File

@@ -11,7 +11,7 @@ import "github.com/cockroachdb/pebble/internal/base"
// parameter controls the visibility of spans (only spans older than the
// snapshot sequence number are visible). The iterator must contain
// fragmented spans: no span may overlap another.
func Get(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) Span {
func Get(cmp base.Compare, iter FragmentIterator, key []byte) *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:
//
@@ -25,15 +25,15 @@ func Get(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) S
// 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() {
if iterSpan == nil {
iterSpan = iter.Next()
if !iterSpan.Valid() {
if iterSpan == nil {
// The iterator is empty.
return Span{}
return nil
}
if cmp(key, iterSpan.Start) < 0 {
// The search key lies before the first span.
return Span{}
return nil
}
}
@@ -43,11 +43,11 @@ func Get(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) S
// once to potentially land on a key with a start key exactly equal to
// key. (See the comment at the beginning of this function.)
iterSpan = iter.Next()
if !iterSpan.Valid() || cmp(key, iterSpan.Start) < 0 {
if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
// We've run out of spans or we've moved on to a span which
// starts after our search key.
return Span{}
return nil
}
}
return iterSpan.Visible(snapshot)
return iterSpan
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@ import "github.com/cockroachdb/pebble/internal/base"
// keyspan.FragmentIterator with point keys.
type InternalIteratorShim struct {
miter MergingIter
span Span
span *Span
iterKey base.InternalKey
}
@@ -31,62 +31,64 @@ func (i *InternalIteratorShim) Init(cmp base.Compare, iters ...FragmentIterator)
// Span returns the span containing the full set of keys over the key span at
// the current iterator position.
func (i *InternalIteratorShim) Span() Span {
func (i *InternalIteratorShim) Span() *Span {
return i.span
}
// SeekGE implements (base.InternalIterator).SeekGE.
func (i *InternalIteratorShim) SeekGE(
key []byte, trySeekUsingNext bool,
) (*base.InternalKey, []byte) {
key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
func (i *InternalIteratorShim) SeekPrefixGE(
prefix, key []byte, trySeekUsingNext bool,
) (*base.InternalKey, []byte) {
prefix, key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekLT implements (base.InternalIterator).SeekLT.
func (i *InternalIteratorShim) SeekLT(key []byte) (*base.InternalKey, []byte) {
func (i *InternalIteratorShim) SeekLT(
key []byte, flags base.SeekLTFlags,
) (*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.Valid() && i.span.Empty() {
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if !i.span.Valid() {
return nil, nil
if i.span == 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.Valid() && i.span.Empty() {
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if !i.span.Valid() {
return nil, nil
if i.span == 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

@@ -20,17 +20,17 @@ import (
type FragmentIterator interface {
// SeekGE moves the iterator to the first span whose start key is greater
// than or equal to the given key.
SeekGE(key []byte) Span
SeekGE(key []byte) *Span
// SeekLT moves the iterator to the last span whose start key is less than
// the given key.
SeekLT(key []byte) Span
SeekLT(key []byte) *Span
// First moves the iterator to the first span.
First() Span
First() *Span
// Last moves the iterator to the last span.
Last() Span
Last() *Span
// Next moves the iterator to the next span.
//
@@ -38,7 +38,7 @@ type FragmentIterator interface {
// key/value pair due to either a prior call to SeekLT or Prev which
// returned an invalid span. It is not allowed to call Next when the
// previous call to SeekGE, SeekPrefixGE or Next returned an invalid span.
Next() Span
Next() *Span
// Prev moves the iterator to the previous span.
//
@@ -46,7 +46,7 @@ type FragmentIterator interface {
// key/value pair due to either a prior call to SeekGE or Next which
// returned an invalid span. It is not allowed to call Prev when the
// previous call to SeekLT or Prev returned an invalid span.
Prev() Span
Prev() *Span
// Error returns any accumulated error.
Error() error
@@ -81,7 +81,19 @@ var _ FragmentIterator = (*Iter)(nil)
// NewIter returns a new iterator over a set of fragmented spans.
func NewIter(cmp base.Compare, spans []Span) *Iter {
return &Iter{
i := &Iter{}
i.Init(cmp, spans)
return i
}
// Count returns the number of spans contained by Iter.
func (i *Iter) Count() int {
return len(i.spans)
}
// Init initializes an Iter with the provided spans.
func (i *Iter) Init(cmp base.Compare, spans []Span) {
*i = Iter{
cmp: cmp,
spans: spans,
index: -1,
@@ -89,7 +101,7 @@ func NewIter(cmp base.Compare, spans []Span) *Iter {
}
// SeekGE implements FragmentIterator.SeekGE.
func (i *Iter) SeekGE(key []byte) Span {
func (i *Iter) SeekGE(key []byte) *Span {
// NB: manually inlined sort.Search is ~5% faster.
//
// Define f(-1) == false and f(n) == true.
@@ -108,13 +120,13 @@ func (i *Iter) SeekGE(key []byte) Span {
// i.index == upper, f(i.index-1) == false, and f(upper) (= f(i.index)) ==
// true => answer is i.index.
if i.index >= len(i.spans) {
return Span{}
return nil
}
return i.spans[i.index]
return &i.spans[i.index]
}
// SeekLT implements FragmentIterator.SeekLT.
func (i *Iter) SeekLT(key []byte) Span {
func (i *Iter) SeekLT(key []byte) *Span {
// NB: manually inlined sort.Search is ~5% faster.
//
// Define f(-1) == false and f(n) == true.
@@ -137,51 +149,51 @@ func (i *Iter) SeekLT(key []byte) Span {
// the largest whose key is < the key sought.
i.index--
if i.index < 0 {
return Span{}
return nil
}
return i.spans[i.index]
return &i.spans[i.index]
}
// First implements FragmentIterator.First.
func (i *Iter) First() Span {
func (i *Iter) First() *Span {
if len(i.spans) == 0 {
return Span{}
return nil
}
i.index = 0
return i.spans[i.index]
return &i.spans[i.index]
}
// Last implements FragmentIterator.Last.
func (i *Iter) Last() Span {
func (i *Iter) Last() *Span {
if len(i.spans) == 0 {
return Span{}
return nil
}
i.index = len(i.spans) - 1
return i.spans[i.index]
return &i.spans[i.index]
}
// Next implements FragmentIterator.Next.
func (i *Iter) Next() Span {
func (i *Iter) Next() *Span {
if i.index >= len(i.spans) {
return Span{}
return nil
}
i.index++
if i.index >= len(i.spans) {
return Span{}
return nil
}
return i.spans[i.index]
return &i.spans[i.index]
}
// Prev implements FragmentIterator.Prev.
func (i *Iter) Prev() Span {
func (i *Iter) Prev() *Span {
if i.index < 0 {
return Span{}
return nil
}
i.index--
if i.index < 0 {
return Span{}
return nil
}
return i.spans[i.index]
return &i.spans[i.index]
}
// Error implements FragmentIterator.Error.

View File

@@ -40,8 +40,8 @@ type LevelIter struct {
// key spaces. This is an optimization to avoid unnecessarily loading files
// in cases where range keys are sparse and rare. dir is set by every
// positioning operation, straddleDir is set to dir whenever a straddling
// Span is synthesized, and straddle is Valid() whenever the last positioning
// operation returned a synthesized straddle span.
// Span is synthesized and the last positioning operation returned a
// synthesized straddle span.
//
// Note that when a straddle span is initialized, iterFile is modified to
// point to the next file in the straddleDir direction. A change of direction
@@ -53,7 +53,7 @@ type LevelIter struct {
// The iter for the current file. It is nil under any of the following conditions:
// - files.Current() == nil
// - err != nil
// - straddle.Valid(), in which case iterFile is not nil and points to the
// - straddleDir != 0, in which case iterFile is not nil and points to the
// next file (in the straddleDir direction).
// - some other constraint, like the bounds in opts, caused the file at index to not
// be relevant to the iteration.
@@ -178,7 +178,7 @@ func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileRetur
return noFileLoaded
}
if indicator != fileAlreadyLoaded {
l.iter, l.err = l.newIter(l.files.Current(), &l.tableOpts)
l.iter, l.err = l.newIter(file, &l.tableOpts)
indicator = newFileLoaded
}
if l.err != nil {
@@ -188,123 +188,149 @@ func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileRetur
}
// SeekGE implements keyspan.FragmentIterator.
func (l *LevelIter) SeekGE(key []byte) Span {
func (l *LevelIter) SeekGE(key []byte) *Span {
l.dir = +1
l.straddle = Span{}
l.straddleDir = 0
l.err = nil // clear cached iteration error
f := l.findFileGE(key)
if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(key, f.SmallestRangeKey.UserKey) < 0 {
// Return a straddling key instead of loading the file.
l.iterFile = f
l.iter = nil
l.straddleDir = +1
// The synthetic span that we are creating starts at the seeked key. This
// is an optimization as it prevents us from loading the adjacent file's
// bounds, at the expense of this iterator appearing "inconsistent" to its
// callers i.e.:
//
// SeekGE(bb) -> {bb-c, empty}
// Next() -> {c-d, RANGEKEYSET}
// Prev() -> {a-c, empty}
//
// Seeing as the inconsistency will only be around empty spans, which are
// expected to be elided by one of the higher-level iterators (either
// top-level Iterator or the defragmenting iter), the entire iterator should
// still appear consistent to the user.
l.straddle = Span{
Start: key,
End: f.SmallestRangeKey.UserKey,
Keys: nil,
prevFile := l.files.Prev()
if prevFile != nil {
// We could unconditionally return an empty span between the seek key and
// f.SmallestRangeKey, however if this span is to the left of all range
// keys on this level, it could lead to inconsistent behaviour in relative
// positioning operations. Consider this example, with a b-c range key:
//
// SeekGE(a) -> a-b:{}
// Next() -> b-c{(#5,RANGEKEYSET,@4,foo)}
// Prev() -> nil
//
// Iterators higher up in the iterator stack rely on this sort of relative
// positioning consistency.
//
// TODO(bilal): Investigate ways to be able to return straddle spans in
// cases similar to the above, while still retaining correctness.
l.files.Next()
// Return a straddling key instead of loading the file.
l.iterFile = f
if err := l.Close(); err != nil {
return nil
}
l.straddleDir = +1
l.straddle = Span{
Start: prevFile.LargestRangeKey.UserKey,
End: f.SmallestRangeKey.UserKey,
Keys: nil,
}
return &l.straddle
}
return l.straddle
}
loadFileIndicator := l.loadFile(f, +1)
if loadFileIndicator == noFileLoaded {
return Span{}
return nil
}
if span := l.iter.SeekGE(key); span.Valid() {
if span := l.iter.SeekGE(key); span != nil {
return span
}
return l.skipEmptyFileForward()
}
// SeekLT implements keyspan.FragmentIterator.
func (l *LevelIter) SeekLT(key []byte) Span {
func (l *LevelIter) SeekLT(key []byte) *Span {
l.dir = -1
l.straddle = Span{}
l.straddleDir = 0
l.err = nil // clear cached iteration error
f := l.findFileLT(key)
if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(f.LargestRangeKey.UserKey, key) < 0 {
// Return a straddling key instead of loading the file.
l.iterFile = f
l.iter = nil
l.straddleDir = -1
// The synthetic span that we are creating ends at the seeked key. This
// is an optimization as it prevents us from loading the adjacent file's
// bounds, at the expense of this iterator appearing "inconsistent" to its
// callers i.e.:
//
// SeekLT(dd) -> {d-dd, empty}
// Prev() -> {c-d, RANGEKEYSET}
// Next() -> {d-e, empty}
//
// Seeing as the inconsistency will only be around empty spans, which are
// expected to be elided by one of the higher-level iterators (either
// top-level Iterator or the defragmenting iter), the entire iterator should
// still appear consistent to the user.
l.straddle = Span{
Start: f.LargestRangeKey.UserKey,
End: key,
Keys: nil,
nextFile := l.files.Next()
if nextFile != nil {
// We could unconditionally return an empty span between f.LargestRangeKey
// and the seek key, however if this span is to the right of all range keys
// on this level, it could lead to inconsistent behaviour in relative
// positioning operations. Consider this example, with a b-c range key:
//
// SeekLT(d) -> c-d:{}
// Prev() -> b-c{(#5,RANGEKEYSET,@4,foo)}
// Next() -> nil
//
// Iterators higher up in the iterator stack rely on this sort of relative
// positioning consistency.
//
// TODO(bilal): Investigate ways to be able to return straddle spans in
// cases similar to the above, while still retaining correctness.
l.files.Prev()
// Return a straddling key instead of loading the file.
l.iterFile = f
if err := l.Close(); err != nil {
return nil
}
l.straddleDir = -1
l.straddle = Span{
Start: f.LargestRangeKey.UserKey,
End: nextFile.SmallestRangeKey.UserKey,
Keys: nil,
}
return &l.straddle
}
return l.straddle
}
if l.loadFile(l.findFileLT(key), -1) == noFileLoaded {
return Span{}
return nil
}
if span := l.iter.SeekLT(key); span.Valid() {
if span := l.iter.SeekLT(key); span != nil {
return span
}
return l.skipEmptyFileBackward()
}
// First implements keyspan.FragmentIterator.
func (l *LevelIter) First() Span {
func (l *LevelIter) First() *Span {
l.dir = +1
l.straddle = Span{}
l.straddleDir = 0
l.err = nil // clear cached iteration error
if l.loadFile(l.files.First(), +1) == noFileLoaded {
return Span{}
return nil
}
if span := l.iter.First(); span.Valid() {
if span := l.iter.First(); span != nil {
return span
}
return l.skipEmptyFileForward()
}
// Last implements keyspan.FragmentIterator.
func (l *LevelIter) Last() Span {
func (l *LevelIter) Last() *Span {
l.dir = -1
l.straddle = Span{}
l.straddleDir = 0
l.err = nil // clear cached iteration error
if l.loadFile(l.files.Last(), -1) == noFileLoaded {
return Span{}
return nil
}
if span := l.iter.Last(); span.Valid() {
if span := l.iter.Last(); span != nil {
return span
}
return l.skipEmptyFileBackward()
}
// Next implements keyspan.FragmentIterator.
func (l *LevelIter) Next() Span {
l.dir = +1
if l.err != nil || (l.iter == nil && l.iterFile == nil) {
return Span{}
func (l *LevelIter) Next() *Span {
if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir > 0) {
return nil
}
if l.iter == nil && l.iterFile == nil {
// l.dir <= 0
return l.First()
}
l.dir = +1
if l.iter != nil {
if span := l.iter.Next(); span.Valid() {
if span := l.iter.Next(); span != nil {
return span
}
}
@@ -312,22 +338,26 @@ func (l *LevelIter) Next() Span {
}
// Prev implements keyspan.FragmentIterator.
func (l *LevelIter) Prev() Span {
l.dir = -1
if l.err != nil || (l.iter == nil && l.iterFile == nil) {
return Span{}
func (l *LevelIter) Prev() *Span {
if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir < 0) {
return nil
}
if l.iter == nil && l.iterFile == nil {
// l.dir >= 0
return l.Last()
}
l.dir = -1
if l.iter != nil {
if span := l.iter.Prev(); span.Valid() {
if span := l.iter.Prev(); span != nil {
return span
}
}
return l.skipEmptyFileBackward()
}
func (l *LevelIter) skipEmptyFileForward() Span {
if !l.straddle.Valid() && l.keyType == manifest.KeyTypeRange &&
func (l *LevelIter) skipEmptyFileForward() *Span {
if l.straddleDir == 0 && l.keyType == manifest.KeyTypeRange &&
l.iterFile != nil && l.iter != nil {
// We were at a file that had spans. Check if the next file that has
// spans is not directly adjacent to the current file i.e. there is a
@@ -337,7 +367,7 @@ func (l *LevelIter) skipEmptyFileForward() Span {
// Straddle spans are not created in rangedel mode.
if err := l.Close(); err != nil {
l.err = err
return Span{}
return nil
}
startKey := l.iterFile.LargestRangeKey.UserKey
// Resetting l.iterFile without loading the file into l.iter is okay and
@@ -345,7 +375,7 @@ func (l *LevelIter) skipEmptyFileForward() Span {
// which it should be due to the Close() call above.
l.iterFile = l.files.Next()
if l.iterFile == nil {
return Span{}
return nil
}
endKey := l.iterFile.SmallestRangeKey.UserKey
if l.cmp(startKey, endKey) < 0 {
@@ -355,17 +385,18 @@ func (l *LevelIter) skipEmptyFileForward() Span {
Start: startKey,
End: endKey,
}
l.straddleDir = l.dir
return l.straddle
l.straddleDir = +1
return &l.straddle
}
} else if l.straddle.Valid() && l.straddleDir < 0 {
} else if l.straddleDir < 0 {
// We were at a straddle key, but are now changing directions. l.iterFile
// was already moved backward by skipEmptyFileBackward, so advance it
// forward.
l.iterFile = l.files.Next()
}
l.straddle = Span{}
var span Span
l.straddleDir = 0
var span *Span
for span.Empty() {
fileToLoad := l.iterFile
if l.keyType == manifest.KeyTypePoint {
@@ -374,7 +405,7 @@ func (l *LevelIter) skipEmptyFileForward() Span {
fileToLoad = l.files.Next()
}
if l.loadFile(fileToLoad, +1) == noFileLoaded {
return Span{}
return nil
}
span = l.iter.First()
// In rangedel mode, we can expect to get empty files that we'd need to
@@ -386,18 +417,18 @@ func (l *LevelIter) skipEmptyFileForward() Span {
return span
}
func (l *LevelIter) skipEmptyFileBackward() Span {
func (l *LevelIter) skipEmptyFileBackward() *Span {
// We were at a file that had spans. Check if the previous file that has
// spans is not directly adjacent to the current file i.e. there is a
// gap in the span keyspace between the two files. In that case, synthesize
// a "straddle span" in l.straddle and return that.
//
// Straddle spans are not created in rangedel mode.
if !l.straddle.Valid() && l.keyType == manifest.KeyTypeRange &&
if l.straddleDir == 0 && l.keyType == manifest.KeyTypeRange &&
l.iterFile != nil && l.iter != nil {
if err := l.Close(); err != nil {
l.err = err
return Span{}
return nil
}
endKey := l.iterFile.SmallestRangeKey.UserKey
// Resetting l.iterFile without loading the file into l.iter is okay and
@@ -405,7 +436,7 @@ func (l *LevelIter) skipEmptyFileBackward() Span {
// which it should be due to the Close() call above.
l.iterFile = l.files.Prev()
if l.iterFile == nil {
return Span{}
return nil
}
startKey := l.iterFile.LargestRangeKey.UserKey
if l.cmp(startKey, endKey) < 0 {
@@ -415,24 +446,25 @@ func (l *LevelIter) skipEmptyFileBackward() Span {
Start: startKey,
End: endKey,
}
l.straddleDir = l.dir
return l.straddle
l.straddleDir = -1
return &l.straddle
}
} else if l.straddle.Valid() && l.straddleDir > 0 {
} else if l.straddleDir > 0 {
// We were at a straddle key, but are now changing directions. l.iterFile
// was already advanced forward by skipEmptyFileForward, so move it
// backward.
l.iterFile = l.files.Prev()
}
l.straddle = Span{}
var span Span
l.straddleDir = 0
var span *Span
for span.Empty() {
fileToLoad := l.iterFile
if l.keyType == manifest.KeyTypePoint {
fileToLoad = l.files.Prev()
}
if l.loadFile(fileToLoad, -1) == noFileLoaded {
return Span{}
return nil
}
span = l.iter.Last()
// In rangedel mode, we can expect to get empty files that we'd need to

View File

@@ -11,6 +11,7 @@ import (
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/internal/invariants"
"github.com/cockroachdb/pebble/internal/manifest"
)
// TODO(jackson): Consider implementing an optimization to seek lower levels
@@ -20,27 +21,47 @@ import (
// seeks would require introducing key comparisons to switchTo{Min,Max}Heap
// where there currently are none.
// Transform defines a transform function to be applied to a Span. A Transform
// takes a Span as input and writes the transformed Span to the provided output
// *Span pointer. The output Span's Keys slice may be reused by Transform to
// reduce allocations.
type Transform func(cmp base.Compare, in Span, out *Span) error
// Transformer defines a transformation to be applied to a Span.
type Transformer interface {
// Transform takes a Span as input and writes the transformed Span to the
// provided output *Span pointer. The output Span's Keys slice may be reused
// by Transform to reduce allocations.
Transform(cmp base.Compare, in Span, out *Span) error
}
func noopTransform(_ base.Compare, s Span, dst *Span) error {
// The TransformerFunc type is an adapter to allow the use of ordinary functions
// as Transformers. If f is a function with the appropriate signature,
// TransformerFunc(f) is a Transformer that calls f.
type TransformerFunc func(base.Compare, Span, *Span) error
// Transform calls f(cmp, in, out).
func (tf TransformerFunc) Transform(cmp base.Compare, in Span, out *Span) error {
return tf(cmp, in, out)
}
var noopTransform Transformer = TransformerFunc(func(_ base.Compare, s Span, dst *Span) error {
dst.Start, dst.End = s.Start, s.End
dst.Keys = append(dst.Keys[:0], s.Keys...)
return nil
}
})
// visibleTransform filters keys that are invisible at the provided snapshot
// sequence number.
func visibleTransform(snapshot uint64) Transform {
return func(_ base.Compare, s Span, dst *Span) error {
s = s.Visible(snapshot)
func visibleTransform(snapshot uint64) Transformer {
return TransformerFunc(func(_ base.Compare, s Span, dst *Span) error {
dst.Start, dst.End = s.Start, s.End
dst.Keys = append(dst.Keys[:0], s.Keys...)
dst.Keys = dst.Keys[:0]
for _, k := range s.Keys {
// 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)
}
}
return nil
}
})
}
// MergingIter merges spans across levels of the LSM, exposing an iterator over
@@ -51,6 +72,10 @@ func visibleTransform(snapshot uint64) Transform {
// 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
@@ -193,17 +218,17 @@ 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.
keys keysBySeqNumKind
// transform defines a function to be applied to a span before it's yielded
// to the user. A transform may filter individual keys contained within the
// span.
transform Transform
// transformer defines a transformation to be applied to a span before it's
// yielded to the user. Transforming may filter individual keys contained
// within the span.
transformer Transformer
// span holds the iterator's current span. This span is used as the
// destination for transforms. Every tranformed span overwrites the
// previous.
@@ -211,6 +236,17 @@ type MergingIter struct {
err error
dir int8
// alloc preallocates mergingIterLevel and mergingIterItems for use by the
// merging iterator. As long as the merging iterator is used with
// manifest.NumLevels+3 and fewer fragment iterators, the merging iterator
// will not need to allocate upon initialization. The value NumLevels+3
// mirrors the preallocated levels in iterAlloc used for point iterators.
// Invariant: cap(levels) == cap(items)
alloc struct {
levels [manifest.NumLevels + 3]mergingIterLevel
items [manifest.NumLevels + 3]mergingIterItem
}
}
// MergingIter implements the FragmentIterator interface.
@@ -225,45 +261,82 @@ type mergingIterLevel struct {
func (l *mergingIterLevel) next() {
if l.heapKey.kind == boundKindFragmentStart {
l.heapKey = endBound(l.heapKey.span)
l.heapKey = boundKey{
kind: boundKindFragmentEnd,
key: l.heapKey.span.End,
span: l.heapKey.span,
}
return
}
l.heapKey = startBound(l.iter.Next())
if s := l.iter.Next(); s == nil {
l.heapKey = boundKey{kind: boundKindInvalid}
} else {
l.heapKey = boundKey{
kind: boundKindFragmentStart,
key: s.Start,
span: s,
}
}
}
func (l *mergingIterLevel) prev() {
if l.heapKey.kind == boundKindFragmentEnd {
l.heapKey = startBound(l.heapKey.span)
l.heapKey = boundKey{
kind: boundKindFragmentStart,
key: l.heapKey.span.Start,
span: l.heapKey.span,
}
return
}
l.heapKey = endBound(l.iter.Prev())
if s := l.iter.Prev(); s == nil {
l.heapKey = boundKey{kind: boundKindInvalid}
} else {
l.heapKey = boundKey{
kind: boundKindFragmentEnd,
key: s.End,
span: s,
}
}
}
// Init initializes the merging iterator with the provided fragment iterators.
func (m *MergingIter) Init(cmp base.Compare, transform Transform, iters ...FragmentIterator) {
func (m *MergingIter) Init(cmp base.Compare, transformer Transformer, iters ...FragmentIterator) {
levels, items := m.levels, m.heap.items
*m = MergingIter{
heap: mergingIterHeap{cmp: cmp},
transform: transform,
heap: mergingIterHeap{cmp: cmp},
transformer: transformer,
}
// Invariant: cap(levels) == cap(items)
if cap(levels) < len(iters) {
m.levels = make([]mergingIterLevel, len(iters))
m.heap.items = make([]mergingIterItem, 0, len(iters))
} else {
// Invariant: cap(levels) >= cap(items)
// Invariant: cap(alloc.levels) == cap(alloc.items)
if len(iters) <= len(m.alloc.levels) {
// The slices allocated on the MergingIter struct are large enough.
m.levels = m.alloc.levels[:len(iters)]
m.heap.items = m.alloc.items[:0]
} else if len(iters) <= cap(levels) {
// The existing heap-allocated slices are large enough, so reuse them.
m.levels = levels[:len(iters)]
m.heap.items = items[:0]
} else {
// Heap allocate new slices.
m.levels = make([]mergingIterLevel, len(iters))
m.heap.items = make([]mergingIterItem, 0, len(iters))
}
for i := range m.levels {
m.levels[i] = mergingIterLevel{}
m.levels[i].iter = iters[i]
m.levels[i] = mergingIterLevel{iter: iters[i]}
}
}
// AddLevel adds a new level to the bottom of the merging iterator. AddLevel
// must be called after Init and before any other method.
func (m *MergingIter) AddLevel(iter FragmentIterator) {
m.levels = append(m.levels, mergingIterLevel{iter: iter})
}
// SeekGE moves the iterator to the first span with a start key greater than or
// equal to key.
func (m *MergingIter) SeekGE(key []byte) Span {
func (m *MergingIter) SeekGE(key []byte) *Span {
m.invalidate() // clear state about current position
for i := range m.levels {
l := &m.levels[i]
@@ -277,24 +350,35 @@ func (m *MergingIter) SeekGE(key []byte) Span {
// Otherwise we use the start boundary of the next span which
// necessarily has a start ≥ key.
s := l.iter.SeekLT(key)
if s.Valid() && m.cmp(s.End, key) >= 0 {
if s != nil && m.cmp(s.End, key) >= 0 {
// s.End ≥ key
// We need to use this span's end bound.
l.heapKey = endBound(s)
l.heapKey = boundKey{
kind: boundKindFragmentEnd,
key: s.End,
span: s,
}
continue
}
// s.End < key
// The span `s` ends before key. Next to the first span with a Start ≥
// key, and use that.
s = l.iter.Next()
l.heapKey = startBound(s)
if s = l.iter.Next(); s == nil {
l.heapKey = boundKey{kind: boundKindInvalid}
} else {
l.heapKey = boundKey{
kind: boundKindFragmentStart,
key: s.Start,
span: s,
}
}
}
m.initMinHeap()
return m.findNextFragmentSet()
}
// SeekLT moves the iterator to the last span with a start key less than key.
func (m *MergingIter) SeekLT(key []byte) Span {
func (m *MergingIter) SeekLT(key []byte) *Span {
// TODO(jackson): Evaluate whether there's an implementation of SeekLT
// independent of SeekGE that is more efficient. It's tricky, because the
// span we should return might straddle `key` itself.
@@ -314,42 +398,56 @@ func (m *MergingIter) SeekLT(key []byte) Span {
// Start user key < key: [b,l)#1. This requires examining bounds both < 'c'
// (the 'b' of [b,m)#1's start key) and bounds ≥ 'c' (the 'l' of ([a,l)#2's
// end key).
if s := m.SeekGE(key); !s.Valid() && m.err != nil {
return Span{}
if s := m.SeekGE(key); s == nil && m.err != nil {
return nil
}
// Prev to the previous span.
return m.Prev()
}
// First seeks the iterator to the first span.
func (m *MergingIter) First() Span {
func (m *MergingIter) First() *Span {
m.invalidate() // clear state about current position
for i := range m.levels {
l := &m.levels[i]
l.heapKey = startBound(l.iter.First())
if s := m.levels[i].iter.First(); s == nil {
m.levels[i].heapKey = boundKey{kind: boundKindInvalid}
} else {
m.levels[i].heapKey = boundKey{
kind: boundKindFragmentStart,
key: s.Start,
span: s,
}
}
}
m.initMinHeap()
return m.findNextFragmentSet()
}
// Last seeks the iterator to the last span.
func (m *MergingIter) Last() Span {
func (m *MergingIter) Last() *Span {
m.invalidate() // clear state about current position
for i := range m.levels {
l := &m.levels[i]
l.heapKey = endBound(l.iter.Last())
if s := m.levels[i].iter.Last(); s == nil {
m.levels[i].heapKey = boundKey{kind: boundKindInvalid}
} else {
m.levels[i].heapKey = boundKey{
kind: boundKindFragmentEnd,
key: s.End,
span: s,
}
}
}
m.initMaxHeap()
return m.findPrevFragmentSet()
}
// Next advances the iterator to the next span.
func (m *MergingIter) Next() Span {
func (m *MergingIter) Next() *Span {
if m.err != nil {
return Span{}
return nil
}
if m.dir == +1 && (m.end == nil || m.start == nil) {
return Span{}
return nil
}
if m.dir != +1 {
m.switchToMinHeap()
@@ -358,12 +456,12 @@ func (m *MergingIter) Next() Span {
}
// Prev advances the iterator to the previous span.
func (m *MergingIter) Prev() Span {
func (m *MergingIter) Prev() *Span {
if m.err != nil {
return Span{}
return nil
}
if m.dir == -1 && (m.end == nil || m.start == nil) {
return Span{}
return nil
}
if m.dir != -1 {
m.switchToMaxHeap()
@@ -533,7 +631,7 @@ func (m *MergingIter) cmp(a, b []byte) int {
return m.heap.cmp(a, b)
}
func (m *MergingIter) findNextFragmentSet() Span {
func (m *MergingIter) findNextFragmentSet() *Span {
// Each iteration of this loop considers a new merged span between unique
// user keys. An iteration may find that there exists no overlap for a given
// span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
@@ -601,16 +699,16 @@ func (m *MergingIter) findNextFragmentSet() Span {
// we elide empty spans created by the mergingIter itself that don't overlap
// with any child iterator returned spans (i.e. empty spans that bridge two
// distinct child-iterator-defined spans).
if found, s := m.synthesizeKeys(+1); found && s.Valid() {
if found, s := m.synthesizeKeys(+1); found && s != nil {
return s
}
}
// Exhausted.
m.clear()
return Span{}
return nil
}
func (m *MergingIter) findPrevFragmentSet() Span {
func (m *MergingIter) findPrevFragmentSet() *Span {
// Each iteration of this loop considers a new merged span between unique
// user keys. An iteration may find that there exists no overlap for a given
// span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
@@ -677,13 +775,13 @@ func (m *MergingIter) findPrevFragmentSet() Span {
// we elide empty spans created by the mergingIter itself that don't overlap
// with any child iterator returned spans (i.e. empty spans that bridge two
// distinct child-iterator-defined spans).
if found, s := m.synthesizeKeys(-1); found && s.Valid() {
if found, s := m.synthesizeKeys(-1); found && s != nil {
return s
}
}
// Exhausted.
m.clear()
return Span{}
return nil
}
func (m *MergingIter) heapRoot() []byte {
@@ -703,7 +801,7 @@ func (m *MergingIter) heapRoot() []byte {
//
// The boolean return value, `found`, is true if the returned span overlaps
// with a span returned by a child iterator.
func (m *MergingIter) synthesizeKeys(dir int8) (bool, Span) {
func (m *MergingIter) synthesizeKeys(dir int8) (bool, *Span) {
if invariants.Enabled {
if m.cmp(m.start, m.end) >= 0 {
panic(fmt.Sprintf("pebble: invariant violation: span start ≥ end: %s >= %s", m.start, m.end))
@@ -719,19 +817,26 @@ 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.
// 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.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, Span{}
return false, nil
}
return found, m.span
return found, &m.span
}
func (m *MergingIter) invalidate() {
@@ -885,28 +990,6 @@ func (h *mergingIterHeap) down(i0, n int) bool {
return i > i0
}
func startBound(s Span) boundKey {
if !s.Valid() {
return boundKey{kind: boundKindInvalid}
}
return boundKey{
kind: boundKindFragmentStart,
key: s.Start,
span: s,
}
}
func endBound(s Span) boundKey {
if !s.Valid() {
return boundKey{kind: boundKindInvalid}
}
return boundKey{
kind: boundKindFragmentEnd,
key: s.End,
span: s,
}
}
type boundKind int8
const (
@@ -922,7 +1005,7 @@ type boundKey struct {
//
// If kind is boundKindFragmentStart, then key is span.Start. If kind is
// boundKindFragmentEnd, then key is span.End.
span Span
span *Span
}
func (k boundKey) valid() bool {

View File

@@ -6,13 +6,9 @@ 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 {
// the target key.
func SeekGE(cmp base.Compare, iter FragmentIterator, key []byte) *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:
//
@@ -29,27 +25,17 @@ func SeekGE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64
// Invariant: key > iterSpan.Start
if !iterSpan.Valid() || cmp(key, iterSpan.End) >= 0 {
if iterSpan == nil || 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 {
// SeekLE seeks to the span that contains or is before the target key.
func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte) *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:
//
@@ -64,13 +50,13 @@ func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64
// and we'll have to move forward.
iterSpan := iter.SeekLT(key)
if !iterSpan.Valid() {
if iterSpan == nil {
// 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 {
if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
// The iterator is exhausted or we've hit the next span.
return Span{}
return nil
}
} else {
// Invariant: key > iterSpan.Start
@@ -79,20 +65,12 @@ func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64
// 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 {
if iterSpan == nil || 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
}

View File

@@ -5,6 +5,7 @@
package keyspan // import "github.com/cockroachdb/pebble/internal/keyspan"
import (
"bytes"
"fmt"
"sort"
"strconv"
@@ -30,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.
@@ -65,8 +80,17 @@ func (k Key) Kind() base.InternalKeyKind {
return base.InternalKeyKind(k.Trailer & 0xff)
}
// 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(equal base.Equal, b Key) bool {
return k.Trailer == b.Trailer &&
equal(k.Suffix, b.Suffix) &&
bytes.Equal(k.Value, b.Value)
}
// Valid returns true if the span is defined.
func (s Span) Valid() bool {
func (s *Span) Valid() bool {
return s.Start != nil && s.End != nil
}
@@ -75,15 +99,18 @@ func (s Span) Valid() bool {
//
// An Empty span may be produced by Visible, or be produced by iterators in
// order to surface the gaps between keys.
func (s Span) Empty() bool {
return len(s.Keys) == 0
func (s *Span) Empty() bool {
return s == nil || len(s.Keys) == 0
}
// SmallestKey returns the smallest internal key defined by the span's keys.
// It panics if the span contains no keys.
func (s Span) SmallestKey() base.InternalKey {
// 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{
@@ -98,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.
func (s Span) LargestKey() base.InternalKey {
// 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()
@@ -109,43 +139,144 @@ 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.
func (s Span) SmallestSeqNum() uint64 {
// 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.
func (s Span) LargestSeqNum() uint64 {
// 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()
}
// TODO(jackson): Replace most of the calls to Visible with more targeted calls
// that avoid the need to construct a new Span.
// Visible returns a span with the subset of keys visible at the provided
// sequence number.
func (s Span) Visible(seqNum uint64) Span {
// 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
}
// Keys from indexed batches may force an allocation. The Keys slice is
// ordered by sequence number, so ordinarily we can return the trailing
// subslice containing keys with sequence numbers less than `seqNum`.
//
// However, batch keys are special. Only visible batch keys are included
// when an Iterator's batch spans are fragmented. They must always be
// visible.
//
// Batch keys can create a sandwich of visible batch keys at the beginning
// of the slice and visible committed keys at the end of the slice, forcing
// us to allocate a new slice and copy the contents.
//
// Care is taking to only incur an allocation only when batch keys and
// visible keys actually sandwich non-visible keys.
// lastBatchIdx and lastNonVisibleIdx are set to the last index of a batch
// key and a non-visible key respectively.
lastBatchIdx := -1
lastNonVisibleIdx := -1
for i := range s.Keys {
if base.Visible(s.Keys[i].SeqNum(), seqNum) {
ret.Keys = s.Keys[i:]
break
if seqNum := s.Keys[i].SeqNum(); seqNum&base.InternalKeySeqNumBatch != 0 {
// Batch key. Always visible.
lastBatchIdx = i
} else if seqNum >= snapshot {
// This key is not visible.
lastNonVisibleIdx = i
}
}
// In the following comments: b = batch, h = hidden, v = visible (committed).
switch {
case lastNonVisibleIdx == -1:
// All keys are visible.
//
// [b b b], [v v v] and [b b b v v v]
ret.Keys = s.Keys
case lastBatchIdx == -1:
// There are no batch keys, so we can return the continuous subslice
// starting after the last non-visible Key.
//
// h h h [v v v]
ret.Keys = s.Keys[lastNonVisibleIdx+1:]
case lastNonVisibleIdx == len(s.Keys)-1:
// While we have a batch key and non-visible keys, there are no
// committed visible keys. The 'sandwich' is missing the bottom layer,
// so we can return the continuous sublice at the beginning.
//
// [b b b] h h h
ret.Keys = s.Keys[0 : lastBatchIdx+1]
default:
// This is the problematic sandwich case. Allocate a new slice, copying
// the batch keys and the visible keys into it.
//
// [b b b] h h h [v v v]
ret.Keys = make([]Key, (lastBatchIdx+1)+(len(s.Keys)-lastNonVisibleIdx-1))
copy(ret.Keys, s.Keys[:lastBatchIdx+1])
copy(ret.Keys[lastBatchIdx+1:], s.Keys[lastNonVisibleIdx+1:])
}
return ret
}
// 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 {
// Only visible batch keys are included when an Iterator's batch spans
// are fragmented. They must always be visible.
return true
} else {
// Otherwise we check the last key. Since keys are ordered decreasing in
// sequence number, the last key has the lowest sequence number of any
// of the span's keys. If any of the keys are visible, the last key must
// be visible. Or put differently: if the last key is not visible, then
// no key is visible.
return s.Keys[len(s.Keys)-1].SeqNum() < snapshot
}
}
// ShallowClone returns the span with a Keys slice owned by the span itself.
// None of the key byte slices are cloned (see Span.DeepClone).
func (s Span) ShallowClone() Span {
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
@@ -154,11 +285,12 @@ func (s Span) ShallowClone() Span {
// DeepClone clones the span, creating copies of all contained slices. DeepClone
// is intended for non-production code paths like tests, the level checker, etc
// because it is allocation heavy.
func (s Span) DeepClone() Span {
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)
@@ -177,15 +309,48 @@ func (s Span) DeepClone() Span {
}
// Contains returns true if the specified key resides within the span's bounds.
func (s Span) Contains(cmp base.Compare, key []byte) bool {
func (s *Span) Contains(cmp base.Compare, key []byte) bool {
return cmp(s.Start, key) <= 0 && cmp(key, s.End) < 0
}
// 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
}
// CoversAt returns true if the span contains a key that is visible at the
// provided snapshot sequence number, and that key's sequence number is higher
// than seqNum.
//
// 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 {
if kseq := s.Keys[i].SeqNum(); kseq&base.InternalKeySeqNumBatch != 0 {
// Only visible batch keys are included when an Iterator's batch spans
// are fragmented. They must always be visible.
return kseq > seqNum
} else if kseq < snapshot {
return kseq > seqNum
}
}
return false
}
// String returns a string representation of the span.
func (s Span) String() string {
return fmt.Sprint(prettySpan{Span: s, formatKey: base.DefaultFormatter})
@@ -223,10 +388,12 @@ func (s prettySpan) Format(fs fmt.State, c rune) {
fmt.Fprintf(fs, "}")
}
// SortKeys sorts a keys slice by trailer.
func SortKeys(keys []Key) {
sorted := keysBySeqNumKind(keys)
sort.Sort(&sorted)
// 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)
sort.Sort(sorted)
}
// ParseSpan parses the string representation of a Span. It's intended for

View File

@@ -12,7 +12,7 @@ import "github.com/cockroachdb/pebble/internal/base"
func Truncate(
cmp base.Compare, iter FragmentIterator, lower, upper []byte, start, end *base.InternalKey,
) FragmentIterator {
return Filter(iter, func(in Span, out *Span) (keep bool) {
return Filter(iter, func(in *Span, out *Span) (keep bool) {
out.Start, out.End = in.Start, in.End
out.Keys = append(out.Keys[:0], in.Keys...)