Initial commit

This commit is contained in:
eleksir
2025-05-08 18:12:52 +03:00
commit b21e3c84c0
1553 changed files with 649819 additions and 0 deletions

View File

@@ -0,0 +1,268 @@
// 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.
//
// hasPrefix and prefix are allowed to be nil, however if hasPrefix != nil,
// prefix must also not be nil.
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 != 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 != 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 != 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 != nil && *i.hasPrefix && i.cmp(span.End, *i.prefix) <= 0 {
// This span ends before the current prefix.
span = nil
}
return span
}
// checkBackward enforces the lower bound, returning nil if the provided span is
// wholly outside the lower bound. It also updates i.pos and i.iterSpan to
// reflect the new iterator position.
func (i *BoundedIter) checkBackwardBound(span *Span) *Span {
// Compare to the lower bound.
if span != nil && i.lower != nil && i.cmp(span.End, i.lower) <= 0 {
span = nil
}
i.iterSpan = span
if i.pos != posAtIterSpan {
i.pos = posAtIterSpan
}
return span
}

View File

@@ -0,0 +1,539 @@
// 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 (
"bytes"
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/internal/bytealloc"
"github.com/cockroachdb/pebble/internal/invariants"
)
// bufferReuseMaxCapacity is the maximum capacity of a DefragmentingIter buffer
// that DefragmentingIter will reuse. Buffers larger than this will be
// discarded and reallocated as necessary.
const bufferReuseMaxCapacity = 10 << 10 // 10 KB
// keysReuseMaxCapacity is the maximum capacity of a []keyspan.Key buffer that
// DefragmentingIter will reuse. Buffers larger than this will be discarded and
// reallocated as necessary.
const keysReuseMaxCapacity = 100
// DefragmentMethod configures the defragmentation performed by the
// DefragmentingIter.
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. It requires spans' keys to be sorted in
// trailer descending order.
//
// This defragmenting method is intended for use in compactions that may see
// internal range keys fragments that may now be joined, because the state that
// required their fragmentation has been dropped.
var DefragmentInternal DefragmentMethod = DefragmentMethodFunc(func(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
}
for i := range a.Keys {
if a.Keys[i].Trailer != b.Keys[i].Trailer {
return false
}
if !equal(a.Keys[i].Suffix, b.Keys[i].Suffix) {
return false
}
if !bytes.Equal(a.Keys[i].Value, b.Keys[i].Value) {
return false
}
}
return true
})
// DefragmentReducer merges the current and next Key slices, returning a new Key
// slice.
//
// Implementations should modify and return `cur` to save on allocations, or
// consider allocating a new slice, as the `cur` slice may be retained by the
// DefragmentingIter and mutated. The `next` slice must not be mutated.
//
// The incoming slices are sorted by (SeqNum, Kind) descending. The output slice
// must also have this sort order.
type DefragmentReducer func(cur, next []Key) []Key
// StaticDefragmentReducer is a no-op DefragmentReducer that simply returns the
// current key slice, effectively retaining the first set of keys encountered
// for a defragmented span.
//
// This reducer can be used, for example, when the set of Keys for each Span
// being reduced is not expected to change, and therefore the keys from the
// first span encountered can be used without considering keys in subsequent
// spans.
var StaticDefragmentReducer DefragmentReducer = func(cur, _ []Key) []Key {
return cur
}
// iterPos is an enum indicating the position of the defragmenting iter's
// wrapped iter. The defragmenting iter must look ahead or behind when
// defragmenting forward or backwards respectively, and this enum records that
// current position.
type iterPos int8
const (
iterPosPrev iterPos = -1
iterPosCurr iterPos = 0
iterPosNext iterPos = +1
)
// DefragmentingIter wraps a key span iterator, defragmenting physical
// fragmentation during iteration.
//
// During flushes and compactions, keys applied over a span may be split at
// sstable boundaries. This fragmentation can produce internal key bounds that
// do not match any of the bounds ever supplied to a user operation. This
// physical fragmentation is necessary to avoid excessively wide sstables.
//
// The defragmenting iterator undoes this physical fragmentation, joining spans
// with abutting bounds and equal state. The defragmenting iterator takes a
// DefragmentMethod to determine what is "equal state" for a span. The
// DefragmentMethod is a function type, allowing arbitrary comparisons between
// Span keys.
//
// Seeking (SeekGE, SeekLT) poses an obstacle to defragmentation. A seek may
// land on a physical fragment in the middle of several fragments that must be
// defragmented. A seek that lands in a fragment straddling the seek key must
// first degfragment in the opposite direction of iteration to find the
// beginning of the defragmented span, and then defragments in the iteration
// direction, ensuring it's found a whole defragmented span.
type DefragmentingIter struct {
// DefragmentingBuffers holds buffers used for copying iterator state.
*DefragmentingBuffers
comparer *base.Comparer
equal base.Equal
iter FragmentIterator
iterSpan *Span
iterPos iterPos
// curr holds the span at the current iterator position.
curr Span
// method is a comparison function for two spans. method is called when two
// spans are abutting to determine whether they may be defragmented.
// 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.
reduce DefragmentReducer
}
// DefragmentingBuffers holds buffers used for copying iterator state.
type DefragmentingBuffers struct {
// currBuf is a buffer for use when copying user keys for curr. currBuf is
// cleared between positioning methods.
currBuf bytealloc.A
// keysBuf is a buffer for use when copying Keys for DefragmentingIter.curr.
keysBuf []Key
// keyBuf is a buffer specifically for the defragmented start key when
// defragmenting backwards or the defragmented end key when defragmenting
// forwards. These bounds are overwritten repeatedly during defragmentation,
// and the defragmentation routines overwrite keyBuf repeatedly to store
// these extended bounds.
keyBuf []byte
}
// PrepareForReuse discards any excessively large buffers.
func (bufs *DefragmentingBuffers) PrepareForReuse() {
if cap(bufs.currBuf) > bufferReuseMaxCapacity {
bufs.currBuf = nil
}
if cap(bufs.keyBuf) > bufferReuseMaxCapacity {
bufs.keyBuf = nil
}
if cap(bufs.keysBuf) > keysReuseMaxCapacity {
bufs.keysBuf = nil
}
}
// Assert that *DefragmentingIter implements the FragmentIterator interface.
var _ FragmentIterator = (*DefragmentingIter)(nil)
// Init initializes the defragmenting iter using the provided defragment
// method.
func (i *DefragmentingIter) Init(
comparer *base.Comparer,
iter FragmentIterator,
equal DefragmentMethod,
reducer DefragmentReducer,
bufs *DefragmentingBuffers,
) {
*i = DefragmentingIter{
DefragmentingBuffers: bufs,
comparer: comparer,
equal: comparer.Equal,
iter: iter,
method: equal,
reduce: reducer,
}
}
// Error returns any accumulated error.
func (i *DefragmentingIter) Error() error {
return i.iter.Error()
}
// Close closes the underlying iterators.
func (i *DefragmentingIter) Close() error {
return i.iter.Close()
}
// SeekGE moves the iterator to the first span covering a key greater than or
// equal to the given key. This is equivalent to seeking to the first span with
// an end key greater than the given key.
func (i *DefragmentingIter) SeekGE(key []byte) *Span {
i.iterSpan = i.iter.SeekGE(key)
if i.iterSpan == nil {
i.iterPos = iterPosCurr
return nil
} else if i.iterSpan.Empty() {
i.iterPos = iterPosCurr
return i.iterSpan
}
// If the span starts strictly after key, we know there mustn't be an
// earlier span that ends at i.iterSpan.Start, otherwise i.iter would've
// returned that span instead.
if i.comparer.Compare(i.iterSpan.Start, key) > 0 {
return i.defragmentForward()
}
// The span we landed on has a Start bound ≤ key. There may be additional
// fragments before this span. Defragment backward to find the start of the
// defragmented span.
i.defragmentBackward()
// Defragmenting backward may have stopped because it encountered an error.
// If so, we must not continue so that i.iter.Error() (and thus i.Error())
// yields the error.
if i.iterSpan == nil && i.iter.Error() != nil {
return nil
}
if i.iterPos == iterPosPrev {
// Next once back onto the span.
i.iterSpan = i.iter.Next()
}
// Defragment the full span from its start.
return i.defragmentForward()
}
// SeekLT moves the iterator to the last span covering a key less than the
// given key. This is equivalent to seeking to the last span with a start
// key less than the given key.
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
}
// If the span ends strictly before key, we know there mustn't be a later
// span that starts at i.iterSpan.End, otherwise i.iter would've returned
// that span instead.
if i.comparer.Compare(i.iterSpan.End, key) < 0 {
return i.defragmentBackward()
}
// The span we landed on has a End bound ≥ key. There may be additional
// fragments after this span. Defragment forward to find the end of the
// defragmented span.
i.defragmentForward()
// Defragmenting forward may have stopped because it encountered an error.
// If so, we must not continue so that i.iter.Error() (and thus i.Error())
// yields the error.
if i.iterSpan == nil && i.iter.Error() != nil {
return nil
}
if i.iterPos == iterPosNext {
// Prev once back onto the span.
i.iterSpan = i.iter.Prev()
}
// Defragment the full span from its end.
return i.defragmentBackward()
}
// First seeks the iterator to the first span and returns it.
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 {
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 {
switch i.iterPos {
case iterPosPrev:
// Switching directions; The iterator is currently positioned over the
// last span of the previous set of fragments. In the below diagram,
// the iterator is positioned over the last span that contributes to
// the defragmented x position. We want to be positioned over the first
// span that contributes to the z position.
//
// x x x y y y z z z
// ^ ^
// old new
//
// Next once to move onto y, defragment forward to land on the first z
// position.
i.iterSpan = i.iter.Next()
if invariants.Enabled && i.iterSpan == nil && i.iter.Error() == nil {
panic("pebble: invariant violation: no next span while switching directions")
}
// We're now positioned on the first span that was defragmented into the
// current iterator position. Skip over the rest of the current iterator
// 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.
return i.defragmentForward()
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 != 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")
}
}
// Prev steps back to the previous span and returns it.
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 != 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
// first fragment of the next set of fragments. In the below diagram,
// the iterator is positioned over the first span that contributes to
// the defragmented z position. We want to be positioned over the last
// span that contributes to the x position.
//
// x x x y y y z z z
// ^ ^
// new old
//
// Prev once to move onto y, defragment backward to land on the last x
// position.
i.iterSpan = i.iter.Prev()
if invariants.Enabled && i.iterSpan == nil && i.iter.Error() == nil {
panic("pebble: invariant violation: no previous span while switching directions")
}
// We're now positioned on the last span that was defragmented into the
// current iterator position. Skip over the rest of the current iterator
// position's constitutent fragments. In the above example, this would
// land on the last 'x'.
i.defragmentBackward()
// 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")
}
}
// 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 (!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. 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,
// return early.
i.iterPos = iterPosCurr
return i.iterSpan
}
i.saveCurrent()
i.iterPos = iterPosNext
i.iterSpan = i.iter.Next()
for i.iterSpan != nil {
if !i.equal(i.curr.End, i.iterSpan.Start) {
// Not a continuation.
break
}
if !i.checkEqual(i.iterSpan, &i.curr) {
// Not a continuation.
break
}
i.keyBuf = append(i.keyBuf[:0], i.iterSpan.End...)
i.curr.End = i.keyBuf
i.keysBuf = i.reduce(i.keysBuf, i.iterSpan.Keys)
i.iterSpan = i.iter.Next()
}
// i.iterSpan == nil
//
// The inner iterator may return nil when it encounters an error. If there
// was an error, we don't know whether there is another span we should
// defragment or not. Return nil so that the caller knows they should check
// Error().
if i.iter.Error() != nil {
return nil
}
i.curr.Keys = i.keysBuf
return &i.curr
}
// defragmentBackward defragments spans in the backward direction, starting from
// 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,
// return early.
i.iterPos = iterPosCurr
return i.iterSpan
}
i.saveCurrent()
i.iterPos = iterPosPrev
i.iterSpan = i.iter.Prev()
for i.iterSpan != nil {
if !i.equal(i.curr.Start, i.iterSpan.End) {
// Not a continuation.
break
}
if !i.checkEqual(i.iterSpan, &i.curr) {
// Not a continuation.
break
}
i.keyBuf = append(i.keyBuf[:0], i.iterSpan.Start...)
i.curr.Start = i.keyBuf
i.keysBuf = i.reduce(i.keysBuf, i.iterSpan.Keys)
i.iterSpan = i.iter.Prev()
}
// i.iterSpan == nil
//
// The inner iterator may return nil when it encounters an error. If there
// was an error, we don't know whether there is another span we should
// defragment or not. Return nil so that the caller knows they should check
// Error().
if i.iter.Error() != nil {
return nil
}
i.curr.Keys = i.keysBuf
return &i.curr
}
func (i *DefragmentingIter) saveCurrent() {
i.currBuf.Reset()
i.keysBuf = i.keysBuf[:0]
i.keyBuf = i.keyBuf[:0]
if i.iterSpan == nil {
return
}
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: 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
}
func (i *DefragmentingIter) saveBytes(b []byte) []byte {
if b == nil {
return nil
}
i.currBuf, b = i.currBuf.Copy(b)
return b
}

