@@ -21,6 +21,7 @@ import (
21
21
"bytes"
22
22
"fmt"
23
23
"runtime"
24
+ "strings"
24
25
"sync"
25
26
"sync/atomic"
26
27
"time"
@@ -55,24 +56,35 @@ const (
55
56
// Apart from basic data storage functionality it also supports batch writes and
56
57
// iterating over the keyspace in binary-alphabetical order.
57
58
type Database struct {
58
- fn string // filename for reporting
59
- db * pebble.DB // Underlying pebble storage engine
60
-
61
- compTimeMeter * metrics.Meter // Meter for measuring the total time spent in database compaction
62
- compReadMeter * metrics.Meter // Meter for measuring the data read during compaction
63
- compWriteMeter * metrics.Meter // Meter for measuring the data written during compaction
64
- writeDelayNMeter * metrics.Meter // Meter for measuring the write delay number due to database compaction
65
- writeDelayMeter * metrics.Meter // Meter for measuring the write delay duration due to database compaction
66
- diskSizeGauge * metrics.Gauge // Gauge for tracking the size of all the levels in the database
67
- diskReadMeter * metrics.Meter // Meter for measuring the effective amount of data read
68
- diskWriteMeter * metrics.Meter // Meter for measuring the effective amount of data written
69
- memCompGauge * metrics.Gauge // Gauge for tracking the number of memory compaction
70
- level0CompGauge * metrics.Gauge // Gauge for tracking the number of table compaction in level0
71
- nonlevel0CompGauge * metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
72
- seekCompGauge * metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
73
- manualMemAllocGauge * metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
74
-
75
- levelsGauge []* metrics.Gauge // Gauge for tracking the number of tables in levels
59
+ fn string // filename for reporting
60
+ db * pebble.DB // Underlying pebble storage engine
61
+ namespace string // Namespace for metrics
62
+
63
+ compTimeMeter * metrics.Meter // Meter for measuring the total time spent in database compaction
64
+ compReadMeter * metrics.Meter // Meter for measuring the data read during compaction
65
+ compWriteMeter * metrics.Meter // Meter for measuring the data written during compaction
66
+ writeDelayNMeter * metrics.Meter // Meter for measuring the write delay number due to database compaction
67
+ writeDelayMeter * metrics.Meter // Meter for measuring the write delay duration due to database compaction
68
+ diskSizeGauge * metrics.Gauge // Gauge for tracking the size of all the levels in the database
69
+ diskReadMeter * metrics.Meter // Meter for measuring the effective amount of data read
70
+ diskWriteMeter * metrics.Meter // Meter for measuring the effective amount of data written
71
+ memCompGauge * metrics.Gauge // Gauge for tracking the number of memory compaction
72
+ level0CompGauge * metrics.Gauge // Gauge for tracking the number of table compaction in level0
73
+ nonlevel0CompGauge * metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
74
+ seekCompGauge * metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
75
+ manualMemAllocGauge * metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
76
+ liveMemTablesGauge * metrics.Gauge // Gauge for tracking the number of live memory tables
77
+ zombieMemTablesGauge * metrics.Gauge // Gauge for tracking the number of zombie memory tables
78
+ blockCacheHitGauge * metrics.Gauge // Gauge for tracking the number of total hit in the block cache
79
+ blockCacheMissGauge * metrics.Gauge // Gauge for tracking the number of total miss in the block cache
80
+ tableCacheHitGauge * metrics.Gauge // Gauge for tracking the number of total hit in the table cache
81
+ tableCacheMissGauge * metrics.Gauge // Gauge for tracking the number of total miss in the table cache
82
+ filterHitGauge * metrics.Gauge // Gauge for tracking the number of total hit in bloom filter
83
+ filterMissGauge * metrics.Gauge // Gauge for tracking the number of total miss in bloom filter
84
+ estimatedCompDebtGauge * metrics.Gauge // Gauge for tracking the number of bytes that need to be compacted
85
+ liveCompGauge * metrics.Gauge // Gauge for tracking the number of in-progress compactions
86
+ liveCompSizeGauge * metrics.Gauge // Gauge for tracking the size of in-progress compactions
87
+ levelsGauge []* metrics.Gauge // Gauge for tracking the number of tables in levels
76
88
77
89
quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
78
90
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
@@ -88,6 +100,7 @@ type Database struct {
88
100
89
101
writeStalled atomic.Bool // Flag whether the write is stalled
90
102
writeDelayStartTime time.Time // The start time of the latest write stall
103
+ writeDelayReason string // The reason of the latest write stall
91
104
writeDelayCount atomic.Int64 // Total number of write stall counts
92
105
writeDelayTime atomic.Int64 // Total time spent in write stalls
93
106
@@ -120,11 +133,30 @@ func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) {
120
133
d .writeDelayStartTime = time .Now ()
121
134
d .writeDelayCount .Add (1 )
122
135
d .writeStalled .Store (true )
136
+
137
+ // Take just the first word of the reason. These are two potential
138
+ // reasons for the write stall:
139
+ // - memtable count limit reached
140
+ // - L0 file count limit exceeded
141
+ reason := b .Reason
142
+ if i := strings .IndexByte (reason , ' ' ); i != - 1 {
143
+ reason = reason [:i ]
144
+ }
145
+ if reason == "L0" || reason == "memtable" {
146
+ d .writeDelayReason = reason
147
+ metrics .GetOrRegisterGauge (d .namespace + "stall/count/" + reason , nil ).Inc (1 )
148
+ }
123
149
}
124
150
125
151
func (d * Database ) onWriteStallEnd () {
126
152
d .writeDelayTime .Add (int64 (time .Since (d .writeDelayStartTime )))
127
153
d .writeStalled .Store (false )
154
+
155
+ if d .writeDelayReason != "" {
156
+ metrics .GetOrRegisterResettingTimer (d .namespace + "stall/time/" + d .writeDelayReason , nil ).UpdateSince (d .writeDelayStartTime )
157
+ d .writeDelayReason = ""
158
+ }
159
+ d .writeDelayStartTime = time.Time {}
128
160
}
129
161
130
162
// panicLogger is just a noop logger to disable Pebble's internal logger.
@@ -270,6 +302,17 @@ func New(file string, cache int, handles int, namespace string, readonly bool) (
270
302
db .nonlevel0CompGauge = metrics .GetOrRegisterGauge (namespace + "compact/nonlevel0" , nil )
271
303
db .seekCompGauge = metrics .GetOrRegisterGauge (namespace + "compact/seek" , nil )
272
304
db .manualMemAllocGauge = metrics .GetOrRegisterGauge (namespace + "memory/manualalloc" , nil )
305
+ db .liveMemTablesGauge = metrics .GetOrRegisterGauge (namespace + "table/live" , nil )
306
+ db .zombieMemTablesGauge = metrics .GetOrRegisterGauge (namespace + "table/zombie" , nil )
307
+ db .blockCacheHitGauge = metrics .GetOrRegisterGauge (namespace + "cache/block/hit" , nil )
308
+ db .blockCacheMissGauge = metrics .GetOrRegisterGauge (namespace + "cache/block/miss" , nil )
309
+ db .tableCacheHitGauge = metrics .GetOrRegisterGauge (namespace + "cache/table/hit" , nil )
310
+ db .tableCacheMissGauge = metrics .GetOrRegisterGauge (namespace + "cache/table/miss" , nil )
311
+ db .filterHitGauge = metrics .GetOrRegisterGauge (namespace + "filter/hit" , nil )
312
+ db .filterMissGauge = metrics .GetOrRegisterGauge (namespace + "filter/miss" , nil )
313
+ db .estimatedCompDebtGauge = metrics .GetOrRegisterGauge (namespace + "compact/estimateDebt" , nil )
314
+ db .liveCompGauge = metrics .GetOrRegisterGauge (namespace + "compact/live/count" , nil )
315
+ db .liveCompSizeGauge = metrics .GetOrRegisterGauge (namespace + "compact/live/size" , nil )
273
316
274
317
// Start up the metrics gathering and return
275
318
go db .meter (metricsGatheringInterval , namespace )
@@ -517,6 +560,18 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
517
560
d .nonlevel0CompGauge .Update (nonLevel0CompCount )
518
561
d .level0CompGauge .Update (level0CompCount )
519
562
d .seekCompGauge .Update (stats .Compact .ReadCount )
563
+ d .liveCompGauge .Update (stats .Compact .NumInProgress )
564
+ d .liveCompSizeGauge .Update (stats .Compact .InProgressBytes )
565
+
566
+ d .liveMemTablesGauge .Update (stats .MemTable .Count )
567
+ d .zombieMemTablesGauge .Update (stats .MemTable .ZombieCount )
568
+ d .estimatedCompDebtGauge .Update (int64 (stats .Compact .EstimatedDebt ))
569
+ d .tableCacheHitGauge .Update (stats .TableCache .Hits )
570
+ d .tableCacheMissGauge .Update (stats .TableCache .Misses )
571
+ d .blockCacheHitGauge .Update (stats .BlockCache .Hits )
572
+ d .blockCacheMissGauge .Update (stats .BlockCache .Misses )
573
+ d .filterHitGauge .Update (stats .Filter .Hits )
574
+ d .filterMissGauge .Update (stats .Filter .Misses )
520
575
521
576
for i , level := range stats .Levels {
522
577
// Append metrics for additional layers
0 commit comments