LCOV - code coverage report
Current view: top level - pebble - metrics.go (source / functions) Hit Total Coverage
Test: 2024-09-13 08:16Z 0665a3e1 - tests only.lcov Lines: 287 302 95.0 %
Date: 2024-09-13 08:16:48 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package pebble
       6             : 
       7             : import (
       8             :         "fmt"
       9             :         "math"
      10             :         "time"
      11             : 
      12             :         "github.com/cockroachdb/pebble/internal/base"
      13             :         "github.com/cockroachdb/pebble/internal/cache"
      14             :         "github.com/cockroachdb/pebble/internal/humanize"
      15             :         "github.com/cockroachdb/pebble/internal/manual"
      16             :         "github.com/cockroachdb/pebble/objstorage/objstorageprovider/sharedcache"
      17             :         "github.com/cockroachdb/pebble/record"
      18             :         "github.com/cockroachdb/pebble/sstable"
      19             :         "github.com/cockroachdb/pebble/wal"
      20             :         "github.com/cockroachdb/redact"
      21             :         "github.com/prometheus/client_golang/prometheus"
      22             : )
      23             : 
      24             : // CacheMetrics holds metrics for the block and table cache.
      25             : type CacheMetrics = cache.Metrics
      26             : 
      27             : // FilterMetrics holds metrics for the filter policy
      28             : type FilterMetrics = sstable.FilterMetrics
      29             : 
      30             : // ThroughputMetric is a cumulative throughput metric. See the detailed
      31             : // comment in base.
      32             : type ThroughputMetric = base.ThroughputMetric
      33             : 
      34             : // SecondaryCacheMetrics holds metrics for the persistent secondary cache
      35             : // that caches commonly accessed blocks from blob storage on a local
      36             : // file system.
      37             : type SecondaryCacheMetrics = sharedcache.Metrics
      38             : 
      39             : // LevelMetrics holds per-level metrics such as the number of files and total
      40             : // size of the files, and compaction related metrics.
      41             : type LevelMetrics struct {
      42             :         // The number of sublevels within the level. The sublevel count corresponds
      43             :         // to the read amplification for the level. An empty level will have a
      44             :         // sublevel count of 0, implying no read amplification. Only L0 will have
      45             :         // a sublevel count other than 0 or 1.
      46             :         Sublevels int32
      47             :         // The total number of files in the level.
      48             :         NumFiles int64
      49             :         // The total number of virtual sstables in the level.
      50             :         NumVirtualFiles uint64
      51             :         // The total size in bytes of the files in the level.
      52             :         Size int64
      53             :         // The total size of the virtual sstables in the level.
      54             :         VirtualSize uint64
      55             :         // The level's compaction score. This is the compensatedScoreRatio in the
      56             :         // candidateLevelInfo.
      57             :         Score float64
      58             :         // The number of incoming bytes from other levels read during
      59             :         // compactions. This excludes bytes moved and bytes ingested. For L0 this is
      60             :         // the bytes written to the WAL.
      61             :         BytesIn uint64
      62             :         // The number of bytes ingested. The sibling metric for tables is
      63             :         // TablesIngested.
      64             :         BytesIngested uint64
      65             :         // The number of bytes moved into the level by a "move" compaction. The
      66             :         // sibling metric for tables is TablesMoved.
      67             :         BytesMoved uint64
      68             :         // The number of bytes read for compactions at the level. This includes bytes
      69             :         // read from other levels (BytesIn), as well as bytes read for the level.
      70             :         BytesRead uint64
      71             :         // The number of bytes written during compactions. The sibling
      72             :         // metric for tables is TablesCompacted. This metric may be summed
      73             :         // with BytesFlushed to compute the total bytes written for the level.
      74             :         BytesCompacted uint64
      75             :         // The number of bytes written during flushes. The sibling
      76             :         // metrics for tables is TablesFlushed. This metric is always
      77             :         // zero for all levels other than L0.
      78             :         BytesFlushed uint64
      79             :         // The number of sstables compacted to this level.
      80             :         TablesCompacted uint64
      81             :         // The number of sstables flushed to this level.
      82             :         TablesFlushed uint64
      83             :         // The number of sstables ingested into the level.
      84             :         TablesIngested uint64
      85             :         // The number of sstables moved to this level by a "move" compaction.
      86             :         TablesMoved uint64
      87             : 
      88             :         MultiLevel struct {
      89             :                 // BytesInTop are the total bytes in a multilevel compaction coming from the top level.
      90             :                 BytesInTop uint64
      91             : 
      92             :                 // BytesIn, exclusively for multiLevel compactions.
      93             :                 BytesIn uint64
      94             : 
      95             :                 // BytesRead, exclusively for multilevel compactions.
      96             :                 BytesRead uint64
      97             :         }
      98             : 
      99             :         // Additional contains misc additional metrics that are not always printed.
     100             :         Additional struct {
     101             :                 // The sum of Properties.ValueBlocksSize for all the sstables in this
     102             :                 // level. Printed by LevelMetrics.format iff there is at least one level
     103             :                 // with a non-zero value.
     104             :                 ValueBlocksSize uint64
     105             :                 // Cumulative metrics about bytes written to data blocks and value blocks,
     106             :                 // via compactions (except move compactions) or flushes. Not printed by
     107             :                 // LevelMetrics.format, but are available to sophisticated clients.
     108             :                 BytesWrittenDataBlocks  uint64
     109             :                 BytesWrittenValueBlocks uint64
     110             :         }
     111             : }
     112             : 
     113             : // Add updates the counter metrics for the level.
     114           1 : func (m *LevelMetrics) Add(u *LevelMetrics) {
     115           1 :         m.NumFiles += u.NumFiles
     116           1 :         m.NumVirtualFiles += u.NumVirtualFiles
     117           1 :         m.VirtualSize += u.VirtualSize
     118           1 :         m.Size += u.Size
     119           1 :         m.BytesIn += u.BytesIn
     120           1 :         m.BytesIngested += u.BytesIngested
     121           1 :         m.BytesMoved += u.BytesMoved
     122           1 :         m.BytesRead += u.BytesRead
     123           1 :         m.BytesCompacted += u.BytesCompacted
     124           1 :         m.BytesFlushed += u.BytesFlushed
     125           1 :         m.TablesCompacted += u.TablesCompacted
     126           1 :         m.TablesFlushed += u.TablesFlushed
     127           1 :         m.TablesIngested += u.TablesIngested
     128           1 :         m.TablesMoved += u.TablesMoved
     129           1 :         m.MultiLevel.BytesInTop += u.MultiLevel.BytesInTop
     130           1 :         m.MultiLevel.BytesRead += u.MultiLevel.BytesRead
     131           1 :         m.MultiLevel.BytesIn += u.MultiLevel.BytesIn
     132           1 :         m.Additional.BytesWrittenDataBlocks += u.Additional.BytesWrittenDataBlocks
     133           1 :         m.Additional.BytesWrittenValueBlocks += u.Additional.BytesWrittenValueBlocks
     134           1 :         m.Additional.ValueBlocksSize += u.Additional.ValueBlocksSize
     135           1 : }
     136             : 
     137             : // WriteAmp computes the write amplification for compactions at this
     138             : // level. Computed as (BytesFlushed + BytesCompacted) / BytesIn.
     139           1 : func (m *LevelMetrics) WriteAmp() float64 {
     140           1 :         if m.BytesIn == 0 {
     141           1 :                 return 0
     142           1 :         }
     143           1 :         return float64(m.BytesFlushed+m.BytesCompacted) / float64(m.BytesIn)
     144             : }
     145             : 
     146             : // Metrics holds metrics for various subsystems of the DB such as the Cache,
     147             : // Compactions, WAL, and per-Level metrics.
     148             : //
     149             : // TODO(peter): The testing of these metrics is relatively weak. There should
     150             : // be testing that performs various operations on a DB and verifies that the
     151             : // metrics reflect those operations.
     152             : type Metrics struct {
     153             :         BlockCache CacheMetrics
     154             : 
     155             :         Compact struct {
     156             :                 // The total number of compactions, and per-compaction type counts.
     157             :                 Count                 int64
     158             :                 DefaultCount          int64
     159             :                 DeleteOnlyCount       int64
     160             :                 ElisionOnlyCount      int64
     161             :                 CopyCount             int64
     162             :                 MoveCount             int64
     163             :                 ReadCount             int64
     164             :                 TombstoneDensityCount int64
     165             :                 RewriteCount          int64
     166             :                 MultiLevelCount       int64
     167             :                 CounterLevelCount     int64
     168             :                 // An estimate of the number of bytes that need to be compacted for the LSM
     169             :                 // to reach a stable state.
     170             :                 EstimatedDebt uint64
     171             :                 // Number of bytes present in sstables being written by in-progress
     172             :                 // compactions. This value will be zero if there are no in-progress
     173             :                 // compactions.
     174             :                 InProgressBytes int64
     175             :                 // Number of compactions that are in-progress.
     176             :                 NumInProgress int64
     177             :                 // MarkedFiles is a count of files that are marked for
     178             :                 // compaction. Such files are compacted in a rewrite compaction
     179             :                 // when no other compactions are picked.
     180             :                 MarkedFiles int
     181             :                 // Duration records the cumulative duration of all compactions since the
     182             :                 // database was opened.
     183             :                 Duration time.Duration
     184             :         }
     185             : 
     186             :         Ingest struct {
     187             :                 // The total number of ingestions
     188             :                 Count uint64
     189             :         }
     190             : 
     191             :         Flush struct {
     192             :                 // The total number of flushes.
     193             :                 Count           int64
     194             :                 WriteThroughput ThroughputMetric
     195             :                 // Number of flushes that are in-progress. In the current implementation
     196             :                 // this will always be zero or one.
     197             :                 NumInProgress int64
     198             :                 // AsIngestCount is a monotonically increasing counter of flush operations
     199             :                 // handling ingested tables.
     200             :                 AsIngestCount uint64
     201             :                 // AsIngestCount is a monotonically increasing counter of tables ingested as
     202             :                 // flushables.
     203             :                 AsIngestTableCount uint64
     204             :                 // AsIngestBytes is a monotonically increasing counter of the bytes flushed
     205             :                 // for flushables that originated as ingestion operations.
     206             :                 AsIngestBytes uint64
     207             :         }
     208             : 
     209             :         Filter FilterMetrics
     210             : 
     211             :         Levels [numLevels]LevelMetrics
     212             : 
     213             :         MemTable struct {
     214             :                 // The number of bytes allocated by memtables and large (flushable)
     215             :                 // batches.
     216             :                 Size uint64
     217             :                 // The count of memtables.
     218             :                 Count int64
     219             :                 // The number of bytes present in zombie memtables which are no longer
     220             :                 // referenced by the current DB state. An unbounded number of memtables
     221             :                 // may be zombie if they're still in use by an iterator. One additional
     222             :                 // memtable may be zombie if it's no longer in use and waiting to be
     223             :                 // recycled.
     224             :                 ZombieSize uint64
     225             :                 // The count of zombie memtables.
     226             :                 ZombieCount int64
     227             :         }
     228             : 
     229             :         Keys struct {
     230             :                 // The approximate count of internal range key set keys in the database.
     231             :                 RangeKeySetsCount uint64
     232             :                 // The approximate count of internal tombstones (DEL, SINGLEDEL and
     233             :                 // RANGEDEL key kinds) within the database.
     234             :                 TombstoneCount uint64
     235             :                 // A cumulative total number of missized DELSIZED keys encountered by
     236             :                 // compactions since the database was opened.
     237             :                 MissizedTombstonesCount uint64
     238             :         }
     239             : 
     240             :         Snapshots struct {
     241             :                 // The number of currently open snapshots.
     242             :                 Count int
     243             :                 // The sequence number of the earliest, currently open snapshot.
     244             :                 EarliestSeqNum base.SeqNum
     245             :                 // A running tally of keys written to sstables during flushes or
     246             :                 // compactions that would've been elided if it weren't for open
     247             :                 // snapshots.
     248             :                 PinnedKeys uint64
     249             :                 // A running cumulative sum of the size of keys and values written to
     250             :                 // sstables during flushes or compactions that would've been elided if
     251             :                 // it weren't for open snapshots.
     252             :                 PinnedSize uint64
     253             :         }
     254             : 
     255             :         Table struct {
     256             :                 // The number of bytes present in obsolete tables which are no longer
     257             :                 // referenced by the current DB state or any open iterators.
     258             :                 ObsoleteSize uint64
     259             :                 // The count of obsolete tables.
     260             :                 ObsoleteCount int64
     261             :                 // The number of bytes present in zombie tables which are no longer
     262             :                 // referenced by the current DB state but are still in use by an iterator.
     263             :                 ZombieSize uint64
     264             :                 // The count of zombie tables.
     265             :                 ZombieCount int64
     266             :                 // The count of sstables backing virtual tables.
     267             :                 BackingTableCount uint64
     268             :                 // The sum of the sizes of the BackingTableCount sstables that are backing virtual tables.
     269             :                 BackingTableSize uint64
     270             :                 // The number of sstables that are compressed with an unknown compression
     271             :                 // algorithm.
     272             :                 CompressedCountUnknown int64
     273             :                 // The number of sstables that are compressed with the default compression
     274             :                 // algorithm, snappy.
     275             :                 CompressedCountSnappy int64
     276             :                 // The number of sstables that are compressed with zstd.
     277             :                 CompressedCountZstd int64
     278             :                 // The number of sstables that are uncompressed.
     279             :                 CompressedCountNone int64
     280             : 
     281             :                 // Local file sizes.
     282             :                 Local struct {
     283             :                         // LiveSize is the number of bytes in live tables.
     284             :                         LiveSize uint64
     285             :                         // ObsoleteSize is the number of bytes in obsolete tables.
     286             :                         ObsoleteSize uint64
     287             :                         // ZombieSize is the number of bytes in zombie tables.
     288             :                         ZombieSize uint64
     289             :                 }
     290             :         }
     291             : 
     292             :         TableCache CacheMetrics
     293             : 
     294             :         // Count of the number of open sstable iterators.
     295             :         TableIters int64
     296             :         // Uptime is the total time since this DB was opened.
     297             :         Uptime time.Duration
     298             : 
     299             :         WAL struct {
     300             :                 // Number of live WAL files.
     301             :                 Files int64
     302             :                 // Number of obsolete WAL files.
     303             :                 ObsoleteFiles int64
     304             :                 // Physical size of the obsolete WAL files.
     305             :                 ObsoletePhysicalSize uint64
     306             :                 // Size of the live data in the WAL files. Note that with WAL file
     307             :                 // recycling this is less than the actual on-disk size of the WAL files.
     308             :                 Size uint64
     309             :                 // Physical size of the WAL files on-disk. With WAL file recycling,
     310             :                 // this is greater than the live data in WAL files.
     311             :                 //
     312             :                 // TODO(sumeer): it seems this does not include ObsoletePhysicalSize.
     313             :                 // Should the comment be updated?
     314             :                 PhysicalSize uint64
     315             :                 // Number of logical bytes written to the WAL.
     316             :                 BytesIn uint64
     317             :                 // Number of bytes written to the WAL.
     318             :                 BytesWritten uint64
     319             :                 // Failover contains failover stats. Empty if failover is not enabled.
     320             :                 Failover wal.FailoverStats
     321             :         }
     322             : 
     323             :         LogWriter struct {
     324             :                 FsyncLatency prometheus.Histogram
     325             :                 record.LogWriterMetrics
     326             :         }
     327             : 
     328             :         CategoryStats []sstable.CategoryStatsAggregate
     329             : 
     330             :         SecondaryCacheMetrics SecondaryCacheMetrics
     331             : 
     332             :         private struct {
     333             :                 optionsFileSize  uint64
     334             :                 manifestFileSize uint64
     335             :         }
     336             : 
     337             :         manualMemory manual.Metrics
     338             : }
     339             : 
     340             : var (
     341             :         // FsyncLatencyBuckets are prometheus histogram buckets suitable for a histogram
     342             :         // that records latencies for fsyncs.
     343             :         FsyncLatencyBuckets = append(
     344             :                 prometheus.LinearBuckets(0.0, float64(time.Microsecond*100), 50),
     345             :                 prometheus.ExponentialBucketsRange(float64(time.Millisecond*5), float64(10*time.Second), 50)...,
     346             :         )
     347             : 
     348             :         // SecondaryCacheIOBuckets exported to enable exporting from package pebble to
     349             :         // enable exporting metrics with below buckets in CRDB.
     350             :         SecondaryCacheIOBuckets = sharedcache.IOBuckets
     351             :         // SecondaryCacheChannelWriteBuckets exported to enable exporting from package
     352             :         // pebble to enable exporting metrics with below buckets in CRDB.
     353             :         SecondaryCacheChannelWriteBuckets = sharedcache.ChannelWriteBuckets
     354             : )
     355             : 
     356             : // DiskSpaceUsage returns the total disk space used by the database in bytes,
     357             : // including live and obsolete files. This only includes local files, i.e.,
     358             : // remote files (as known to objstorage.Provider) are not included.
     359           1 : func (m *Metrics) DiskSpaceUsage() uint64 {
     360           1 :         var usageBytes uint64
     361           1 :         usageBytes += m.WAL.PhysicalSize
     362           1 :         usageBytes += m.WAL.ObsoletePhysicalSize
     363           1 :         usageBytes += m.Table.Local.LiveSize
     364           1 :         usageBytes += m.Table.Local.ObsoleteSize
     365           1 :         usageBytes += m.Table.Local.ZombieSize
     366           1 :         usageBytes += m.private.optionsFileSize
     367           1 :         usageBytes += m.private.manifestFileSize
     368           1 :         // TODO(sumeer): InProgressBytes does not distinguish between local and
     369           1 :         // remote files. This causes a small error. Fix.
     370           1 :         usageBytes += uint64(m.Compact.InProgressBytes)
     371           1 :         return usageBytes
     372           1 : }
     373             : 
     374             : // NumVirtual is the number of virtual sstables in the latest version
     375             : // summed over every level in the lsm.
     376           1 : func (m *Metrics) NumVirtual() uint64 {
     377           1 :         var n uint64
     378           1 :         for _, level := range m.Levels {
     379           1 :                 n += level.NumVirtualFiles
     380           1 :         }
     381           1 :         return n
     382             : }
     383             : 
     384             : // VirtualSize is the sum of the sizes of the virtual sstables in the
     385             : // latest version. BackingTableSize - VirtualSize gives an estimate for
     386             : // the space amplification caused by not compacting virtual sstables.
     387           1 : func (m *Metrics) VirtualSize() uint64 {
     388           1 :         var size uint64
     389           1 :         for _, level := range m.Levels {
     390           1 :                 size += level.VirtualSize
     391           1 :         }
     392           1 :         return size
     393             : }
     394             : 
     395             : // ReadAmp returns the current read amplification of the database.
     396             : // It's computed as the number of sublevels in L0 + the number of non-empty
     397             : // levels below L0.
     398           1 : func (m *Metrics) ReadAmp() int {
     399           1 :         var ramp int32
     400           1 :         for _, l := range m.Levels {
     401           1 :                 ramp += l.Sublevels
     402           1 :         }
     403           1 :         return int(ramp)
     404             : }
     405             : 
     406             : // Total returns the sum of the per-level metrics and WAL metrics.
     407           1 : func (m *Metrics) Total() LevelMetrics {
     408           1 :         var total LevelMetrics
     409           1 :         for level := 0; level < numLevels; level++ {
     410           1 :                 l := &m.Levels[level]
     411           1 :                 total.Add(l)
     412           1 :                 total.Sublevels += l.Sublevels
     413           1 :         }
     414             :         // Compute total bytes-in as the bytes written to the WAL + bytes ingested.
     415           1 :         total.BytesIn = m.WAL.BytesWritten + total.BytesIngested
     416           1 :         // Add the total bytes-in to the total bytes-flushed. This is to account for
     417           1 :         // the bytes written to the log and bytes written externally and then
     418           1 :         // ingested.
     419           1 :         total.BytesFlushed += total.BytesIn
     420           1 :         return total
     421             : }
     422             : 
     423             : // String pretty-prints the metrics as below:
     424             : //
     425             : //            |                             |       |       |   ingested   |     moved    |    written   |       |    amp
     426             : //      level | tables  size val-bl vtables | score |   in  | tables  size | tables  size | tables  size |  read |   r   w
     427             : //      ------+-----------------------------+-------+-------+--------------+--------------+--------------+-------+---------
     428             : //          0 |   101   102B     0B       0 | 103.0 |  104B |   112   104B |   113   106B |   221   217B |  107B |   1  2.1
     429             : //          1 |   201   202B     0B       0 | 203.0 |  204B |   212   204B |   213   206B |   421   417B |  207B |   2  2.0
     430             : //          2 |   301   302B     0B       0 | 303.0 |  304B |   312   304B |   313   306B |   621   617B |  307B |   3  2.0
     431             : //          3 |   401   402B     0B       0 | 403.0 |  404B |   412   404B |   413   406B |   821   817B |  407B |   4  2.0
     432             : //          4 |   501   502B     0B       0 | 503.0 |  504B |   512   504B |   513   506B |  1.0K  1017B |  507B |   5  2.0
     433             : //          5 |   601   602B     0B       0 | 603.0 |  604B |   612   604B |   613   606B |  1.2K  1.2KB |  607B |   6  2.0
     434             : //          6 |   701   702B     0B       0 |     - |  704B |   712   704B |   713   706B |  1.4K  1.4KB |  707B |   7  2.0
     435             : //      total |  2.8K  2.7KB     0B       0 |     - | 2.8KB |  2.9K  2.8KB |  2.9K  2.8KB |  5.7K  8.4KB | 2.8KB |  28  3.0
     436             : //      -------------------------------------------------------------------------------------------------------------------
     437             : //      WAL: 22 files (24B)  in: 25B  written: 26B (4% overhead)
     438             : //      Flushes: 8
     439             : //      Compactions: 5  estimated debt: 6B  in progress: 2 (7B)
     440             : //      default: 27  delete: 28  elision: 29  move: 30  read: 31  rewrite: 32  multi-level: 33
     441             : //      MemTables: 12 (11B)  zombie: 14 (13B)
     442             : //      Zombie tables: 16 (15B)
     443             : //      Backing tables: 0 (0B)
     444             : //      Block cache: 2 entries (1B)  hit rate: 42.9%
     445             : //      Table cache: 18 entries (17B)  hit rate: 48.7%
     446             : //      Secondary cache: 40 entries (40B)  hit rate: 49.9%
     447             : //      Snapshots: 4  earliest seq num: 1024
     448             : //      Table iters: 21
     449             : //      Filter utility: 47.4%
     450             : //      Ingestions: 27  as flushable: 36 (34B in 35 tables)
     451           1 : func (m *Metrics) String() string {
     452           1 :         return redact.StringWithoutMarkers(m)
     453           1 : }
     454             : 
     455             : var _ redact.SafeFormatter = &Metrics{}
     456             : 
     457             : // SafeFormat implements redact.SafeFormatter.
     458           1 : func (m *Metrics) SafeFormat(w redact.SafePrinter, _ rune) {
     459           1 :         // NB: Pebble does not make any assumptions as to which Go primitive types
     460           1 :         // have been registered as safe with redact.RegisterSafeType and does not
     461           1 :         // register any types itself. Some of the calls to `redact.Safe`, etc are
     462           1 :         // superfluous in the context of CockroachDB, which registers all the Go
     463           1 :         // numeric types as safe.
     464           1 : 
     465           1 :         // TODO(jackson): There are a few places where we use redact.SafeValue
     466           1 :         // instead of redact.RedactableString. This is necessary because of a bug
     467           1 :         // whereby formatting a redact.RedactableString argument does not respect
     468           1 :         // width specifiers. When the issue is fixed, we can convert these to
     469           1 :         // RedactableStrings. https://github.com/cockroachdb/redact/issues/17
     470           1 : 
     471           1 :         multiExists := m.Compact.MultiLevelCount > 0
     472           1 :         appendIfMulti := func(line redact.SafeString) {
     473           1 :                 if multiExists {
     474           1 :                         w.SafeString(line)
     475           1 :                 }
     476             :         }
     477           1 :         newline := func() {
     478           1 :                 w.SafeString("\n")
     479           1 :         }
     480             : 
     481           1 :         w.SafeString("      |                             |       |       |   ingested   |     moved    |    written   |       |    amp")
     482           1 :         appendIfMulti("   |     multilevel")
     483           1 :         newline()
     484           1 :         w.SafeString("level | tables  size val-bl vtables | score |   in  | tables  size | tables  size | tables  size |  read |   r   w")
     485           1 :         appendIfMulti("  |    top   in  read")
     486           1 :         newline()
     487           1 :         w.SafeString("------+-----------------------------+-------+-------+--------------+--------------+--------------+-------+---------")
     488           1 :         appendIfMulti("-+------------------")
     489           1 :         newline()
     490           1 : 
     491           1 :         // formatRow prints out a row of the table.
     492           1 :         formatRow := func(m *LevelMetrics, score float64) {
     493           1 :                 scoreStr := "-"
     494           1 :                 if !math.IsNaN(score) {
     495           1 :                         // Try to keep the string no longer than 5 characters.
     496           1 :                         switch {
     497           1 :                         case score < 99.995:
     498           1 :                                 scoreStr = fmt.Sprintf("%.2f", score)
     499           1 :                         case score < 999.95:
     500           1 :                                 scoreStr = fmt.Sprintf("%.1f", score)
     501           0 :                         default:
     502           0 :                                 scoreStr = fmt.Sprintf("%.0f", score)
     503             :                         }
     504             :                 }
     505           1 :                 var wampStr string
     506           1 :                 if wamp := m.WriteAmp(); wamp > 99.5 {
     507           0 :                         wampStr = fmt.Sprintf("%.0f", wamp)
     508           1 :                 } else {
     509           1 :                         wampStr = fmt.Sprintf("%.1f", wamp)
     510           1 :                 }
     511             : 
     512           1 :                 w.Printf("| %5s %6s %6s %7s | %5s | %5s | %5s %6s | %5s %6s | %5s %6s | %5s | %3d %4s",
     513           1 :                         humanize.Count.Int64(m.NumFiles),
     514           1 :                         humanize.Bytes.Int64(m.Size),
     515           1 :                         humanize.Bytes.Uint64(m.Additional.ValueBlocksSize),
     516           1 :                         humanize.Count.Uint64(m.NumVirtualFiles),
     517           1 :                         redact.Safe(scoreStr),
     518           1 :                         humanize.Bytes.Uint64(m.BytesIn),
     519           1 :                         humanize.Count.Uint64(m.TablesIngested),
     520           1 :                         humanize.Bytes.Uint64(m.BytesIngested),
     521           1 :                         humanize.Count.Uint64(m.TablesMoved),
     522           1 :                         humanize.Bytes.Uint64(m.BytesMoved),
     523           1 :                         humanize.Count.Uint64(m.TablesFlushed+m.TablesCompacted),
     524           1 :                         humanize.Bytes.Uint64(m.BytesFlushed+m.BytesCompacted),
     525           1 :                         humanize.Bytes.Uint64(m.BytesRead),
     526           1 :                         redact.Safe(m.Sublevels),
     527           1 :                         redact.Safe(wampStr))
     528           1 : 
     529           1 :                 if multiExists {
     530           1 :                         w.Printf(" | %5s %5s %5s",
     531           1 :                                 humanize.Bytes.Uint64(m.MultiLevel.BytesInTop),
     532           1 :                                 humanize.Bytes.Uint64(m.MultiLevel.BytesIn),
     533           1 :                                 humanize.Bytes.Uint64(m.MultiLevel.BytesRead))
     534           1 :                 }
     535           1 :                 newline()
     536             :         }
     537             : 
     538           1 :         var total LevelMetrics
     539           1 :         for level := 0; level < numLevels; level++ {
     540           1 :                 l := &m.Levels[level]
     541           1 :                 w.Printf("%5d ", redact.Safe(level))
     542           1 : 
     543           1 :                 // Format the score.
     544           1 :                 score := math.NaN()
     545           1 :                 if level < numLevels-1 {
     546           1 :                         score = l.Score
     547           1 :                 }
     548           1 :                 formatRow(l, score)
     549           1 :                 total.Add(l)
     550           1 :                 total.Sublevels += l.Sublevels
     551             :         }
     552             :         // Compute total bytes-in as the bytes written to the WAL + bytes ingested.
     553           1 :         total.BytesIn = m.WAL.BytesWritten + total.BytesIngested
     554           1 :         // Add the total bytes-in to the total bytes-flushed. This is to account for
     555           1 :         // the bytes written to the log and bytes written externally and then
     556           1 :         // ingested.
     557           1 :         total.BytesFlushed += total.BytesIn
     558           1 :         w.SafeString("total ")
     559           1 :         formatRow(&total, math.NaN())
     560           1 : 
     561           1 :         w.SafeString("-------------------------------------------------------------------------------------------------------------------")
     562           1 :         appendIfMulti("--------------------")
     563           1 :         newline()
     564           1 :         w.Printf("WAL: %d files (%s)  in: %s  written: %s (%.0f%% overhead)",
     565           1 :                 redact.Safe(m.WAL.Files),
     566           1 :                 humanize.Bytes.Uint64(m.WAL.Size),
     567           1 :                 humanize.Bytes.Uint64(m.WAL.BytesIn),
     568           1 :                 humanize.Bytes.Uint64(m.WAL.BytesWritten),
     569           1 :                 redact.Safe(percent(int64(m.WAL.BytesWritten)-int64(m.WAL.BytesIn), int64(m.WAL.BytesIn))))
     570           1 :         failoverStats := m.WAL.Failover
     571           1 :         failoverStats.FailoverWriteAndSyncLatency = nil
     572           1 :         if failoverStats == (wal.FailoverStats{}) {
     573           1 :                 w.Printf("\n")
     574           1 :         } else {
     575           0 :                 w.Printf(" failover: (switches: %d, primary: %s, secondary: %s)\n", m.WAL.Failover.DirSwitchCount,
     576           0 :                         m.WAL.Failover.PrimaryWriteDuration.String(), m.WAL.Failover.SecondaryWriteDuration.String())
     577           0 :         }
     578             : 
     579           1 :         w.Printf("Flushes: %d\n", redact.Safe(m.Flush.Count))
     580           1 : 
     581           1 :         w.Printf("Compactions: %d  estimated debt: %s  in progress: %d (%s)\n",
     582           1 :                 redact.Safe(m.Compact.Count),
     583           1 :                 humanize.Bytes.Uint64(m.Compact.EstimatedDebt),
     584           1 :                 redact.Safe(m.Compact.NumInProgress),
     585           1 :                 humanize.Bytes.Int64(m.Compact.InProgressBytes))
     586           1 : 
     587           1 :         w.Printf("             default: %d  delete: %d  elision: %d  move: %d  read: %d  tombstone-density: %d  rewrite: %d  copy: %d  multi-level: %d\n",
     588           1 :                 redact.Safe(m.Compact.DefaultCount),
     589           1 :                 redact.Safe(m.Compact.DeleteOnlyCount),
     590           1 :                 redact.Safe(m.Compact.ElisionOnlyCount),
     591           1 :                 redact.Safe(m.Compact.MoveCount),
     592           1 :                 redact.Safe(m.Compact.ReadCount),
     593           1 :                 redact.Safe(m.Compact.TombstoneDensityCount),
     594           1 :                 redact.Safe(m.Compact.RewriteCount),
     595           1 :                 redact.Safe(m.Compact.CopyCount),
     596           1 :                 redact.Safe(m.Compact.MultiLevelCount))
     597           1 : 
     598           1 :         w.Printf("MemTables: %d (%s)  zombie: %d (%s)\n",
     599           1 :                 redact.Safe(m.MemTable.Count),
     600           1 :                 humanize.Bytes.Uint64(m.MemTable.Size),
     601           1 :                 redact.Safe(m.MemTable.ZombieCount),
     602           1 :                 humanize.Bytes.Uint64(m.MemTable.ZombieSize))
     603           1 : 
     604           1 :         w.Printf("Zombie tables: %d (%s, local: %s)\n",
     605           1 :                 redact.Safe(m.Table.ZombieCount),
     606           1 :                 humanize.Bytes.Uint64(m.Table.ZombieSize),
     607           1 :                 humanize.Bytes.Uint64(m.Table.Local.ZombieSize))
     608           1 : 
     609           1 :         w.Printf("Backing tables: %d (%s)\n",
     610           1 :                 redact.Safe(m.Table.BackingTableCount),
     611           1 :                 humanize.Bytes.Uint64(m.Table.BackingTableSize))
     612           1 :         w.Printf("Virtual tables: %d (%s)\n",
     613           1 :                 redact.Safe(m.NumVirtual()),
     614           1 :                 humanize.Bytes.Uint64(m.VirtualSize()))
     615           1 :         w.Printf("Local tables size: %s\n", humanize.Bytes.Uint64(m.Table.Local.LiveSize))
     616           1 :         w.SafeString("Compression types:")
     617           1 :         if count := m.Table.CompressedCountSnappy; count > 0 {
     618           1 :                 w.Printf(" snappy: %d", redact.Safe(count))
     619           1 :         }
     620           1 :         if count := m.Table.CompressedCountZstd; count > 0 {
     621           0 :                 w.Printf(" zstd: %d", redact.Safe(count))
     622           0 :         }
     623           1 :         if count := m.Table.CompressedCountNone; count > 0 {
     624           0 :                 w.Printf(" none: %d", redact.Safe(count))
     625           0 :         }
     626           1 :         if count := m.Table.CompressedCountUnknown; count > 0 {
     627           1 :                 w.Printf(" unknown: %d", redact.Safe(count))
     628           1 :         }
     629           1 :         w.Print("\n")
     630           1 : 
     631           1 :         formatCacheMetrics := func(m *CacheMetrics, name redact.SafeString) {
     632           1 :                 w.Printf("%s: %s entries (%s)  hit rate: %.1f%%\n",
     633           1 :                         name,
     634           1 :                         humanize.Count.Int64(m.Count),
     635           1 :                         humanize.Bytes.Int64(m.Size),
     636           1 :                         redact.Safe(hitRate(m.Hits, m.Misses)))
     637           1 :         }
     638           1 :         formatCacheMetrics(&m.BlockCache, "Block cache")
     639           1 :         formatCacheMetrics(&m.TableCache, "Table cache")
     640           1 : 
     641           1 :         formatSharedCacheMetrics := func(w redact.SafePrinter, m *SecondaryCacheMetrics, name redact.SafeString) {
     642           1 :                 w.Printf("%s: %s entries (%s)  hit rate: %.1f%%\n",
     643           1 :                         name,
     644           1 :                         humanize.Count.Int64(m.Count),
     645           1 :                         humanize.Bytes.Int64(m.Size),
     646           1 :                         redact.Safe(hitRate(m.ReadsWithFullHit, m.ReadsWithPartialHit+m.ReadsWithNoHit)))
     647           1 :         }
     648           1 :         formatSharedCacheMetrics(w, &m.SecondaryCacheMetrics, "Secondary cache")
     649           1 : 
     650           1 :         w.Printf("Snapshots: %d  earliest seq num: %d\n",
     651           1 :                 redact.Safe(m.Snapshots.Count),
     652           1 :                 redact.Safe(m.Snapshots.EarliestSeqNum))
     653           1 : 
     654           1 :         w.Printf("Table iters: %d\n", redact.Safe(m.TableIters))
     655           1 :         w.Printf("Filter utility: %.1f%%\n", redact.Safe(hitRate(m.Filter.Hits, m.Filter.Misses)))
     656           1 :         w.Printf("Ingestions: %d  as flushable: %d (%s in %d tables)\n",
     657           1 :                 redact.Safe(m.Ingest.Count),
     658           1 :                 redact.Safe(m.Flush.AsIngestCount),
     659           1 :                 humanize.Bytes.Uint64(m.Flush.AsIngestBytes),
     660           1 :                 redact.Safe(m.Flush.AsIngestTableCount))
     661           1 : 
     662           1 :         var inUseTotal uint64
     663           1 :         for i := range m.manualMemory {
     664           1 :                 inUseTotal += m.manualMemory[i].InUseBytes
     665           1 :         }
     666           1 :         inUse := func(purpose manual.Purpose) uint64 {
     667           1 :                 return m.manualMemory[purpose].InUseBytes
     668           1 :         }
     669           1 :         w.Printf("Cgo memory usage: %s  block cache: %s (data: %s, maps: %s, entries: %s)  memtables: %s\n",
     670           1 :                 humanize.Bytes.Uint64(inUseTotal),
     671           1 :                 humanize.Bytes.Uint64(inUse(manual.BlockCacheData)+inUse(manual.BlockCacheMap)+inUse(manual.BlockCacheEntry)),
     672           1 :                 humanize.Bytes.Uint64(inUse(manual.BlockCacheData)),
     673           1 :                 humanize.Bytes.Uint64(inUse(manual.BlockCacheMap)),
     674           1 :                 humanize.Bytes.Uint64(inUse(manual.BlockCacheEntry)),
     675           1 :                 humanize.Bytes.Uint64(inUse(manual.MemTable)),
     676           1 :         )
     677             : }
     678             : 
     679           1 : func hitRate(hits, misses int64) float64 {
     680           1 :         return percent(hits, hits+misses)
     681           1 : }
     682             : 
     683           1 : func percent(numerator, denominator int64) float64 {
     684           1 :         if denominator == 0 {
     685           1 :                 return 0
     686           1 :         }
     687           1 :         return 100 * float64(numerator) / float64(denominator)
     688             : }
     689             : 
     690             : // StringForTests is identical to m.String() on 64-bit platforms. It is used to
     691             : // provide a platform-independent result for tests.
     692           1 : func (m *Metrics) StringForTests() string {
     693           1 :         mCopy := *m
     694           1 :         if math.MaxInt == math.MaxInt32 {
     695           0 :                 // This is the difference in Sizeof(sstable.Reader{})) between 64 and 32 bit
     696           0 :                 // platforms.
     697           0 :                 const tableCacheSizeAdjustment = 212
     698           0 :                 mCopy.TableCache.Size += mCopy.TableCache.Count * tableCacheSizeAdjustment
     699           0 :         }
     700             :         // Don't show cgo memory statistics as they can vary based on architecture,
     701             :         // invariants tag, etc.
     702           1 :         mCopy.manualMemory = manual.Metrics{}
     703           1 :         return redact.StringWithoutMarkers(&mCopy)
     704             : }

Generated by: LCOV version 1.14