Skip to content

Commit 45d293d

Browse files
committed
db: make iterator tracking configurable
1 parent 0d8ff1c commit 45d293d

File tree

11 files changed

+87
-23
lines changed

11 files changed

+87
-23
lines changed

db.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@ func (d *DB) newIter(
11141114
dbi.batch.batch = batch
11151115
dbi.batch.batchSeqNum = batch.nextSeqNum()
11161116
}
1117-
if !dbi.batchOnlyIter {
1117+
if !dbi.batchOnlyIter && d.iterTracker != nil {
11181118
dbi.tracker = d.iterTracker
11191119
dbi.trackerHandle = d.iterTracker.Start()
11201120
}
@@ -1624,8 +1624,10 @@ func (d *DB) Close() error {
16241624
err = firstError(err, errors.Errorf("leaked snapshots: %d open snapshots on DB %p", v, d))
16251625
}
16261626

1627-
d.iterTracker.Close()
1628-
d.iterTracker = nil
1627+
if d.iterTracker != nil {
1628+
d.iterTracker.Close()
1629+
d.iterTracker = nil
1630+
}
16291631

16301632
return err
16311633
}

metamorphic/options.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,20 @@ func RandomOptions(rng *rand.Rand, kf KeyFormat, cfg RandomOptionsCfg) *TestOpti
934934
}
935935
}
936936

937+
switch rand.IntN(2) {
938+
case 0:
939+
opts.Experimental.IteratorTracking.PollInterval = 100 * time.Millisecond
940+
opts.Experimental.IteratorTracking.MaxAge = 10 * time.Second
941+
case 1:
942+
// Disable tracking.
943+
opts.Experimental.IteratorTracking.PollInterval = -1
944+
opts.Experimental.IteratorTracking.MaxAge = -1
945+
case 2:
946+
// Default settings.
947+
opts.Experimental.IteratorTracking.PollInterval = 0
948+
opts.Experimental.IteratorTracking.MaxAge = 0
949+
}
950+
937951
testOpts.seedEFOS = rng.Uint64()
938952
testOpts.ingestSplit = rng.IntN(2) == 0
939953
opts.Experimental.IngestSplit = func() bool { return testOpts.ingestSplit }

open.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,11 @@ func Open(dirname string, opts *Options) (db *DB, err error) {
205205
} else {
206206
d.compactionScheduler = newConcurrencyLimitScheduler(defaultTimeSource{})
207207
}
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-
})
208+
if iterTrackOpts := opts.Experimental.IteratorTracking; iterTrackOpts.PollInterval > 0 && iterTrackOpts.MaxAge > 0 {
209+
d.iterTracker = inflight.NewPollingTracker(iterTrackOpts.PollInterval, iterTrackOpts.MaxAge, func(report string) {
210+
d.opts.Logger.Infof("Long-lived iterators detected:\n%s", report)
211+
})
212+
}
213213

