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 }