github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/tool/logs/compaction_test.go (about)

     1  // Copyright 2021 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 logs
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"math"
    11  	"os"
    12  	"path/filepath"
    13  	"regexp"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/cockroachdb/datadriven"
    18  	"github.com/cockroachdb/errors"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  const (
    23  	compactionStartLine23_1 = `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n5,pebble,s6] 1216510  [JOB 284925] compacting(default) L2 [442555] (4.2 M) + L3 [445853] (8.4 M)`
    24  	compactionStartLine     = `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n5,pebble,s6] 1216510  [JOB 284925] compacting(default) L2 [442555] (4.2MB) Score=1.01 + L3 [445853] (8.4MB) Score=0.99;  OverlappingRatio: Single 8.03, Multi 25.05;`
    25  
    26  	compactionEndLine23_1 = `I211215 14:26:56.318543 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1886 ⋮ [n5,pebble,s6] 1216554  [JOB 284925] compacted(default) L2 [442555] (4.2 M) + L3 [445853] (8.4 M) -> L3 [445883 445887] (13 M), in 0.3s, output rate 42 M/s`
    27  	compactionEndLine     = `I211215 14:26:56.318543 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1886 ⋮ [n5,pebble,s6] 1216554  [JOB 284925] compacted(default) L2 [442555] (4.2MB) Score=1.01 + L3 [445853] (8.4MB) Score=1.01 -> L3 [445883 445887] (13MB), in 0.3s, output rate 42MB/s`
    28  
    29  	compactionMultiLevelStartLine = `I211215 14:26:56.318543 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1886 ⋮ [n5,pebble,s6] 1216554 [JOB 11] compacting(default) [multilevel] L2 [250858] (2.1MB) Score=1.09 + L3 [247985 247989 247848] (17MB) Score=0.99 + L4 [250817 250834 238396] (28MB) Score=1.00; OverlappingRatio: Single 3.77, Multi 1.46;`
    30  	compactionMultiLevelEndline   = `I211215 14:26:56.318543 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1886 ⋮ [n5,pebble,s6] 1216554 [JOB 11] compacted(default) [multilevel] L2 [250858] (2.1MB) Score=1.09 + L3 [247985 247989 247848] (17MB) Score=0.99 + L4 [250817 250834 238396] (28MB) Score=1.00 -> L4 [250859 250860 250861 250862 250863] (46MB), in 0.2s (0.2s total), output rate 185MB/s`
    31  
    32  	flushStartLine = `I211213 16:23:48.903751 21136 3@vendor/github.com/cockroachdb/pebble/event.go:599 ⋮ [n9,pebble,s8] 24 [JOB 10] flushing 2 memtables to L0`
    33  
    34  	flushEndLine23_1 = `I211213 16:23:49.134464 21136 3@vendor/github.com/cockroachdb/pebble/event.go:603 ⋮ [n9,pebble,s8] 26 [JOB 10] flushed 2 memtables to L0 [1535806] (1.3 M), in 0.2s, output rate 5.8 M/s`
    35  	flushEndLine     = `I211213 16:23:49.134464 21136 3@vendor/github.com/cockroachdb/pebble/event.go:603 ⋮ [n9,pebble,s8] 26 [JOB 10] flushed 2 memtables to L0 [1535806] (1.3MB), in 0.2s, output rate 5.8MB/s`
    36  
    37  	readAmpLine23_1 = `  total     31766   188 G       -   257 G   187 G    48 K   3.6 G     744   536 G    49 K   278 G       5     2.1`
    38  	readAmpLine     = `total |   32K 188GB     0B |     - | 257GB |   48K  187GB |   744  3.6GB |   49K  536GB | 278GB |   5  2.1`
    39  
    40  	compactionStartNoNodeStoreLine23_1 = `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n?,pebble,s?] 1216510  [JOB 284925] compacting(default) L2 [442555] (4.2 M) + L3 [445853] (8.4 M)`
    41  	compactionStartNoNodeStoreLine     = `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n?,pebble,s?] 1216510  [JOB 284925] compacting(default) L2 [442555] (4.2 M) + L3 [445853] (8.4MB)`
    42  	flushStartNoNodeStoreLine          = `I211213 16:23:48.903751 21136 3@vendor/github.com/cockroachdb/pebble/event.go:599 ⋮ [n?,pebble,s?] 24 [JOB 10] flushing 2 memtables to L0`
    43  
    44  	flushableIngestionLine23_1 = `I230831 04:13:28.824280 3780 3@pebble/event.go:685 ⋮ [n10,s10,pebble] 365  [JOB 226] flushed 6 ingested flushables L0:024334 (1.5 K) + L0:024339 (1.0 K) + L0:024335 (1.9 K) + L0:024336 (1.1 K) + L0:024337 (1.1 K) + L0:024338 (12 K) in 0.0s (0.0s total), output rate 67 M/s`
    45  	flushableIngestionLine     = `I230831 04:13:28.824280 3780 3@pebble/event.go:685 ⋮ [n10,s10,pebble] 365  [JOB 226] flushed 6 ingested flushables L0:024334 (1.5KB) + L0:024339 (1.0KB) + L0:024335 (1.9KB) + L0:024336 (1.1KB) + L0:024337 (1.1KB) + L0:024338 (12KB) in 0.0s (0.0s total), output rate 67MB/s`
    46  )
    47  
    48  func TestCompactionLogs_Regex(t *testing.T) {
    49  	tcs := []struct {
    50  		name    string
    51  		re      *regexp.Regexp
    52  		line    string
    53  		matches map[int]string
    54  	}{
    55  		{
    56  			name: "compaction start - sentinel",
    57  			re:   sentinelPattern,
    58  			line: compactionStartLine23_1,
    59  			matches: map[int]string{
    60  				sentinelPatternPrefixIdx: "compact",
    61  				sentinelPatternSuffixIdx: "ing",
    62  			},
    63  		},
    64  		{
    65  			name: "compaction start - sentinel",
    66  			re:   sentinelPattern,
    67  			line: compactionStartLine,
    68  			matches: map[int]string{
    69  				sentinelPatternPrefixIdx: "compact",
    70  				sentinelPatternSuffixIdx: "ing",
    71  			},
    72  		},
    73  		{
    74  			name: "compaction end - sentinel",
    75  			re:   sentinelPattern,
    76  			line: compactionEndLine23_1,
    77  			matches: map[int]string{
    78  				sentinelPatternPrefixIdx: "compact",
    79  				sentinelPatternSuffixIdx: "ed",
    80  			},
    81  		},
    82  		{
    83  			name: "compaction end - sentinel",
    84  			re:   sentinelPattern,
    85  			line: compactionEndLine,
    86  			matches: map[int]string{
    87  				sentinelPatternPrefixIdx: "compact",
    88  				sentinelPatternSuffixIdx: "ed",
    89  			},
    90  		},
    91  		{
    92  			name: "flush start - sentinel",
    93  			re:   sentinelPattern,
    94  			line: flushStartLine,
    95  			matches: map[int]string{
    96  				sentinelPatternPrefixIdx: "flush",
    97  				sentinelPatternSuffixIdx: "ing",
    98  			},
    99  		},
   100  		{
   101  			name: "flush end - sentinel",
   102  			re:   sentinelPattern,
   103  			line: flushEndLine23_1,
   104  			matches: map[int]string{
   105  				sentinelPatternPrefixIdx: "flush",
   106  				sentinelPatternSuffixIdx: "ed",
   107  			},
   108  		},
   109  		{
   110  			name: "flush end - sentinel",
   111  			re:   sentinelPattern,
   112  			line: flushEndLine,
   113  			matches: map[int]string{
   114  				sentinelPatternPrefixIdx: "flush",
   115  				sentinelPatternSuffixIdx: "ed",
   116  			},
   117  		},
   118  		{
   119  			name: "compaction start",
   120  			re:   compactionPattern,
   121  			line: compactionStartLine23_1,
   122  			matches: map[int]string{
   123  				compactionPatternJobIdx:    "284925",
   124  				compactionPatternSuffixIdx: "ing",
   125  				compactionPatternTypeIdx:   "default",
   126  				compactionPatternFromIdx:   "2",
   127  				compactionPatternToIdx:     "3",
   128  				compactionPatternLevels:    "L2 [442555] (4.2 M) + L3 [445853] (8.4 M)",
   129  			},
   130  		},
   131  		{
   132  			name: "compaction start",
   133  			re:   compactionPattern,
   134  			line: compactionStartLine,
   135  			matches: map[int]string{
   136  				compactionPatternJobIdx:    "284925",
   137  				compactionPatternSuffixIdx: "ing",
   138  				compactionPatternTypeIdx:   "default",
   139  				compactionPatternFromIdx:   "2",
   140  				compactionPatternToIdx:     "3",
   141  				compactionPatternLevels:    "L2 [442555] (4.2MB) Score=1.01 + L3 [445853] (8.4MB) Score=0.99",
   142  			},
   143  		},
   144  		{
   145  			name: "compaction start multilevel",
   146  			re:   compactionPattern,
   147  			line: compactionMultiLevelStartLine,
   148  			matches: map[int]string{
   149  				compactionPatternJobIdx:    "11",
   150  				compactionPatternSuffixIdx: "ing",
   151  				compactionPatternTypeIdx:   "default",
   152  				compactionPatternFromIdx:   "2",
   153  				compactionPatternToIdx:     "4",
   154  				compactionPatternLevels:    "L2 [250858] (2.1MB) Score=1.09 + L3 [247985 247989 247848] (17MB) Score=0.99 + L4 [250817 250834 238396] (28MB) Score=1.00",
   155  			},
   156  		},
   157  		{
   158  			name: "compaction start - no node / store",
   159  			re:   compactionPattern,
   160  			line: compactionStartNoNodeStoreLine,
   161  			matches: map[int]string{
   162  				compactionPatternJobIdx:    "284925",
   163  				compactionPatternSuffixIdx: "ing",
   164  				compactionPatternTypeIdx:   "default",
   165  				compactionPatternFromIdx:   "2",
   166  				compactionPatternToIdx:     "3",
   167  			},
   168  		},
   169  		{
   170  			name: "compaction end",
   171  			re:   compactionPattern,
   172  			line: compactionEndLine,
   173  			matches: map[int]string{
   174  				compactionPatternJobIdx:    "284925",
   175  				compactionPatternSuffixIdx: "ed",
   176  				compactionPatternTypeIdx:   "default",
   177  				compactionPatternFromIdx:   "2",
   178  				compactionPatternToIdx:     "3",
   179  				compactionPatternBytesIdx:  "13MB",
   180  			},
   181  		},
   182  		{
   183  			name: "compaction end",
   184  			re:   compactionPattern,
   185  			line: compactionMultiLevelEndline,
   186  			matches: map[int]string{
   187  				compactionPatternJobIdx:    "11",
   188  				compactionPatternSuffixIdx: "ed",
   189  				compactionPatternTypeIdx:   "default",
   190  				compactionPatternFromIdx:   "2",
   191  				compactionPatternToIdx:     "4",
   192  				compactionPatternBytesIdx:  "46MB",
   193  			},
   194  		},
   195  		{
   196  			name: "flush start",
   197  			re:   flushPattern,
   198  			line: flushStartLine,
   199  			matches: map[int]string{
   200  				flushPatternJobIdx:    "10",
   201  				flushPatternSuffixIdx: "ing",
   202  				flushPatternBytesIdx:  "",
   203  			},
   204  		},
   205  		{
   206  			name: "flush start - no node / store",
   207  			re:   flushPattern,
   208  			line: flushStartNoNodeStoreLine,
   209  			matches: map[int]string{
   210  				flushPatternJobIdx:    "10",
   211  				flushPatternSuffixIdx: "ing",
   212  				flushPatternBytesIdx:  "",
   213  			},
   214  		},
   215  		{
   216  			name: "flush end",
   217  			re:   flushPattern,
   218  			line: flushEndLine,
   219  			matches: map[int]string{
   220  				flushPatternJobIdx:    "10",
   221  				flushPatternSuffixIdx: "ed",
   222  				flushPatternBytesIdx:  "1.3MB",
   223  			},
   224  		},
   225  		{
   226  			name: "read amp suffix",
   227  			re:   readAmpPattern,
   228  			line: readAmpLine,
   229  			matches: map[int]string{
   230  				readAmpPatternValueIdx: "5",
   231  			},
   232  		},
   233  		{
   234  			name: "read amp suffix 23.1",
   235  			re:   readAmpPattern,
   236  			line: readAmpLine23_1,
   237  			matches: map[int]string{
   238  				readAmpPatternValueIdx: "5",
   239  			},
   240  		},
   241  		{
   242  			name: "ingestion during flush job 23.1",
   243  			re:   flushableIngestedPattern,
   244  			line: flushableIngestionLine23_1,
   245  			matches: map[int]string{
   246  				flushableIngestedPatternJobIdx: "226",
   247  			},
   248  		},
   249  		{
   250  			name: "ingestion during flush 23.1",
   251  			re:   ingestedFilePattern,
   252  			line: flushableIngestionLine23_1,
   253  			matches: map[int]string{
   254  				// Just looking at the first match for these.
   255  				ingestedFilePatternLevelIdx: "0",
   256  				ingestedFilePatternFileIdx:  "024334",
   257  				ingestedFilePatternBytesIdx: "1.5 K",
   258  			},
   259  		},
   260  		{
   261  			name: "ingestion during flush job",
   262  			re:   flushableIngestedPattern,
   263  			line: flushableIngestionLine,
   264  			matches: map[int]string{
   265  				flushableIngestedPatternJobIdx: "226",
   266  			},
   267  		},
   268  		{
   269  			name: "ingestion during flush",
   270  			re:   ingestedFilePattern,
   271  			line: flushableIngestionLine,
   272  			matches: map[int]string{
   273  				// Just looking at the first match for these.
   274  				ingestedFilePatternLevelIdx: "0",
   275  				ingestedFilePatternFileIdx:  "024334",
   276  				ingestedFilePatternBytesIdx: "1.5KB",
   277  			},
   278  		},
   279  	}
   280  
   281  	for _, tc := range tcs {
   282  		t.Run(tc.name, func(t *testing.T) {
   283  			matches := tc.re.FindStringSubmatch(tc.line)
   284  			require.NotNil(t, matches)
   285  			for idx, want := range tc.matches {
   286  				require.Equal(t, want, matches[idx])
   287  			}
   288  		})
   289  	}
   290  }
   291  
   292  func TestParseLogContext(t *testing.T) {
   293  	testCases := []struct {
   294  		line      string
   295  		timestamp string
   296  		node      int
   297  		store     int
   298  	}{
   299  		{
   300  			line:      `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n5,pebble,s6] foo`,
   301  			timestamp: "211215 14:26:56.012382",
   302  			node:      5,
   303  			store:     6,
   304  		},
   305  		{
   306  			line:      `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [T?,n5,pebble,s6] foo`,
   307  			timestamp: "211215 14:26:56.012382",
   308  			node:      5,
   309  			store:     6,
   310  		},
   311  		{
   312  			line:      `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [T15,n5,pebble,s6] foo`,
   313  			timestamp: "211215 14:26:56.012382",
   314  			node:      5,
   315  			store:     6,
   316  		},
   317  		{
   318  			line:      `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [T1,n?,pebble,s6] foo`,
   319  			timestamp: "211215 14:26:56.012382",
   320  			node:      -1,
   321  			store:     6,
   322  		},
   323  		{
   324  			line:      `I211215 14:26:56.012382 51831533 3@vendor/github.com/cockroachdb/pebble/compaction.go:1845 ⋮ [n5,pebble,s?] foo`,
   325  			timestamp: "211215 14:26:56.012382",
   326  			node:      5,
   327  			store:     -1,
   328  		},
   329  	}
   330  	for _, tc := range testCases {
   331  		t.Run("", func(t *testing.T) {
   332  			var b logEventCollector
   333  			require.NoError(t, parseLogContext(tc.line, &b))
   334  			expT, err := time.Parse(timeFmt, tc.timestamp)
   335  			require.NoError(t, err)
   336  			require.Equal(t, expT, b.ctx.timestamp)
   337  			require.Equal(t, tc.node, b.ctx.node)
   338  			require.Equal(t, tc.store, b.ctx.store)
   339  		})
   340  	}
   341  }
   342  
   343  func TestCompactionLogs(t *testing.T) {
   344  	dir := t.TempDir()
   345  	datadriven.Walk(t, "testdata", func(t *testing.T, path string) {
   346  		var c *logEventCollector
   347  		var logNum int
   348  		resetFn := func() {
   349  			c = newEventCollector()
   350  			logNum = 0
   351  		}
   352  		resetFn()
   353  		datadriven.RunTest(t, path, func(t *testing.T, td *datadriven.TestData) string {
   354  			switch td.Cmd {
   355  			case "log":
   356  				basename := fmt.Sprintf("%d.log", logNum)
   357  				logNum++
   358  				f, err := os.Create(filepath.Join(dir, basename))
   359  				if err != nil {
   360  					panic(err)
   361  				}
   362  				if _, err = f.WriteString(td.Input); err != nil {
   363  					panic(err)
   364  				}
   365  				_ = f.Close()
   366  
   367  				if err = parseLog(f.Name(), c); err != nil {
   368  					return err.Error()
   369  				}
   370  				return basename
   371  
   372  			case "summarize":
   373  				window := 1 * time.Minute
   374  				longRunning := time.Duration(math.MaxInt64)
   375  
   376  				var err error
   377  				for _, cmdArg := range td.CmdArgs {
   378  					switch cmdArg.Key {
   379  					case "window":
   380  						window, err = time.ParseDuration(cmdArg.Vals[0])
   381  						if err != nil {
   382  							panic(errors.Newf("could not parse window: %s", err))
   383  						}
   384  
   385  					case "long-running":
   386  						longRunning, err = time.ParseDuration(cmdArg.Vals[0])
   387  						if err != nil {
   388  							panic(errors.Newf("could not parse long-running: %s", err))
   389  						}
   390  
   391  					default:
   392  						panic(errors.Newf("unknown arg %q", cmdArg.Key))
   393  					}
   394  				}
   395  
   396  				a := newAggregator(window, longRunning, c.events, c.readAmps)
   397  				windows := a.aggregate()
   398  
   399  				var b bytes.Buffer
   400  				for _, w := range windows {
   401  					b.WriteString(w.String())
   402  				}
   403  
   404  				return b.String()
   405  
   406  			case "reset":
   407  				resetFn()
   408  				return ""
   409  
   410  			default:
   411  				return fmt.Sprintf("unknown command %q", td.Cmd)
   412  			}
   413  		})
   414  	})
   415  }
   416  
   417  func TestParseInputBytes(t *testing.T) {
   418  	testCases := []struct {
   419  		s    string
   420  		want uint64
   421  	}{
   422  		// Test both 23.1 and current formats.
   423  		{
   424  			"(10 B)",
   425  			10,
   426  		},
   427  		{
   428  			"(10B)",
   429  			10,
   430  		},
   431  		{
   432  			"(10 M)",
   433  			10 << 20,
   434  		},
   435  		{
   436  			"(10MB)",
   437  			10 << 20,
   438  		},
   439  		{
   440  			"(10 M) + (20 M)",
   441  			30 << 20,
   442  		},
   443  		{
   444  			"(10MB) + (20MB)",
   445  			30 << 20,
   446  		},
   447  		{
   448  			"(10 M) + (20 M) + (30 M)",
   449  			60 << 20,
   450  		},
   451  		{
   452  			"(10MB) + (20MB) + (30MB)",
   453  			60 << 20,
   454  		},
   455  		{
   456  			"foo",
   457  			0,
   458  		},
   459  	}
   460  	for _, tc := range testCases {
   461  		t.Run(tc.s, func(t *testing.T) {
   462  			got, err := sumInputBytes(tc.s)
   463  			require.NoError(t, err)
   464  			require.Equal(t, tc.want, got)
   465  		})
   466  	}
   467  }