Skip to content

Commit 0d8ff1c

Browse files
committed
db: track and report long-standing iterators
We wire up iterators to an `inflight.Tracker`. Every 5 minutes we log a report on iterators that have been open for more than 1 minute.
1 parent 0d82adc commit 0d8ff1c

File tree

4 files changed

+38
-6
lines changed

4 files changed

+38
-6
lines changed

db.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/cockroachdb/pebble/internal/arenaskl"
2222
"github.com/cockroachdb/pebble/internal/base"
2323
"github.com/cockroachdb/pebble/internal/cache"
24+
"github.com/cockroachdb/pebble/internal/inflight"
2425
"github.com/cockroachdb/pebble/internal/invalidating"
2526
"github.com/cockroachdb/pebble/internal/invariants"
2627
"github.com/cockroachdb/pebble/internal/keyspan"
@@ -545,6 +546,8 @@ type DB struct {
545546
// the time at database Open; may be used to compute metrics like effective
546547
// compaction concurrency
547548
openedAt time.Time
549+
550+
iterTracker *inflight.Tracker
548551
}
549552

550553
var _ Reader = (*DB)(nil)
@@ -1111,6 +1114,10 @@ func (d *DB) newIter(
11111114
dbi.batch.batch = batch
11121115
dbi.batch.batchSeqNum = batch.nextSeqNum()
11131116
}
1117+
if !dbi.batchOnlyIter {
1118+
dbi.tracker = d.iterTracker
1119+
dbi.trackerHandle = d.iterTracker.Start()
1120+
}
11141121
return finishInitializingIter(ctx, buf)
11151122
}
11161123