View File

@@ -0,0 +1,13 @@
// Package keyspan provides facilities for sorting, fragmenting and
// iterating over spans of user keys.
//
// A Span represents a range of user key space with an inclusive start
// key and exclusive end key. A span may hold any number of Keys which are
// applied over the entirety of the span's keyspace.
//
// Spans are used within Pebble as an in-memory representation of range
// deletion tombstones, and range key sets, unsets and deletes. Spans
// are fragmented at overlapping key boundaries by the Fragmenter type.
// This package's various iteration facilities require these
// non-overlapping fragmented spans.
package keyspan

View File

@@ -0,0 +1,115 @@
// 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"
// FilterFunc defines a transform from the input Span into the output Span. The
// function returns true if the Span should be returned by the iterator, and
// false if the Span should be skipped. The FilterFunc is permitted to mutate
// 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)
// filteringIter is a FragmentIterator that uses a FilterFunc to select which
// Spans from the input iterator are returned in the output.
//
// A note on Span lifetimes: as the FilterFunc reuses a Span with a mutable
// slice of Keys to reduce allocations, Spans returned by this iterator are only
// valid until the next relative or absolute positioning method is called.
type filteringIter struct {
iter FragmentIterator
filterFn FilterFunc
cmp base.Compare
// span is a mutable Span passed to the filterFn. The filterFn is free to
// mutate this Span. The slice of Keys in the Span is reused with every call
// to the filterFn.
span Span
}
var _ FragmentIterator = (*filteringIter)(nil)
// Filter returns a new filteringIter that will filter the Spans from the
// provided child iterator using the provided FilterFunc.
func Filter(iter FragmentIterator, filter FilterFunc, cmp base.Compare) FragmentIterator {
return &filteringIter{iter: iter, filterFn: filter, cmp: cmp}
}
// SeekGE implements FragmentIterator.
func (i *filteringIter) SeekGE(key []byte) *Span {
span := i.filter(i.iter.SeekGE(key), +1)
// i.filter could return a span that's less than key, _if_ the filterFunc
// (which has no knowledge of the seek key) mutated the span to end at a key
// less than or equal to `key`. Detect this case and next/invalidate the iter.
if span != nil && i.cmp(span.End, key) <= 0 {
return i.Next()
}
return span
}
// SeekLT implements FragmentIterator.
func (i *filteringIter) SeekLT(key []byte) *Span {
span := i.filter(i.iter.SeekLT(key), -1)
// i.filter could return a span that's >= key, _if_ the filterFunc (which has
// no knowledge of the seek key) mutated the span to start at a key greater
// than or equal to `key`. Detect this case and prev/invalidate the iter.
if span != nil && i.cmp(span.Start, key) >= 0 {
return i.Prev()
}
return span
}
// First implements FragmentIterator.
func (i *filteringIter) First() *Span {
return i.filter(i.iter.First(), +1)
}
// Last implements FragmentIterator.
func (i *filteringIter) Last() *Span {
return i.filter(i.iter.Last(), -1)
}
// Next implements FragmentIterator.
func (i *filteringIter) Next() *Span {
return i.filter(i.iter.Next(), +1)
}
// Prev implements FragmentIterator.
func (i *filteringIter) Prev() *Span {
return i.filter(i.iter.Prev(), -1)
}
// Error implements FragmentIterator.
func (i *filteringIter) Error() error {
return i.iter.Error()
}
// Close implements FragmentIterator.
func (i *filteringIter) Close() error {
return i.iter.Close()
}
// filter uses the filterFn (if configured) to filter and possibly mutate the
// 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 {
if i.filterFn == nil {
return span
}
for i.Error() == nil && span != nil {
if keep := i.filterFn(span, &i.span); keep {
return &i.span
}
if dir == +1 {
span = i.iter.Next()
} else {
span = i.iter.Prev()
}
}
return span
}

