Skip to content

Commit 3355a02

Browse files
committed
internal/rangekey: reduce range-key iteration allocations
Remove the two remaining excess allocations incured when iterating with range keys enabled, in the absence of any committed range keys. This brings the number of allocations to parity with iteration with points only. The two removed allocations stemmed from use of closures constructed at iteration construction. These closures have been replaced with interfaces. ``` name old time/op new time/op delta IteratorScan/keys=100,r-amp=1,key-types=points-only-10 5.76µs ± 0% 5.87µs ± 0% +1.86% (p=0.000 n=8+8) IteratorScan/keys=100,r-amp=1,key-types=points-and-ranges-10 8.81µs ± 2% 8.81µs ± 3% ~ (p=0.684 n=10+10) IteratorScan/keys=100,r-amp=3,key-types=points-only-10 10.1µs ± 2% 10.4µs ± 3% ~ (p=0.063 n=10+10) IteratorScan/keys=100,r-amp=3,key-types=points-and-ranges-10 13.4µs ± 3% 13.8µs ± 1% +2.83% (p=0.022 n=10+9) IteratorScan/keys=100,r-amp=7,key-types=points-only-10 15.5µs ± 0% 15.7µs ± 2% +1.41% (p=0.028 n=9+10) IteratorScan/keys=100,r-amp=7,key-types=points-and-ranges-10 18.8µs ± 1% 19.0µs ± 2% ~ (p=0.123 n=10+10) IteratorScan/keys=100,r-amp=10,key-types=points-only-10 19.0µs ± 1% 19.2µs ± 1% ~ (p=0.146 n=10+8) IteratorScan/keys=100,r-amp=10,key-types=points-and-ranges-10 22.7µs ± 2% 22.9µs ± 2% +0.99% (p=0.011 n=10+10) IteratorScan/keys=1000,r-amp=1,key-types=points-only-10 44.5µs ± 0% 44.8µs ± 1% +0.60% (p=0.002 n=10+9) IteratorScan/keys=1000,r-amp=1,key-types=points-and-ranges-10 71.8µs ± 0% 71.5µs ± 3% ~ (p=0.052 n=10+10) IteratorScan/keys=1000,r-amp=3,key-types=points-only-10 77.4µs ± 1% 77.4µs ± 0% ~ (p=0.633 n=10+8) IteratorScan/keys=1000,r-amp=3,key-types=points-and-ranges-10 104µs ± 0% 104µs ± 1% -0.43% (p=0.023 n=10+10) IteratorScan/keys=1000,r-amp=7,key-types=points-only-10 104µs ± 1% 104µs ± 1% ~ (p=0.393 n=10+10) IteratorScan/keys=1000,r-amp=7,key-types=points-and-ranges-10 132µs ± 1% 133µs ± 0% ~ (p=0.063 n=10+10) IteratorScan/keys=1000,r-amp=10,key-types=points-only-10 118µs ± 1% 118µs ± 1% ~ (p=0.853 n=10+10) IteratorScan/keys=1000,r-amp=10,key-types=points-and-ranges-10 145µs ± 0% 145µs ± 1% ~ (p=0.579 n=10+10) IteratorScan/keys=10000,r-amp=1,key-types=points-only-10 417µs ± 0% 418µs ± 0% ~ (p=0.113 n=10+9) IteratorScan/keys=10000,r-amp=1,key-types=points-and-ranges-10 671µs ± 0% 667µs ± 2% -0.54% (p=0.043 n=10+10) IteratorScan/keys=10000,r-amp=3,key-types=points-only-10 708µs ± 2% 719µs ± 1% +1.54% (p=0.004 n=10+9) IteratorScan/keys=10000,r-amp=3,key-types=points-and-ranges-10 971µs ± 1% 973µs ± 2% ~ (p=0.739 n=10+10) IteratorScan/keys=10000,r-amp=7,key-types=points-only-10 948µs ± 1% 965µs ± 3% +1.82% (p=0.004 n=10+10) IteratorScan/keys=10000,r-amp=7,key-types=points-and-ranges-10 1.20ms ± 1% 1.22ms ± 1% +1.22% (p=0.004 n=10+10) IteratorScan/keys=10000,r-amp=10,key-types=points-only-10 1.05ms ± 1% 1.07ms ± 1% +1.86% (p=0.000 n=10+10) IteratorScan/keys=10000,r-amp=10,key-types=points-and-ranges-10 1.31ms ± 1% 1.32ms ± 1% +1.17% (p=0.000 n=10+9) name old alloc/op new alloc/op delta IteratorScan/keys=100,r-amp=1,key-types=points-only-10 16.0B ± 0% 16.0B ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=1,key-types=points-and-ranges-10 48.0B ± 0% 16.0B ± 0% -66.67% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=3,key-types=points-only-10 48.0B ± 0% 48.0B ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=3,key-types=points-and-ranges-10 80.0B ± 0% 48.0B ± 0% -40.00% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=7,key-types=points-only-10 112B ± 0% 112B ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=7,key-types=points-and-ranges-10 144B ± 0% 112B ± 0% -22.22% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=10,key-types=points-only-10 160B ± 0% 160B ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=10,key-types=points-and-ranges-10 192B ± 0% 160B ± 0% -16.67% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=1,key-types=points-only-10 16.0B ± 0% 16.0B ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=1,key-types=points-and-ranges-10 48.0B ± 0% 16.0B ± 0% -66.67% (p=0.000 n=9+9) IteratorScan/keys=1000,r-amp=3,key-types=points-only-10 48.0B ± 0% 48.0B ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=3,key-types=points-and-ranges-10 81.0B ± 0% 48.6B ± 1% -40.00% (p=0.000 n=8+10) IteratorScan/keys=1000,r-amp=7,key-types=points-only-10 113B ± 0% 113B ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=7,key-types=points-and-ranges-10 145B ± 0% 113B ± 0% -21.91% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=10,key-types=points-only-10 161B ± 0% 161B ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=10,key-types=points-and-ranges-10 194B ± 0% 162B ± 0% -16.49% (p=0.000 n=9+8) IteratorScan/keys=10000,r-amp=1,key-types=points-only-10 18.8B ±15% 18.8B ±15% ~ (p=1.000 n=10+10) IteratorScan/keys=10000,r-amp=1,key-types=points-and-ranges-10 54.3B ± 8% 24.0B ± 0% -55.80% (p=0.000 n=10+6) IteratorScan/keys=10000,r-amp=3,key-types=points-only-10 53.0B ± 8% 53.8B ± 9% ~ (p=0.577 n=10+10) IteratorScan/keys=10000,r-amp=3,key-types=points-and-ranges-10 88.8B ± 7% 60.4B ± 1% -31.95% (p=0.000 n=10+7) IteratorScan/keys=10000,r-amp=7,key-types=points-only-10 122B ± 0% 122B ± 0% ~ (p=0.082 n=9+9) IteratorScan/keys=10000,r-amp=7,key-types=points-and-ranges-10 160B ± 0% 123B ± 6% -23.00% (p=0.000 n=9+10) IteratorScan/keys=10000,r-amp=10,key-types=points-only-10 169B ± 4% 172B ± 0% ~ (p=0.294 n=10+8) IteratorScan/keys=10000,r-amp=10,key-types=points-and-ranges-10 206B ± 5% 178B ± 0% -13.51% (p=0.000 n=10+8) name old allocs/op new allocs/op delta IteratorScan/keys=100,r-amp=1,key-types=points-only-10 1.00 ± 0% 1.00 ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=1,key-types=points-and-ranges-10 3.00 ± 0% 1.00 ± 0% -66.67% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=3,key-types=points-only-10 3.00 ± 0% 3.00 ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=3,key-types=points-and-ranges-10 5.00 ± 0% 3.00 ± 0% -40.00% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=7,key-types=points-only-10 7.00 ± 0% 7.00 ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=7,key-types=points-and-ranges-10 9.00 ± 0% 7.00 ± 0% -22.22% (p=0.000 n=10+10) IteratorScan/keys=100,r-amp=10,key-types=points-only-10 10.0 ± 0% 10.0 ± 0% ~ (all equal) IteratorScan/keys=100,r-amp=10,key-types=points-and-ranges-10 12.0 ± 0% 10.0 ± 0% -16.67% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=1,key-types=points-only-10 1.00 ± 0% 1.00 ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=1,key-types=points-and-ranges-10 3.00 ± 0% 1.00 ± 0% -66.67% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=3,key-types=points-only-10 3.00 ± 0% 3.00 ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=3,key-types=points-and-ranges-10 5.00 ± 0% 3.00 ± 0% -40.00% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=7,key-types=points-only-10 7.00 ± 0% 7.00 ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=7,key-types=points-and-ranges-10 9.00 ± 0% 7.00 ± 0% -22.22% (p=0.000 n=10+10) IteratorScan/keys=1000,r-amp=10,key-types=points-only-10 10.0 ± 0% 10.0 ± 0% ~ (all equal) IteratorScan/keys=1000,r-amp=10,key-types=points-and-ranges-10 12.0 ± 0% 10.0 ± 0% -16.67% (p=0.000 n=10+10) IteratorScan/keys=10000,r-amp=1,key-types=points-only-10 1.00 ± 0% 1.00 ± 0% ~ (all equal) IteratorScan/keys=10000,r-amp=1,key-types=points-and-ranges-10 3.00 ± 0% 1.00 ± 0% -66.67% (p=0.000 n=10+10) IteratorScan/keys=10000,r-amp=3,key-types=points-only-10 3.00 ± 0% 3.00 ± 0% ~ (all equal) IteratorScan/keys=10000,r-amp=3,key-types=points-and-ranges-10 5.00 ± 0% 3.00 ± 0% -40.00% (p=0.000 n=10+10) IteratorScan/keys=10000,r-amp=7,key-types=points-only-10 7.00 ± 0% 7.00 ± 0% ~ (all equal) IteratorScan/keys=10000,r-amp=7,key-types=points-and-ranges-10 9.00 ± 0% 7.00 ± 0% -22.22% (p=0.000 n=10+10) IteratorScan/keys=10000,r-amp=10,key-types=points-only-10 10.0 ± 0% 10.0 ± 0% ~ (all equal) IteratorScan/keys=10000,r-amp=10,key-types=points-and-ranges-10 12.0 ± 0% 10.0 ± 0% -16.67% (p=0.000 n=10+10) ```
1 parent 4e33626 commit 3355a02

