Initial commit
This commit is contained in:
416
vendor/github.com/cockroachdb/pebble/internal/keyspan/defragment.go
generated
vendored
Normal file
416
vendor/github.com/cockroachdb/pebble/internal/keyspan/defragment.go
generated
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
// 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/invariants"
|
||||
)
|
||||
|
||||
// bufferReuseMaxCapacity is the maximum capacity of a DefragmentingIter buffer
|
||||
// that DefragmentingIter will reuse. Buffers greater than this will be
|
||||
// discarded and reallocated as necessary.
|
||||
const bufferReuseMaxCapacity = 10 << 10 // 10 KB
|
||||
|
||||
// DefragmentMethod configures the defragmentation performed by the
|
||||
// DefragmentingIter.
|
||||
type DefragmentMethod func(base.Compare, Span, Span) bool
|
||||
|
||||
// DefragmentInternal configures a DefragmentingIter to defragment spans
|
||||
// only if they have identical keys.
|
||||
//
|
||||
// This defragmenting method is intended for use in compactions that may see
|
||||
// internal range keys fragments that may now be joined, because the state that
|
||||
// required their fragmentation has been dropped.
|
||||
var DefragmentInternal DefragmentMethod = func(cmp base.Compare, a, b Span) bool {
|
||||
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 cmp(a.Keys[i].Suffix, b.Keys[i].Suffix) != 0 {
|
||||
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 first degfragments 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 {
|
||||
cmp base.Compare
|
||||
iter FragmentIterator
|
||||
iterSpan Span
|
||||
iterPos iterPos
|
||||
|
||||
// curr holds the span at the current iterator position. currBuf is a buffer
|
||||
// for use when copying user keys for curr. keysBuf is a buffer for use when
|
||||
// copying Keys for curr. currBuf is cleared between positioning methods.
|
||||
//
|
||||
// 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.
|
||||
curr Span
|
||||
currBuf []byte
|
||||
keysBuf []Key
|
||||
keyBuf []byte
|
||||
|
||||
// equal is a comparison function for two spans. equal is called when two
|
||||
// spans are abutting to determine whether they may be defragmented.
|
||||
// equal does not itself check for adjacency for the two spans.
|
||||
equal DefragmentMethod
|
||||
|
||||
// reduce is the reducer function used to collect Keys across all spans that
|
||||
// constitute a defragmented span.
|
||||
reduce DefragmentReducer
|
||||
}
|
||||
|
||||
// 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(
|
||||
cmp base.Compare, iter FragmentIterator, equal DefragmentMethod, reducer DefragmentReducer,
|
||||
) {
|
||||
*i = DefragmentingIter{
|
||||
cmp: cmp,
|
||||
iter: iter,
|
||||
equal: 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 seeks the iterator to the first span with a start key greater than or
|
||||
// equal to key and returns it.
|
||||
func (i *DefragmentingIter) SeekGE(key []byte) Span {
|
||||
i.iterSpan = i.iter.SeekGE(key)
|
||||
if !i.iterSpan.Valid() {
|
||||
i.iterPos = iterPosCurr
|
||||
return i.iterSpan
|
||||
}
|
||||
// Save the current span and peek backwards.
|
||||
i.saveCurrent(i.iterSpan)
|
||||
i.iterSpan = i.iter.Prev()
|
||||
if i.cmp(i.curr.Start, i.iterSpan.End) == 0 && i.checkEqual(i.iterSpan, i.curr) {
|
||||
// A continuation. The span we originally landed on and defragmented
|
||||
// backwards has a true Start key < key. To obey the FragmentIterator
|
||||
// contract, we must not return this defragmented span. Defragment
|
||||
// forward to finish defragmenting the span in the forward direction.
|
||||
i.defragmentForward()
|
||||
|
||||
// Now we must be on a span that truly has a defragmented Start key >
|
||||
// key.
|
||||
return i.defragmentForward()
|
||||
}
|
||||
|
||||
// The span previous to i.curr does not defragment, so we should return it.
|
||||
// Next the underlying iterator back onto the span we previously saved to
|
||||
// i.curr and then defragment forward.
|
||||
i.iterSpan = i.iter.Next()
|
||||
return i.defragmentForward()
|
||||
}
|
||||
|
||||
// SeekLT seeks the iterator to the last span with a start key less than
|
||||
// key and returns it.
|
||||
func (i *DefragmentingIter) SeekLT(key []byte) Span {
|
||||
i.iterSpan = i.iter.SeekLT(key)
|
||||
// Defragment forward to find the end of the defragmented span.
|
||||
i.defragmentForward()
|
||||
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()
|
||||
return i.defragmentForward()
|
||||
}
|
||||
|
||||
// Last seeks the iterator to the last span and returns it.
|
||||
func (i *DefragmentingIter) Last() Span {
|
||||
i.iterSpan = i.iter.Last()
|
||||
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 !i.iterSpan.Valid() {
|
||||
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()
|
||||
|
||||
// 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.Valid() && !i.iterSpan.Empty() {
|
||||
panic("pebble: invariant violation: iterPosCurr with valid iterSpan")
|
||||
}
|
||||
|
||||
i.iterSpan = i.iter.Next()
|
||||
return i.defragmentForward()
|
||||
case iterPosNext:
|
||||
// Already at the next span.
|
||||
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.
|
||||
return i.defragmentBackward()
|
||||
case iterPosCurr:
|
||||
// iterPosCurr is only used when the iter is exhausted or when the iterator
|
||||
// is at an empty span.
|
||||
if invariants.Enabled && i.iterSpan.Valid() && !i.iterSpan.Empty() {
|
||||
panic("pebble: invariant violation: iterPosCurr with valid iterSpan")
|
||||
}
|
||||
|
||||
i.iterSpan = i.iter.Prev()
|
||||
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 !i.iterSpan.Valid() {
|
||||
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.
|
||||
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 i.equal(i.cmp, i.iterSpan, i.curr) && !(left.Empty() && right.Empty())
|
||||
}
|
||||
|
||||
// defragmentForward defragments spans in the forward direction, starting from
|
||||
// i.iter's current position.
|
||||
func (i *DefragmentingIter) defragmentForward() Span {
|
||||
if !i.iterSpan.Valid() {
|
||||
i.iterPos = iterPosCurr
|
||||
return i.iterSpan
|
||||
}
|
||||
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.iterSpan)
|
||||
|
||||
i.iterPos = iterPosNext
|
||||
i.iterSpan = i.iter.Next()
|
||||
for i.iterSpan.Valid() {
|
||||
if i.cmp(i.curr.End, i.iterSpan.Start) != 0 {
|
||||
// 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.curr.Keys = i.keysBuf
|
||||
return i.curr
|
||||
}
|
||||
|
||||
// defragmentBackward defragments spans in the backward direction, starting from
|
||||
// i.iter's current position.
|
||||
func (i *DefragmentingIter) defragmentBackward() Span {
|
||||
if !i.iterSpan.Valid() {
|
||||
i.iterPos = iterPosCurr
|
||||
return i.iterSpan
|
||||
}
|
||||
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.iterSpan)
|
||||
|
||||
i.iterPos = iterPosPrev
|
||||
i.iterSpan = i.iter.Prev()
|
||||
for i.iterSpan.Valid() {
|
||||
if i.cmp(i.curr.Start, i.iterSpan.End) != 0 {
|
||||
// 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.curr.Keys = i.keysBuf
|
||||
return i.curr
|
||||
}
|
||||
|
||||
func (i *DefragmentingIter) saveCurrent(span Span) {
|
||||
i.currBuf = i.currBuf[:0]
|
||||
i.keysBuf = i.keysBuf[:0]
|
||||
i.keyBuf = i.keyBuf[:0]
|
||||
if cap(i.currBuf) > bufferReuseMaxCapacity {
|
||||
i.currBuf = nil
|
||||
}
|
||||
if cap(i.keyBuf) > bufferReuseMaxCapacity {
|
||||
i.keyBuf = nil
|
||||
}
|
||||
i.curr = Span{
|
||||
Start: i.saveBytes(span.Start),
|
||||
End: i.saveBytes(span.End),
|
||||
}
|
||||
for j := range span.Keys {
|
||||
i.keysBuf = append(i.keysBuf, Key{
|
||||
Trailer: span.Keys[j].Trailer,
|
||||
Suffix: i.saveBytes(span.Keys[j].Suffix),
|
||||
Value: i.saveBytes(span.Keys[j].Value),
|
||||
})
|
||||
}
|
||||
i.curr.Keys = i.keysBuf
|
||||
}
|
||||
|
||||
func (i *DefragmentingIter) saveBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
ret := append(i.currBuf, b...)
|
||||
i.currBuf = ret[len(ret):]
|
||||
return ret
|
||||
}
|
||||
13
vendor/github.com/cockroachdb/pebble/internal/keyspan/doc.go
generated
vendored
Normal file
13
vendor/github.com/cockroachdb/pebble/internal/keyspan/doc.go
generated
vendored
Normal 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
|
||||
98
vendor/github.com/cockroachdb/pebble/internal/keyspan/filter.go
generated
vendored
Normal file
98
vendor/github.com/cockroachdb/pebble/internal/keyspan/filter.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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) FragmentIterator {
|
||||
return &filteringIter{iter: iter, filterFn: filter}
|
||||
}
|
||||
|
||||
// SeekGE implements FragmentIterator.
|
||||
func (i *filteringIter) SeekGE(key []byte) Span {
|
||||
return i.filter(i.iter.SeekGE(key), +1)
|
||||
}
|
||||
|
||||
// SeekLT implements FragmentIterator.
|
||||
func (i *filteringIter) SeekLT(key []byte) Span {
|
||||
return i.filter(i.iter.SeekLT(key), -1)
|
||||
}
|
||||
|
||||
// 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.Valid() {
|
||||
if keep := i.filterFn(span, &i.span); keep {
|
||||
return i.span
|
||||
}
|
||||
if dir == +1 {
|
||||
span = i.Next()
|
||||
} else {
|
||||
span = i.Prev()
|
||||
}
|
||||
}
|
||||
return span
|
||||
}
|
||||
447
vendor/github.com/cockroachdb/pebble/internal/keyspan/fragmenter.go
generated
vendored
Normal file
447
vendor/github.com/cockroachdb/pebble/internal/keyspan/fragmenter.go
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
// 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.
|
||||
func (f *Fragmenter) Add(s Span) {
|
||||
if f.finished {
|
||||
panic("pebble: span fragmenter already finished")
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// Covers returns true if the specified key is covered by one of the pending
|
||||
// spans. The 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) bool {
|
||||
if f.finished {
|
||||
panic("pebble: span fragmenter already finished")
|
||||
}
|
||||
if len(f.pending) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
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.
|
||||
if s.Visible(snapshot).Covers(seqNum) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
53
vendor/github.com/cockroachdb/pebble/internal/keyspan/get.go
generated
vendored
Normal file
53
vendor/github.com/cockroachdb/pebble/internal/keyspan/get.go
generated
vendored
Normal 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, snapshot uint64) Span {
|
||||
// NB: We use SeekLT in order to land on the proper span for a search
|
||||
// key that resides in the middle of a span. Consider the scenario:
|
||||
//
|
||||
// a---e
|
||||
// e---i
|
||||
//
|
||||
// The spans are indexed by their start keys `a` and `e`. If the
|
||||
// search key is `c` we want to land on the span [a,e). If we were
|
||||
// to use SeekGE then the search key `c` would land on the span
|
||||
// [e,i) and we'd have to backtrack. The one complexity here is what
|
||||
// happens for the search key `e`. In that case SeekLT will land us
|
||||
// on the span [a,e) and we'll have to move forward.
|
||||
iterSpan := iter.SeekLT(key)
|
||||
if !iterSpan.Valid() {
|
||||
iterSpan = iter.Next()
|
||||
if !iterSpan.Valid() {
|
||||
// The iterator is empty.
|
||||
return Span{}
|
||||
}
|
||||
if cmp(key, iterSpan.Start) < 0 {
|
||||
// The search key lies before the first span.
|
||||
return Span{}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.Valid() || cmp(key, iterSpan.Start) < 0 {
|
||||
// We've run out of spans or we've moved on to a span which
|
||||
// starts after our search key.
|
||||
return Span{}
|
||||
}
|
||||
}
|
||||
return iterSpan.Visible(snapshot)
|
||||
}
|
||||
798
vendor/github.com/cockroachdb/pebble/internal/keyspan/interleaving_iter.go
generated
vendored
Normal file
798
vendor/github.com/cockroachdb/pebble/internal/keyspan/interleaving_iter.go
generated
vendored
Normal file
@@ -0,0 +1,798 @@
|
||||
// Copyright 2021 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"
|
||||
)
|
||||
|
||||
// TODO(jackson): The interleaving iterator has various invariants that it
|
||||
// asserts. We should eventually gate these behind `invariants.Enabled`.
|
||||
|
||||
// Hooks configure the interleaving iterator's behavior.
|
||||
type Hooks struct {
|
||||
// SpanChanged is invoked by interleaving iterator whenever the Span
|
||||
// returned by InterleavaingIterator.Span changes. As the iterator passes
|
||||
// into or out of a Span, it invokes SpanChanged, passing the new Span.
|
||||
SpanChanged func(Span)
|
||||
// SkipPoint is invoked by the interleaving iterator whenever the iterator
|
||||
// encounters a point key covered by a Span. If SkipPoint returns true, the
|
||||
// interleaving iterator skips the point key without returning it. This is
|
||||
// used during range key iteration to skip over point keys 'masked' by range
|
||||
// keys.
|
||||
SkipPoint func(userKey []byte) bool
|
||||
}
|
||||
|
||||
// InterleavingIter combines an iterator over point keys with an iterator over
|
||||
// key spans.
|
||||
//
|
||||
// Throughout Pebble, some keys apply at single discrete points within the user
|
||||
// keyspace. Other keys apply over continuous spans of the user key space.
|
||||
// Internally, iterators over point keys adhere to the base.InternalIterator
|
||||
// interface, and iterators over spans adhere to the keyspan.FragmentIterator
|
||||
// interface. The InterleavingIterator wraps a point iterator and span iterator,
|
||||
// providing access to all the elements of both iterators.
|
||||
//
|
||||
// The InterleavingIterator implements the point base.InternalIterator
|
||||
// interface. After any of the iterator's methods return a key, a caller may
|
||||
// call Span to retrieve the span covering the returned key, if any. A span is
|
||||
// considered to 'cover' a returned key if the span's [start, end) bounds
|
||||
// include the key's user key.
|
||||
//
|
||||
// In addition to tracking the current covering span, InterleavingIter returns a
|
||||
// special InternalKey at span start boundaries. Start boundaries are surfaced
|
||||
// as a synthetic span marker: an InternalKey with the boundary as the user key,
|
||||
// the infinite sequence number and a key kind selected from an arbitrary key
|
||||
// the infinite sequence number and an arbitrary contained key's kind. Since
|
||||
// which of the Span's key's kind is surfaced is undefined, the caller should
|
||||
// not use the InternalKey's kind. The caller should only rely on the `Span`
|
||||
// method for retrieving information about spanning keys. The interleaved
|
||||
// synthetic keys have the infinite sequence number so that they're interleaved
|
||||
// before any point keys with the same user key when iterating forward and after
|
||||
// when iterating backward.
|
||||
//
|
||||
// Interleaving the synthetic start key boundaries at the maximum sequence
|
||||
// number provides an opportunity for the higher-level, public Iterator to
|
||||
// observe the Span, even if no live points keys exist within the boudns of the
|
||||
// Span.
|
||||
//
|
||||
// When returning a synthetic marker key for a start boundary, InterleavingIter
|
||||
// will truncate the span's start bound to the SeekGE or SeekPrefixGE search
|
||||
// key. For example, a SeekGE("d") that finds a span [a, z) may return a
|
||||
// synthetic span marker key `d#72057594037927935,21`.
|
||||
//
|
||||
// If bounds have been applied to the iterator through SetBounds,
|
||||
// InterleavingIter will truncate the bounds of spans returned through Span to
|
||||
// the set bounds. The bounds returned through Span are not truncated by a
|
||||
// SeekGE or SeekPrefixGE search key. Consider, for example SetBounds('c', 'e'),
|
||||
// with an iterator containing the Span [a,z):
|
||||
//
|
||||
// First() = `c#72057594037927935,21` Span() = [c,e)
|
||||
// SeekGE('d') = `d#72057594037927935,21` Span() = [c,e)
|
||||
//
|
||||
// InterleavedIter does not interleave synthetic markers for spans that do not
|
||||
// contain any keys.
|
||||
//
|
||||
// Hooks
|
||||
//
|
||||
// InterelavingIter takes a Hooks parameter that may be used to configure the
|
||||
// behavior of the iterator. See the documentation on the Hooks type.
|
||||
//
|
||||
// All spans containing keys are exposed during iteration.
|
||||
type InterleavingIter struct {
|
||||
cmp base.Compare
|
||||
pointIter base.InternalIteratorWithStats
|
||||
keyspanIter FragmentIterator
|
||||
hooks Hooks
|
||||
|
||||
// lower and upper hold the iteration bounds set through SetBounds.
|
||||
lower, upper []byte
|
||||
// keyBuf is used to copy SeekGE or SeekPrefixGE arguments when they're used
|
||||
// to truncate a span. The byte slices backing a SeekGE/SeekPrefixGE search
|
||||
// keys can come directly from the end user, so they're copied into keyBuf
|
||||
// to ensure key stability.
|
||||
keyBuf []byte
|
||||
pointKey *base.InternalKey
|
||||
pointVal []byte
|
||||
// span, spanStart and spanEnd describe the current span state.
|
||||
// span{Start,End} are a function of the span and the Iterator's bounds.
|
||||
// span{Start,End} will be nil iff span is !Valid().
|
||||
span Span
|
||||
spanStart []byte
|
||||
spanEnd []byte
|
||||
// spanMarker holds the synthetic key that is returned when the iterator
|
||||
// passes over a key span's start bound.
|
||||
spanMarker base.InternalKey
|
||||
|
||||
// Keeping all of the bools together reduces the sizeof the struct.
|
||||
|
||||
// spanCoversKey indicates whether the current span covers the last-returned
|
||||
// key.
|
||||
spanCoversKey bool
|
||||
// pointKeyInterleaved indicates whether the current point key has been
|
||||
// interleaved in the current direction.
|
||||
pointKeyInterleaved bool
|
||||
// keyspanInterleaved indicates whether or not the current span has been
|
||||
// interleaved at its start key in the current direction. A span marker is
|
||||
// interleaved when first passing over the start key.
|
||||
//
|
||||
// When iterating in the forward direction, the span start key is
|
||||
// interleaved when the span first begins to cover the current iterator
|
||||
// position. The keyspan iterator isn't advanced until the
|
||||
// InterleavingIterator moves beyond the current span's end key. This field
|
||||
// is used to remember that the span has already been interleaved and
|
||||
// shouldn't be interleaved again.
|
||||
//
|
||||
// When iterating in the reverse direction, the span start key is
|
||||
// interleaved immediately before the iterator will move to a key no longer
|
||||
// be covered by the span. This field behaves analagously to
|
||||
// pointKeyInterleaved and if true signals that we must Prev the keyspan
|
||||
// iterator on the next Prev call.
|
||||
keyspanInterleaved bool
|
||||
// spanMarkerTruncated is set by SeekGE/SeekPrefixGE calls that truncate a
|
||||
// span's start bound marker to the search key. It's returned to false on
|
||||
// the next repositioning of the keyspan iterator.
|
||||
spanMarkerTruncated bool
|
||||
// dir indicates the direction of iteration: forward (+1) or backward (-1)
|
||||
dir int8
|
||||
}
|
||||
|
||||
// Assert that *InterleavingIter implements the InternalIterator interface.
|
||||
var _ base.InternalIterator = &InterleavingIter{}
|
||||
|
||||
// Init initializes the InterleavingIter to interleave point keys from pointIter
|
||||
// with key spans from keyspanIter.
|
||||
//
|
||||
// The point iterator must already have the provided bounds. Init does not
|
||||
// propagate the bounds down the iterator stack.
|
||||
func (i *InterleavingIter) Init(
|
||||
cmp base.Compare,
|
||||
pointIter base.InternalIteratorWithStats,
|
||||
keyspanIter FragmentIterator,
|
||||
hooks Hooks,
|
||||
lowerBound, upperBound []byte,
|
||||
) {
|
||||
*i = InterleavingIter{
|
||||
cmp: cmp,
|
||||
pointIter: pointIter,
|
||||
keyspanIter: keyspanIter,
|
||||
hooks: hooks,
|
||||
lower: lowerBound,
|
||||
upper: upperBound,
|
||||
}
|
||||
}
|
||||
|
||||
// SeekGE implements (base.InternalIterator).SeekGE.
|
||||
//
|
||||
// If there exists a span with a start key ≤ the first matching point key,
|
||||
// SeekGE will return a synthetic span marker key for the span. If this span's
|
||||
// start key is less than key, the returned marker will be truncated to key.
|
||||
// Note that this search-key truncation of the marker's key is not applied to
|
||||
// the span returned by Span.
|
||||
//
|
||||
// NB: In accordance with the base.InternalIterator contract:
|
||||
// i.lower ≤ key
|
||||
func (i *InterleavingIter) SeekGE(key []byte, trySeekUsingNext bool) (*base.InternalKey, []byte) {
|
||||
i.pointKey, i.pointVal = i.pointIter.SeekGE(key, trySeekUsingNext)
|
||||
i.pointKeyInterleaved = false
|
||||
i.keyspanSeekGE(key)
|
||||
i.dir = +1
|
||||
return i.interleaveForward(key)
|
||||
}
|
||||
|
||||
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
|
||||
//
|
||||
// If there exists a span with a start key ≤ the first matching point key,
|
||||
// SeekPrefixGE will return a synthetic span marker key for the span. If this
|
||||
// span's start key is less than key, the returned marker will be truncated to
|
||||
// key. Note that this search-key truncation of the marker's key is not applied
|
||||
// to the span returned by Span.
|
||||
//
|
||||
// NB: In accordance with the base.InternalIterator contract:
|
||||
// i.lower ≤ key
|
||||
func (i *InterleavingIter) SeekPrefixGE(
|
||||
prefix, key []byte, trySeekUsingNext bool,
|
||||
) (*base.InternalKey, []byte) {
|
||||
i.pointKey, i.pointVal = i.pointIter.SeekPrefixGE(prefix, key, trySeekUsingNext)
|
||||
i.pointKeyInterleaved = false
|
||||
i.keyspanSeekGE(key)
|
||||
i.dir = +1
|
||||
return i.interleaveForward(key)
|
||||
}
|
||||
|
||||
// SeekLT implements (base.InternalIterator).SeekLT.
|
||||
func (i *InterleavingIter) SeekLT(key []byte) (*base.InternalKey, []byte) {
|
||||
i.pointKey, i.pointVal = i.pointIter.SeekLT(key)
|
||||
i.pointKeyInterleaved = false
|
||||
i.keyspanSeekLT(key)
|
||||
i.dir = -1
|
||||
return i.interleaveBackward()
|
||||
}
|
||||
|
||||
// First implements (base.InternalIterator).First.
|
||||
func (i *InterleavingIter) First() (*base.InternalKey, []byte) {
|
||||
i.pointKey, i.pointVal = i.pointIter.First()
|
||||
i.pointKeyInterleaved = false
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.First()))
|
||||
i.dir = +1
|
||||
return i.interleaveForward(i.lower)
|
||||
}
|
||||
|
||||
// Last implements (base.InternalIterator).Last.
|
||||
func (i *InterleavingIter) Last() (*base.InternalKey, []byte) {
|
||||
i.pointKey, i.pointVal = i.pointIter.Last()
|
||||
i.pointKeyInterleaved = false
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Last()))
|
||||
i.dir = -1
|
||||
return i.interleaveBackward()
|
||||
}
|
||||
|
||||
// Next implements (base.InternalIterator).Next.
|
||||
func (i *InterleavingIter) Next() (*base.InternalKey, []byte) {
|
||||
if i.dir == -1 {
|
||||
// Switching directions.
|
||||
i.dir = +1
|
||||
|
||||
// The existing point key (denoted below with *) is either the last
|
||||
// key we returned (the current iterator position):
|
||||
// points: x (y*) z
|
||||
// or the upcoming point key in the backward direction if we just
|
||||
// returned a span start boundary key:
|
||||
// points: x* z
|
||||
// spans: ([y-?))
|
||||
// direction. Either way, we must move to the next point key.
|
||||
switch {
|
||||
case i.pointKey == nil && i.lower == nil:
|
||||
i.pointKey, i.pointVal = i.pointIter.First()
|
||||
case i.pointKey == nil && i.lower != nil:
|
||||
i.pointKey, i.pointVal = i.pointIter.SeekGE(i.lower, false)
|
||||
default:
|
||||
i.pointKey, i.pointVal = i.pointIter.Next()
|
||||
}
|
||||
i.pointKeyInterleaved = false
|
||||
|
||||
if !i.span.Valid() {
|
||||
// There was no span in the reverse direction, but there may be
|
||||
// a span in the forward direction.
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.Next()))
|
||||
i.keyspanInterleaved = false
|
||||
} else {
|
||||
// Regardless of the current iterator state, we mark any existing
|
||||
// span as interleaved when switching to forward iteration,
|
||||
// justified below.
|
||||
//
|
||||
// If the point key is the last key returned:
|
||||
// pointIter : ... (y) z ...
|
||||
// keyspanIter : ... ([x - )) ...
|
||||
// ^
|
||||
// The span's start key must be ≤ the point key, otherwise we'd have
|
||||
// interleaved the span's start key. From a forward-iteration
|
||||
// perspective, the span's start key is in the past and should be
|
||||
// considered already-interleaved.
|
||||
//
|
||||
// If the span start boundary key is the last key returned:
|
||||
// pointIter : ... (x) z ...
|
||||
// keyspanIter : ... ([y - )) ...
|
||||
// ^
|
||||
// i.span.Start is the key we last returned during reverse
|
||||
// iteration. From the perspective of forward-iteration, its start
|
||||
// key was just visited.
|
||||
i.keyspanInterleaved = true
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh the point key if the current point key has already been
|
||||
// interleaved.
|
||||
if i.pointKeyInterleaved {
|
||||
i.pointKey, i.pointVal = i.pointIter.Next()
|
||||
i.pointKeyInterleaved = false
|
||||
}
|
||||
// If we already interleaved the current span start key, and the point key
|
||||
// is ≥ the span's end key, move to the next span.
|
||||
if i.keyspanInterleaved && i.pointKey != nil && i.span.Valid() &&
|
||||
i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.Next()))
|
||||
}
|
||||
return i.interleaveForward(i.lower)
|
||||
}
|
||||
|
||||
// Prev implements (base.InternalIterator).Prev.
|
||||
func (i *InterleavingIter) Prev() (*base.InternalKey, []byte) {
|
||||
if i.dir == +1 {
|
||||
// Switching directions.
|
||||
i.dir = -1
|
||||
|
||||
if i.keyspanInterleaved {
|
||||
// The current span's start key has already been interleaved in the
|
||||
// forward direction. The start key may have been interleaved a
|
||||
// while ago, or it might've been interleaved at the current
|
||||
// iterator position. If it was interleaved a while ago, the current
|
||||
// span is still relevant and we should not move the keyspan
|
||||
// iterator.
|
||||
//
|
||||
// If it was just interleaved at the current iterator position, the
|
||||
// span start was the last key returned to the user. We should
|
||||
// prev past it so we don't return it again, with an exception.
|
||||
// Consider span [a, z) and this sequence of iterator calls:
|
||||
//
|
||||
// SeekGE('c') = c.RANGEKEYSET#72057594037927935
|
||||
// Prev() = a.RANGEKEYSET#72057594037927935
|
||||
//
|
||||
// If the current span's start key was last surfaced truncated due
|
||||
// to a SeekGE or SeekPrefixGE call, then it's still relevant in the
|
||||
// reverse direction with an untruncated start key.
|
||||
//
|
||||
// We can determine whether the last key returned was a point key by
|
||||
// checking i.pointKeyInterleaved, because every Next/Prev will
|
||||
// advance the point iterator and reset pointKeyInterleaved if it
|
||||
// was.
|
||||
if i.pointKeyInterleaved || i.spanMarkerTruncated {
|
||||
// The last returned key was a point key, OR a truncated span
|
||||
// marker key. Don't move, but re-save the span because it
|
||||
// should no longer be considered truncated or interleaved.
|
||||
i.saveKeyspan(i.span)
|
||||
} else {
|
||||
// The last returned key is this key's start boundary, so Prev
|
||||
// past it so we don't return it again.
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Prev()))
|
||||
}
|
||||
} else {
|
||||
// If the current span's start key has not been interleaved, then
|
||||
// the span's start key is greater than the current iterator
|
||||
// position (denoted in parenthesis), and the current span's start
|
||||
// key is ahead of our iterator position. Move it to the previous
|
||||
// span:
|
||||
// points: (x*)
|
||||
// span: [y-z)*
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Prev()))
|
||||
}
|
||||
|
||||
// The existing point key (denoted below with *) is either the last
|
||||
// key we returned (the current iterator position):
|
||||
// points: x (y*) z
|
||||
// or the upcoming point key in the forward direction if we just
|
||||
// returned a span start boundary key :
|
||||
// points: x z*
|
||||
// spans: ([y-?))
|
||||
// direction. Either way, we must move the point iterator backwards.
|
||||
switch {
|
||||
case i.pointKey == nil && i.upper == nil:
|
||||
i.pointKey, i.pointVal = i.pointIter.Last()
|
||||
case i.pointKey == nil && i.upper != nil:
|
||||
i.pointKey, i.pointVal = i.pointIter.SeekLT(i.upper)
|
||||
default:
|
||||
i.pointKey, i.pointVal = i.pointIter.Prev()
|
||||
}
|
||||
i.pointKeyInterleaved = false
|
||||
}
|
||||
|
||||
// Refresh the point key if we just returned the current point key.
|
||||
if i.pointKeyInterleaved {
|
||||
i.pointKey, i.pointVal = i.pointIter.Prev()
|
||||
i.pointKeyInterleaved = false
|
||||
}
|
||||
// Refresh the span if we just returned the span's start boundary key.
|
||||
if i.keyspanInterleaved {
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Prev()))
|
||||
}
|
||||
return i.interleaveBackward()
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) interleaveForward(lowerBound []byte) (*base.InternalKey, []byte) {
|
||||
// This loop determines whether a point key or a span marker key should be
|
||||
// interleaved on each iteration. If masking is disabled and the span is
|
||||
// nonempty, this loop executes for exactly one iteration. If masking is
|
||||
// enabled and a masked key is determined to be interleaved next, this loop
|
||||
// continues until the interleaved key is unmasked. If a span's start key
|
||||
// should be interleaved next, but the span is empty, the loop continues to
|
||||
// the next key.
|
||||
for {
|
||||
// Check invariants.
|
||||
// INVARIANT: !pointKeyInterleaved
|
||||
if i.pointKeyInterleaved {
|
||||
panic("pebble: invariant violation: point key interleaved")
|
||||
}
|
||||
switch {
|
||||
case !i.span.Valid():
|
||||
case i.pointKey == nil:
|
||||
default:
|
||||
// INVARIANT: !keyspanInterleaved || pointKey < span.End
|
||||
// The caller is responsible for advancing this span if it's already
|
||||
// been interleaved and the span ends before the point key.
|
||||
// Absolute positioning methods will never have already interleaved
|
||||
// the span's start key, so only Next needs to handle the case where
|
||||
// pointKey >= span.End.
|
||||
if i.keyspanInterleaved && i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
|
||||
panic("pebble: invariant violation: span interleaved, but point key >= span end")
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave.
|
||||
switch {
|
||||
case !i.span.Valid():
|
||||
// If we're out of spans, just return the point key.
|
||||
return i.yieldPointKey(false /* covered */)
|
||||
case i.pointKey == nil:
|
||||
if i.pointKeyInterleaved {
|
||||
panic("pebble: invariant violation: point key already interleaved")
|
||||
}
|
||||
// If we're out of point keys, we need to return a span marker. If
|
||||
// the current span has already been interleaved, advance it. Since
|
||||
// there are no more point keys, we don't need to worry about
|
||||
// advancing past the current point key.
|
||||
if i.keyspanInterleaved {
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.Next()))
|
||||
if !i.span.Valid() {
|
||||
return i.yieldNil()
|
||||
}
|
||||
}
|
||||
if i.span.Empty() {
|
||||
i.keyspanInterleaved = true
|
||||
continue
|
||||
}
|
||||
return i.yieldSyntheticSpanMarker(lowerBound)
|
||||
default:
|
||||
if i.cmp(i.pointKey.UserKey, i.span.Start) >= 0 {
|
||||
// The span start key lies before the point key. If we haven't
|
||||
// interleaved it, we should.
|
||||
if !i.keyspanInterleaved {
|
||||
if i.span.Empty() {
|
||||
if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
|
||||
// Advance the keyspan iterator, as just flipping
|
||||
// keyspanInterleaved would likely trip up the invariant check
|
||||
// above.
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.Next()))
|
||||
} else {
|
||||
i.keyspanInterleaved = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
return i.yieldSyntheticSpanMarker(lowerBound)
|
||||
}
|
||||
|
||||
// Otherwise, the span's start key is already interleaved and we
|
||||
// need to return the point key. The current span necessarily
|
||||
// must cover the point key:
|
||||
//
|
||||
// Since the span's start is less than or equal to the point
|
||||
// key, the only way for this span to not cover the point would
|
||||
// be if the span's end is less than or equal to the point.
|
||||
// (For example span = [a, b), point key = c).
|
||||
//
|
||||
// However, the invariant at the beginning of the function
|
||||
// guarantees that if:
|
||||
// * we have both a point key and a span
|
||||
// * and the span has already been interleaved
|
||||
// => then the point key must be less than the span's end, and
|
||||
// the point key must be covered by the current span.
|
||||
|
||||
// The span covers the point key. If a SkipPoint hook is
|
||||
// configured, ask it if we should skip this point key.
|
||||
if i.hooks.SkipPoint != nil && i.hooks.SkipPoint(i.pointKey.UserKey) {
|
||||
i.pointKey, i.pointVal = i.pointIter.Next()
|
||||
// We may have just invalidated the invariant that
|
||||
// ensures the span's End is > the point key, so
|
||||
// reestablish it before the next iteration.
|
||||
if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.End) >= 0 {
|
||||
i.saveKeyspan(i.checkForwardBound(i.keyspanIter.Next()))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Point key is unmasked but covered.
|
||||
return i.yieldPointKey(true /* covered */)
|
||||
}
|
||||
return i.yieldPointKey(false /* covered */)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) interleaveBackward() (*base.InternalKey, []byte) {
|
||||
// This loop determines whether a point key or a span's start key should be
|
||||
// interleaved on each iteration. If masking is disabled and the span is
|
||||
// nonempty, this loop executes for exactly one iteration. If masking is
|
||||
// enabled and a masked key is determined to be interleaved next, this loop
|
||||
// continues until the interleaved key is unmasked. If a span's start key
|
||||
// should be interleaved next, but the span is empty, the loop continues to
|
||||
// the next key.
|
||||
for {
|
||||
// Check invariants.
|
||||
// INVARIANT: !pointKeyInterleaved
|
||||
if i.pointKeyInterleaved {
|
||||
panic("pebble: invariant violation: point key interleaved")
|
||||
}
|
||||
|
||||
// Interleave.
|
||||
switch {
|
||||
case !i.span.Valid():
|
||||
// If we're out of spans, just return the point key.
|
||||
return i.yieldPointKey(false /* covered */)
|
||||
case i.pointKey == nil:
|
||||
// If we're out of point keys, we need to return a span marker.
|
||||
if i.span.Empty() {
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Prev()))
|
||||
continue
|
||||
}
|
||||
return i.yieldSyntheticSpanMarker(i.lower)
|
||||
default:
|
||||
// If the span's start key is greater than the point key, return a
|
||||
// marker for the span.
|
||||
if i.cmp(i.span.Start, i.pointKey.UserKey) > 0 {
|
||||
if i.span.Empty() {
|
||||
i.saveKeyspan(i.checkBackwardBound(i.keyspanIter.Prev()))
|
||||
continue
|
||||
}
|
||||
return i.yieldSyntheticSpanMarker(i.lower)
|
||||
}
|
||||
// We have a span but it has not been interleaved and begins at a
|
||||
// key equal to or before the current point key. The point key
|
||||
// should be interleaved next, if it's not masked.
|
||||
if i.cmp(i.pointKey.UserKey, i.span.End) < 0 {
|
||||
// The span covers the point key. The point key might be masked
|
||||
// too if masking is enabled.
|
||||
|
||||
// The span covers the point key. If a SkipPoint hook is
|
||||
// configured, ask it if we should skip this point key.
|
||||
if i.hooks.SkipPoint != nil && i.hooks.SkipPoint(i.pointKey.UserKey) {
|
||||
i.pointKey, i.pointVal = i.pointIter.Prev()
|
||||
continue
|
||||
}
|
||||
|
||||
// Point key is unmasked but covered.
|
||||
return i.yieldPointKey(true /* covered */)
|
||||
}
|
||||
return i.yieldPointKey(false /* covered */)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keyspanSeekGE seeks the keyspan iterator to the first span covering k ≥ key.
|
||||
// Note that this differs from the FragmentIterator.SeekGE semantics, which
|
||||
// seek to the first span with a start key ≥ key.
|
||||
func (i *InterleavingIter) keyspanSeekGE(key []byte) {
|
||||
// Seek using SeekLT to look for a span that starts before key, with an end
|
||||
// boundary extending beyond key.
|
||||
s := i.keyspanIter.SeekLT(key)
|
||||
if !s.Valid() || i.cmp(s.End, key) <= 0 {
|
||||
// The iterator is exhausted in the reverse direction, or the span we
|
||||
// found ends before key. Next to the first key with a start ≥ key.
|
||||
s = i.keyspanIter.Next()
|
||||
}
|
||||
i.saveKeyspan(i.checkForwardBound(s))
|
||||
}
|
||||
|
||||
// keyspanSeekLT seeks the keyspan iterator to the last span covering k < key.
|
||||
// Note that this differs from the FragmentIterator.SeekLT semantics, which
|
||||
// seek to the last span with a start key < key.
|
||||
func (i *InterleavingIter) keyspanSeekLT(key []byte) {
|
||||
s := i.checkBackwardBound(i.keyspanIter.SeekLT(key))
|
||||
// s.Start is not guaranteed to be less than key, because of the bounds
|
||||
// enforcement. Consider the following example:
|
||||
//
|
||||
// Bounds are set to [d,e). The user performs a SeekLT(d). The
|
||||
// FragmentIterator.SeekLT lands on a span [b,f). This span has a start key
|
||||
// less than d, as expected. Above, checkBackwardBound truncates the span to
|
||||
// match the iterator's current bounds, modifying the span to [d,e), which
|
||||
// does not overlap the search space of [-∞, d).
|
||||
//
|
||||
// This problem is a consequence of the SeekLT's exclusive search key and
|
||||
// the fact that we don't perform bounds truncation at every leaf iterator.
|
||||
if i.cmp(s.Start, key) >= 0 {
|
||||
s = Span{}
|
||||
}
|
||||
i.saveKeyspan(s)
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) checkForwardBound(s Span) Span {
|
||||
// Check the upper bound if we have one.
|
||||
if s.Valid() && i.upper != nil && i.cmp(s.Start, i.upper) >= 0 {
|
||||
return Span{}
|
||||
}
|
||||
|
||||
// TODO(jackson): The key comparisons below truncate bounds whenever the
|
||||
// keyspan iterator is repositioned. We could perform this lazily, and do it
|
||||
// the first time the user actually asks for this span's bounds in
|
||||
// SpanBounds. This would reduce work in the case where there's no span
|
||||
// covering the point and the keyspan iterator is non-empty.
|
||||
|
||||
// NB: These truncations don't require setting `keyspanMarkerTruncated`:
|
||||
// That flag only applies to truncated span marker keys.
|
||||
if i.lower != nil && i.cmp(s.Start, i.lower) < 0 {
|
||||
s.Start = i.lower
|
||||
}
|
||||
if i.upper != nil && i.cmp(i.upper, s.End) < 0 {
|
||||
s.End = i.upper
|
||||
}
|
||||
if i.cmp(s.Start, s.End) == 0 {
|
||||
return Span{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) checkBackwardBound(s Span) Span {
|
||||
// Check the lower bound if we have one.
|
||||
if s.Valid() && i.lower != nil && i.cmp(s.End, i.lower) <= 0 {
|
||||
return Span{}
|
||||
}
|
||||
|
||||
// TODO(jackson): The key comparisons below truncate bounds whenever the
|
||||
// keyspan iterator is repositioned. We could perform this lazily, and do it
|
||||
// the first time the user actually asks for this span's bounds in
|
||||
// SpanBounds. This would reduce work in the case where there's no span
|
||||
// covering the point and the keyspan iterator is non-empty.
|
||||
|
||||
// NB: These truncations don't require setting `keyspanMarkerTruncated`:
|
||||
// That flag only applies to truncated span marker keys.
|
||||
if i.lower != nil && i.cmp(s.Start, i.lower) < 0 {
|
||||
s.Start = i.lower
|
||||
}
|
||||
if i.upper != nil && i.cmp(i.upper, s.End) < 0 {
|
||||
s.End = i.upper
|
||||
}
|
||||
if i.cmp(s.Start, s.End) == 0 {
|
||||
return Span{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) yieldNil() (*base.InternalKey, []byte) {
|
||||
i.spanCoversKey = false
|
||||
return i.verify(nil, nil)
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) yieldPointKey(covered bool) (*base.InternalKey, []byte) {
|
||||
i.pointKeyInterleaved = true
|
||||
i.spanCoversKey = covered
|
||||
return i.verify(i.pointKey, i.pointVal)
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) yieldSyntheticSpanMarker(lowerBound []byte) (*base.InternalKey, []byte) {
|
||||
i.spanMarker.UserKey = i.span.Start
|
||||
i.spanMarker.Trailer = base.MakeTrailer(base.InternalKeySeqNumMax, i.span.Keys[0].Kind())
|
||||
i.keyspanInterleaved = true
|
||||
i.spanCoversKey = true
|
||||
|
||||
// Truncate the key we return to our lower bound if we have one. Note that
|
||||
// we use the lowerBound function parameter, not i.lower. The lowerBound
|
||||
// argument is guaranteed to be ≥ i.lower. It may be equal to the SetBounds
|
||||
// lower bound, or it could come from a SeekGE or SeekPrefixGE search key.
|
||||
if lowerBound != nil && i.cmp(lowerBound, i.span.Start) > 0 {
|
||||
// Truncating to the lower bound may violate the upper bound if
|
||||
// lowerBound == i.upper. For example, a SeekGE(k) uses k as a lower
|
||||
// bound for truncating a span. The span a-z will be truncated to [k,
|
||||
// z). If i.upper == k, we'd mistakenly try to return a span [k, k), an
|
||||
// invariant violation.
|
||||
if i.cmp(lowerBound, i.upper) == 0 {
|
||||
return i.yieldNil()
|
||||
}
|
||||
|
||||
// If the lowerBound argument came from a SeekGE or SeekPrefixGE
|
||||
// call, and it may be backed by a user-provided byte slice that is not
|
||||
// guaranteed to be stable.
|
||||
//
|
||||
// If the lowerBound argument is the lower bound set by SetBounds,
|
||||
// Pebble owns the slice's memory. However, consider two successive
|
||||
// calls to SetBounds(). The second may overwrite the lower bound.
|
||||
// Although the external contract requires a seek after a SetBounds,
|
||||
// Pebble's tests don't always. For this reason and to simplify
|
||||
// reasoning around lifetimes, always copy the bound into keyBuf when
|
||||
// truncating.
|
||||
i.keyBuf = append(i.keyBuf[:0], lowerBound...)
|
||||
i.spanMarker.UserKey = i.keyBuf
|
||||
i.spanMarkerTruncated = true
|
||||
}
|
||||
return i.verify(&i.spanMarker, nil)
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) verify(k *base.InternalKey, v []byte) (*base.InternalKey, []byte) {
|
||||
// TODO(jackson): Wrap the entire body of this function in an
|
||||
// invariants.Enabled conditional, so that in production builds this
|
||||
// function is empty and may be inlined away.
|
||||
|
||||
switch {
|
||||
case k != nil && !i.keyspanInterleaved && !i.pointKeyInterleaved:
|
||||
panic("pebble: invariant violation: both keys marked as noninterleaved")
|
||||
case i.dir == -1 && k != nil && i.keyspanInterleaved == i.pointKeyInterleaved:
|
||||
// During reverse iteration, if we're returning a key, either the span's
|
||||
// start key must have been interleaved OR the current point key value
|
||||
// is being returned, not both.
|
||||
//
|
||||
// This invariant holds because in reverse iteration the start key of the
|
||||
// span behaves like a point. Once the start key is interleaved, we move
|
||||
// the keyspan iterator to the previous span.
|
||||
panic(fmt.Sprintf("pebble: invariant violation: interleaving (point %t, span %t)",
|
||||
i.pointKeyInterleaved, i.keyspanInterleaved))
|
||||
case i.dir == -1 && i.spanMarkerTruncated:
|
||||
panic("pebble: invariant violation: truncated span key in reverse iteration")
|
||||
case k != nil && i.lower != nil && i.cmp(k.UserKey, i.lower) < 0:
|
||||
panic("pebble: invariant violation: key < lower bound")
|
||||
case k != nil && i.upper != nil && i.cmp(k.UserKey, i.upper) >= 0:
|
||||
panic("pebble: invariant violation: key ≥ upper bound")
|
||||
case i.span.Valid() && k != nil && i.hooks.SkipPoint != nil && i.pointKeyInterleaved &&
|
||||
i.cmp(k.UserKey, i.spanStart) >= 0 && i.cmp(k.UserKey, i.spanEnd) < 0 && i.hooks.SkipPoint(k.UserKey):
|
||||
panic("pebble: invariant violation: point key eligible for skipping returned")
|
||||
}
|
||||
|
||||
return k, v
|
||||
}
|
||||
|
||||
func (i *InterleavingIter) saveKeyspan(s Span) {
|
||||
i.keyspanInterleaved = false
|
||||
i.spanMarkerTruncated = false
|
||||
i.span = s
|
||||
if !s.Valid() {
|
||||
i.spanStart = nil
|
||||
i.spanEnd = nil
|
||||
if i.hooks.SpanChanged != nil {
|
||||
i.hooks.SpanChanged(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
i.spanStart = s.Start
|
||||
i.spanEnd = s.End
|
||||
|
||||
if i.hooks.SpanChanged != nil {
|
||||
i.hooks.SpanChanged(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Span returns the span covering the last key returned, if any. A span key is
|
||||
// considered to 'cover' a key if the key falls within the span's user key
|
||||
// bounds.
|
||||
func (i *InterleavingIter) Span() Span {
|
||||
if !i.spanCoversKey {
|
||||
return Span{}
|
||||
}
|
||||
// Return the span with truncated bounds.
|
||||
return Span{
|
||||
Start: i.spanStart,
|
||||
End: i.spanEnd,
|
||||
Keys: i.span.Keys,
|
||||
}
|
||||
}
|
||||
|
||||
// SetBounds implements (base.InternalIterator).SetBounds.
|
||||
func (i *InterleavingIter) SetBounds(lower, upper []byte) {
|
||||
i.lower, i.upper = lower, upper
|
||||
i.pointIter.SetBounds(lower, upper)
|
||||
}
|
||||
|
||||
// Error implements (base.InternalIterator).Error.
|
||||
func (i *InterleavingIter) Error() error {
|
||||
return firstError(i.pointIter.Error(), i.keyspanIter.Error())
|
||||
}
|
||||
|
||||
// Close implements (base.InternalIterator).Close.
|
||||
func (i *InterleavingIter) Close() error {
|
||||
perr := i.pointIter.Close()
|
||||
rerr := i.keyspanIter.Close()
|
||||
return firstError(perr, rerr)
|
||||
}
|
||||
|
||||
// String implements (base.InternalIterator).String.
|
||||
func (i *InterleavingIter) String() string {
|
||||
return fmt.Sprintf("keyspan-interleaving(%q)", i.pointIter.String())
|
||||
}
|
||||
|
||||
var _ base.InternalIteratorWithStats = &InterleavingIter{}
|
||||
|
||||
// Stats implements InternalIteratorWithStats.
|
||||
func (i *InterleavingIter) Stats() base.InternalIteratorStats {
|
||||
return i.pointIter.Stats()
|
||||
}
|
||||
|
||||
// ResetStats implements InternalIteratorWithStats.
|
||||
func (i *InterleavingIter) ResetStats() {
|
||||
i.pointIter.ResetStats()
|
||||
}
|
||||
|
||||
func firstError(err0, err1 error) error {
|
||||
if err0 != nil {
|
||||
return err0
|
||||
}
|
||||
return err1
|
||||
}
|
||||
110
vendor/github.com/cockroachdb/pebble/internal/keyspan/internal_iter_shim.go
generated
vendored
Normal file
110
vendor/github.com/cockroachdb/pebble/internal/keyspan/internal_iter_shim.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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
|
||||
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, 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, trySeekUsingNext bool,
|
||||
) (*base.InternalKey, []byte) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE.
|
||||
func (i *InternalIteratorShim) SeekPrefixGE(
|
||||
prefix, key []byte, trySeekUsingNext bool,
|
||||
) (*base.InternalKey, []byte) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SeekLT implements (base.InternalIterator).SeekLT.
|
||||
func (i *InternalIteratorShim) SeekLT(key []byte) (*base.InternalKey, []byte) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// First implements (base.InternalIterator).First.
|
||||
func (i *InternalIteratorShim) First() (*base.InternalKey, []byte) {
|
||||
i.span = i.miter.First()
|
||||
for i.span.Valid() && i.span.Empty() {
|
||||
i.span = i.miter.Next()
|
||||
}
|
||||
if !i.span.Valid() {
|
||||
return nil, nil
|
||||
}
|
||||
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
|
||||
return &i.iterKey, i.span.End
|
||||
}
|
||||
|
||||
// Last implements (base.InternalIterator).Last.
|
||||
func (i *InternalIteratorShim) Last() (*base.InternalKey, []byte) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Next implements (base.InternalIterator).Next.
|
||||
func (i *InternalIteratorShim) Next() (*base.InternalKey, []byte) {
|
||||
i.span = i.miter.Next()
|
||||
for i.span.Valid() && i.span.Empty() {
|
||||
i.span = i.miter.Next()
|
||||
}
|
||||
if !i.span.Valid() {
|
||||
return nil, nil
|
||||
}
|
||||
i.iterKey = base.InternalKey{UserKey: i.span.Start, Trailer: i.span.Keys[0].Trailer}
|
||||
return &i.iterKey, i.span.End
|
||||
}
|
||||
|
||||
// Prev implements (base.InternalIterator).Prev.
|
||||
func (i *InternalIteratorShim) Prev() (*base.InternalKey, []byte) {
|
||||
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()
|
||||
}
|
||||
199
vendor/github.com/cockroachdb/pebble/internal/keyspan/iter.go
generated
vendored
Normal file
199
vendor/github.com/cockroachdb/pebble/internal/keyspan/iter.go
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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 whose start key is greater
|
||||
// than or equal to the given key.
|
||||
SeekGE(key []byte) Span
|
||||
|
||||
// SeekLT moves the iterator to the last span whose start key is less than
|
||||
// the given key.
|
||||
SeekLT(key []byte) Span
|
||||
|
||||
// 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.
|
||||
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 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 {
|
||||
return &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(-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.
|
||||
if i.index >= len(i.spans) {
|
||||
return Span{}
|
||||
}
|
||||
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 Span{}
|
||||
}
|
||||
return i.spans[i.index]
|
||||
}
|
||||
|
||||
// First implements FragmentIterator.First.
|
||||
func (i *Iter) First() Span {
|
||||
if len(i.spans) == 0 {
|
||||
return Span{}
|
||||
}
|
||||
i.index = 0
|
||||
return i.spans[i.index]
|
||||
}
|
||||
|
||||
// Last implements FragmentIterator.Last.
|
||||
func (i *Iter) Last() Span {
|
||||
if len(i.spans) == 0 {
|
||||
return Span{}
|
||||
}
|
||||
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 Span{}
|
||||
}
|
||||
i.index++
|
||||
if i.index >= len(i.spans) {
|
||||
return Span{}
|
||||
}
|
||||
return i.spans[i.index]
|
||||
}
|
||||
|
||||
// Prev implements FragmentIterator.Prev.
|
||||
func (i *Iter) Prev() Span {
|
||||
if i.index < 0 {
|
||||
return Span{}
|
||||
}
|
||||
i.index--
|
||||
if i.index < 0 {
|
||||
return Span{}
|
||||
}
|
||||
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"
|
||||
}
|
||||
471
vendor/github.com/cockroachdb/pebble/internal/keyspan/level_iter.go
generated
vendored
Normal file
471
vendor/github.com/cockroachdb/pebble/internal/keyspan/level_iter.go
generated
vendored
Normal file
@@ -0,0 +1,471 @@
|
||||
// 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/manifest"
|
||||
)
|
||||
|
||||
// Logger defines an interface for writing log messages.
|
||||
type Logger interface {
|
||||
Infof(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
logger Logger
|
||||
cmp base.Compare
|
||||
// Denotes if this level iter should read point key spans (i.e. rangedels,
|
||||
// or range keys. If key type is Point, 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 straddle is Valid() whenever 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. It is nil under any of the following conditions:
|
||||
// - files.Current() == nil
|
||||
// - err != nil
|
||||
// - straddle.Valid(), in which case iterFile is not nil and points to the
|
||||
// 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 *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,
|
||||
logger Logger,
|
||||
keyType manifest.KeyType,
|
||||
) *LevelIter {
|
||||
l := &LevelIter{}
|
||||
l.Init(opts, cmp, newIter, files, level, logger, keyType)
|
||||
return l
|
||||
}
|
||||
|
||||
// Init initializes a LevelIter.
|
||||
func (l *LevelIter) Init(
|
||||
opts SpanIterOptions,
|
||||
cmp base.Compare,
|
||||
newIter TableNewSpanIter,
|
||||
files manifest.LevelIterator,
|
||||
level manifest.Level,
|
||||
logger Logger,
|
||||
keyType manifest.KeyType,
|
||||
) {
|
||||
l.err = nil
|
||||
l.level = level
|
||||
l.logger = logger
|
||||
l.tableOpts.RangeKeyFilters = opts.RangeKeyFilters
|
||||
l.cmp = cmp
|
||||
l.iterFile = nil
|
||||
l.newIter = newIter
|
||||
switch keyType {
|
||||
case manifest.KeyTypePoint, 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(l.files.Current(), &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.err = nil // clear cached iteration error
|
||||
|
||||
f := l.findFileGE(key)
|
||||
if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(key, f.SmallestRangeKey.UserKey) < 0 {
|
||||
// Return a straddling key instead of loading the file.
|
||||
l.iterFile = f
|
||||
l.iter = nil
|
||||
l.straddleDir = +1
|
||||
// The synthetic span that we are creating starts at the seeked key. This
|
||||
// is an optimization as it prevents us from loading the adjacent file's
|
||||
// bounds, at the expense of this iterator appearing "inconsistent" to its
|
||||
// callers i.e.:
|
||||
//
|
||||
// SeekGE(bb) -> {bb-c, empty}
|
||||
// Next() -> {c-d, RANGEKEYSET}
|
||||
// Prev() -> {a-c, empty}
|
||||
//
|
||||
// Seeing as the inconsistency will only be around empty spans, which are
|
||||
// expected to be elided by one of the higher-level iterators (either
|
||||
// top-level Iterator or the defragmenting iter), the entire iterator should
|
||||
// still appear consistent to the user.
|
||||
l.straddle = Span{
|
||||
Start: key,
|
||||
End: f.SmallestRangeKey.UserKey,
|
||||
Keys: nil,
|
||||
}
|
||||
return l.straddle
|
||||
}
|
||||
loadFileIndicator := l.loadFile(f, +1)
|
||||
if loadFileIndicator == noFileLoaded {
|
||||
return Span{}
|
||||
}
|
||||
if span := l.iter.SeekGE(key); span.Valid() {
|
||||
return span
|
||||
}
|
||||
return l.skipEmptyFileForward()
|
||||
}
|
||||
|
||||
// SeekLT implements keyspan.FragmentIterator.
|
||||
func (l *LevelIter) SeekLT(key []byte) Span {
|
||||
l.dir = -1
|
||||
l.err = nil // clear cached iteration error
|
||||
|
||||
f := l.findFileLT(key)
|
||||
if f != nil && l.keyType == manifest.KeyTypeRange && l.cmp(f.LargestRangeKey.UserKey, key) < 0 {
|
||||
// Return a straddling key instead of loading the file.
|
||||
l.iterFile = f
|
||||
l.iter = nil
|
||||
l.straddleDir = -1
|
||||
// The synthetic span that we are creating ends at the seeked key. This
|
||||
// is an optimization as it prevents us from loading the adjacent file's
|
||||
// bounds, at the expense of this iterator appearing "inconsistent" to its
|
||||
// callers i.e.:
|
||||
//
|
||||
// SeekLT(dd) -> {d-dd, empty}
|
||||
// Prev() -> {c-d, RANGEKEYSET}
|
||||
// Next() -> {d-e, empty}
|
||||
//
|
||||
// Seeing as the inconsistency will only be around empty spans, which are
|
||||
// expected to be elided by one of the higher-level iterators (either
|
||||
// top-level Iterator or the defragmenting iter), the entire iterator should
|
||||
// still appear consistent to the user.
|
||||
l.straddle = Span{
|
||||
Start: f.LargestRangeKey.UserKey,
|
||||
End: key,
|
||||
Keys: nil,
|
||||
}
|
||||
return l.straddle
|
||||
}
|
||||
if l.loadFile(l.findFileLT(key), -1) == noFileLoaded {
|
||||
return Span{}
|
||||
}
|
||||
if span := l.iter.SeekLT(key); span.Valid() {
|
||||
return span
|
||||
}
|
||||
return l.skipEmptyFileBackward()
|
||||
}
|
||||
|
||||
// First implements keyspan.FragmentIterator.
|
||||
func (l *LevelIter) First() Span {
|
||||
l.dir = +1
|
||||
l.err = nil // clear cached iteration error
|
||||
|
||||
if l.loadFile(l.files.First(), +1) == noFileLoaded {
|
||||
return Span{}
|
||||
}
|
||||
if span := l.iter.First(); span.Valid() {
|
||||
return span
|
||||
}
|
||||
return l.skipEmptyFileForward()
|
||||
}
|
||||
|
||||
// Last implements keyspan.FragmentIterator.
|
||||
func (l *LevelIter) Last() Span {
|
||||
l.dir = -1
|
||||
l.err = nil // clear cached iteration error
|
||||
|
||||
if l.loadFile(l.files.Last(), -1) == noFileLoaded {
|
||||
return Span{}
|
||||
}
|
||||
if span := l.iter.Last(); span.Valid() {
|
||||
return span
|
||||
}
|
||||
return l.skipEmptyFileBackward()
|
||||
}
|
||||
|
||||
// Next implements keyspan.FragmentIterator.
|
||||
func (l *LevelIter) Next() Span {
|
||||
l.dir = +1
|
||||
if l.err != nil || (l.iter == nil && l.iterFile == nil) {
|
||||
return Span{}
|
||||
}
|
||||
|
||||
if l.iter != nil {
|
||||
if span := l.iter.Next(); span.Valid() {
|
||||
return span
|
||||
}
|
||||
}
|
||||
return l.skipEmptyFileForward()
|
||||
}
|
||||
|
||||
// Prev implements keyspan.FragmentIterator.
|
||||
func (l *LevelIter) Prev() Span {
|
||||
l.dir = -1
|
||||
if l.err != nil || (l.iter == nil && l.iterFile == nil) {
|
||||
return Span{}
|
||||
}
|
||||
|
||||
if l.iter != nil {
|
||||
if span := l.iter.Prev(); span.Valid() {
|
||||
return span
|
||||
}
|
||||
}
|
||||
return l.skipEmptyFileBackward()
|
||||
}
|
||||
|
||||
func (l *LevelIter) skipEmptyFileForward() Span {
|
||||
if !l.straddle.Valid() && 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 Span{}
|
||||
}
|
||||
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 Span{}
|
||||
}
|
||||
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 = l.dir
|
||||
return l.straddle
|
||||
}
|
||||
} else if l.straddle.Valid() && l.straddleDir < 0 {
|
||||
// We were at a straddle key, but are now changing directions. l.iterFile
|
||||
// was already moved backward by skipEmptyFileBackward, so advance it
|
||||
// forward.
|
||||
l.iterFile = l.files.Next()
|
||||
}
|
||||
l.straddle = Span{}
|
||||
var span Span
|
||||
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 Span{}
|
||||
}
|
||||
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 span
|
||||
}
|
||||
|
||||
func (l *LevelIter) skipEmptyFileBackward() Span {
|
||||
// We were at a file that had spans. Check if the previous file that has
|
||||
// spans is not directly adjacent to the current file i.e. there is a
|
||||
// gap in the span keyspace between the two files. In that case, synthesize
|
||||
// a "straddle span" in l.straddle and return that.
|
||||
//
|
||||
// Straddle spans are not created in rangedel mode.
|
||||
if !l.straddle.Valid() && l.keyType == manifest.KeyTypeRange &&
|
||||
l.iterFile != nil && l.iter != nil {
|
||||
if err := l.Close(); err != nil {
|
||||
l.err = err
|
||||
return Span{}
|
||||
}
|
||||
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 Span{}
|
||||
}
|
||||
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 = l.dir
|
||||
return l.straddle
|
||||
}
|
||||
} else if l.straddle.Valid() && l.straddleDir > 0 {
|
||||
// We were at a straddle key, but are now changing directions. l.iterFile
|
||||
// was already advanced forward by skipEmptyFileForward, so move it
|
||||
// backward.
|
||||
l.iterFile = l.files.Prev()
|
||||
}
|
||||
l.straddle = Span{}
|
||||
var span Span
|
||||
for span.Empty() {
|
||||
fileToLoad := l.iterFile
|
||||
if l.keyType == manifest.KeyTypePoint {
|
||||
fileToLoad = l.files.Prev()
|
||||
}
|
||||
if l.loadFile(fileToLoad, -1) == noFileLoaded {
|
||||
return Span{}
|
||||
}
|
||||
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 span
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
948
vendor/github.com/cockroachdb/pebble/internal/keyspan/merging_iter.go
generated
vendored
Normal file
948
vendor/github.com/cockroachdb/pebble/internal/keyspan/merging_iter.go
generated
vendored
Normal file
@@ -0,0 +1,948 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/cockroachdb/pebble/internal/base"
|
||||
"github.com/cockroachdb/pebble/internal/invariants"
|
||||
)
|
||||
|
||||
// TODO(jackson): Consider implementing an optimization to seek lower levels
|
||||
// past higher levels' RANGEKEYDELs. This would be analaogous to the
|
||||
// optimization pebble.mergingIter performs for RANGEDELs during point key
|
||||
// seeks. It may not be worth it, because range keys are rare and cascading
|
||||
// seeks would require introducing key comparisons to switchTo{Min,Max}Heap
|
||||
// where there currently are none.
|
||||
|
||||
// Transform defines a transform function to be applied to a Span. A Transform
|
||||
// takes a Span as input and writes the transformed Span to the provided output
|
||||
// *Span pointer. The output Span's Keys slice may be reused by Transform to
|
||||
// reduce allocations.
|
||||
type Transform func(cmp base.Compare, in Span, out *Span) error
|
||||
|
||||
func noopTransform(_ base.Compare, s Span, dst *Span) error {
|
||||
dst.Start, dst.End = s.Start, s.End
|
||||
dst.Keys = append(dst.Keys[:0], s.Keys...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// visibleTransform filters keys that are invisible at the provided snapshot
|
||||
// sequence number.
|
||||
func visibleTransform(snapshot uint64) Transform {
|
||||
return func(_ base.Compare, s Span, dst *Span) error {
|
||||
s = s.Visible(snapshot)
|
||||
dst.Start, dst.End = s.Start, s.End
|
||||
dst.Keys = append(dst.Keys[:0], s.Keys...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MergingIter merges spans across levels of the LSM, exposing an iterator over
|
||||
// spans that yields sets of spans fragmented at unique user key boundaries.
|
||||
//
|
||||
// A MergingIter is initialized with an arbitrary number of child iterators over
|
||||
// fragmented spans. Each child iterator exposes fragmented key spans, such that
|
||||
// overlapping keys are surfaced in a single Span. Key spans from one child
|
||||
// iterator may overlap key spans from another child iterator arbitrarily.
|
||||
//
|
||||
// Algorithm
|
||||
//
|
||||
// The merging iterator wraps child iterators, merging and fragmenting spans
|
||||
// across levels. The high-level algorithm is:
|
||||
//
|
||||
// 1. Initialize the heap with bound keys from child iterators' spans.
|
||||
// 2. Find the next [or previous] two unique user keys' from bounds.
|
||||
// 3. Consider the span formed between the two unique user keys a candidate
|
||||
// span.
|
||||
// 4. Determine if any of the child iterators' spans overlap the candidate
|
||||
// span.
|
||||
// 4a. If any of the child iterator's current bounds are end keys
|
||||
// (during forward iteration) or start keys (during reverse
|
||||
// iteration), then all the spans with that bound overlap the
|
||||
// candidate span.
|
||||
// 4b. Apply the configured transform, which may remove keys.
|
||||
// 4b. If no spans overlap, forget the smallest (forward iteration)
|
||||
// or largest (reverse iteration) unique user key and advance
|
||||
// the iterators to the next unique user key. Start again from 3.
|
||||
//
|
||||
// Detailed algorithm
|
||||
//
|
||||
// Each level (i0, i1, ...) has a user-provided input FragmentIterator. The
|
||||
// merging iterator steps through individual boundaries of the underlying
|
||||
// spans separately. If the underlying FragmentIterator has fragments
|
||||
// [a,b){#2,#1} [b,c){#1} the mergingIterLevel.{next,prev} step through:
|
||||
//
|
||||
// (a, start), (b, end), (b, start), (c, end)
|
||||
//
|
||||
// Note that (a, start) and (b, end) are observed ONCE each, despite two keys
|
||||
// sharing those bounds. Also note that (b, end) and (b, start) are two distinct
|
||||
// iterator positions of a mergingIterLevel.
|
||||
//
|
||||
// The merging iterator maintains a heap (min during forward iteration, max
|
||||
// during reverse iteration) containing the boundKeys. Each boundKey is a
|
||||
// 3-tuple holding the bound user key, whether the bound is a start or end key
|
||||
// and the set of keys from that level that have that bound. The heap orders
|
||||
// based on the boundKey's user key only.
|
||||
//
|
||||
// The merging iterator is responsible for merging spans across levels to
|
||||
// determine which span is next, but it's also responsible for fragmenting
|
||||
// overlapping spans. Consider the example:
|
||||
//
|
||||
// i0: b---d e-----h
|
||||
// i1: a---c h-----k
|
||||
// i2: a------------------------------p
|
||||
//
|
||||
// fragments: a-b-c-d-e-----h-----k----------p
|
||||
//
|
||||
// None of the individual child iterators contain a span with the exact bounds
|
||||
// [c,d), but the merging iterator must produce a span [c,d). To accomplish
|
||||
// this, the merging iterator visits every span between unique boundary user
|
||||
// keys. In the above example, this is:
|
||||
//
|
||||
// [a,b), [b,c), [c,d), [d,e), [e, h), [h, k), [k, p)
|
||||
//
|
||||
// The merging iterator first initializes the heap to prepare for iteration.
|
||||
// The description below discusses the mechanics of forward iteration after a
|
||||
// call to First, but the mechanics are similar for reverse iteration and
|
||||
// other positioning methods.
|
||||
//
|
||||
// During a call to First, the heap is initialized by seeking every
|
||||
// mergingIterLevel to the first bound of the first fragment. In the above
|
||||
// example, this seeks the child iterators to:
|
||||
//
|
||||
// i0: (b, boundKindFragmentStart, [ [b,d) ])
|
||||
// i1: (a, boundKindFragmentStart, [ [a,c) ])
|
||||
// i2: (a, boundKindFragmentStart, [ [a,p) ])
|
||||
//
|
||||
// After fixing up the heap, the root of the heap is a boundKey with the
|
||||
// smallest user key ('a' in the example). Once the heap is setup for iteration
|
||||
// in the appropriate direction and location, the merging iterator uses
|
||||
// find{Next,Prev}FragmentSet to find the next/previous span bounds.
|
||||
//
|
||||
// During forward iteration, the root of the heap's user key is the start key
|
||||
// key of next merged span. findNextFragmentSet sets m.start to this user
|
||||
// key. The heap may contain other boundKeys with the same user key if another
|
||||
// level has a fragment starting or ending at the same key, so the
|
||||
// findNextFragmentSet method pulls from the heap until it finds the first key
|
||||
// greater than m.start. This key is used as the end key.
|
||||
//
|
||||
// In the above example, this results in m.start = 'a', m.end = 'b' and child
|
||||
// iterators in the following positions:
|
||||
//
|
||||
// i0: (b, boundKindFragmentStart, [ [b,d) ])
|
||||
// i1: (c, boundKindFragmentEnd, [ [a,c) ])
|
||||
// i2: (p, boundKindFragmentEnd, [ [a,p) ])
|
||||
//
|
||||
// With the user key bounds of the next merged span established,
|
||||
// findNextFragmentSet must determine which, if any, fragments overlap the span.
|
||||
// During forward iteration any child iterator that is now positioned at an end
|
||||
// boundary has an overlapping span. (Justification: The child iterator's end
|
||||
// boundary is ≥ m.end. The corresponding start boundary must be ≤ m.start since
|
||||
// there were no other user keys between m.start and m.end. So the fragments
|
||||
// associated with the iterator's current end boundary have start and end bounds
|
||||
// such that start ≤ m.start < m.end ≤ end).
|
||||
//
|
||||
// findNextFragmentSet iterates over the levels, collecting keys from any child
|
||||
// iterators positioned at end boundaries. In the above example, i1 and i2 are
|
||||
// positioned at end boundaries, so findNextFragmentSet collects the keys of
|
||||
// [a,c) and [a,p). These spans contain the merging iterator's [m.start, m.end)
|
||||
// span, but they may also extend beyond the m.start and m.end. The merging
|
||||
// iterator returns the keys with the merging iter's m.start and m.end bounds,
|
||||
// preserving the underlying keys' sequence numbers, key kinds and values.
|
||||
//
|
||||
// A MergingIter is configured with a Transform that's applied to the span
|
||||
// before surfacing it to the iterator user. A Transform may remove keys
|
||||
// arbitrarily, but it may not modify the values themselves.
|
||||
//
|
||||
// It may be the case that findNextFragmentSet finds no levels positioned at end
|
||||
// boundaries, or that there are no spans remaining after applying a transform,
|
||||
// in which case the span [m.start, m.end) overlaps with nothing. In this case
|
||||
// findNextFragmentSet loops, repeating the above process again until it finds a
|
||||
// span that does contain keys.
|
||||
//
|
||||
// Memory safety
|
||||
//
|
||||
// The FragmentIterator interface only guarantees stability of a Span and its
|
||||
// associated slices until the next positioning method is called. Adjacent Spans
|
||||
// may be contained in different sstables, requring the FragmentIterator
|
||||
// implementation to close one sstable, releasing its memory, before opening the
|
||||
// next. Most of the state used by the MergingIter is derived from spans at
|
||||
// current child iterator positions only, ensuring state is stable. The one
|
||||
// exception is the start bound during forward iteration and the end bound
|
||||
// during reverse iteration.
|
||||
//
|
||||
// If the heap root originates from an end boundary when findNextFragmentSet
|
||||
// begins, a Next on the heap root level may invalidate the end boundary. To
|
||||
// accommodate this, find{Next,Prev}FragmentSet copy the initial boundary if the
|
||||
// subsequent Next/Prev would move to the next span.
|
||||
type MergingIter struct {
|
||||
levels []mergingIterLevel
|
||||
heap mergingIterHeap
|
||||
// start and end hold the bounds for the span currently under the
|
||||
// iterator position.
|
||||
//
|
||||
// Invariant: None of the levels' iterators contain spans with a bound
|
||||
// between start and end. For all bounds b, b ≤ start || b ≥ end.
|
||||
start, end []byte
|
||||
// buf is a buffer used to save [start, end) boundary keys.
|
||||
buf []byte
|
||||
// keys holds all of the keys across all levels that overlap the key span
|
||||
// [start, end), sorted by sequence number and kind descending. This slice
|
||||
// is reconstituted in synthesizeKeys from each mergingIterLevel's keys
|
||||
// every time the [start, end) bounds change.
|
||||
//
|
||||
// Each element points into a child iterator's memory, so the keys may not
|
||||
// be directly modified.
|
||||
keys keysBySeqNumKind
|
||||
// transform defines a function to be applied to a span before it's yielded
|
||||
// to the user. A transform may filter individual keys contained within the
|
||||
// span.
|
||||
transform Transform
|
||||
// span holds the iterator's current span. This span is used as the
|
||||
// destination for transforms. Every tranformed span overwrites the
|
||||
// previous.
|
||||
span Span
|
||||
|
||||
err error
|
||||
dir int8
|
||||
}
|
||||
|
||||
// MergingIter implements the FragmentIterator interface.
|
||||
var _ FragmentIterator = (*MergingIter)(nil)
|
||||
|
||||
type mergingIterLevel struct {
|
||||
iter FragmentIterator
|
||||
|
||||
// heapKey holds the current key at this level for use within the heap.
|
||||
heapKey boundKey
|
||||
}
|
||||
|
||||
func (l *mergingIterLevel) next() {
|
||||
if l.heapKey.kind == boundKindFragmentStart {
|
||||
l.heapKey = endBound(l.heapKey.span)
|
||||
return
|
||||
}
|
||||
l.heapKey = startBound(l.iter.Next())
|
||||
}
|
||||
|
||||
func (l *mergingIterLevel) prev() {
|
||||
if l.heapKey.kind == boundKindFragmentEnd {
|
||||
l.heapKey = startBound(l.heapKey.span)
|
||||
return
|
||||
}
|
||||
l.heapKey = endBound(l.iter.Prev())
|
||||
}
|
||||
|
||||
// Init initializes the merging iterator with the provided fragment iterators.
|
||||
func (m *MergingIter) Init(cmp base.Compare, transform Transform, iters ...FragmentIterator) {
|
||||
levels, items := m.levels, m.heap.items
|
||||
|
||||
*m = MergingIter{
|
||||
heap: mergingIterHeap{cmp: cmp},
|
||||
transform: transform,
|
||||
}
|
||||
// Invariant: cap(levels) == cap(items)
|
||||
if cap(levels) < len(iters) {
|
||||
m.levels = make([]mergingIterLevel, len(iters))
|
||||
m.heap.items = make([]mergingIterItem, 0, len(iters))
|
||||
} else {
|
||||
m.levels = levels[:len(iters)]
|
||||
m.heap.items = items[:0]
|
||||
}
|
||||
for i := range m.levels {
|
||||
m.levels[i] = mergingIterLevel{}
|
||||
m.levels[i].iter = iters[i]
|
||||
}
|
||||
}
|
||||
|
||||
// SeekGE moves the iterator to the first span with a start key greater than or
|
||||
// equal to key.
|
||||
func (m *MergingIter) SeekGE(key []byte) Span {
|
||||
m.invalidate() // clear state about current position
|
||||
for i := range m.levels {
|
||||
l := &m.levels[i]
|
||||
|
||||
// A SeekGE requires we position each level at the smallest bound ≥ key.
|
||||
// We must search through both inclusive start and exclusive end bounds.
|
||||
// Note that this search requirement differs from FragmentIterator's
|
||||
// .SeekGE'semantics, which returns the span with the smallest start key
|
||||
// ≥ key. To remedy this difference, we find the last span less than
|
||||
// key. If its end boundary is greater than or equal to key, we use it.
|
||||
// Otherwise we use the start boundary of the next span which
|
||||
// necessarily has a start ≥ key.
|
||||
s := l.iter.SeekLT(key)
|
||||
if s.Valid() && m.cmp(s.End, key) >= 0 {
|
||||
// s.End ≥ key
|
||||
// We need to use this span's end bound.
|
||||
l.heapKey = endBound(s)
|
||||
continue
|
||||
}
|
||||
// s.End < key
|
||||
// The span `s` ends before key. Next to the first span with a Start ≥
|
||||
// key, and use that.
|
||||
s = l.iter.Next()
|
||||
l.heapKey = startBound(s)
|
||||
}
|
||||
m.initMinHeap()
|
||||
return m.findNextFragmentSet()
|
||||
}
|
||||
|
||||
// SeekLT moves the iterator to the last span with a start key less than key.
|
||||
func (m *MergingIter) SeekLT(key []byte) Span {
|
||||
// TODO(jackson): Evaluate whether there's an implementation of SeekLT
|
||||
// independent of SeekGE that is more efficient. It's tricky, because the
|
||||
// span we should return might straddle `key` itself.
|
||||
//
|
||||
// Consider the scenario:
|
||||
// a----------l #2
|
||||
// b-----------m #1
|
||||
//
|
||||
// The merged, fully-fragmented spans that MergingIter exposes to the caller
|
||||
// have bounds:
|
||||
// a-b #2
|
||||
// b--------l #2
|
||||
// b--------l #1
|
||||
// l-m #1
|
||||
//
|
||||
// A call SeekLT(c) must return the largest of the above spans with a
|
||||
// Start user key < key: [b,l)#1. This requires examining bounds both < 'c'
|
||||
// (the 'b' of [b,m)#1's start key) and bounds ≥ 'c' (the 'l' of ([a,l)#2's
|
||||
// end key).
|
||||
if s := m.SeekGE(key); !s.Valid() && m.err != nil {
|
||||
return Span{}
|
||||
}
|
||||
// Prev to the previous span.
|
||||
return m.Prev()
|
||||
}
|
||||
|
||||
// First seeks the iterator to the first span.
|
||||
func (m *MergingIter) First() Span {
|
||||
m.invalidate() // clear state about current position
|
||||
for i := range m.levels {
|
||||
l := &m.levels[i]
|
||||
l.heapKey = startBound(l.iter.First())
|
||||
}
|
||||
m.initMinHeap()
|
||||
return m.findNextFragmentSet()
|
||||
}
|
||||
|
||||
// Last seeks the iterator to the last span.
|
||||
func (m *MergingIter) Last() Span {
|
||||
m.invalidate() // clear state about current position
|
||||
for i := range m.levels {
|
||||
l := &m.levels[i]
|
||||
l.heapKey = endBound(l.iter.Last())
|
||||
}
|
||||
m.initMaxHeap()
|
||||
return m.findPrevFragmentSet()
|
||||
}
|
||||
|
||||
// Next advances the iterator to the next span.
|
||||
func (m *MergingIter) Next() Span {
|
||||
if m.err != nil {
|
||||
return Span{}
|
||||
}
|
||||
if m.dir == +1 && (m.end == nil || m.start == nil) {
|
||||
return Span{}
|
||||
}
|
||||
if m.dir != +1 {
|
||||
m.switchToMinHeap()
|
||||
}
|
||||
return m.findNextFragmentSet()
|
||||
}
|
||||
|
||||
// Prev advances the iterator to the previous span.
|
||||
func (m *MergingIter) Prev() Span {
|
||||
if m.err != nil {
|
||||
return Span{}
|
||||
}
|
||||
if m.dir == -1 && (m.end == nil || m.start == nil) {
|
||||
return Span{}
|
||||
}
|
||||
if m.dir != -1 {
|
||||
m.switchToMaxHeap()
|
||||
}
|
||||
return m.findPrevFragmentSet()
|
||||
}
|
||||
|
||||
// Error returns any accumulated error.
|
||||
func (m *MergingIter) Error() error {
|
||||
if m.heap.len() == 0 || m.err != nil {
|
||||
return m.err
|
||||
}
|
||||
return m.levels[m.heap.items[0].index].iter.Error()
|
||||
}
|
||||
|
||||
// Close closes the iterator, releasing all acquired resources.
|
||||
func (m *MergingIter) Close() error {
|
||||
for i := range m.levels {
|
||||
if err := m.levels[i].iter.Close(); err != nil && m.err == nil {
|
||||
m.err = err
|
||||
}
|
||||
}
|
||||
m.levels = nil
|
||||
m.heap.items = m.heap.items[:0]
|
||||
return m.err
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (m *MergingIter) String() string {
|
||||
return "merging-keyspan"
|
||||
}
|
||||
|
||||
func (m *MergingIter) initMinHeap() {
|
||||
m.dir = +1
|
||||
m.heap.reverse = false
|
||||
m.initHeap()
|
||||
}
|
||||
|
||||
func (m *MergingIter) initMaxHeap() {
|
||||
m.dir = -1
|
||||
m.heap.reverse = true
|
||||
m.initHeap()
|
||||
}
|
||||
|
||||
func (m *MergingIter) initHeap() {
|
||||
m.heap.items = m.heap.items[:0]
|
||||
for i := range m.levels {
|
||||
if l := &m.levels[i]; l.heapKey.kind != boundKindInvalid {
|
||||
m.heap.items = append(m.heap.items, mergingIterItem{
|
||||
index: i,
|
||||
boundKey: &l.heapKey,
|
||||
})
|
||||
} else {
|
||||
m.err = firstError(m.err, l.iter.Error())
|
||||
if m.err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
m.heap.init()
|
||||
}
|
||||
|
||||
func (m *MergingIter) switchToMinHeap() {
|
||||
// switchToMinHeap reorients the heap for forward iteration, without moving
|
||||
// the current MergingIter position.
|
||||
|
||||
// The iterator is currently positioned at the span [m.start, m.end),
|
||||
// oriented in the reverse direction, so each level's iterator is positioned
|
||||
// to the largest key ≤ m.start. To reorient in the forward direction, we
|
||||
// must advance each level's iterator to the smallest key ≥ m.end. Consider
|
||||
// this three-level example.
|
||||
//
|
||||
// i0: b---d e-----h
|
||||
// i1: a---c h-----k
|
||||
// i2: a------------------------------p
|
||||
//
|
||||
// merged: a-b-c-d-e-----h-----k----------p
|
||||
//
|
||||
// If currently positioned at the merged span [c,d), then the level
|
||||
// iterators' heap keys are:
|
||||
//
|
||||
// i0: (b, [b, d)) i1: (c, [a,c)) i2: (a, [a,p))
|
||||
//
|
||||
// Reversing the heap should not move the merging iterator and should not
|
||||
// change the current [m.start, m.end) bounds. It should only prepare for
|
||||
// forward iteration by updating the child iterators' heap keys to:
|
||||
//
|
||||
// i0: (d, [b, d)) i1: (h, [h,k)) i2: (p, [a,p))
|
||||
//
|
||||
// In every level the first key ≥ m.end is the next in the iterator.
|
||||
// Justification: Suppose not and a level iterator's next key was some key k
|
||||
// such that k < m.end. The max-heap invariant dictates that the current
|
||||
// iterator position is the largest entry with a user key ≥ m.start. This
|
||||
// means k > m.start. We started with the assumption that k < m.end, so
|
||||
// m.start < k < m.end. But then k is between our current span bounds,
|
||||
// and reverse iteration would have constructed the current interval to be
|
||||
// [k, m.end) not [m.start, m.end).
|
||||
|
||||
if invariants.Enabled {
|
||||
for i := range m.levels {
|
||||
l := &m.levels[i]
|
||||
if l.heapKey.kind != boundKindInvalid && m.cmp(l.heapKey.key, m.start) > 0 {
|
||||
panic("pebble: invariant violation: max-heap key > m.start")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := range m.levels {
|
||||
m.levels[i].next()
|
||||
}
|
||||
m.initMinHeap()
|
||||
}
|
||||
|
||||
func (m *MergingIter) switchToMaxHeap() {
|
||||
// switchToMaxHeap reorients the heap for reverse iteration, without moving
|
||||
// the current MergingIter position.
|
||||
|
||||
// The iterator is currently positioned at the span [m.start, m.end),
|
||||
// oriented in the forward direction. Each level's iterator is positioned at
|
||||
// the smallest bound ≥ m.end. To reorient in the reverse direction, we must
|
||||
// move each level's iterator to the largest key ≤ m.start. Consider this
|
||||
// three-level example.
|
||||
//
|
||||
// i0: b---d e-----h
|
||||
// i1: a---c h-----k
|
||||
// i2: a------------------------------p
|
||||
//
|
||||
// merged: a-b-c-d-e-----h-----k----------p
|
||||
//
|
||||
// If currently positioned at the merged span [c,d), then the level
|
||||
// iterators' heap keys are:
|
||||
//
|
||||
// i0: (d, [b, d)) i1: (h, [h,k)) i2: (p, [a,p))
|
||||
//
|
||||
// Reversing the heap should not move the merging iterator and should not
|
||||
// change the current [m.start, m.end) bounds. It should only prepare for
|
||||
// reverse iteration by updating the child iterators' heap keys to:
|
||||
//
|
||||
// i0: (b, [b, d)) i1: (c, [a,c)) i2: (a, [a,p))
|
||||
//
|
||||
// In every level the largest key ≤ m.start is the prev in the iterator.
|
||||
// Justification: Suppose not and a level iterator's prev key was some key k
|
||||
// such that k > m.start. The min-heap invariant dictates that the current
|
||||
// iterator position is the smallest entry with a user key ≥ m.end. This
|
||||
// means k < m.end, otherwise the iterator would be positioned at k. We
|
||||
// started with the assumption that k > m.start, so m.start < k < m.end. But
|
||||
// then k is between our current span bounds, and reverse iteration
|
||||
// would have constructed the current interval to be [m.start, k) not
|
||||
// [m.start, m.end).
|
||||
|
||||
if invariants.Enabled {
|
||||
for i := range m.levels {
|
||||
l := &m.levels[i]
|
||||
if l.heapKey.kind != boundKindInvalid && m.cmp(l.heapKey.key, m.end) < 0 {
|
||||
panic("pebble: invariant violation: min-heap key < m.end")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := range m.levels {
|
||||
m.levels[i].prev()
|
||||
}
|
||||
m.initMaxHeap()
|
||||
}
|
||||
|
||||
func (m *MergingIter) cmp(a, b []byte) int {
|
||||
return m.heap.cmp(a, b)
|
||||
}
|
||||
|
||||
func (m *MergingIter) findNextFragmentSet() Span {
|
||||
// Each iteration of this loop considers a new merged span between unique
|
||||
// user keys. An iteration may find that there exists no overlap for a given
|
||||
// span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
|
||||
// below loop will still consider [b,d) before continuing to [d, e)). It
|
||||
// returns when it finds a span that is covered by at least one key.
|
||||
|
||||
for m.heap.len() > 0 && m.err == nil {
|
||||
// Initialize the next span's start bound. SeekGE and First prepare the
|
||||
// heap without advancing. Next leaves the heap in a state such that the
|
||||
// root is the smallest bound key equal to the returned span's end key,
|
||||
// so the heap is already positioned at the next merged span's start key.
|
||||
|
||||
// NB: m.heapRoot() might be either an end boundary OR a start boundary
|
||||
// of a level's span. Both end and start boundaries may still be a start
|
||||
// key of a span in the set of fragmented spans returned by MergingIter.
|
||||
// Consider the scenario:
|
||||
// a----------l #1
|
||||
// b-----------m #2
|
||||
//
|
||||
// The merged, fully-fragmented spans that MergingIter exposes to the caller
|
||||
// have bounds:
|
||||
// a-b #1
|
||||
// b--------l #1
|
||||
// b--------l #2
|
||||
// l-m #2
|
||||
//
|
||||
// When advancing to l-m#2, we must set m.start to 'l', which originated
|
||||
// from [a,l)#1's end boundary.
|
||||
m.start = m.heap.items[0].boundKey.key
|
||||
|
||||
// Before calling nextEntry, consider whether it might invalidate our
|
||||
// start boundary. If the start boundary key originated from an end
|
||||
// boundary, then we need to copy the start key before advancing the
|
||||
// underlying iterator to the next Span.
|
||||
if m.heap.items[0].boundKey.kind == boundKindFragmentEnd {
|
||||
m.buf = append(m.buf[:0], m.start...)
|
||||
m.start = m.buf
|
||||
}
|
||||
|
||||
// There may be many entries all with the same user key. Spans in other
|
||||
// levels may also start or end at this same user key. For eg:
|
||||
// L1: [a, c) [c, d)
|
||||
// L2: [c, e)
|
||||
// If we're positioned at L1's end(c) end boundary, we want to advance
|
||||
// to the first bound > c.
|
||||
m.nextEntry()
|
||||
for len(m.heap.items) > 0 && m.err == nil && m.cmp(m.heapRoot(), m.start) == 0 {
|
||||
m.nextEntry()
|
||||
}
|
||||
if len(m.heap.items) == 0 || m.err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// The current entry at the top of the heap is the first key > m.start.
|
||||
// It must become the end bound for the span we will return to the user.
|
||||
// In the above example, the root of the heap is L1's end(d).
|
||||
m.end = m.heap.items[0].boundKey.key
|
||||
|
||||
// Each level within m.levels may have a span that overlaps the
|
||||
// fragmented key span [m.start, m.end). Update m.keys to point to them
|
||||
// and sort them by kind, sequence number. There may not be any keys
|
||||
// defined over [m.start, m.end) if we're between the end of one span
|
||||
// and the start of the next, OR if the configured transform filters any
|
||||
// keys out. We allow empty spans that were emitted by child iterators, but
|
||||
// we elide empty spans created by the mergingIter itself that don't overlap
|
||||
// with any child iterator returned spans (i.e. empty spans that bridge two
|
||||
// distinct child-iterator-defined spans).
|
||||
if found, s := m.synthesizeKeys(+1); found && s.Valid() {
|
||||
return s
|
||||
}
|
||||
}
|
||||
// Exhausted.
|
||||
m.clear()
|
||||
return Span{}
|
||||
}
|
||||
|
||||
func (m *MergingIter) findPrevFragmentSet() Span {
|
||||
// Each iteration of this loop considers a new merged span between unique
|
||||
// user keys. An iteration may find that there exists no overlap for a given
|
||||
// span, (eg, if the spans [a,b), [d, e) exist within level iterators, the
|
||||
// below loop will still consider [b,d) before continuing to [a, b)). It
|
||||
// returns when it finds a span that is covered by at least one key.
|
||||
|
||||
for m.heap.len() > 0 && m.err == nil {
|
||||
// Initialize the next span's end bound. SeekLT and Last prepare the
|
||||
// heap without advancing. Prev leaves the heap in a state such that the
|
||||
// root is the largest bound key equal to the returned span's start key,
|
||||
// so the heap is already positioned at the next merged span's end key.
|
||||
|
||||
// NB: m.heapRoot() might be either an end boundary OR a start boundary
|
||||
// of a level's span. Both end and start boundaries may still be a start
|
||||
// key of a span returned by MergingIter. Consider the scenario:
|
||||
// a----------l #2
|
||||
// b-----------m #1
|
||||
//
|
||||
// The merged, fully-fragmented spans that MergingIter exposes to the caller
|
||||
// have bounds:
|
||||
// a-b #2
|
||||
// b--------l #2
|
||||
// b--------l #1
|
||||
// l-m #1
|
||||
//
|
||||
// When Preving to a-b#2, we must set m.end to 'b', which originated
|
||||
// from [b,m)#1's start boundary.
|
||||
m.end = m.heap.items[0].boundKey.key
|
||||
|
||||
// Before calling prevEntry, consider whether it might invalidate our
|
||||
// end boundary. If the end boundary key originated from a start
|
||||
// boundary, then we need to copy the end key before advancing the
|
||||
// underlying iterator to the previous Span.
|
||||
if m.heap.items[0].boundKey.kind == boundKindFragmentStart {
|
||||
m.buf = append(m.buf[:0], m.end...)
|
||||
m.end = m.buf
|
||||
}
|
||||
|
||||
// There may be many entries all with the same user key. Spans in other
|
||||
// levels may also start or end at this same user key. For eg:
|
||||
// L1: [a, c) [c, d)
|
||||
// L2: [c, e)
|
||||
// If we're positioned at L1's start(c) start boundary, we want to prev
|
||||
// to move to the first bound < c.
|
||||
m.prevEntry()
|
||||
for len(m.heap.items) > 0 && m.err == nil && m.cmp(m.heapRoot(), m.end) == 0 {
|
||||
m.prevEntry()
|
||||
}
|
||||
if len(m.heap.items) == 0 || m.err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// The current entry at the top of the heap is the first key < m.end.
|
||||
// It must become the start bound for the span we will return to the
|
||||
// user. In the above example, the root of the heap is L1's start(a).
|
||||
m.start = m.heap.items[0].boundKey.key
|
||||
|
||||
// Each level within m.levels may have a set of keys that overlap the
|
||||
// fragmented key span [m.start, m.end). Update m.keys to point to them
|
||||
// and sort them by kind, sequence number. There may not be any keys
|
||||
// spanning [m.start, m.end) if we're between the end of one span and
|
||||
// the start of the next, OR if the configured transform filters any
|
||||
// keys out. We allow empty spans that were emitted by child iterators, but
|
||||
// we elide empty spans created by the mergingIter itself that don't overlap
|
||||
// with any child iterator returned spans (i.e. empty spans that bridge two
|
||||
// distinct child-iterator-defined spans).
|
||||
if found, s := m.synthesizeKeys(-1); found && s.Valid() {
|
||||
return s
|
||||
}
|
||||
}
|
||||
// Exhausted.
|
||||
m.clear()
|
||||
return Span{}
|
||||
}
|
||||
|
||||
func (m *MergingIter) heapRoot() []byte {
|
||||
return m.heap.items[0].boundKey.key
|
||||
}
|
||||
|
||||
// synthesizeKeys is called by find{Next,Prev}FragmentSet to populate and
|
||||
// sort the set of keys overlapping [m.start, m.end).
|
||||
//
|
||||
// During forward iteration, if the current heap item is a fragment end,
|
||||
// then the fragment's start must be ≤ m.start and the fragment overlaps the
|
||||
// current iterator position of [m.start, m.end).
|
||||
//
|
||||
// During reverse iteration, if the current heap item is a fragment start,
|
||||
// then the fragment's end must be ≥ m.end and the fragment overlaps the
|
||||
// current iteration position of [m.start, m.end).
|
||||
//
|
||||
// The boolean return value, `found`, is true if the returned span overlaps
|
||||
// with a span returned by a child iterator.
|
||||
func (m *MergingIter) synthesizeKeys(dir int8) (bool, Span) {
|
||||
if invariants.Enabled {
|
||||
if m.cmp(m.start, m.end) >= 0 {
|
||||
panic(fmt.Sprintf("pebble: invariant violation: span start ≥ end: %s >= %s", m.start, m.end))
|
||||
}
|
||||
}
|
||||
|
||||
m.keys = m.keys[:0]
|
||||
found := false
|
||||
for i := range m.levels {
|
||||
if dir == +1 && m.levels[i].heapKey.kind == boundKindFragmentEnd ||
|
||||
dir == -1 && m.levels[i].heapKey.kind == boundKindFragmentStart {
|
||||
m.keys = append(m.keys, m.levels[i].heapKey.span.Keys...)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
sort.Sort(&m.keys)
|
||||
|
||||
// Apply the configured transform. See VisibleTransform.
|
||||
s := Span{
|
||||
Start: m.start,
|
||||
End: m.end,
|
||||
Keys: m.keys,
|
||||
}
|
||||
if err := m.transform(m.cmp, s, &m.span); err != nil {
|
||||
m.err = err
|
||||
return false, Span{}
|
||||
}
|
||||
return found, m.span
|
||||
}
|
||||
|
||||
func (m *MergingIter) invalidate() {
|
||||
m.err = nil
|
||||
}
|
||||
|
||||
func (m *MergingIter) clear() {
|
||||
for fi := range m.keys {
|
||||
m.keys[fi] = Key{}
|
||||
}
|
||||
m.keys = m.keys[:0]
|
||||
}
|
||||
|
||||
// nextEntry steps to the next entry.
|
||||
func (m *MergingIter) nextEntry() {
|
||||
l := &m.levels[m.heap.items[0].index]
|
||||
l.next()
|
||||
if !l.heapKey.valid() {
|
||||
// l.iter is exhausted.
|
||||
m.err = l.iter.Error()
|
||||
if m.err == nil {
|
||||
m.heap.pop()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if m.heap.len() > 1 {
|
||||
m.heap.fix(0)
|
||||
}
|
||||
}
|
||||
|
||||
// prevEntry steps to the previous entry.
|
||||
func (m *MergingIter) prevEntry() {
|
||||
l := &m.levels[m.heap.items[0].index]
|
||||
l.prev()
|
||||
if !l.heapKey.valid() {
|
||||
// l.iter is exhausted.
|
||||
m.err = l.iter.Error()
|
||||
if m.err == nil {
|
||||
m.heap.pop()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if m.heap.len() > 1 {
|
||||
m.heap.fix(0)
|
||||
}
|
||||
}
|
||||
|
||||
// DebugString returns a string representing the current internal state of the
|
||||
// merging iterator and its heap for debugging purposes.
|
||||
func (m *MergingIter) DebugString() string {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "Current bounds: [%q, %q)\n", m.start, m.end)
|
||||
for i := range m.levels {
|
||||
fmt.Fprintf(&buf, "%d: heap key %s\n", i, m.levels[i].heapKey)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type mergingIterItem struct {
|
||||
// boundKey points to the corresponding mergingIterLevel's `iterKey`.
|
||||
*boundKey
|
||||
// index is the index of this level within the MergingIter's levels field.
|
||||
index int
|
||||
}
|
||||
|
||||
// mergingIterHeap is copied from mergingIterHeap defined in the root pebble
|
||||
// package for use with point keys.
|
||||
|
||||
type mergingIterHeap struct {
|
||||
cmp base.Compare
|
||||
reverse bool
|
||||
items []mergingIterItem
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) len() int {
|
||||
return len(h.items)
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) less(i, j int) bool {
|
||||
// This key comparison only uses the user key and not the boundKind. Bound
|
||||
// kind doesn't matter because when stepping over a user key,
|
||||
// findNextFragmentSet and findPrevFragmentSet skip past all heap items with
|
||||
// that user key, and makes no assumptions on ordering. All other heap
|
||||
// examinations only consider the user key.
|
||||
ik, jk := h.items[i].key, h.items[j].key
|
||||
c := h.cmp(ik, jk)
|
||||
if h.reverse {
|
||||
return c > 0
|
||||
}
|
||||
return c < 0
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) swap(i, j int) {
|
||||
h.items[i], h.items[j] = h.items[j], h.items[i]
|
||||
}
|
||||
|
||||
// init, fix, up and down are copied from the go stdlib.
|
||||
func (h *mergingIterHeap) init() {
|
||||
// heapify
|
||||
n := h.len()
|
||||
for i := n/2 - 1; i >= 0; i-- {
|
||||
h.down(i, n)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) fix(i int) {
|
||||
if !h.down(i, h.len()) {
|
||||
h.up(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) pop() *mergingIterItem {
|
||||
n := h.len() - 1
|
||||
h.swap(0, n)
|
||||
h.down(0, n)
|
||||
item := &h.items[n]
|
||||
h.items = h.items[:n]
|
||||
return item
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) up(j int) {
|
||||
for {
|
||||
i := (j - 1) / 2 // parent
|
||||
if i == j || !h.less(j, i) {
|
||||
break
|
||||
}
|
||||
h.swap(i, j)
|
||||
j = i
|
||||
}
|
||||
}
|
||||
|
||||
func (h *mergingIterHeap) down(i0, n int) bool {
|
||||
i := i0
|
||||
for {
|
||||
j1 := 2*i + 1
|
||||
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
|
||||
break
|
||||
}
|
||||
j := j1 // left child
|
||||
if j2 := j1 + 1; j2 < n && h.less(j2, j1) {
|
||||
j = j2 // = 2*i + 2 // right child
|
||||
}
|
||||
if !h.less(j, i) {
|
||||
break
|
||||
}
|
||||
h.swap(i, j)
|
||||
i = j
|
||||
}
|
||||
return i > i0
|
||||
}
|
||||
|
||||
func startBound(s Span) boundKey {
|
||||
if !s.Valid() {
|
||||
return boundKey{kind: boundKindInvalid}
|
||||
}
|
||||
return boundKey{
|
||||
kind: boundKindFragmentStart,
|
||||
key: s.Start,
|
||||
span: s,
|
||||
}
|
||||
}
|
||||
|
||||
func endBound(s Span) boundKey {
|
||||
if !s.Valid() {
|
||||
return boundKey{kind: boundKindInvalid}
|
||||
}
|
||||
return boundKey{
|
||||
kind: boundKindFragmentEnd,
|
||||
key: s.End,
|
||||
span: s,
|
||||
}
|
||||
}
|
||||
|
||||
type boundKind int8
|
||||
|
||||
const (
|
||||
boundKindInvalid boundKind = iota
|
||||
boundKindFragmentStart
|
||||
boundKindFragmentEnd
|
||||
)
|
||||
|
||||
type boundKey struct {
|
||||
kind boundKind
|
||||
key []byte
|
||||
// span holds the span the bound key comes from.
|
||||
//
|
||||
// If kind is boundKindFragmentStart, then key is span.Start. If kind is
|
||||
// boundKindFragmentEnd, then key is span.End.
|
||||
span Span
|
||||
}
|
||||
|
||||
func (k boundKey) valid() bool {
|
||||
return k.kind != boundKindInvalid
|
||||
}
|
||||
|
||||
func (k boundKey) String() string {
|
||||
var buf bytes.Buffer
|
||||
switch k.kind {
|
||||
case boundKindInvalid:
|
||||
fmt.Fprint(&buf, "invalid")
|
||||
case boundKindFragmentStart:
|
||||
fmt.Fprint(&buf, "fragment-start")
|
||||
case boundKindFragmentEnd:
|
||||
fmt.Fprint(&buf, "fragment-end ")
|
||||
default:
|
||||
fmt.Fprintf(&buf, "unknown-kind(%d)", k.kind)
|
||||
}
|
||||
fmt.Fprintf(&buf, " %s [", k.key)
|
||||
fmt.Fprintf(&buf, "%s", k.span)
|
||||
fmt.Fprint(&buf, "]")
|
||||
return buf.String()
|
||||
}
|
||||
98
vendor/github.com/cockroachdb/pebble/internal/keyspan/seek.go
generated
vendored
Normal file
98
vendor/github.com/cockroachdb/pebble/internal/keyspan/seek.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||||
// of this source code is governed by a BSD-style license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
package keyspan
|
||||
|
||||
import "github.com/cockroachdb/pebble/internal/base"
|
||||
|
||||
// TODO(jackson): Move snapshot visiblity outside of SeekGE/SeekLE and into the
|
||||
// callsite. This should simplify the code some more.
|
||||
|
||||
// SeekGE seeks to the span that contains the target key or the first span past
|
||||
// the target key. The snapshot parameter controls the visibility of keys (only
|
||||
// spans older than the snapshot sequence number are visible).
|
||||
func SeekGE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) Span {
|
||||
// NB: We use SeekLT in order to land on the proper span for a search
|
||||
// key that resides in the middle of a span. Consider the scenario:
|
||||
//
|
||||
// a---e
|
||||
// e---i
|
||||
//
|
||||
// The spans are indexed by their start keys `a` and `e`. If the
|
||||
// search key is `c` we want to land on the span [a,e). If we were to
|
||||
// use SeekGE then the search key `c` would land on the span [e,i) and
|
||||
// we'd have to backtrack. The one complexity here is what happens for the
|
||||
// search key `e`. In that case SeekLT will land us on the span [a,e)
|
||||
// and we'll have to move forward.
|
||||
iterSpan := iter.SeekLT(key)
|
||||
|
||||
// Invariant: key > iterSpan.Start
|
||||
|
||||
if !iterSpan.Valid() || cmp(key, iterSpan.End) >= 0 {
|
||||
// The current span lies entirely before the search key, or the iterator
|
||||
// is exhausted. Advance the iterator to the next span which is
|
||||
// guaranteed to lie at or past the search key.
|
||||
iterSpan = iter.Next()
|
||||
}
|
||||
// The iterator is positioned at a valid iterSpan which is the first
|
||||
// iterator position that satisfies the requirement that it contains or is
|
||||
// past the target key. It may not be visible based on the snapshot. So now
|
||||
// we only need to move forward and return the first span with visible keys.
|
||||
iterSpan = iterSpan.Visible(snapshot)
|
||||
for iterSpan.Valid() && iterSpan.Empty() {
|
||||
iterSpan = iter.Next().Visible(snapshot)
|
||||
}
|
||||
return iterSpan
|
||||
}
|
||||
|
||||
// SeekLE seeks to the span that contains or is before the target key. The
|
||||
// snapshot parameter controls the visibility of keys (only spans older than the
|
||||
// snapshot sequence number are visible).
|
||||
func SeekLE(cmp base.Compare, iter FragmentIterator, key []byte, snapshot uint64) Span {
|
||||
// NB: We use SeekLT in order to land on the proper span for a search
|
||||
// key that resides in the middle of a span. Consider the scenario:
|
||||
//
|
||||
// a---e
|
||||
// e---i
|
||||
//
|
||||
// The spans are indexed by their start keys `a` and `e`. If the
|
||||
// search key is `c` we want to land on the span [a,e). If we were to
|
||||
// use SeekGE then the search key `c` would land on the span [e,i) and
|
||||
// we'd have to backtrack. The one complexity here is what happens for the
|
||||
// search key `e`. In that case SeekLT will land us on the span [a,e)
|
||||
// and we'll have to move forward.
|
||||
iterSpan := iter.SeekLT(key)
|
||||
|
||||
if !iterSpan.Valid() {
|
||||
// Advance the iterator once to see if the next span has a start key
|
||||
// equal to key.
|
||||
iterSpan = iter.Next()
|
||||
if !iterSpan.Valid() || cmp(key, iterSpan.Start) < 0 {
|
||||
// The iterator is exhausted or we've hit the next span.
|
||||
return Span{}
|
||||
}
|
||||
} else {
|
||||
// Invariant: key > iterSpan.Start
|
||||
if cmp(key, iterSpan.End) >= 0 {
|
||||
// The current span lies entirely before the search key. Check to see if
|
||||
// the next span contains the search key. If it doesn't, we'll backup
|
||||
// and return to our earlier candidate.
|
||||
iterSpan = iter.Next()
|
||||
if !iterSpan.Valid() || cmp(key, iterSpan.Start) < 0 {
|
||||
// The next span is past our search key or there is no next span. Go
|
||||
// back.
|
||||
iterSpan = iter.Prev()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We're positioned at a span that contains or is before the search key. It
|
||||
// may not be visible based on the snapshot. So now we only need to move
|
||||
// backward and return the first span with visible keys.
|
||||
iterSpan = iterSpan.Visible(snapshot)
|
||||
for iterSpan.Valid() && iterSpan.Empty() {
|
||||
iterSpan = iter.Prev().Visible(snapshot)
|
||||
}
|
||||
return iterSpan
|
||||
}
|
||||
278
vendor/github.com/cockroachdb/pebble/internal/keyspan/span.go
generated
vendored
Normal file
278
vendor/github.com/cockroachdb/pebble/internal/keyspan/span.go
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
// 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 (
|
||||
"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. 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Kind returns the kind component of the key.
|
||||
func (k Key) Kind() base.InternalKeyKind {
|
||||
return base.InternalKeyKind(k.Trailer & 0xff)
|
||||
}
|
||||
|
||||
// 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 len(s.Keys) == 0
|
||||
}
|
||||
|
||||
// SmallestKey returns the smallest internal key defined by the span's keys.
|
||||
// It panics if the span contains no keys.
|
||||
func (s Span) SmallestKey() base.InternalKey {
|
||||
if len(s.Keys) == 0 {
|
||||
panic("pebble: Span contains no keys")
|
||||
}
|
||||
// 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 panics if the span contains no keys.
|
||||
func (s Span) LargestKey() base.InternalKey {
|
||||
if len(s.Keys) == 0 {
|
||||
panic("pebble: Span contains no keys")
|
||||
}
|
||||
// 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 panics if the span contains no keys.
|
||||
func (s Span) SmallestSeqNum() uint64 {
|
||||
if len(s.Keys) == 0 {
|
||||
panic("pebble: Span contains no keys")
|
||||
}
|
||||
return s.Keys[len(s.Keys)-1].SeqNum()
|
||||
}
|
||||
|
||||
// LargestSeqNum returns the largest sequence number of a key contained within
|
||||
// the span. It panics if the span contains no keys.
|
||||
func (s Span) LargestSeqNum() uint64 {
|
||||
if len(s.Keys) == 0 {
|
||||
panic("pebble: Span contains no keys")
|
||||
}
|
||||
return s.Keys[0].SeqNum()
|
||||
}
|
||||
|
||||
// Visible returns a span with the subset of keys visible at the provided
|
||||
// sequence number.
|
||||
func (s Span) Visible(seqNum uint64) Span {
|
||||
ret := Span{Start: s.Start, End: s.End}
|
||||
for i := range s.Keys {
|
||||
if base.Visible(s.Keys[i].SeqNum(), seqNum) {
|
||||
ret.Keys = s.Keys[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// 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)),
|
||||
}
|
||||
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)),
|
||||
}
|
||||
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.
|
||||
func (s Span) Covers(seqNum uint64) bool {
|
||||
return !s.Empty() && s.Keys[0].SeqNum() > seqNum
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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, "}")
|
||||
}
|
||||
|
||||
// SortKeys sorts a keys slice by trailer.
|
||||
func SortKeys(keys []Key) {
|
||||
sorted := keysBySeqNumKind(keys)
|
||||
sort.Sort(&sorted)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
60
vendor/github.com/cockroachdb/pebble/internal/keyspan/truncate.go
generated
vendored
Normal file
60
vendor/github.com/cockroachdb/pebble/internal/keyspan/truncate.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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,
|
||||
) 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].
|
||||
//
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
// Truncate the bounds to lower and upper.
|
||||
if cmp(in.Start, lower) < 0 {
|
||||
out.Start = lower
|
||||
}
|
||||
if cmp(in.End, upper) > 0 {
|
||||
out.End = upper
|
||||
}
|
||||
return !out.Empty() && cmp(out.Start, out.End) < 0
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user