github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/metrics.go (about)

     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  	"bytes"
     9  	"fmt"
    10  
    11  	"github.com/petermattis/pebble/internal/humanize"
    12  )
    13  
    14  // LevelMetrics holds per-level metrics such as the number of files and total
    15  // size of the files, and compaction related metrics.
    16  type LevelMetrics struct {
    17  	// The total number of files in the level.
    18  	NumFiles int64
    19  	// The total size in bytes of the files in the level.
    20  	Size uint64
    21  	// The level's compaction score.
    22  	Score float64
    23  	// The number of incoming bytes from other levels read during
    24  	// compactions. This excludes bytes moved and bytes ingested. For L0 this is
    25  	// the bytes written to the WAL.
    26  	BytesIn uint64
    27  	// The number of bytes ingested.
    28  	BytesIngested uint64
    29  	// The number of bytes moved into the level by a "move" compaction.
    30  	BytesMoved uint64
    31  	// The number of bytes read for compactions at the level. This includes bytes
    32  	// read from other levels (BytesIn), as well as bytes read for the level.
    33  	BytesRead uint64
    34  	// The number of bytes written during compactions.
    35  	BytesWritten uint64
    36  }
    37  
    38  // Add updates the counter metrics for the level.
    39  func (m *LevelMetrics) Add(u *LevelMetrics) {
    40  	m.BytesIn += u.BytesIn
    41  	m.BytesIngested += u.BytesIngested
    42  	m.BytesMoved += u.BytesMoved
    43  	m.BytesRead += u.BytesRead
    44  	m.BytesWritten += u.BytesWritten
    45  }
    46  
    47  // WriteAmp computes the write amplification for compactions at this
    48  // level. Computed as BytesWritten / BytesIn.
    49  func (m *LevelMetrics) WriteAmp() float64 {
    50  	if m.BytesIn == 0 {
    51  		return 0
    52  	}
    53  	return float64(m.BytesWritten) / float64(m.BytesIn)
    54  }
    55  
    56  // format generates a string of the receiver's metrics, formatting it into the
    57  // supplied buffer.
    58  func (m *LevelMetrics) format(buf *bytes.Buffer) {
    59  	fmt.Fprintf(buf, "%6d %7s %7.2f %7s %7s %7s %7s %7s %7.1f\n",
    60  		m.NumFiles,
    61  		humanize.Uint64(m.Size),
    62  		m.Score,
    63  		humanize.Uint64(m.BytesIn),
    64  		humanize.Uint64(m.BytesIngested),
    65  		humanize.Uint64(m.BytesMoved),
    66  		humanize.Uint64(m.BytesRead),
    67  		humanize.Uint64(m.BytesWritten),
    68  		m.WriteAmp(),
    69  	)
    70  }
    71  
    72  // VersionMetrics holds metrics for each level.
    73  type VersionMetrics struct {
    74  	WAL struct {
    75  		// Number of live WAL files.
    76  		Files int64
    77  		// Number of obsolete WAL files.
    78  		ObsoleteFiles int64
    79  		// Size of the live data in the WAL files. Note that with WAL file
    80  		// recycling this is less than the actual on-disk size of the WAL files.
    81  		Size uint64
    82  		// Number of logical bytes written to the WAL.
    83  		BytesIn uint64
    84  		// Number of bytes written to the WAL.
    85  		BytesWritten uint64
    86  	}
    87  	Levels [numLevels]LevelMetrics
    88  }
    89  
    90  func (m *VersionMetrics) formatWAL(buf *bytes.Buffer) {
    91  	var writeAmp float64
    92  	if m.WAL.BytesIn > 0 {
    93  		writeAmp = float64(m.WAL.BytesWritten) / float64(m.WAL.BytesIn)
    94  	}
    95  	fmt.Fprintf(buf, "  WAL %6d %7s       - %7s       -       -       - %7s %7.1f\n",
    96  		m.WAL.Files,
    97  		humanize.Uint64(m.WAL.Size),
    98  		humanize.Uint64(m.WAL.BytesIn),
    99  		humanize.Uint64(m.WAL.BytesWritten),
   100  		writeAmp)
   101  }
   102  
   103  // Pretty-print the metrics, showing a line for the WAL, a line per-level, and
   104  // a total:
   105  //
   106  //   level__files____size___score______in__ingest____move____read___write___w-amp
   107  //     WAL      1    53 M       -   744 M       -       -       -   765 M     1.0
   108  //       0      6   285 M    3.00   712 M     0 B     0 B     0 B   707 M     1.0
   109  //       1      0     0 B    0.00     0 B     0 B     0 B     0 B     0 B     0.0
   110  //       2      0     0 B    0.00     0 B     0 B     0 B     0 B     0 B     0.0
   111  //       3      0     0 B    0.00     0 B     0 B     0 B     0 B     0 B     0.0
   112  //       4      0     0 B    0.00     0 B     0 B     0 B     0 B     0 B     0.0
   113  //       5     80   312 M    1.09   328 M     0 B     0 B   580 M   580 M     1.8
   114  //       6     23   110 M    0.35   110 M     0 B     0 B   146 M   146 M     1.3
   115  //   total    109   706 M    0.00   765 M     0 B     0 B   726 M   2.1 G     2.9
   116  //
   117  // The WAL "in" metric is the size of the batches written to the WAL. The WAL
   118  // "write" metric is the size of the physical data written to the WAL which
   119  // includes record fragment overhead. Write amplification is computed as
   120  // bytes-written / bytes-in, except for the total row where bytes-in is
   121  // replaced with WAL-bytes-written + bytes-ingested.
   122  func (m *VersionMetrics) String() string {
   123  	var buf bytes.Buffer
   124  	var total LevelMetrics
   125  	fmt.Fprintf(&buf, "level__files____size___score______in__ingest____move____read___write___w-amp\n")
   126  	m.formatWAL(&buf)
   127  	for level := 0; level < numLevels; level++ {
   128  		l := &m.Levels[level]
   129  		fmt.Fprintf(&buf, "%5d ", level)
   130  		l.format(&buf)
   131  		total.Add(l)
   132  		total.NumFiles += l.NumFiles
   133  		total.Size += l.Size
   134  	}
   135  	// Compute total bytes-in as the bytes written to the WAL + bytes ingested
   136  	total.BytesIn = m.WAL.BytesWritten + total.BytesIngested
   137  	// Add the total bytes-in to the total bytes-written. This is to account for
   138  	// the bytes written to the log and bytes written externally and then
   139  	// ingested.
   140  	total.BytesWritten += total.BytesIn
   141  	fmt.Fprintf(&buf, "total ")
   142  	total.format(&buf)
   143  	return buf.String()
   144  }