File tree

6 files changed

+78
-51
lines changed

6 files changed

+78
-51
lines changed

internal/keyspan/defragment.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,29 @@ const bufferReuseMaxCapacity = 10 << 10 // 10 KB
1818

1919
// DefragmentMethod configures the defragmentation performed by the
2020
// DefragmentingIter.
21-
type DefragmentMethod func(base.Compare, Span, Span) bool
21+
type DefragmentMethod interface {
22+
// ShouldDefragment takes two abutting spans and returns whether the two
23+
// spans should be combined into a single, defragmented Span.
24+
ShouldDefragment(cmp base.Compare, left, right Span) bool
25+
}
26+
27+
// The DefragmentMethodFunc type is an adapter to allow the use of ordinary
28+
// functions as DefragmentMethods. If f is a function with the appropriate
29+
// signature, DefragmentMethodFunc(f) is a DefragmentMethod that calls f.
30+
type DefragmentMethodFunc func(cmp base.Compare, left, right Span) bool
31+
32+
// ShouldDefragment calls f(cmp, left, right).
33+
func (f DefragmentMethodFunc) ShouldDefragment(cmp base.Compare, left, right Span) bool {
34+
return f(cmp, left, right)
35+
}
2236

2337
// DefragmentInternal configures a DefragmentingIter to defragment spans
2438
// only if they have identical keys.
2539
//
2640
// This defragmenting method is intended for use in compactions that may see
2741
// internal range keys fragments that may now be joined, because the state that
2842
// required their fragmentation has been dropped.
29-
var DefragmentInternal DefragmentMethod = func(cmp base.Compare, a, b Span) bool {
43+
var DefragmentInternal DefragmentMethod = DefragmentMethodFunc(func(cmp base.Compare, a, b Span) bool {
3044
if len(a.Keys) != len(b.Keys) {
3145
return false
3246
}
@@ -42,7 +56,7 @@ var DefragmentInternal DefragmentMethod = func(cmp base.Compare, a, b Span) bool
4256
}
4357
}
4458
return true
45-
}
59+
})
4660

