@@ -21,6 +21,7 @@ import (
2121 "bytes"
2222 "fmt"
2323 "runtime"
24+ "strings"
2425 "sync"
2526 "sync/atomic"
2627 "time"
@@ -55,24 +56,35 @@ const (
5556// Apart from basic data storage functionality it also supports batch writes and
5657// iterating over the keyspace in binary-alphabetical order.
5758type 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
7688
7789 quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
7890 quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
@@ -88,6 +100,7 @@ type Database struct {
88100
89101 writeStalled atomic.Bool // Flag whether the write is stalled
90102 writeDelayStartTime time.Time // The start time of the latest write stall
103+ writeDelayReason string // The reason of the latest write stall
91104 writeDelayCount atomic.Int64 // Total number of write stall counts
92105 writeDelayTime atomic.Int64 // Total time spent in write stalls
93106
@@ -120,11 +133,30 @@ func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) {
120133 d .writeDelayStartTime = time .Now ()
121134 d .writeDelayCount .Add (1 )
122135 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+ }
123149}
124150
125151func (d * Database ) onWriteStallEnd () {
126152 d .writeDelayTime .Add (int64 (time .Since (d .writeDelayStartTime )))
127153 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 {}
128160}
129161
130162// 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) (
270302 db .nonlevel0CompGauge = metrics .GetOrRegisterGauge (namespace + "compact/nonlevel0" , nil )
271303 db .seekCompGauge = metrics .GetOrRegisterGauge (namespace + "compact/seek" , nil )
272304 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 )
273316
274317 // Start up the metrics gathering and return
275318 go db .meter (metricsGatheringInterval , namespace )
@@ -517,6 +560,18 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
517560 d .nonlevel0CompGauge .Update (nonLevel0CompCount )
518561 d .level0CompGauge .Update (level0CompCount )
519562 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 )
520575
521576 for i , level := range stats .Levels {
522577 // Append metrics for additional layers
0 commit comments