github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/metrics_test.go (about)

     1  // Copyright 2019 The LevelDB-Go and Pebble and Bitalostored 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 bitalostable
     6  
     7  import (
     8  	"fmt"
     9  	"testing"
    10  
    11  	"github.com/cockroachdb/redact"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/zuoyebang/bitalostable/internal/datadriven"
    14  	"github.com/zuoyebang/bitalostable/internal/humanize"
    15  	"github.com/zuoyebang/bitalostable/vfs"
    16  )
    17  
    18  func TestMetricsFormat(t *testing.T) {
    19  	var m Metrics
    20  	m.BlockCache.Size = 1
    21  	m.BlockCache.Count = 2
    22  	m.BlockCache.Hits = 3
    23  	m.BlockCache.Misses = 4
    24  	m.Compact.Count = 5
    25  	m.Compact.DefaultCount = 27
    26  	m.Compact.DeleteOnlyCount = 28
    27  	m.Compact.ElisionOnlyCount = 29
    28  	m.Compact.MoveCount = 30
    29  	m.Compact.ReadCount = 31
    30  	m.Compact.RewriteCount = 32
    31  	m.Compact.MultiLevelCount = 33
    32  	m.Compact.EstimatedDebt = 6
    33  	m.Compact.InProgressBytes = 7
    34  	m.Compact.NumInProgress = 2
    35  	m.Flush.Count = 8
    36  	m.Filter.Hits = 9
    37  	m.Filter.Misses = 10
    38  	m.MemTable.Size = 11
    39  	m.MemTable.Count = 12
    40  	m.MemTable.ZombieSize = 13
    41  	m.MemTable.ZombieCount = 14
    42  	m.Snapshots.Count = 4
    43  	m.Snapshots.EarliestSeqNum = 1024
    44  	m.Table.ZombieSize = 15
    45  	m.Table.ZombieCount = 16
    46  	m.TableCache.Size = 17
    47  	m.TableCache.Count = 18
    48  	m.TableCache.Hits = 19
    49  	m.TableCache.Misses = 20
    50  	m.TableIters = 21
    51  	m.WAL.Files = 22
    52  	m.WAL.ObsoleteFiles = 23
    53  	m.WAL.Size = 24
    54  	m.WAL.BytesIn = 25
    55  	m.WAL.BytesWritten = 26
    56  
    57  	for i := range m.Levels {
    58  		l := &m.Levels[i]
    59  		base := uint64((i + 1) * 100)
    60  		l.Sublevels = int32(i + 1)
    61  		l.NumFiles = int64(base) + 1
    62  		l.Size = int64(base) + 2
    63  		l.Score = float64(base) + 3
    64  		l.BytesIn = base + 4
    65  		l.BytesIngested = base + 4
    66  		l.BytesMoved = base + 6
    67  		l.BytesRead = base + 7
    68  		l.BytesCompacted = base + 8
    69  		l.BytesFlushed = base + 9
    70  		l.TablesCompacted = base + 10
    71  		l.TablesFlushed = base + 11
    72  		l.TablesIngested = base + 12
    73  		l.TablesMoved = base + 13
    74  	}
    75  
    76  	const expected = `
    77  __level_____count____size___score______in__ingest(sz_cnt)____move(sz_cnt)___write(sz_cnt)____read___r-amp___w-amp
    78      WAL        22    24 B       -    25 B       -       -       -       -    26 B       -       -       -     1.0
    79        0       101   102 B  103.00   104 B   104 B     112   106 B     113   217 B     221   107 B       1     2.1
    80        1       201   202 B  203.00   204 B   204 B     212   206 B     213   417 B     421   207 B       2     2.0
    81        2       301   302 B  303.00   304 B   304 B     312   306 B     313   617 B     621   307 B       3     2.0
    82        3       401   402 B  403.00   404 B   404 B     412   406 B     413   817 B     821   407 B       4     2.0
    83        4       501   502 B  503.00   504 B   504 B     512   506 B     513  1017 B   1.0 K   507 B       5     2.0
    84        5       601   602 B  603.00   604 B   604 B     612   606 B     613   1.2 K   1.2 K   607 B       6     2.0
    85        6       701   702 B       -   704 B   704 B     712   706 B     713   1.4 K   1.4 K   707 B       7     2.0
    86    total      2807   2.7 K       -   2.8 K   2.8 K   2.9 K   2.8 K   2.9 K   8.4 K   5.7 K   2.8 K      28     3.0
    87    flush         8
    88  compact         5     6 B     7 B       2          (size == estimated-debt, score = in-progress-bytes, in = num-in-progress)
    89    ctype        27      28      29      30      31      32      33  (default, delete, elision, move, read, rewrite, multi-level)
    90   memtbl        12    11 B
    91  zmemtbl        14    13 B
    92     ztbl        16    15 B
    93   bcache         2     1 B   42.9%  (score == hit-rate)
    94   tcache        18    17 B   48.7%  (score == hit-rate)
    95    snaps         4       -    1024  (score == earliest seq num)
    96   titers        21
    97   filter         -       -   47.4%  (score == utility)
    98  `
    99  	if s := "\n" + m.String(); expected != s {
   100  		t.Fatalf("expected%s\nbut found%s", expected, s)
   101  	}
   102  }
   103  
   104  func TestMetrics(t *testing.T) {
   105  	opts := &Options{
   106  		FS:                    vfs.NewMem(),
   107  		L0CompactionThreshold: 8,
   108  	}
   109  
   110  	// Prevent foreground flushes and compactions from triggering asynchronous
   111  	// follow-up compactions. This avoids asynchronously-scheduled work from
   112  	// interfering with the expected metrics output and reduces test flakiness.
   113  	opts.DisableAutomaticCompactions = true
   114  
   115  	d, err := Open("", opts)
   116  	require.NoError(t, err)
   117  	defer func() {
   118  		require.NoError(t, d.Close())
   119  	}()
   120  
   121  	iters := make(map[string]*Iterator)
   122  	defer func() {
   123  		for _, i := range iters {
   124  			require.NoError(t, i.Close())
   125  		}
   126  	}()
   127  
   128  	datadriven.RunTest(t, "testdata/metrics", func(td *datadriven.TestData) string {
   129  		switch td.Cmd {
   130  		case "batch":
   131  			b := d.NewBatch()
   132  			if err := runBatchDefineCmd(td, b); err != nil {
   133  				return err.Error()
   134  			}
   135  			b.Commit(nil)
   136  			return ""
   137  
   138  		case "compact":
   139  			if err := runCompactCmd(td, d); err != nil {
   140  				return err.Error()
   141  			}
   142  
   143  			d.mu.Lock()
   144  			s := d.mu.versions.currentVersion().String()
   145  			d.mu.Unlock()
   146  			return s
   147  
   148  		case "flush":
   149  			if err := d.Flush(); err != nil {
   150  				return err.Error()
   151  			}
   152  
   153  			d.mu.Lock()
   154  			s := d.mu.versions.currentVersion().String()
   155  			d.mu.Unlock()
   156  			return s
   157  
   158  		case "iter-close":
   159  			if len(td.CmdArgs) != 1 {
   160  				return "iter-close <name>"
   161  			}
   162  			name := td.CmdArgs[0].String()
   163  			if iter := iters[name]; iter != nil {
   164  				if err := iter.Close(); err != nil {
   165  					return err.Error()
   166  				}
   167  				delete(iters, name)
   168  			} else {
   169  				return fmt.Sprintf("%s: not found", name)
   170  			}
   171  
   172  			// The deletion of obsolete files happens asynchronously when an iterator
   173  			// is closed. Wait for the obsolete tables to be deleted. Note that
   174  			// waiting on cleaner.cond isn't precisely correct.
   175  			d.mu.Lock()
   176  			for d.mu.cleaner.cleaning || len(d.mu.versions.obsoleteTables) > 0 {
   177  				d.mu.cleaner.cond.Wait()
   178  			}
   179  			d.mu.Unlock()
   180  			return ""
   181  
   182  		case "iter-new":
   183  			if len(td.CmdArgs) != 1 {
   184  				return "iter-new <name>"
   185  			}
   186  			name := td.CmdArgs[0].String()
   187  			if iter := iters[name]; iter != nil {
   188  				if err := iter.Close(); err != nil {
   189  					return err.Error()
   190  				}
   191  			}
   192  			iter := d.NewIter(nil)
   193  			// Some iterators (eg. levelIter) do not instantiate the underlying
   194  			// iterator until the first positioning call. Position the iterator
   195  			// so that levelIters will have loaded an sstable.
   196  			iter.First()
   197  			iters[name] = iter
   198  			return ""
   199  
   200  		case "metrics":
   201  			// The asynchronous loading of table stats can change metrics, so
   202  			// wait for all the tables' stats to be loaded.
   203  			d.mu.Lock()
   204  			d.waitTableStats()
   205  			d.mu.Unlock()
   206  
   207  			return d.Metrics().String()
   208  
   209  		case "disk-usage":
   210  			return humanize.IEC.Uint64(d.Metrics().DiskSpaceUsage()).String()
   211  
   212  		default:
   213  			return fmt.Sprintf("unknown command: %s", td.Cmd)
   214  		}
   215  	})
   216  }
   217  
   218  func TestMetricsRedact(t *testing.T) {
   219  	const expected = `
   220  __level_____count____size___score______in__ingest(sz_cnt)____move(sz_cnt)___write(sz_cnt)____read___r-amp___w-amp
   221      WAL         0     0 B       -     0 B       -       -       -       -     0 B       -       -       -     0.0
   222        0         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   223        1         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   224        2         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   225        3         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   226        4         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   227        5         0     0 B    0.00     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   228        6         0     0 B       -     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   229    total         0     0 B       -     0 B     0 B       0     0 B       0     0 B       0     0 B       0     0.0
   230    flush         0
   231  compact         0     0 B     0 B       0          (size == estimated-debt, score = in-progress-bytes, in = num-in-progress)
   232    ctype         0       0       0       0       0       0       0  (default, delete, elision, move, read, rewrite, multi-level)
   233   memtbl         0     0 B
   234  zmemtbl         0     0 B
   235     ztbl         0     0 B
   236   bcache         0     0 B    0.0%  (score == hit-rate)
   237   tcache         0     0 B    0.0%  (score == hit-rate)
   238    snaps         0       -       0  (score == earliest seq num)
   239   titers         0
   240   filter         -       -    0.0%  (score == utility)
   241  `
   242  
   243  	got := redact.Sprintf("%s", &Metrics{}).Redact()
   244  	if s := "\n" + got; expected != s {
   245  		t.Fatalf("expected%s\nbut found%s", expected, s)
   246  	}
   247  }