@@ -1121,6 +1128,7 @@ func (d *DB) newIter(
11211128
func finishInitializingIter(ctx context.Context, buf *iterAlloc) *Iterator {
11221129
// Short-hand.
11231130
dbi := &buf.dbi
1131+
11241132
var memtables flushableList
11251133
if dbi.readState != nil {
11261134
memtables = dbi.readState.memtables
@@ -1616,6 +1624,9 @@ func (d *DB) Close() error {
16161624
err = firstError(err, errors.Errorf("leaked snapshots: %d open snapshots on DB %p", v, d))
16171625
}
16181626

1627+
d.iterTracker.Close()
1628+
d.iterTracker = nil
1629+
16191630
return err
16201631
}
16211632

iterator.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/cockroachdb/pebble/internal/base"
1717
"github.com/cockroachdb/pebble/internal/bytealloc"
1818
"github.com/cockroachdb/pebble/internal/humanize"
19+
"github.com/cockroachdb/pebble/internal/inflight"
1920
"github.com/cockroachdb/pebble/internal/invariants"
2021
"github.com/cockroachdb/pebble/internal/keyspan"
2122
"github.com/cockroachdb/pebble/internal/keyspan/keyspanimpl"
@@ -209,12 +210,14 @@ type Iterator struct {
209210
// short-lived (since they pin memtables and sstables), (b) plumbing a
210211
// context into every method is very painful, (c) they do not (yet) respect
211212
// context cancellation and are only used for tracing.
212-
ctx context.Context
213-
opts IterOptions
214-
merge Merge
215-
comparer *base.Comparer
216-
iter internalIterator
217-
pointIter topLevelIterator
213+
ctx context.Context
214+
tracker *inflight.Tracker
215+
trackerHandle inflight.Handle
216+
opts IterOptions
217+
merge Merge
218+
comparer *base.Comparer
219+
iter internalIterator
220+
pointIter topLevelIterator
218221
// Either readState or version is set, but not both.
219222
readState *readState
220223
version *manifest.Version
@@ -2362,6 +2365,9 @@ const maxKeyBufCacheSize = 4 << 10 // 4 KB
23622365
// It is not valid to call any method, including Close, after the iterator
23632366
// has been closed.
23642367
func (i *Iterator) Close() error {
2368+
if i.tracker != nil {
2369+
i.tracker.Stop(i.trackerHandle)
2370+
}
23652371
// Close the child iterator before releasing the readState because when the
23662372
// readState is released sstables referenced by the readState may be deleted
23672373
// which will fail on Windows if the sstables are still open by the child
@@ -2895,6 +2901,10 @@ func (i *Iterator) CloneWithContext(ctx context.Context, opts CloneOptions) (*It
28952901
newIterRangeKey: i.newIterRangeKey,
28962902
seqNum: i.seqNum,
28972903
}
2904+
if i.tracker != nil {
2905+
dbi.tracker = i.tracker
2906+
dbi.trackerHandle = i.tracker.Start()
2907+
}
28982908
if i.batch != nil {
28992909
dbi.batch = &buf.batchState
29002910
dbi.batch.batch = i.batch.batch

open.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/cockroachdb/pebble/internal/arenaskl"
2424
"github.com/cockroachdb/pebble/internal/base"
2525
"github.com/cockroachdb/pebble/internal/cache"
26+
"github.com/cockroachdb/pebble/internal/inflight"
2627
"github.com/cockroachdb/pebble/internal/invariants"
2728
"github.com/cockroachdb/pebble/internal/keyspan"
2829
"github.com/cockroachdb/pebble/internal/manifest"
@@ -204,6 +205,11 @@ func Open(dirname string, opts *Options) (db *DB, err error) {
204205
} else {
205206
d.compactionScheduler = newConcurrencyLimitScheduler(defaultTimeSource{})
206207
}
208+
const iterTrackerPollInterval = 5 * time.Minute
209+
const iterTrackerMaxAge = 1 * time.Minute
210+
d.iterTracker = inflight.NewPollingTracker(iterTrackerPollInterval, iterTrackerMaxAge, func(report string) {
211+
d.opts.Logger.Infof("Long-lived iterators detected:\n%s", report)
212+
})
207213

208214
defer func() {
209215
// If an error or panic occurs during open, attempt to release the manually
@@ -236,6 +242,7 @@ func Open(dirname string, opts *Options) (db *DB, err error) {
236242
if d.mu.versions.manifestFile != nil {
237243
_ = d.mu.versions.manifestFile.Close()
238244
}
245+
d.iterTracker.Close()
239246
if r != nil {
240247
panic(r)
241248
}

scan_internal.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/cockroachdb/errors"
1414
"github.com/cockroachdb/pebble/internal/base"
15+
"github.com/cockroachdb/pebble/internal/inflight"
1516
"github.com/cockroachdb/pebble/internal/invariants"
1617
"github.com/cockroachdb/pebble/internal/keyspan"
1718
"github.com/cockroachdb/pebble/internal/keyspan/keyspanimpl"
@@ -187,6 +188,7 @@ func (d *DB) newInternalIter(
187188
*dbi = scanInternalIterator{
188189
ctx: ctx,
189190
db: d,
191+
trackerHandle: d.iterTracker.Start(),
190192
comparer: d.opts.Comparer,
191193
merge: d.opts.Merger.Merge,
192194
readState: readState,
@@ -578,6 +580,7 @@ type IteratorLevel struct {
578580
type scanInternalIterator struct {
579581
ctx context.Context
580582
db *DB
583+
trackerHandle inflight.Handle
581584
opts ScanInternalOptions
582585
comparer *base.Comparer
583586
merge Merge
@@ -1283,6 +1286,7 @@ func (i *scanInternalIterator) error() error {
12831286

12841287
// Close closes this iterator, and releases any pooled objects.
12851288
func (i *scanInternalIterator) Close() error {
1289+
i.db.iterTracker.Stop(i.trackerHandle)
12861290
err := i.iter.Close()
12871291
err = errors.CombineErrors(err, i.blobValueFetcher.Close())
12881292
if i.readState != nil {

0 commit comments

Comments
 (0)