214214
defer func() {
215215
// If an error or panic occurs during open, attempt to release the manually
@@ -242,7 +242,10 @@ func Open(dirname string, opts *Options) (db *DB, err error) {
242242
if d.mu.versions.manifestFile != nil {
243243
_ = d.mu.versions.manifestFile.Close()
244244
}
245-
d.iterTracker.Close()
245+
if d.iterTracker != nil {
246+
d.iterTracker.Close()
247+
d.iterTracker = nil
248+
}
246249
if r != nil {
247250
panic(r)
248251
}

options.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,21 @@ type Options struct {
792792
// virtual table rewrite compactions entirely. The default value is 0.30
793793
// (rewrite when >= 30% of backing data is unreferenced).
794794
VirtualTableRewriteUnreferencedFraction func() float64
795+
796+
// IteratorTracking configures periodic logging of iterators held open for
797+
// too long.
798+
IteratorTracking struct {
799+
// PollInterval is the interval at which to log a report of long-lived iterators.
800+
// If negative, disables iterator tracking.
801+
//
802+
// The default value is 5 minutes.
803+
PollInterval time.Duration
804+
// MaxAge is the age above which iterators are considered long-lived. If
805+
// negative, disables iterator tracking.
806+
//
807+
// The default value is 1 minute.
808+
MaxAge time.Duration
809+
}
795810
}
796811

797812
// Filters is a map from filter policy name to filter policy. It is used for
@@ -1644,6 +1659,12 @@ func (o *Options) EnsureDefaults() {
16441659
if o.Experimental.VirtualTableRewriteUnreferencedFraction == nil {
16451660
o.Experimental.VirtualTableRewriteUnreferencedFraction = func() float64 { return defaultVirtualTableUnreferencedFraction }
16461661
}
1662+
if o.Experimental.IteratorTracking.PollInterval == 0 {
1663+
o.Experimental.IteratorTracking.PollInterval = 5 * time.Minute
1664+
}
1665+
if o.Experimental.IteratorTracking.MaxAge == 0 {
1666+
o.Experimental.IteratorTracking.MaxAge = time.Minute
1667+
}
16471668
// TODO(jackson): Enable value separation by default once we have confidence
16481669
// in a default policy.
16491670

@@ -1786,6 +1807,13 @@ func (o *Options) String() string {
17861807
fmt.Fprintf(&buf, " secondary_cache_size_bytes=%d\n", o.Experimental.SecondaryCacheSizeBytes)
17871808
fmt.Fprintf(&buf, " create_on_shared=%d\n", o.Experimental.CreateOnShared)
17881809

1810+
if o.Experimental.IteratorTracking.PollInterval != 0 {
1811+
fmt.Fprintf(&buf, " iterator_tracking_poll_interval=%s\n", o.Experimental.IteratorTracking.PollInterval)
1812+
}
1813+
if o.Experimental.IteratorTracking.MaxAge != 0 {
1814+
fmt.Fprintf(&buf, " iterator_tracking_max_age=%s\n", o.Experimental.IteratorTracking.MaxAge)
1815+
}
1816+
17891817
// Private options.
17901818
//
17911819
// These options are only encoded if true, because we do not want them to
@@ -2228,6 +2256,10 @@ func (o *Options) Parse(s string, hooks *ParseHooks) error {
22282256
var createOnSharedInt int64
22292257
createOnSharedInt, err = strconv.ParseInt(value, 10, 64)
22302258
o.Experimental.CreateOnShared = remote.CreateOnSharedStrategy(createOnSharedInt)
2259+
case "iterator_tracking_poll_interval":
2260+
o.Experimental.IteratorTracking.PollInterval, err = time.ParseDuration(value)
2261+
case "iterator_tracking_max_age":
2262+
o.Experimental.IteratorTracking.MaxAge, err = time.ParseDuration(value)
22312263
default:
22322264
if hooks != nil && hooks.SkipUnknown != nil && hooks.SkipUnknown(section+"."+key, value) {
22332265
return nil

options_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ func TestDefaultOptionsString(t *testing.T) {
140140
wal_bytes_per_sync=0
141141
secondary_cache_size_bytes=0
142142
create_on_shared=0
143+
iterator_tracking_poll_interval=5m0s
144+
iterator_tracking_max_age=1m0s
143145
144146
[Level "0"]
145147
block_restart_interval=16

replay/testdata/replay

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tree
1111
508 000007.sst
1212
0 LOCK
1313
133 MANIFEST-000001
14-
2769 OPTIONS-000003
14+
2841 OPTIONS-000003
1515
0 marker.format-version.000001.013
1616
0 marker.manifest.000001.MANIFEST-000001
1717
simple/
@@ -21,7 +21,7 @@ tree
2121
11 000004.log
2222
480 000005.sst
2323
85 MANIFEST-000001
24-
2769 OPTIONS-000003
24+
2841 OPTIONS-000003
2525
0 marker.format-version.000001.013
2626
0 marker.manifest.000001.MANIFEST-000001
2727

@@ -75,6 +75,8 @@ cat build/OPTIONS-000003
7575
wal_bytes_per_sync=0
7676
secondary_cache_size_bytes=0
7777
create_on_shared=0
78+
iterator_tracking_poll_interval=5m0s
79+
iterator_tracking_max_age=1m0s
7880

7981
[Level "0"]
8082
block_restart_interval=16

replay/testdata/replay_ingest

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tree
1212
0 LOCK
1313
172 MANIFEST-000001
1414
209 MANIFEST-000008
15-
2770 OPTIONS-000003
15+
2842 OPTIONS-000003
1616
0 marker.format-version.000012.025
1717
0 marker.manifest.000002.MANIFEST-000008
1818
simple_ingest/
@@ -25,7 +25,7 @@ tree
2525
678 000004.sst
2626
661 000005.sst
2727
172 MANIFEST-000001
28-
2770 OPTIONS-000003
28+
2842 OPTIONS-000003
2929
0 marker.format-version.000001.025
3030
0 marker.manifest.000001.MANIFEST-000001
3131

@@ -79,6 +79,8 @@ cat build/OPTIONS-000003
7979
wal_bytes_per_sync=0
8080
secondary_cache_size_bytes=0
8181
create_on_shared=0
82+
iterator_tracking_poll_interval=5m0s
83+
iterator_tracking_max_age=1m0s
8284

8385
[Level "0"]
8486
block_restart_interval=16

replay/testdata/replay_paced

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ tree
1414
0 LOCK
1515
133 MANIFEST-000001
1616
205 MANIFEST-000010
17-
2769 OPTIONS-000003
17+
2841 OPTIONS-000003
1818
0 marker.format-version.000001.013
1919
0 marker.manifest.000002.MANIFEST-000010
2020
high_read_amp/
@@ -26,7 +26,7 @@ tree
2626
11 000008.log
2727
454 000009.sst
2828
157 MANIFEST-000010
29-
2769 OPTIONS-000003
29+
2841 OPTIONS-000003
3030
0 marker.format-version.000001.013
3131
0 marker.manifest.000001.MANIFEST-000010
3232

replay/testdata/replay_val_sep

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ tree
1717
0 LOCK
1818
152 MANIFEST-000010
1919
250 MANIFEST-000013
20-
2947 OPTIONS-000003
20+
3019 OPTIONS-000003
2121
0 marker.format-version.000011.024
2222
0 marker.manifest.000003.MANIFEST-000013
2323
simple_val_sep/
@@ -32,7 +32,7 @@ tree
3232
11 000011.log
3333
707 000012.sst
3434
187 MANIFEST-000013
35-
2947 OPTIONS-000003
35+
3019 OPTIONS-000003
3636
0 marker.format-version.000001.024
3737
0 marker.manifest.000001.MANIFEST-000013
3838

@@ -89,6 +89,8 @@ cat build/OPTIONS-000003
8989
wal_bytes_per_sync=0
9090
secondary_cache_size_bytes=0
9191
create_on_shared=0
92+
iterator_tracking_poll_interval=5m0s
93+
iterator_tracking_max_age=1m0s
9294

9395
[Value Separation]
9496
enabled=true

scan_internal.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ func (d *DB) newInternalIter(
188188
*dbi = scanInternalIterator{
189189
ctx: ctx,
190190
db: d,
191-
trackerHandle: d.iterTracker.Start(),
192191
comparer: d.opts.Comparer,
193192
merge: d.opts.Merger.Merge,
194193
readState: readState,
@@ -199,6 +198,9 @@ func (d *DB) newInternalIter(
199198
seqNum: seqNum,
200199
mergingIter: &buf.iterAlloc.merging,
201200
}
201+
if d.iterTracker != nil {
202+
dbi.trackerHandle = d.iterTracker.Start()
203+
}
202204
dbi.blobValueFetcher.Init(&vers.BlobFiles, d.fileCache, block.ReadEnv{},
203205
blob.SuggestedCachedReaders(vers.MaxReadAmp()))
204206

@@ -1286,7 +1288,10 @@ func (i *scanInternalIterator) error() error {
12861288

12871289
// Close closes this iterator, and releases any pooled objects.
12881290
func (i *scanInternalIterator) Close() error {
1289-
i.db.iterTracker.Stop(i.trackerHandle)
1291+
if i.trackerHandle != 0 {
1292+
i.db.iterTracker.Stop(i.trackerHandle)
1293+
i.trackerHandle = 0
1294+
}
12901295
err := i.iter.Close()
12911296
err = errors.CombineErrors(err, i.blobValueFetcher.Close())
12921297
if i.readState != nil {

0 commit comments

Comments
 (0)