4761
// DefragmentReducer merges the current and next Key slices, returning a new Key
4862
// slice.
@@ -119,10 +133,10 @@ type DefragmentingIter struct {
119133
keysBuf []Key
120134
keyBuf []byte
121135

122-
// equal is a comparison function for two spans. equal is called when two
136+
// method is a comparison function for two spans. method is called when two
123137
// spans are abutting to determine whether they may be defragmented.
124-
// equal does not itself check for adjacency for the two spans.
125-
equal DefragmentMethod
138+
// method does not itself check for adjacency for the two spans.
139+
method DefragmentMethod
126140

127141
// reduce is the reducer function used to collect Keys across all spans that
128142
// constitute a defragmented span.
@@ -140,7 +154,7 @@ func (i *DefragmentingIter) Init(
140154
*i = DefragmentingIter{
141155
cmp: cmp,
142156
iter: iter,
143-
equal: equal,
157+
method: equal,
144158
reduce: reducer,
145159
}
146160
}
@@ -307,7 +321,7 @@ func (i *DefragmentingIter) Prev() Span {
307321
// DefragmentMethod and ensures both spans are NOT empty; not defragmenting empty
308322
// spans is an optimization that lets us load fewer sstable blocks.
309323
func (i *DefragmentingIter) checkEqual(left, right Span) bool {
310-
return i.equal(i.cmp, i.iterSpan, i.curr) && !(left.Empty() && right.Empty())
324+
return (!left.Empty() && !right.Empty()) && i.method.ShouldDefragment(i.cmp, i.iterSpan, i.curr)
311325
}
312326

313327
// defragmentForward defragments spans in the forward direction, starting from

internal/keyspan/defragment_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
func TestDefragmentingIter(t *testing.T) {
2424
cmp := testkeys.Comparer.Compare
2525
internalEqual := DefragmentInternal
26-
alwaysEqual := func(_ base.Compare, _, _ Span) bool { return true }
26+
alwaysEqual := DefragmentMethodFunc(func(_ base.Compare, _, _ Span) bool { return true })
2727
staticReducer := StaticDefragmentReducer
2828
collectReducer := func(cur, next []Key) []Key {
2929
c := keysBySeqNumKind(append(cur, next...))

internal/keyspan/merging_iter.go

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,39 @@ import (
2020
// seeks would require introducing key comparisons to switchTo{Min,Max}Heap
2121
// where there currently are none.
2222

23-
// Transform defines a transform function to be applied to a Span. A Transform
24-
// takes a Span as input and writes the transformed Span to the provided output
25-
// *Span pointer. The output Span's Keys slice may be reused by Transform to
26-
// reduce allocations.
27-
type Transform func(cmp base.Compare, in Span, out *Span) error
23+
// Transformer defines a transformation to be applied to a Span.
24+
type Transformer interface {
25+
// Transform takes a Span as input and writes the transformed Span to the
26+
// provided output *Span pointer. The output Span's Keys slice may be reused
27+
// by Transform to reduce allocations.
28+
Transform(cmp base.Compare, in Span, out *Span) error
29+
}
30+
31+
// The TransformerFunc type is an adapter to allow the use of ordinary functions
32+
// as Transformers. If f is a function with the appropriate signature,
33+
// TransformerFunc(f) is a Transformer that calls f.
34+
type TransformerFunc func(base.Compare, Span, *Span) error
35+
36+
// Transform calls f(cmp, in, out).
37+
func (tf TransformerFunc) Transform(cmp base.Compare, in Span, out *Span) error {
38+
return tf(cmp, in, out)
39+
}
2840

29-
func noopTransform(_ base.Compare, s Span, dst *Span) error {
41+
var noopTransform Transformer = TransformerFunc(func(_ base.Compare, s Span, dst *Span) error {
3042
dst.Start, dst.End = s.Start, s.End
3143
dst.Keys = append(dst.Keys[:0], s.Keys...)
3244
return nil
33-
}
45+
})
3446

3547
// visibleTransform filters keys that are invisible at the provided snapshot
3648
// sequence number.
37-
func visibleTransform(snapshot uint64) Transform {
38-
return func(_ base.Compare, s Span, dst *Span) error {
49+
func visibleTransform(snapshot uint64) Transformer {
50+
return TransformerFunc(func(_ base.Compare, s Span, dst *Span) error {
3951
s = s.Visible(snapshot)
4052
dst.Start, dst.End = s.Start, s.End
4153
dst.Keys = append(dst.Keys[:0], s.Keys...)
4254
return nil
43-
}
55+
})
4456
}
4557

4658
// MergingIter merges spans across levels of the LSM, exposing an iterator over
@@ -200,10 +212,10 @@ type MergingIter struct {
200212
// Each element points into a child iterator's memory, so the keys may not
201213
// be directly modified.
202214
keys keysBySeqNumKind
203-
// transform defines a function to be applied to a span before it's yielded
204-
// to the user. A transform may filter individual keys contained within the
205-
// span.
206-
transform Transform
215+
// transformer defines a transformation to be applied to a span before it's
216+
// yielded to the user. Transforming may filter individual keys contained
217+
// within the span.
218+
transformer Transformer
207219
// span holds the iterator's current span. This span is used as the
208220
// destination for transforms. Every tranformed span overwrites the
209221
// previous.
@@ -240,12 +252,12 @@ func (l *mergingIterLevel) prev() {
240252
}
241253

242254
// Init initializes the merging iterator with the provided fragment iterators.
243-
func (m *MergingIter) Init(cmp base.Compare, transform Transform, iters ...FragmentIterator) {
255+
func (m *MergingIter) Init(cmp base.Compare, transformer Transformer, iters ...FragmentIterator) {
244256
levels, items := m.levels, m.heap.items
245257

246258
*m = MergingIter{
247-
heap: mergingIterHeap{cmp: cmp},
248-
transform: transform,
259+
heap: mergingIterHeap{cmp: cmp},
260+
transformer: transformer,
249261
}
250262
// Invariant: cap(levels) == cap(items)
251263
if cap(levels) < len(iters) {
@@ -727,7 +739,7 @@ func (m *MergingIter) synthesizeKeys(dir int8) (bool, Span) {
727739
End: m.end,
728740
Keys: m.keys,
729741
}
730-
if err := m.transform(m.cmp, s, &m.span); err != nil {
742+
if err := m.transformer.Transform(m.cmp, s, &m.span); err != nil {
731743
m.err = err
732744
return false, Span{}
733745
}

internal/rangekey/coalesce.go

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ func (ui *UserIteratorConfig) Init(
4040
ui.snapshot = snapshot
4141
ui.defragBufA.keys = ui.defragBufAlloc[0][:0]
4242
ui.defragBufB.keys = ui.defragBufAlloc[1][:0]
43-
ui.miter.Init(cmp, ui.transform, levelIters...)
44-
ui.diter.Init(cmp, &ui.miter, ui.defragmentMethod, keyspan.StaticDefragmentReducer)
43+
ui.miter.Init(cmp, ui, levelIters...)
44+
ui.diter.Init(cmp, &ui.miter, ui, keyspan.StaticDefragmentReducer)
4545
return &ui.diter
4646
}
4747

48-
// transform implements the keyspan.Transform function signature for use with a
48+
// Transform implements the keyspan.Transformer interface for use with a
4949
// keyspan.MergingIter. It transforms spans by resolving range keys at the
5050
// provided snapshot sequence number. Shadowing of keys is resolved (eg, removal
5151
// of unset keys, removal of keys overwritten by a set at the same suffix, etc)
5252
// and then non-RangeKeySet keys are removed. The resulting transformed spans
5353
// only contain RangeKeySets describing the state visible at the provided
5454
// sequence number.
55-
func (ui *UserIteratorConfig) transform(cmp base.Compare, s keyspan.Span, dst *keyspan.Span) error {
55+
func (ui *UserIteratorConfig) Transform(cmp base.Compare, s keyspan.Span, dst *keyspan.Span) error {
5656
// Apply shadowing of keys.
5757
if err := Coalesce(cmp, s.Visible(ui.snapshot), dst); err != nil {
5858
return err
@@ -80,24 +80,23 @@ func (ui *UserIteratorConfig) transform(cmp base.Compare, s keyspan.Span, dst *k
8080
return nil
8181
}
8282

83-
// defragmentMethod implements the DefragmentMethod function signature and
84-
// configures a DefragmentingIter to defragment spans of range keys if their
85-
// user-visible state is identical. This defragmenting method assumes the
86-
// provided spans have already been transformed through
87-
// (UserIterationConfig).transform, so all RangeKeySets are user-visible sets.
88-
// This defragmenter checks for equality between set suffixes and values
89-
// (ignoring sequence numbers). It's intended for use during user iteration,
90-
// when the wrapped keyspan iterator is merging spans across all levels of the
91-
// LSM.
83+
// ShouldDefragment implements the DefragmentMethod interface and configures a
84+
// DefragmentingIter to defragment spans of range keys if their user-visible
85+
// state is identical. This defragmenting method assumes the provided spans have
86+
// already been transformed through (UserIterationConfig).Transform, so all
87+
// RangeKeySets are user-visible sets. This defragmenter checks for equality
88+
// between set suffixes and values (ignoring sequence numbers). It's intended
89+
// for use during user iteration, when the wrapped keyspan iterator is merging
90+
// spans across all levels of the LSM.
9291
//
93-
// The returned defragmenting method is stateful, and must not be used on
94-
// multiple DefragmentingIters concurrently.
95-
func (ui *UserIteratorConfig) defragmentMethod(cmp base.Compare, a, b keyspan.Span) bool {
96-
// UserIterationDefragmenter must only be used on spans that have
97-
// transformed by ui.transform. The transform applies shadowing and removes
98-
// all keys besides the resulting Sets. Since shadowing has been applied,
99-
// each Set must set a unique suffix. If the two spans are equivalent, they
100-
// must have the same number of range key sets.
92+
// This implementation is stateful, and must not be used on multiple
93+
// DefragmentingIters concurrently.
94+
func (ui *UserIteratorConfig) ShouldDefragment(cmp base.Compare, a, b keyspan.Span) bool {
95+
// This implementation must only be used on spans that have transformed by
96+
// ui.Transform. The transform applies shadowing and removes all keys
97+
// besides the resulting Sets. Since shadowing has been applied, each Set
98+
// must set a unique suffix. If the two spans are equivalent, they must have
99+
// the same number of range key sets.
101100
if len(a.Keys) != len(b.Keys) || len(a.Keys) == 0 {
102101
return false
103102
}

internal/rangekey/coalesce_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ func TestIter(t *testing.T) {
6666
for _, line := range lines {
6767
spans = append(spans, keyspan.ParseSpan(line))
6868
}
69-
transform := func(cmp base.Compare, s keyspan.Span, dst *keyspan.Span) error {
69+
transform := keyspan.TransformerFunc(func(cmp base.Compare, s keyspan.Span, dst *keyspan.Span) error {
7070
s = s.Visible(visibleSeqNum)
7171
return Coalesce(cmp, s, dst)
72-
}
72+
})
7373
iter.Init(cmp, transform, keyspan.NewIter(cmp, spans))
7474
return "OK"
7575
case "iter":

table_stats.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,9 @@ func foreachDefragmentedTombstone(
458458
fn func([]byte, []byte, uint64, uint64) error,
459459
) error {
460460
// Use an equals func that will always merge abutting spans.
461-
equal := func(_ base.Compare, _, _ keyspan.Span) bool { return true }
461+
equal := keyspan.DefragmentMethodFunc(func(_ base.Compare, _, _ keyspan.Span) bool {
462+
return true
463+
})
462464
// Reduce keys by maintaining a slice of length two, corresponding to the
463465
// largest and smallest keys in the defragmented span. This maintains the
464466
// contract that the emitted slice is sorted by (SeqNum, Kind) descending.

0 commit comments

Comments
 (0)