github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/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 TestCompactionLogs(t *testing.T) { 293 dir := t.TempDir() 294 datadriven.Walk(t, "testdata", func(t *testing.T, path string) { 295 var c *logEventCollector 296 var logNum int 297 resetFn := func() { 298 c = newEventCollector() 299 logNum = 0 300 } 301 resetFn() 302 datadriven.RunTest(t, path, func(t *testing.T, td *datadriven.TestData) string { 303 switch td.Cmd { 304 case "log": 305 basename := fmt.Sprintf("%d.log", logNum) 306 logNum++ 307 f, err := os.Create(filepath.Join(dir, basename)) 308 if err != nil { 309 panic(err) 310 } 311 if _, err = f.WriteString(td.Input); err != nil { 312 panic(err) 313 } 314 _ = f.Close() 315 316 if err = parseLog(f.Name(), c); err != nil { 317 return err.Error() 318 } 319 return basename 320 321 case "summarize": 322 window := 1 * time.Minute 323 longRunning := time.Duration(math.MaxInt64) 324 325 var err error 326 for _, cmdArg := range td.CmdArgs { 327 switch cmdArg.Key { 328 case "window": 329 window, err = time.ParseDuration(cmdArg.Vals[0]) 330 if err != nil { 331 panic(errors.Newf("could not parse window: %s", err)) 332 } 333 334 case "long-running": 335 longRunning, err = time.ParseDuration(cmdArg.Vals[0]) 336 if err != nil { 337 panic(errors.Newf("could not parse long-running: %s", err)) 338 } 339 340 default: 341 panic(errors.Newf("unknown arg %q", cmdArg.Key)) 342 } 343 } 344 345 a := newAggregator(window, longRunning, c.events, c.readAmps) 346 windows := a.aggregate() 347 348 var b bytes.Buffer 349 for _, w := range windows { 350 b.WriteString(w.String()) 351 } 352 353 return b.String() 354 355 case "reset": 356 resetFn() 357 return "" 358 359 default: 360 return fmt.Sprintf("unknown command %q", td.Cmd) 361 } 362 }) 363 }) 364 } 365 366 func TestParseInputBytes(t *testing.T) { 367 testCases := []struct { 368 s string 369 want uint64 370 }{ 371 // Test both 23.1 and current formats. 372 { 373 "(10 B)", 374 10, 375 }, 376 { 377 "(10B)", 378 10, 379 }, 380 { 381 "(10 M)", 382 10 << 20, 383 }, 384 { 385 "(10MB)", 386 10 << 20, 387 }, 388 { 389 "(10 M) + (20 M)", 390 30 << 20, 391 }, 392 { 393 "(10MB) + (20MB)", 394 30 << 20, 395 }, 396 { 397 "(10 M) + (20 M) + (30 M)", 398 60 << 20, 399 }, 400 { 401 "(10MB) + (20MB) + (30MB)", 402 60 << 20, 403 }, 404 { 405 "foo", 406 0, 407 }, 408 } 409 for _, tc := range testCases { 410 t.Run(tc.s, func(t *testing.T) { 411 got, err := sumInputBytes(tc.s) 412 require.NoError(t, err) 413 require.Equal(t, tc.want, got) 414 }) 415 } 416 }