Upgrade versions of vendored libs
This commit is contained in:
265
vendor/github.com/cockroachdb/pebble/internal/keyspan/bounded.go
generated
vendored
Normal file
265
vendor/github.com/cockroachdb/pebble/internal/keyspan/bounded.go
generated
vendored
Normal 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
|
||||
}
|
||||
178
vendor/github.com/cockroachdb/pebble/internal/keyspan/defragment.go
generated
vendored
178
vendor/github.com/cockroachdb/pebble/internal/keyspan/defragment.go
generated
vendored
@@ -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
|
||||
|
||||
24
vendor/github.com/cockroachdb/pebble/internal/keyspan/filter.go
generated
vendored
24
vendor/github.com/cockroachdb/pebble/internal/keyspan/filter.go
generated
vendored
@@ -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
|
||||
|
||||
6
vendor/github.com/cockroachdb/pebble/internal/keyspan/fragmenter.go
generated
vendored
6
vendor/github.com/cockroachdb/pebble/internal/keyspan/fragmenter.go
generated
vendored
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
16
vendor/github.com/cockroachdb/pebble/internal/keyspan/get.go
generated
vendored
16
vendor/github.com/cockroachdb/pebble/internal/keyspan/get.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
697
vendor/github.com/cockroachdb/pebble/internal/keyspan/interleaving_iter.go
generated
vendored
697
vendor/github.com/cockroachdb/pebble/internal/keyspan/interleaving_iter.go
generated
vendored
File diff suppressed because it is too large
Load Diff
40
vendor/github.com/cockroachdb/pebble/internal/keyspan/internal_iter_shim.go
generated
vendored
40
vendor/github.com/cockroachdb/pebble/internal/keyspan/internal_iter_shim.go
generated
vendored
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
66
vendor/github.com/cockroachdb/pebble/internal/keyspan/iter.go
generated
vendored
66
vendor/github.com/cockroachdb/pebble/internal/keyspan/iter.go
generated
vendored
@@ -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.
|
||||
|
||||
208
vendor/github.com/cockroachdb/pebble/internal/keyspan/level_iter.go
generated
vendored
208
vendor/github.com/cockroachdb/pebble/internal/keyspan/level_iter.go
generated
vendored
@@ -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
|
||||
|
||||
263
vendor/github.com/cockroachdb/pebble/internal/keyspan/merging_iter.go
generated
vendored
263
vendor/github.com/cockroachdb/pebble/internal/keyspan/merging_iter.go
generated
vendored
@@ -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 {
|
||||
|
||||
40
vendor/github.com/cockroachdb/pebble/internal/keyspan/seek.go
generated
vendored
40
vendor/github.com/cockroachdb/pebble/internal/keyspan/seek.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
233
vendor/github.com/cockroachdb/pebble/internal/keyspan/span.go
generated
vendored
233
vendor/github.com/cockroachdb/pebble/internal/keyspan/span.go
generated
vendored
@@ -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
|
||||
|
||||
2
vendor/github.com/cockroachdb/pebble/internal/keyspan/truncate.go
generated
vendored
2
vendor/github.com/cockroachdb/pebble/internal/keyspan/truncate.go
generated
vendored
@@ -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...)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user