View File

@@ -0,0 +1,483 @@
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package keyspan
import (
"fmt"
"sort"
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/internal/invariants"
)
type spansByStartKey struct {
cmp base.Compare
buf []Span
}
func (v *spansByStartKey) Len() int { return len(v.buf) }
func (v *spansByStartKey) Less(i, j int) bool {
return v.cmp(v.buf[i].Start, v.buf[j].Start) < 0
}
func (v *spansByStartKey) Swap(i, j int) {
v.buf[i], v.buf[j] = v.buf[j], v.buf[i]
}
type spansByEndKey struct {
cmp base.Compare
buf []Span
}
func (v *spansByEndKey) Len() int { return len(v.buf) }
func (v *spansByEndKey) Less(i, j int) bool {
return v.cmp(v.buf[i].End, v.buf[j].End) < 0
}
func (v *spansByEndKey) Swap(i, j int) {
v.buf[i], v.buf[j] = v.buf[j], v.buf[i]
}
// keysBySeqNumKind sorts spans by the start key's sequence number in
// descending order. If two spans have equal sequence number, they're compared
// by key kind in descending order. This ordering matches the ordering of
// base.InternalCompare among keys with matching user keys.
type keysBySeqNumKind []Key
func (v *keysBySeqNumKind) Len() int { return len(*v) }
func (v *keysBySeqNumKind) Less(i, j int) bool { return (*v)[i].Trailer > (*v)[j].Trailer }
func (v *keysBySeqNumKind) Swap(i, j int) { (*v)[i], (*v)[j] = (*v)[j], (*v)[i] }
// Sort the spans by start key. This is the ordering required by the
// Fragmenter. Usually spans are naturally sorted by their start key,
// but that isn't true for range deletion tombstones in the legacy
// range-del-v1 block format.
func Sort(cmp base.Compare, spans []Span) {
sorter := spansByStartKey{
cmp: cmp,
buf: spans,
}
sort.Sort(&sorter)
}
// Fragmenter fragments a set of spans such that overlapping spans are
// split at their overlap points. The fragmented spans are output to the
// supplied Output function.
type Fragmenter struct {
Cmp base.Compare
Format base.FormatKey
// Emit is called to emit a fragmented span and its keys. Every key defined
// within the emitted Span applies to the entirety of the Span's key span.
// Keys are ordered in decreasing order of their sequence numbers, and if
// equal, decreasing order of key kind.
Emit func(Span)
// pending contains the list of pending fragments that have not been
// flushed to the block writer. Note that the spans have not been
// fragmented on the end keys yet. That happens as the spans are
// flushed. All pending spans have the same Start.
pending []Span
// doneBuf is used to buffer completed span fragments when flushing to a
// specific key (e.g. TruncateAndFlushTo). It is cached in the Fragmenter to
// allow reuse.
doneBuf []Span
// sortBuf is used to sort fragments by end key when flushing.
sortBuf spansByEndKey
// flushBuf is used to sort keys by (seqnum,kind) before emitting.
flushBuf keysBySeqNumKind
// flushedKey is the key that fragments have been flushed up to. Any
// additional spans added to the fragmenter must have a start key >=
// flushedKey. A nil value indicates flushedKey has not been set.
flushedKey []byte
finished bool
}
func (f *Fragmenter) checkInvariants(buf []Span) {
for i := 1; i < len(buf); i++ {
if f.Cmp(buf[i].Start, buf[i].End) >= 0 {
panic(fmt.Sprintf("pebble: empty pending span invariant violated: %s", buf[i]))
}
if f.Cmp(buf[i-1].Start, buf[i].Start) != 0 {
panic(fmt.Sprintf("pebble: pending span invariant violated: %s %s",
f.Format(buf[i-1].Start), f.Format(buf[i].Start)))
}
}
}
// Add adds a span to the fragmenter. Spans may overlap and the
// fragmenter will internally split them. The spans must be presented in
// increasing start key order. That is, Add must be called with a series
// of spans like:
//
// a---e
// c---g
// c-----i
// j---n
// j-l
//
// We need to fragment the spans at overlap points. In the above
// example, we'd create:
//
// a-c-e
// c-e-g
// c-e-g-i
// j-l-n
// j-l
//
// The fragments need to be output sorted by start key, and for equal start
// keys, sorted by descending sequence number. This last part requires a mild
// bit of care as the fragments are not created in descending sequence number
// order.
//
// Once a start key has been seen, we know that we'll never see a smaller
// start key and can thus flush all of the fragments that lie before that
// start key.
//
// Walking through the example above, we start with:
//
// a---e
//
// Next we add [c,g) resulting in:
//
// a-c-e
// c---g
//
// The fragment [a,c) is flushed leaving the pending spans as:
//
// c-e
// c---g
//
// The next span is [c,i):
//
// c-e
// c---g
// c-----i
//
// No fragments are flushed. The next span is [j,n):
//
// c-e
// c---g
// c-----i
// j---n
//
// The fragments [c,e), [c,g) and [c,i) are flushed. We sort these fragments
// by their end key, then split the fragments on the end keys:
//
// c-e
// c-e-g
// c-e---i
//
// The [c,e) fragments all get flushed leaving:
//
// e-g
// e---i
//
// This process continues until there are no more fragments to flush.
//
// WARNING: the slices backing Start, End, Keys, Key.Suffix and Key.Value are
// all retained after this method returns and should not be modified. This is
// safe for spans that are added from a memtable or batch. It is partially
// unsafe for a span read from an sstable. Specifically, the Keys slice of a
// Span returned during sstable iteration is only valid until the next iterator
// operation. The stability of the user keys depend on whether the block is
// prefix compressed, and in practice Pebble never prefix compresses range
// 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); {
case c < 0:
panic(fmt.Sprintf("pebble: start key (%s) < flushed key (%s)",
f.Format(s.Start), f.Format(f.flushedKey)))
}
}
if f.Cmp(s.Start, s.End) >= 0 {
// An empty span, we can ignore it.
return
}
if invariants.RaceEnabled {
f.checkInvariants(f.pending)
defer func() { f.checkInvariants(f.pending) }()
}
if len(f.pending) > 0 {
// Since all of the pending spans have the same start key, we only need
// to compare against the first one.
switch c := f.Cmp(f.pending[0].Start, s.Start); {
case c > 0:
panic(fmt.Sprintf("pebble: keys must be added in order: %s > %s",
f.Format(f.pending[0].Start), f.Format(s.Start)))
case c == 0:
// The new span has the same start key as the existing pending
// spans. Add it to the pending buffer.
f.pending = append(f.pending, s)
return
}
// At this point we know that the new start key is greater than the pending
// spans start keys.
f.truncateAndFlush(s.Start)
}
f.pending = append(f.pending, s)
}
// Cover is returned by Framenter.Covers and describes a span's relationship to
// a key at a particular snapshot.
type Cover int8
const (
// NoCover indicates the tested key does not fall within the span's bounds,
// or the span contains no keys with sequence numbers higher than the key's.
NoCover Cover = iota
// CoversInvisibly indicates the tested key does fall within the span's
// bounds and the span contains at least one key with a higher sequence
// number, but none visible at the provided snapshot.
CoversInvisibly
// CoversVisibly indicates the tested key does fall within the span's
// bounds, and the span constains at least one key with a sequence number
// higher than the key's sequence number that is visible at the provided
// snapshot.
CoversVisibly
)
// Covers returns an enum indicating whether the specified key is covered by one
// of the pending keys. The provided key must be consistent with the ordering of
// the spans. That is, it is invalid to specify a key here that is out of order
// with the span start keys passed to Add.
func (f *Fragmenter) Covers(key base.InternalKey, snapshot uint64) Cover {
if f.finished {
panic("pebble: span fragmenter already finished")
}
if len(f.pending) == 0 {
return NoCover
}
if f.Cmp(f.pending[0].Start, key.UserKey) > 0 {
panic(fmt.Sprintf("pebble: keys must be in order: %s > %s",
f.Format(f.pending[0].Start), key.Pretty(f.Format)))
}
cover := NoCover
seqNum := key.SeqNum()
for _, s := range f.pending {
if f.Cmp(key.UserKey, s.End) < 0 {
// 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.
for i := range s.Keys {
if kseq := s.Keys[i].SeqNum(); kseq > seqNum {
// This key from the span has a higher sequence number than
// `key`. It covers `key`, although the span's key might not
// be visible if its snapshot is too high.
//
// Batch keys are always be visible.
if kseq < snapshot || kseq&base.InternalKeySeqNumBatch != 0 {
return CoversVisibly
}
// s.Keys[i] is not visible.
cover = CoversInvisibly
}
}
}
}
return cover
}
// Empty returns true if all fragments added so far have finished flushing.
func (f *Fragmenter) Empty() bool {
return f.finished || len(f.pending) == 0
}
// TruncateAndFlushTo flushes all of the fragments with a start key <= key,
// truncating spans to the specified end key. Used during compaction to force
// emitting of spans which straddle an sstable boundary. Consider
// the scenario:
//
// a---------k#10
// f#8
// f#7
//
// Let's say the next user key after f is g. Calling TruncateAndFlushTo(g) will
// flush this span:
//
// a-------g#10
// f#8
// f#7
//
// And leave this one in f.pending:
//
// g----k#10
//
// WARNING: The fragmenter could hold on to the specified end key. Ensure it's
// a safe byte slice that could outlast the current sstable output, and one
// that will never be modified.
func (f *Fragmenter) TruncateAndFlushTo(key []byte) {
if f.finished {
panic("pebble: span fragmenter already finished")
}
if f.flushedKey != nil {
switch c := f.Cmp(key, f.flushedKey); {
case c < 0:
panic(fmt.Sprintf("pebble: start key (%s) < flushed key (%s)",
f.Format(key), f.Format(f.flushedKey)))
}
}
if invariants.RaceEnabled {
f.checkInvariants(f.pending)
defer func() { f.checkInvariants(f.pending) }()
}
if len(f.pending) > 0 {
// Since all of the pending spans have the same start key, we only need
// to compare against the first one.
switch c := f.Cmp(f.pending[0].Start, key); {
case c > 0:
panic(fmt.Sprintf("pebble: keys must be added in order: %s > %s",
f.Format(f.pending[0].Start), f.Format(key)))
case c == 0:
return
}
}
f.truncateAndFlush(key)
}
// Start returns the start key of the first span in the pending buffer, or nil
// if there are no pending spans. The start key of all pending spans is the same
// as that of the first one.
func (f *Fragmenter) Start() []byte {
if len(f.pending) > 0 {
return f.pending[0].Start
}
return nil
}
// Flushes all pending spans up to key (exclusive).
//
// WARNING: The specified key is stored without making a copy, so all callers
// must ensure it is safe.
func (f *Fragmenter) truncateAndFlush(key []byte) {
f.flushedKey = append(f.flushedKey[:0], key...)
done := f.doneBuf[:0]
pending := f.pending
f.pending = f.pending[:0]
// pending and f.pending share the same underlying storage. As we iterate
// over pending we append to f.pending, but only one entry is appended in
// each iteration, after we have read the entry being overwritten.
for _, s := range pending {
if f.Cmp(key, s.End) < 0 {
// s: a--+--e
// new: c------
if f.Cmp(s.Start, key) < 0 {
done = append(done, Span{
Start: s.Start,
End: key,
Keys: s.Keys,
})
}
f.pending = append(f.pending, Span{
Start: key,
End: s.End,
Keys: s.Keys,
})
} else {
// s: a-----e
// new: e----
done = append(done, s)
}
}
f.doneBuf = done[:0]
f.flush(done, nil)
}
// flush a group of range spans to the block. The spans are required to all have
// the same start key. We flush all span fragments until startKey > lastKey. If
// lastKey is nil, all span fragments are flushed. The specification of a
// non-nil lastKey occurs for range deletion tombstones during compaction where
// we want to flush (but not truncate) all range tombstones that start at or
// before the first key in the next sstable. Consider:
//
// a---e#10
// a------h#9
//
// If a compaction splits the sstables at key c we want the first sstable to
// contain the tombstones [a,e)#10 and [a,e)#9. Fragmentation would naturally
// produce a tombstone [e,h)#9, but we don't need to output that tombstone to
// the first sstable.
func (f *Fragmenter) flush(buf []Span, lastKey []byte) {
if invariants.RaceEnabled {
f.checkInvariants(buf)
}
// Sort the spans by end key. This will allow us to walk over the spans and
// easily determine the next split point (the smallest end-key).
f.sortBuf.cmp = f.Cmp
f.sortBuf.buf = buf
sort.Sort(&f.sortBuf)
// Loop over the spans, splitting by end key.
for len(buf) > 0 {
// A prefix of spans will end at split. remove represents the count of
// that prefix.
remove := 1
split := buf[0].End
f.flushBuf = append(f.flushBuf[:0], buf[0].Keys...)
for i := 1; i < len(buf); i++ {
if f.Cmp(split, buf[i].End) == 0 {
remove++
}
f.flushBuf = append(f.flushBuf, buf[i].Keys...)
}
sort.Sort(&f.flushBuf)
f.Emit(Span{
Start: buf[0].Start,
End: split,
// Copy the sorted keys to a new slice.
//
// This allocation is an unfortunate side effect of the Fragmenter and
// the expectation that the spans it produces are available in-memory
// indefinitely.
//
// Eventually, we should be able to replace the fragmenter with the
// keyspan.MergingIter which will perform just-in-time
// fragmentation, and only guaranteeing the memory lifetime for the
// current span. The MergingIter fragments while only needing to
// access one Span per level. It only accesses the Span at the
// current position for each level. During compactions, we can write
// these spans to sstables without retaining previous Spans.
Keys: append([]Key(nil), f.flushBuf...),
})
if lastKey != nil && f.Cmp(split, lastKey) > 0 {
break
}
// Adjust the start key for every remaining span.
buf = buf[remove:]
for i := range buf {
buf[i].Start = split
}
}
}
// Finish flushes any remaining fragments to the output. It is an error to call
// this if any other spans will be added.
func (f *Fragmenter) Finish() {
if f.finished {
panic("pebble: span fragmenter already finished")
}
f.flush(f.pending, nil)
f.finished = true
}

