Skip to content

Commit a07853d

Browse files
committed
db: treesteps support for mergingIter
Add treesteps instrumentation to mergingIter and a corresponding test.
1 parent c402451 commit a07853d

File tree

7 files changed

+296
-27
lines changed

7 files changed

+296
-27
lines changed

internal/keyspan/assert_iter.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ func (i *assertIter) WrapChildren(wrap WrapFn) {
183183

184184
// TreeStepsNode is part of the FragmentIterator interface.
185185
func (i *assertIter) TreeStepsNode() treesteps.NodeInfo {
186-
info := treesteps.NodeInfof(i, "%T(%p)", i, i)
187-
info.AddChildren(i.iter)
188-
return info
186+
// Pass through, hiding this node from the hierarchy.
187+
return i.iter.TreeStepsNode()
189188
}

internal/keyspan/test_utils.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ func (i *invalidatingIter) WrapChildren(wrap WrapFn) {
582582

583583
// TreeStepsNode is part of the FragmentIterator interface.
584584
func (i *invalidatingIter) TreeStepsNode() treesteps.NodeInfo {
585-
info := treesteps.NodeInfof(i, "%T(%p)", i, i)
586-
info.AddChildren(i.iter)
587-
return info
585+
// Pass through, hiding this node from the hierarchy.
586+
return i.iter.TreeStepsNode()
588587
}

merging_iter.go

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ type mergingIterLevel struct {
4242
// positioning tombstones at lower levels which cannot possibly shadow the
4343
// current key.
4444
tombstone *keyspan.Span
45+
46+
// lastKey is used only during treesteps recordings.
47+
lastIterKey invariants.Value[string]
4548
}
4649

4750
// Assert that *mergingIterLevel implements rangeDelIterSetter.
@@ -56,6 +59,17 @@ func (ml *mergingIterLevel) setRangeDelIter(iter keyspan.FragmentIterator) {
5659
ml.rangeDelIterGeneration++
5760
}
5861

62+
// updateLastIterKey updates the lastIterKey field; only used for treesteps. We
63+
// cannot use iterKV directly because it is not valid while we are updating it
64+
// (i.e. when stepping through an operation on ml.iter).
65+
func (ml *mergingIterLevel) updateLastIterKey() {
66+
if ml.iterKV == nil {
67+
ml.lastIterKey.Set("<nil>")
68+
} else {
69+
ml.lastIterKey.Set(ml.iterKV.K.String())
70+
}
71+
}
72+
5973
// mergingIter provides a merged view of multiple iterators from different
6074
// levels of the LSM.
6175
//
@@ -328,6 +342,9 @@ func (m *mergingIter) initHeap() {
328342
for i := range m.levels {
329343
if l := &m.levels[i]; l.iterKV != nil {
330344
m.heap.items = append(m.heap.items, mergingIterHeapItem{mergingIterLevel: l})
345+
if treesteps.Enabled && treesteps.IsRecording(m) {
346+
l.updateLastIterKey()
347+
}
331348
}
332349
}
333350
m.heap.init()
@@ -433,6 +450,7 @@ func (m *mergingIter) switchToMinHeap() error {
433450
}
434451
// key >= iter-key
435452
}
453+
l.updateLastIterKey()
436454
if l.iterKV == nil {
437455
if err := l.iter.Error(); err != nil {
438456
return err
@@ -486,6 +504,7 @@ func (m *mergingIter) switchToMaxHeap() error {
486504
}
487505
// key <= iter-key
488506
}
507+
l.updateLastIterKey()
489508
if l.iterKV == nil {
490509
if err := l.iter.Error(); err != nil {
491510
return err
@@ -563,6 +582,9 @@ func (m *mergingIter) nextEntry(l *mergingIterLevel, succKey []byte) error {
563582
oldTopLevel--
564583
}
565584
}
585+
if treesteps.Enabled && treesteps.IsRecording(m) {
586+
l.updateLastIterKey()
587+
}
566588

567589
// The cached tombstones are only valid for the levels
568590
// [0,oldTopLevel]. Updated the cached tombstones for any levels in the range
@@ -775,6 +797,10 @@ func (m *mergingIter) prevEntry(l *mergingIterLevel) error {
775797
m.heap.pop()
776798
}
777799

800+
if treesteps.Enabled && treesteps.IsRecording(m) {
801+
l.updateLastIterKey()
802+
}
803+
778804
// The cached tombstones are only valid for the levels
779805
// [0,oldTopLevel]. Updated the cached tombstones for any levels in the range
780806
// [oldTopLevel+1,heap[0].index].
@@ -1021,7 +1047,13 @@ func (m *mergingIter) String() string {
10211047
// SeekGE implements base.InternalIterator.SeekGE. Note that SeekGE only checks
10221048
// the upper bound. It is up to the caller to ensure that key is greater than
10231049
// or equal to the lower bound.
1024-
func (m *mergingIter) SeekGE(key []byte, flags base.SeekGEFlags) *base.InternalKV {
1050+
func (m *mergingIter) SeekGE(key []byte, flags base.SeekGEFlags) (kv *base.InternalKV) {
1051+
if treesteps.Enabled && treesteps.IsRecording(m) {
1052+
op := treesteps.StartOpf(m, "SeekGE(%q, %d)", key, flags)
1053+
defer func() {
1054+
op.Finishf("= %s", kv.String())
1055+
}()
1056+
}
10251057
m.prefix = nil
10261058
m.err = m.seekGE(key, 0 /* start level */, flags)
10271059
if m.err != nil {
@@ -1039,7 +1071,13 @@ func (m *mergingIter) SeekPrefixGE(prefix, key []byte, flags base.SeekGEFlags) *
10391071
// SeekPrefixGEStrict explicitly checks that the key has a matching prefix.
10401072
func (m *mergingIter) SeekPrefixGEStrict(
10411073
prefix, key []byte, flags base.SeekGEFlags,
1042-
) *base.InternalKV {
1074+
) (kv *base.InternalKV) {
1075+
if treesteps.Enabled && treesteps.IsRecording(m) {
1076+
op := treesteps.StartOpf(m, "SeekPrefixGE(%q, %q, %d)", prefix, key, flags)
1077+
defer func() {
1078+
op.Finishf("= %s", kv.String())
1079+
}()
1080+
}
10431081
m.prefix = prefix
10441082
m.err = m.seekGE(key, 0 /* start level */, flags)
10451083
if m.err != nil {
@@ -1114,7 +1152,13 @@ func (m *mergingIter) seekLT(key []byte, level int, flags base.SeekLTFlags) erro
11141152
// SeekLT implements base.InternalIterator.SeekLT. Note that SeekLT only checks
11151153
// the lower bound. It is up to the caller to ensure that key is less than the
11161154
// upper bound.
1117-
func (m *mergingIter) SeekLT(key []byte, flags base.SeekLTFlags) *base.InternalKV {
1155+
func (m *mergingIter) SeekLT(key []byte, flags base.SeekLTFlags) (kv *base.InternalKV) {
1156+
if treesteps.Enabled && treesteps.IsRecording(m) {
1157+
op := treesteps.StartOpf(m, "SeekLT(%q, %d)", key, flags)
1158+
defer func() {
1159+
op.Finishf("= %s", kv.String())
1160+
}()
1161+
}
11181162
m.prefix = nil
11191163
m.err = m.seekLT(key, 0 /* start level */, flags)
11201164
if m.err != nil {
@@ -1126,7 +1170,13 @@ func (m *mergingIter) SeekLT(key []byte, flags base.SeekLTFlags) *base.InternalK
11261170
// First implements base.InternalIterator.First. Note that First only checks
11271171
// the upper bound. It is up to the caller to ensure that key is greater than
11281172
// or equal to the lower bound (e.g. via a call to SeekGE(lower)).
1129-
func (m *mergingIter) First() *base.InternalKV {
1173+
func (m *mergingIter) First() (kv *base.InternalKV) {
1174+
if treesteps.Enabled && treesteps.IsRecording(m) {
1175+
op := treesteps.StartOpf(m, "First()")
1176+
defer func() {
1177+
op.Finishf("= %s", kv.String())
1178+
}()
1179+
}
11301180
m.err = nil // clear cached iteration error
11311181
m.prefix = nil
11321182
m.heap.items = m.heap.items[:0]
@@ -1148,7 +1198,13 @@ func (m *mergingIter) First() *base.InternalKV {
11481198
// Last implements base.InternalIterator.Last. Note that Last only checks the
11491199
// lower bound. It is up to the caller to ensure that key is less than the
11501200
// upper bound (e.g. via a call to SeekLT(upper))
1151-
func (m *mergingIter) Last() *base.InternalKV {
1201+
func (m *mergingIter) Last() (kv *base.InternalKV) {
1202+
if treesteps.Enabled && treesteps.IsRecording(m) {
1203+
op := treesteps.StartOpf(m, "Last()")
1204+
defer func() {
1205+
op.Finishf("= %s", kv.String())
1206+
}()
1207+
}
11521208
m.err = nil // clear cached iteration error
11531209
m.prefix = nil
11541210
for i := range m.levels {
@@ -1166,7 +1222,13 @@ func (m *mergingIter) Last() *base.InternalKV {
11661222
return m.findPrevEntry()
11671223
}
11681224

1169-
func (m *mergingIter) Next() *base.InternalKV {
1225+
func (m *mergingIter) Next() (kv *base.InternalKV) {
1226+
if treesteps.Enabled && treesteps.IsRecording(m) {
1227+
op := treesteps.StartOpf(m, "Next()")
1228+
defer func() {
1229+
op.Finishf("= %s", kv.String())
1230+
}()
1231+
}
11701232
if m.err != nil {
11711233
return nil
11721234
}
@@ -1199,7 +1261,13 @@ func (m *mergingIter) Next() *base.InternalKV {
11991261
return iterKV
12001262
}
12011263

1202-
func (m *mergingIter) NextPrefix(succKey []byte) *base.InternalKV {
1264+
func (m *mergingIter) NextPrefix(succKey []byte) (kv *base.InternalKV) {
1265+
if treesteps.Enabled && treesteps.IsRecording(m) {
1266+
op := treesteps.StartOpf(m, "NextPrefix(%q)", succKey)
1267+
defer func() {
1268+
op.Finishf("= %s", kv.String())
1269+
}()
1270+
}
12031271
if m.dir != 1 {
12041272
panic("pebble: cannot switch directions with NextPrefix")
12051273
}
@@ -1269,7 +1337,13 @@ func (m *mergingIter) NextPrefix(succKey []byte) *base.InternalKV {
12691337
return m.findNextEntry()
12701338
}
12711339

1272-
func (m *mergingIter) Prev() *base.InternalKV {
1340+
func (m *mergingIter) Prev() (kv *base.InternalKV) {
1341+
if treesteps.Enabled && treesteps.IsRecording(m) {
1342+
op := treesteps.StartOpf(m, "Prev()")
1343+
defer func() {
1344+
op.Finishf("= %s", kv.String())
1345+
}()
1346+
}
12731347
if m.err != nil {
12741348
return nil
12751349
}
@@ -1330,11 +1404,47 @@ func (m *mergingIter) SetContext(ctx context.Context) {
13301404
}
13311405
}
13321406

1407+
type dummyNode struct {
1408+
info treesteps.NodeInfo
1409+
}
1410+
1411+
func (d *dummyNode) TreeStepsNode() treesteps.NodeInfo {
1412+
return d.info
1413+
}
1414+
13331415
// TreeStepsNode is part of the InternalIterator interface.
13341416
func (m *mergingIter) TreeStepsNode() treesteps.NodeInfo {
1417+
levelName := func(index int) string {
1418+
return string('A' + byte(index))
1419+
}
13351420
info := treesteps.NodeInfof(m, "mergingIter")
1421+
if m.heap.len() > 0 {
1422+
item := m.heap.items[0].mergingIterLevel
1423+
heapProp := "heap min"
1424+
if m.heap.reverse {
1425+
heapProp = "heap max"
1426+
}
1427+
info.AddPropf(heapProp, "%s:%s", levelName(item.index), item.lastIterKey.Get())
1428+
}
1429+
if m.prefix != nil {
1430+
info.AddPropf("prefix", "%s", m.prefix)
1431+
}
13361432
for i := range m.levels {
1337-
info.AddChildren(m.levels[i].iter)
1433+
l := &m.levels[i]
1434+
name := levelName(i)
1435+
if l.iterKV != nil {
1436+
name = fmt.Sprintf("%s:%s", name, l.lastIterKey.Get())
1437+
}
1438+
d := &dummyNode{}
1439+
d.info = treesteps.NodeInfof(d, "%s", name)
1440+
if l.tombstone != nil {
1441+
d.info.AddPropf("tombstone", "%s", l.tombstone.String())
1442+
}
1443+
d.info.AddChildren(l.iter)
1444+
if l.rangeDelIter != nil {
1445+
d.info.AddChildren(l.rangeDelIter)
1446+
}
1447+
info.AddChildren(d)
13381448
}
13391449
return info
13401450
}

sstable/colblk/keyspan.go

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,24 @@ func (i *keyspanIter) init(
421421
}
422422
}
423423

424+
func spanStr(s *keyspan.Span) string {
425+
if s == nil || !s.Valid() {
426+
return "<nil>"
427+
}
428+
return s.String()
429+
}
430+
424431
// SeekGE moves the iterator to the first span covering a key greater than
425432
// or equal to the given key. This is equivalent to seeking to the first
426433
// span with an end key greater than the given key.
427-
func (i *keyspanIter) SeekGE(key []byte) (*keyspan.Span, error) {
434+
func (i *keyspanIter) SeekGE(key []byte) (span *keyspan.Span, _ error) {
435+
if treesteps.Enabled && treesteps.IsRecording(i) {
436+
op := treesteps.StartOpf(i, "SeekGE(%q)", key)
437+
defer func() {
438+
op.Finishf("= %s", spanStr(span))
439+
}()
440+
}
441+
428442
// Seek among the boundary keys.
429443
j, eq := i.r.searchBoundaryKeysWithSyntheticPrefix(i.cmp, key, i.transforms.SyntheticPrefix())
430444
// If the found boundary key does not exactly equal the given key, it's
@@ -439,7 +453,13 @@ func (i *keyspanIter) SeekGE(key []byte) (*keyspan.Span, error) {
439453
// SeekLT moves the iterator to the last span covering a key less than the
440454
// given key. This is equivalent to seeking to the last span with a start
441455
// key less than the given key.
442-
func (i *keyspanIter) SeekLT(key []byte) (*keyspan.Span, error) {
456+
func (i *keyspanIter) SeekLT(key []byte) (span *keyspan.Span, _ error) {
457+
if treesteps.Enabled && treesteps.IsRecording(i) {
458+
op := treesteps.StartOpf(i, "SeekLT(%q)", key)
459+
defer func() {
460+
op.Finishf("= %s", spanStr(span))
461+
}()
462+
}
443463
j, _ := i.r.searchBoundaryKeysWithSyntheticPrefix(i.cmp, key, i.transforms.SyntheticPrefix())
444464
// searchBoundaryKeys seeks to the first boundary key greater than or equal
445465
// to key. The span beginning at the boundary key j necessarily does NOT
@@ -455,22 +475,46 @@ func (i *keyspanIter) SeekLT(key []byte) (*keyspan.Span, error) {
455475
}
456476

457477
// First moves the iterator to the first span.
458-
func (i *keyspanIter) First() (*keyspan.Span, error) {
478+
func (i *keyspanIter) First() (span *keyspan.Span, _ error) {
479+
if treesteps.Enabled && treesteps.IsRecording(i) {
480+
op := treesteps.StartOpf(i, "First()")
481+
defer func() {
482+
op.Finishf("= %s", spanStr(span))
483+
}()
484+
}
459485
return i.gatherKeysForward(0), nil
460486
}
461487

462488
// Last moves the iterator to the last span.
463-
func (i *keyspanIter) Last() (*keyspan.Span, error) {
489+
func (i *keyspanIter) Last() (span *keyspan.Span, _ error) {
490+
if treesteps.Enabled && treesteps.IsRecording(i) {
491+
op := treesteps.StartOpf(i, "Last()")
492+
defer func() {
493+
op.Finishf("= %s", spanStr(span))
494+
}()
495+
}
464496
return i.gatherKeysBackward(int(i.r.boundaryKeysCount) - 2), nil
465497
}
466498

467499
// Next moves the iterator to the next span.
468-
func (i *keyspanIter) Next() (*keyspan.Span, error) {
500+
func (i *keyspanIter) Next() (span *keyspan.Span, _ error) {
501+
if treesteps.Enabled && treesteps.IsRecording(i) {
502+
op := treesteps.StartOpf(i, "Next()")
503+
defer func() {
504+
op.Finishf("= %s", spanStr(span))
505+
}()
506+
}
469507
return i.gatherKeysForward(i.startBoundIndex + 1), nil
470508
}
471509

472510
// Prev moves the iterator to the previous span.
473-
func (i *keyspanIter) Prev() (*keyspan.Span, error) {
511+
func (i *keyspanIter) Prev() (span *keyspan.Span, _ error) {
512+
if treesteps.Enabled && treesteps.IsRecording(i) {
513+
op := treesteps.StartOpf(i, "Prev()")
514+
defer func() {
515+
op.Finishf("= %s", spanStr(span))
516+
}()
517+
}
474518
return i.gatherKeysBackward(max(i.startBoundIndex-1, -1)), nil
475519
}
476520

@@ -610,5 +654,5 @@ func (i *keyspanIter) WrapChildren(keyspan.WrapFn) {}
610654

611655
// TreeStepsNode is part of the FragmentIterator interface.
612656
func (i *keyspanIter) TreeStepsNode() treesteps.NodeInfo {
613-
return treesteps.NodeInfof(i, "%T(%p)", i, i)
657+
return treesteps.NodeInfof(i, "colblk.keyspanIter")
614658
}

testdata/treesteps/level_iter

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ L1
1919
i#1,SET:vi
2020
----
2121
L1:
22-
000004:[a#10,SET-c#10,SET] seqnums:[10-10] points:[a#10,SET-c#10,SET] size:471
23-
000005:[d#5,SET-f#5,SET] seqnums:[5-5] points:[d#5,SET-f#5,SET] size:491
24-
000006:[g#1,SET-i#1,SET] seqnums:[1-1] points:[g#1,SET-i#1,SET] size:471
22+
000004:[a#10,SET-c#10,SET] seqnums:[10-10] points:[a#10,SET-c#10,SET] size:672
23+
000005:[d#5,SET-f#5,SET] seqnums:[5-5] points:[d#5,SET-f#5,SET] size:798
24+
000006:[g#1,SET-i#1,SET] seqnums:[1-1] points:[g#1,SET-i#1,SET] size:669
2525

2626
level-iter depth=1
2727
seek-ge b

0 commit comments

Comments
 (0)