View File

@@ -0,0 +1,53 @@
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package keyspan
import "github.com/cockroachdb/pebble/internal/base"
// Get returns the newest span that contains the target key. If no span
// contains the target key, an empty span is returned. The snapshot
// 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) *Span {
// NB: We use SeekLT in order to land on the proper span for a search
// key that resides in the middle of a span. Consider the scenario:
//
// a---e
// e---i
//
// The spans are indexed by their start keys `a` and `e`. If the
// search key is `c` we want to land on the span [a,e). If we were
// to use SeekGE then the search key `c` would land on the span
// [e,i) and we'd have to backtrack. The one complexity here is what
// happens for the search key `e`. In that case SeekLT will land us
// on the span [a,e) and we'll have to move forward.
iterSpan := iter.SeekLT(key)
if iterSpan == nil {
iterSpan = iter.Next()
if iterSpan == nil {
// The iterator is empty.
return nil
}
if cmp(key, iterSpan.Start) < 0 {
// The search key lies before the first span.
return nil
}
}
// Invariant: key > iterSpan.Start
if cmp(key, iterSpan.End) >= 0 {
// The current span lies before the search key. Advance the iterator
// 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 == 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 nil
}
}
return iterSpan
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
// 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"
// InternalIteratorShim is a temporary iterator type used as a shim between
// keyspan.MergingIter and base.InternalIterator. It's used temporarily for
// range deletions during compactions, allowing range deletions to be
// interleaved by a compaction input iterator.
//
// TODO(jackson): This type should be removed, and the usages converted to using
// an InterleavingIterator type that interleaves keyspan.Spans from a
// keyspan.FragmentIterator with point keys.
type InternalIteratorShim struct {
miter MergingIter
mbufs MergingBuffers
span *Span
iterKey base.InternalKey
}
// Assert that InternalIteratorShim implements InternalIterator.
var _ base.InternalIterator = &InternalIteratorShim{}
// Init initializes the internal iterator shim to merge the provided fragment
// iterators.
func (i *InternalIteratorShim) Init(cmp base.Compare, iters ...FragmentIterator) {
i.miter.Init(cmp, noopTransform, &i.mbufs, iters...)
}
// Span returns the span containing the full set of keys over the key span at
// the current iterator position.
func (i *InternalIteratorShim) Span() *Span {
return i.span
}
// SeekGE implements (base.InternalIterator).SeekGE.
func (i *InternalIteratorShim) SeekGE(
key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
func (i *InternalIteratorShim) SeekPrefixGE(
prefix, key []byte, flags base.SeekGEFlags,
) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// SeekLT implements (base.InternalIterator).SeekLT.
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, base.LazyValue) {
i.span = i.miter.First()
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if i.span == nil {
return nil, base.LazyValue{}
}
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
return &i.iterKey, base.MakeInPlaceValue(i.span.End)
}
// Last implements (base.InternalIterator).Last.
func (i *InternalIteratorShim) Last() (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// Next implements (base.InternalIterator).Next.
func (i *InternalIteratorShim) Next() (*base.InternalKey, base.LazyValue) {
i.span = i.miter.Next()
for i.span != nil && i.span.Empty() {
i.span = i.miter.Next()
}
if i.span == nil {
return nil, base.LazyValue{}
}
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
return &i.iterKey, base.MakeInPlaceValue(i.span.End)
}
// NextPrefix implements (base.InternalIterator).NextPrefix.
func (i *InternalIteratorShim) NextPrefix([]byte) (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// Prev implements (base.InternalIterator).Prev.
func (i *InternalIteratorShim) Prev() (*base.InternalKey, base.LazyValue) {
panic("unimplemented")
}
// Error implements (base.InternalIterator).Error.
func (i *InternalIteratorShim) Error() error {
return i.miter.Error()
}
// Close implements (base.InternalIterator).Close.
func (i *InternalIteratorShim) Close() error {
return i.miter.Close()
}
// SetBounds implements (base.InternalIterator).SetBounds.
func (i *InternalIteratorShim) SetBounds(lower, upper []byte) {
}
// String implements fmt.Stringer.
func (i *InternalIteratorShim) String() string {
return i.miter.String()
}

View File

@@ -0,0 +1,220 @@
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package keyspan
import (
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/internal/manifest"
)
// FragmentIterator defines an iterator interface over spans. The spans
// surfaced by a FragmentIterator must be non-overlapping. This is achieved by
// fragmenting spans at overlap points (see Fragmenter).
//
// A Span returned by a FragmentIterator is only valid until the next
// positioning method. Some implementations (eg, keyspan.Iter) may provide
// longer lifetimes but implementations need only guarantee stability until the
// next positioning method.
type FragmentIterator interface {
// SeekGE moves the iterator to the first span covering a key greater than
// or equal to the given key. This is equivalent to seeking to the first
// span with an end key greater than the given key.
SeekGE(key []byte) *Span
// SeekLT moves the iterator to the last span covering a key less than the
// given key. This is equivalent to seeking to the last span with a start
// key less than the given key.
SeekLT(key []byte) *Span
// First moves the iterator to the first span.
First() *Span
// Last moves the iterator to the last span.
Last() *Span
// Next moves the iterator to the next span.
//
// It is valid to call Next when the iterator is positioned before the first
// 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
// Prev moves the iterator to the previous span.
//
// It is valid to call Prev when the iterator is positioned after the last
// 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
// Error returns any accumulated error.
//
// TODO(jackson): Lift errors into return values on the positioning methods.
Error() error
// Close closes the iterator and returns any accumulated error. Exhausting
// the iterator is not considered to be an error. It is valid to call Close
// multiple times. Other methods should not be called after the iterator has
// been closed.
Close() error
}
// TableNewSpanIter creates a new iterator for range key spans for the given
// file.
type TableNewSpanIter func(file *manifest.FileMetadata, iterOptions SpanIterOptions) (FragmentIterator, error)
// SpanIterOptions is a subset of IterOptions that are necessary to instantiate
// per-sstable span iterators.
type SpanIterOptions struct {
// RangeKeyFilters can be used to avoid scanning tables and blocks in tables
// when iterating over range keys.
RangeKeyFilters []base.BlockPropertyFilter
}
// Iter is an iterator over a set of fragmented spans.
type Iter struct {
cmp base.Compare
spans []Span
index int
}
// Iter implements the FragmentIterator interface.
var _ FragmentIterator = (*Iter)(nil)
// NewIter returns a new iterator over a set of fragmented spans.
func NewIter(cmp base.Compare, spans []Span) *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,
}
}
// SeekGE implements FragmentIterator.SeekGE.
func (i *Iter) SeekGE(key []byte) *Span {
// NB: manually inlined sort.Search is ~5% faster.
//
// Define f(j) = false iff the span i.spans[j] is strictly before `key`
// (equivalently, i.spans[j].End ≤ key.)
//
// Define f(-1) == false and f(n) == true.
// Invariant: f(index-1) == false, f(upper) == true.
i.index = 0
upper := len(i.spans)
for i.index < upper {
h := int(uint(i.index+upper) >> 1) // avoid overflow when computing h
// i.index ≤ h < upper
if i.cmp(key, i.spans[h].End) >= 0 {
i.index = h + 1 // preserves f(i-1) == false
} else {
upper = h // preserves f(j) == true
}
}
// 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 nil
}
return &i.spans[i.index]
}
// SeekLT implements FragmentIterator.SeekLT.
func (i *Iter) SeekLT(key []byte) *Span {
// NB: manually inlined sort.Search is ~5% faster.
//
// Define f(-1) == false and f(n) == true.
// Invariant: f(index-1) == false, f(upper) == true.
i.index = 0
upper := len(i.spans)
for i.index < upper {
h := int(uint(i.index+upper) >> 1) // avoid overflow when computing h
// i.index ≤ h < upper
if i.cmp(key, i.spans[h].Start) > 0 {
i.index = h + 1 // preserves f(i-1) == false
} else {
upper = h // preserves f(j) == true
}
}
// i.index == upper, f(i.index-1) == false, and f(upper) (= f(i.index)) ==
// true => answer is i.index.
// Since keys are strictly increasing, if i.index > 0 then i.index-1 will be
// the largest whose key is < the key sought.
i.index--
if i.index < 0 {
return nil
}
return &i.spans[i.index]
}
// First implements FragmentIterator.First.
func (i *Iter) First() *Span {
if len(i.spans) == 0 {
return nil
}
i.index = 0
return &i.spans[i.index]
}
// Last implements FragmentIterator.Last.
func (i *Iter) Last() *Span {
if len(i.spans) == 0 {
return nil
}
i.index = len(i.spans) - 1
return &i.spans[i.index]
}
// Next implements FragmentIterator.Next.
func (i *Iter) Next() *Span {
if i.index >= len(i.spans) {
return nil
}
i.index++
if i.index >= len(i.spans) {
return nil
}
return &i.spans[i.index]
}
// Prev implements FragmentIterator.Prev.
func (i *Iter) Prev() *Span {
if i.index < 0 {
return nil
}
i.index--
if i.index < 0 {
return nil
}
return &i.spans[i.index]
}
// Error implements FragmentIterator.Error.
func (i *Iter) Error() error {
return nil
}
// Close implements FragmentIterator.Close.
func (i *Iter) Close() error {
return nil
}
func (i *Iter) String() string {
return "fragmented-spans"
}

View File

@@ -0,0 +1,521 @@
// 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 (
"fmt"
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/internal/invariants"
"github.com/cockroachdb/pebble/internal/manifest"
)
// LevelIter provides a merged view of spans from sstables in a level.
// It takes advantage of level invariants to only have one sstable span block
// open at one time, opened using the newIter function passed in.
type LevelIter struct {
cmp base.Compare
// Denotes the kind of key the level iterator should read. If the key type
// is KeyTypePoint, the level iterator will read range tombstones (which
// only affect point keys). If the key type is KeyTypeRange, the level
// iterator will read range keys. It is invalid to configure an iterator
// with the KeyTypePointAndRange key type.
//
// If key type is KeyTypePoint, no straddle spans are emitted between files,
// and point key bounds are used to find files instead of range key bounds.
//
// TODO(bilal): Straddle spans can safely be produced in rangedel mode once
// we can guarantee that we will never read sstables in a level that split
// user keys across them. This might be guaranteed in a future release, but
// as of CockroachDB 22.2 it is not guaranteed, so to be safe disable it when
// keyType == KeyTypePoint
keyType manifest.KeyType
// The LSM level this LevelIter is initialized for. Used in logging.
level manifest.Level
// The below fields are used to fill in gaps between adjacent files' range
// 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 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
// on a straddle key therefore necessitates the value of iterFile to be
// reverted.
dir int
straddle Span
straddleDir int
// The iter for the current file (iterFile). It is nil under any of the
// following conditions:
// - files.Current() == nil
// - err != nil
// - 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.
iter FragmentIterator
// iterFile holds the current file.
// INVARIANT: iterFile = files.Current()
iterFile *manifest.FileMetadata
newIter TableNewSpanIter
files manifest.LevelIterator
err error
// The options that were passed in.
tableOpts SpanIterOptions
// TODO(bilal): Add InternalIteratorStats.
}
// LevelIter implements the keyspan.FragmentIterator interface.
var _ FragmentIterator = (*LevelIter)(nil)
// NewLevelIter returns a LevelIter.
func NewLevelIter(
opts SpanIterOptions,
cmp base.Compare,
newIter TableNewSpanIter,
files manifest.LevelIterator,
level manifest.Level,
keyType manifest.KeyType,
) *LevelIter {
l := &LevelIter{}
l.Init(opts, cmp, newIter, files, level, keyType)
return l
}
// Init initializes a LevelIter.
func (l *LevelIter) Init(
opts SpanIterOptions,
cmp base.Compare,
newIter TableNewSpanIter,
files manifest.LevelIterator,
level manifest.Level,
keyType manifest.KeyType,
) {
l.err = nil
l.level = level
l.tableOpts = opts
l.cmp = cmp
l.iterFile = nil
l.newIter = newIter
switch keyType {
case manifest.KeyTypePoint:
l.keyType = keyType
l.files = files.Filter(keyType)
case manifest.KeyTypeRange:
l.keyType = keyType
l.files = files.Filter(keyType)
default:
panic(fmt.Sprintf("unsupported key type: %v", keyType))
}
}
func (l *LevelIter) findFileGE(key []byte) *manifest.FileMetadata {
// Find the earliest file whose largest key is >= key.
//
// If the earliest file has its largest key == key and that largest key is a
// range deletion sentinel, we know that we manufactured this sentinel to convert
// the exclusive range deletion end key into an inclusive key (reminder: [start, end)#seqnum
// is the form of a range deletion sentinel which can contribute a largest key = end#sentinel).
// In this case we don't return this as the earliest file since there is nothing actually
// equal to key in it.
m := l.files.SeekGE(l.cmp, key)
for m != nil {
largestKey := m.LargestRangeKey
if l.keyType == manifest.KeyTypePoint {
largestKey = m.LargestPointKey
}
if !largestKey.IsExclusiveSentinel() || l.cmp(largestKey.UserKey, key) != 0 {
break
}
m = l.files.Next()
}
return m
}
func (l *LevelIter) findFileLT(key []byte) *manifest.FileMetadata {
// Find the last file whose smallest key is < key.
return l.files.SeekLT(l.cmp, key)
}
type loadFileReturnIndicator int8
const (
noFileLoaded loadFileReturnIndicator = iota
fileAlreadyLoaded
newFileLoaded
)
func (l *LevelIter) loadFile(file *manifest.FileMetadata, dir int) loadFileReturnIndicator {
indicator := noFileLoaded
if l.iterFile == file {
if l.err != nil {
return noFileLoaded
}
if l.iter != nil {
// We are already at the file, but we would need to check for bounds.
// Set indicator accordingly.
indicator = fileAlreadyLoaded
}
// We were already at file, but don't have an iterator, probably because the file was
// beyond the iteration bounds. It may still be, but it is also possible that the bounds
// have changed. We handle that below.
}
// Note that LevelIter.Close() can be called multiple times.
if indicator != fileAlreadyLoaded {
if err := l.Close(); err != nil {
return noFileLoaded
}
}
l.iterFile = file
if file == nil {
return noFileLoaded
}
if indicator != fileAlreadyLoaded {
l.iter, l.err = l.newIter(file, l.tableOpts)
indicator = newFileLoaded
}
if l.err != nil {
return noFileLoaded
}
return indicator
}
// SeekGE implements keyspan.FragmentIterator.
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 {
// Peek at the previous file.
prevFile := l.files.Prev()
l.files.Next()
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.
// Return a straddling key instead of loading the file.
l.iterFile = f
if err := l.Close(); err != nil {
return l.verify(nil)
}
l.straddleDir = +1
l.straddle = Span{
Start: prevFile.LargestRangeKey.UserKey,
End: f.SmallestRangeKey.UserKey,
Keys: nil,
}
return l.verify(&l.straddle)
}
}
loadFileIndicator := l.loadFile(f, +1)
if loadFileIndicator == noFileLoaded {
return l.verify(nil)
}
if span := l.iter.SeekGE(key); span != nil {
return l.verify(span)
}
return l.skipEmptyFileForward()
}
// SeekLT implements keyspan.FragmentIterator.
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 {
// Peek at the next file.
nextFile := l.files.Next()
l.files.Prev()
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.
// Return a straddling key instead of loading the file.
l.iterFile = f
if err := l.Close(); err != nil {
return l.verify(nil)
}
l.straddleDir = -1
l.straddle = Span{
Start: f.LargestRangeKey.UserKey,
End: nextFile.SmallestRangeKey.UserKey,
Keys: nil,
}
return l.verify(&l.straddle)
}
}
if l.loadFile(f, -1) == noFileLoaded {
return l.verify(nil)
}
if span := l.iter.SeekLT(key); span != nil {
return l.verify(span)
}
return l.skipEmptyFileBackward()
}
// First implements keyspan.FragmentIterator.
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 l.verify(nil)
}
if span := l.iter.First(); span != nil {
return l.verify(span)
}
return l.skipEmptyFileForward()
}
// Last implements keyspan.FragmentIterator.
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 l.verify(nil)
}
if span := l.iter.Last(); span != nil {
return l.verify(span)
}
return l.skipEmptyFileBackward()
}
// Next implements keyspan.FragmentIterator.
func (l *LevelIter) Next() *Span {
if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir > 0) {
return l.verify(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 != nil {
return l.verify(span)
}
}
return l.skipEmptyFileForward()
}
// Prev implements keyspan.FragmentIterator.
func (l *LevelIter) Prev() *Span {
if l.err != nil || (l.iter == nil && l.iterFile == nil && l.dir < 0) {
return l.verify(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 != nil {
return l.verify(span)
}
}
return l.skipEmptyFileBackward()
}
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
// 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 err := l.Close(); err != nil {
l.err = err
return l.verify(nil)
}
startKey := l.iterFile.LargestRangeKey.UserKey
// Resetting l.iterFile without loading the file into l.iter is okay and
// does not change the logic in loadFile() as long as l.iter is also nil;
// which it should be due to the Close() call above.
l.iterFile = l.files.Next()
if l.iterFile == nil {
return l.verify(nil)
}
endKey := l.iterFile.SmallestRangeKey.UserKey
if l.cmp(startKey, endKey) < 0 {
// There is a gap between the two files. Synthesize a straddling span
// to avoid unnecessarily loading the next file.
l.straddle = Span{
Start: startKey,
End: endKey,
}
l.straddleDir = +1
return l.verify(&l.straddle)
}
} 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{}
l.straddleDir = 0
var span *Span
for span.Empty() {
fileToLoad := l.iterFile
if l.keyType == manifest.KeyTypePoint {
// We haven't iterated to the next file yet if we're in point key
// (rangedel) mode.
fileToLoad = l.files.Next()
}
if l.loadFile(fileToLoad, +1) == noFileLoaded {
return l.verify(nil)
}
span = l.iter.First()
// In rangedel mode, we can expect to get empty files that we'd need to
// skip over, but not in range key mode.
if l.keyType == manifest.KeyTypeRange {
break
}
}
return l.verify(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.straddleDir == 0 && l.keyType == manifest.KeyTypeRange &&
l.iterFile != nil && l.iter != nil {
if err := l.Close(); err != nil {
l.err = err
return l.verify(nil)
}
endKey := l.iterFile.SmallestRangeKey.UserKey
// Resetting l.iterFile without loading the file into l.iter is okay and
// does not change the logic in loadFile() as long as l.iter is also nil;
// which it should be due to the Close() call above.
l.iterFile = l.files.Prev()
if l.iterFile == nil {
return l.verify(nil)
}
startKey := l.iterFile.LargestRangeKey.UserKey
if l.cmp(startKey, endKey) < 0 {
// There is a gap between the two files. Synthesize a straddling span
// to avoid unnecessarily loading the next file.
l.straddle = Span{
Start: startKey,
End: endKey,
}
l.straddleDir = -1
return l.verify(&l.straddle)
}
} 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{}
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 l.verify(nil)
}
span = l.iter.Last()
// In rangedel mode, we can expect to get empty files that we'd need to
// skip over, but not in range key mode as the filter on the FileMetadata
// should guarantee we always get a non-empty file.
if l.keyType == manifest.KeyTypeRange {
break
}
}
return l.verify(span)
}
// verify is invoked whenever a span is returned from an iterator positioning
// method to a caller. During invariant builds, it asserts invariants to the
// caller.
func (l *LevelIter) verify(s *Span) *Span {
// NB: Do not add any logic outside the invariants.Enabled conditional to
// ensure that verify is always compiled away in production builds.
if invariants.Enabled {
if f := l.files.Current(); f != l.iterFile {
panic(fmt.Sprintf("LevelIter.files.Current (%s) and l.iterFile (%s) diverged",
f, l.iterFile))
}
}
return s
}
// Error implements keyspan.FragmentIterator.
func (l *LevelIter) Error() error {
if l.err != nil || l.iter == nil {
return l.err
}
return l.iter.Error()
}
// Close implements keyspan.FragmentIterator.
func (l *LevelIter) Close() error {
if l.iter != nil {
l.err = l.iter.Close()
l.iter = nil
}
return l.err
}
// String implements keyspan.FragmentIterator.
func (l *LevelIter) String() string {
if l.iterFile != nil {
return fmt.Sprintf("%s: fileNum=%s", l.level, l.iterFile.FileNum)
}
return fmt.Sprintf("%s: fileNum=<nil>", l.level)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package keyspan
import "github.com/cockroachdb/pebble/internal/base"
// 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:
//
// a---e
// e---i
//
// The spans are indexed by their start keys `a` and `e`. If the
// search key is `c` we want to land on the span [a,e). If we were to
// use SeekGE then the search key `c` would land on the span [e,i) and
// we'd have to backtrack. The one complexity here is what happens for the
// search key `e`. In that case SeekLT will land us on the span [a,e)
// and we'll have to move forward.
iterSpan := iter.SeekLT(key)
if iterSpan == nil {
// Advance the iterator once to see if the next span has a start key
// equal to key.
iterSpan = iter.Next()
if iterSpan == nil || cmp(key, iterSpan.Start) < 0 {
// The iterator is exhausted or we've hit the next span.
return nil
}
} else {
// Invariant: key > iterSpan.Start
if cmp(key, iterSpan.End) >= 0 {
// The current span lies entirely before the search key. Check to see if
// the next span contains the search key. If it doesn't, we'll backup
// and return to our earlier candidate.
iterSpan = iter.Next()
if iterSpan == 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()
}
}
}
return iterSpan
}

View File

@@ -0,0 +1,467 @@
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package keyspan // import "github.com/cockroachdb/pebble/internal/keyspan"
import (
"bytes"
"fmt"
"sort"
"strconv"
"strings"
"unicode"
"github.com/cockroachdb/pebble/internal/base"
)
// Span represents a set of keys over a span of user key space. All of the keys
// within a Span are applied across the span's key span indicated by Start and
// End. Each internal key applied over the user key span appears as a separate
// Key, with its own kind and sequence number. Optionally, each Key may also
// have a Suffix and/or Value.
//
// Note that the start user key is inclusive and the end user key is exclusive.
//
// Currently the only supported key kinds are:
//
// RANGEDEL, RANGEKEYSET, RANGEKEYUNSET, RANGEKEYDEL.
type Span struct {
// Start and End encode the user key range of all the contained items, with
// an inclusive start key and exclusive end key. Both Start and End must be
// 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, 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
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.
type Key struct {
// Trailer contains the key kind and sequence number.
Trailer uint64
// Suffix holds an optional suffix associated with the key. This is only
// non-nil for RANGEKEYSET and RANGEKEYUNSET keys.
Suffix []byte
// Value holds a logical value associated with the Key. It is NOT the
// internal value stored in a range key or range deletion block. This is
// only non-nil for RANGEKEYSET keys.
Value []byte
}
// SeqNum returns the sequence number component of the key.
func (k Key) SeqNum() uint64 {
return k.Trailer >> 8
}
// VisibleAt returns true if the provided key is visible at the provided
// snapshot sequence number. It interprets batch sequence numbers as always
// visible, because non-visible batch span keys are filtered when they're
// fragmented.
func (k Key) VisibleAt(snapshot uint64) bool {
seq := k.SeqNum()
return seq < snapshot || seq&base.InternalKeySeqNumBatch != 0
}
// Kind returns the kind component of the key.
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 {
return s.Start != nil && s.End != nil
}
// Empty returns true if the span does not contain any keys. An empty span may
// still be Valid. A non-empty span must be Valid.
//
// 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 s == nil || len(s.Keys) == 0
}
// SmallestKey returns the smallest internal key defined by the span's keys.
// It requires the Span's keys be in ByTrailerDesc order. It panics if the span
// contains no keys or its keys are sorted in a different order.
func (s *Span) SmallestKey() base.InternalKey {
if len(s.Keys) == 0 {
panic("pebble: Span contains no keys")
} else if s.KeysOrder != ByTrailerDesc {
panic("pebble: span's keys unexpectedly not in trailer order")
}
// The first key has the highest (sequence number,kind) tuple.
return base.InternalKey{
UserKey: s.Start,
Trailer: s.Keys[0].Trailer,
}
}
// LargestKey returns the largest internal key defined by the span's keys. The
// returned key will always be a "sentinel key" at the end boundary. The
// "sentinel key" models the exclusive end boundary by returning an InternalKey
// with the maximal sequence number, ensuring all InternalKeys with the same
// user key sort after the sentinel key.
//
// 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()
return base.MakeExclusiveSentinelKey(kind, s.End)
}
// SmallestSeqNum returns the smallest sequence number of a key contained within
// 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 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. 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 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 {
c := Span{
Start: s.Start,
End: s.End,
Keys: make([]Key, len(s.Keys)),
KeysOrder: s.KeysOrder,
}
copy(c.Keys, s.Keys)
return c
}
// 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 {
c := Span{
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)
for i := range s.Keys {
c.Keys[i].Trailer = s.Keys[i].Trailer
if len(s.Keys[i].Suffix) > 0 {
c.Keys[i].Suffix = make([]byte, len(s.Keys[i].Suffix))
copy(c.Keys[i].Suffix, s.Keys[i].Suffix)
}
if len(s.Keys[i].Value) > 0 {
c.Keys[i].Value = make([]byte, len(s.Keys[i].Value))
copy(c.Keys[i].Value, s.Keys[i].Value)
}
}
return c
}
// Contains returns true if the specified key resides within the span's bounds.
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})
}
// Pretty returns a formatter for the span.
func (s Span) Pretty(f base.FormatKey) fmt.Formatter {
// TODO(jackson): Take a base.FormatValue to format Key.Value too.
return prettySpan{s, f}
}
type prettySpan struct {
Span
formatKey base.FormatKey
}
func (s prettySpan) Format(fs fmt.State, c rune) {
if !s.Valid() {
fmt.Fprintf(fs, "<invalid>")
return
}
fmt.Fprintf(fs, "%s-%s:{", s.formatKey(s.Start), s.formatKey(s.End))
for i, k := range s.Keys {
if i > 0 {
fmt.Fprint(fs, " ")
}
fmt.Fprintf(fs, "(#%d,%s", k.SeqNum(), k.Kind())
if len(k.Suffix) > 0 || len(k.Value) > 0 {
fmt.Fprintf(fs, ",%s", k.Suffix)
}
if len(k.Value) > 0 {
fmt.Fprintf(fs, ",%s", k.Value)
}
fmt.Fprint(fs, ")")
}
fmt.Fprintf(fs, "}")
}
// 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)
}
// KeysBySuffix implements sort.Interface, sorting its member Keys slice to by
// Suffix in the order dictated by Cmp.
type KeysBySuffix struct {
Cmp base.Compare
Keys []Key
}
func (s *KeysBySuffix) Len() int { return len(s.Keys) }
func (s *KeysBySuffix) Less(i, j int) bool { return s.Cmp(s.Keys[i].Suffix, s.Keys[j].Suffix) < 0 }
func (s *KeysBySuffix) Swap(i, j int) { s.Keys[i], s.Keys[j] = s.Keys[j], s.Keys[i] }
// ParseSpan parses the string representation of a Span. It's intended for
// tests. ParseSpan panics if passed a malformed span representation.
func ParseSpan(input string) Span {
var s Span
parts := strings.FieldsFunc(input, func(r rune) bool {
switch r {
case '-', ':', '{', '}':
return true
default:
return unicode.IsSpace(r)
}
})
s.Start, s.End = []byte(parts[0]), []byte(parts[1])
// Each of the remaining parts represents a single Key.
s.Keys = make([]Key, 0, len(parts)-2)
for _, p := range parts[2:] {
keyFields := strings.FieldsFunc(p, func(r rune) bool {
switch r {
case '#', ',', '(', ')':
return true
default:
return unicode.IsSpace(r)
}
})
var k Key
// Parse the sequence number.
seqNum, err := strconv.ParseUint(keyFields[0], 10, 64)
if err != nil {
panic(fmt.Sprintf("invalid sequence number: %q: %s", keyFields[0], err))
}
// Parse the key kind.
kind := base.ParseKind(keyFields[1])
k.Trailer = base.MakeTrailer(seqNum, kind)
// Parse the optional suffix.
if len(keyFields) >= 3 {
k.Suffix = []byte(keyFields[2])
}
// Parse the optional value.
if len(keyFields) >= 4 {
k.Value = []byte(keyFields[3])
}
s.Keys = append(s.Keys, k)
}
return s
}

View File

@@ -0,0 +1,50 @@
// Copyright 2023 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"
// 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
}
// 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) Transformer {
return TransformerFunc(func(_ base.Compare, s Span, dst *Span) error {
dst.Start, dst.End = s.Start, s.End
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
})
}

View File

@@ -0,0 +1,73 @@
// Copyright 2019 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"
// Truncate creates a new iterator where every span in the supplied iterator is
// truncated to be contained within the range [lower, upper). If start and end
// are specified, filter out any spans that are completely outside those bounds.
func Truncate(
cmp base.Compare,
iter FragmentIterator,
lower, upper []byte,
start, end *base.InternalKey,
panicOnUpperTruncate bool,
) FragmentIterator {
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...)
// Ignore this span if it lies completely outside start, end. Note that
// end endInclusive indicated whether end is inclusive.
//
// The comparison between s.End and start is by user key only, as
// the span is exclusive at s.End, so comparing by user keys
// is sufficient.
if start != nil && cmp(in.End, start.UserKey) <= 0 {
return false
}
if end != nil {
v := cmp(in.Start, end.UserKey)
switch {
case v > 0:
// Wholly outside the end bound. Skip it.
return false
case v == 0:
// This span begins at the same user key as `end`. Whether or
// not any of the keys contained within the span are relevant is
// dependent on Trailers. Any keys contained within the span
// with trailers larger than end cover the small sliver of
// keyspace between [k#inf, k#<end-seqnum>]. Since keys are
// sorted descending by Trailer within the span, we need to find
// the prefix of keys with larger trailers.
for i := range in.Keys {
if in.Keys[i].Trailer < end.Trailer {
out.Keys = out.Keys[:i]
break
}
}
default:
// Wholly within the end bound. Keep it.
}
}
var truncated bool
// Truncate the bounds to lower and upper.
if cmp(in.Start, lower) < 0 {
out.Start = lower
}
if cmp(in.End, upper) > 0 {
truncated = true
out.End = upper
}
if panicOnUpperTruncate && truncated {
panic("pebble: upper bound should not be truncated")
}
return !out.Empty() && cmp(out.Start, out.End) < 0
}, cmp)
}