github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/keyspan/level_iter_test.go (about) 1 // Copyright 2022 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 keyspan 6 7 import ( 8 "fmt" 9 "log" 10 "strings" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 "github.com/zuoyebang/bitalostable/internal/base" 15 "github.com/zuoyebang/bitalostable/internal/datadriven" 16 "github.com/zuoyebang/bitalostable/internal/manifest" 17 ) 18 19 func TestLevelIterEquivalence(t *testing.T) { 20 type level [][]Span 21 testCases := []struct { 22 name string 23 levels []level 24 }{ 25 { 26 "single level, no gaps, no overlaps", 27 []level{ 28 { 29 { 30 Span{ 31 Start: []byte("a"), 32 End: []byte("b"), 33 Keys: []Key{{ 34 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 35 Suffix: nil, 36 Value: []byte("foo"), 37 }}, 38 }, 39 Span{ 40 Start: []byte("b"), 41 End: []byte("c"), 42 Keys: []Key{{ 43 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 44 Suffix: nil, 45 Value: []byte("foo"), 46 }}, 47 }, 48 Span{ 49 Start: []byte("c"), 50 End: []byte("d"), 51 Keys: []Key{{ 52 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 53 Suffix: nil, 54 Value: []byte("foo"), 55 }}, 56 }, 57 }, 58 { 59 Span{ 60 Start: []byte("d"), 61 End: []byte("e"), 62 Keys: []Key{{ 63 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 64 Suffix: nil, 65 Value: []byte("foo"), 66 }}, 67 }, 68 Span{ 69 Start: []byte("e"), 70 End: []byte("f"), 71 Keys: []Key{{ 72 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 73 Suffix: nil, 74 Value: []byte("foo"), 75 }}, 76 }, 77 Span{ 78 Start: []byte("f"), 79 End: []byte("g"), 80 Keys: []Key{{ 81 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 82 Suffix: nil, 83 Value: []byte("foo"), 84 }}, 85 }, 86 }, 87 }, 88 }, 89 }, 90 { 91 "single level, overlapping fragments", 92 []level{ 93 { 94 { 95 Span{ 96 Start: []byte("a"), 97 End: []byte("b"), 98 Keys: []Key{ 99 { 100 Trailer: base.MakeTrailer(4, base.InternalKeyKindRangeKeySet), 101 Suffix: nil, 102 Value: []byte("bar"), 103 }, 104 { 105 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 106 Suffix: nil, 107 Value: []byte("foo"), 108 }, 109 }, 110 }, 111 Span{ 112 Start: []byte("b"), 113 End: []byte("c"), 114 Keys: []Key{ 115 { 116 Trailer: base.MakeTrailer(4, base.InternalKeyKindRangeKeySet), 117 Suffix: nil, 118 Value: []byte("bar"), 119 }, 120 { 121 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 122 Suffix: nil, 123 Value: []byte("foo"), 124 }, 125 }, 126 }, 127 Span{ 128 Start: []byte("c"), 129 End: []byte("d"), 130 Keys: []Key{{ 131 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 132 Suffix: nil, 133 Value: []byte("foo"), 134 }}, 135 }, 136 }, 137 { 138 Span{ 139 Start: []byte("d"), 140 End: []byte("e"), 141 Keys: []Key{{ 142 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 143 Suffix: nil, 144 Value: []byte("foo"), 145 }}, 146 }, 147 Span{ 148 Start: []byte("e"), 149 End: []byte("f"), 150 Keys: []Key{{ 151 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 152 Suffix: nil, 153 Value: []byte("foo"), 154 }}, 155 }, 156 Span{ 157 Start: []byte("f"), 158 End: []byte("g"), 159 Keys: []Key{{ 160 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 161 Suffix: nil, 162 Value: []byte("foo"), 163 }}, 164 }, 165 }, 166 }, 167 }, 168 }, 169 { 170 "single level, gaps between files and range keys", 171 []level{ 172 { 173 { 174 Span{ 175 Start: []byte("a"), 176 End: []byte("b"), 177 Keys: []Key{{ 178 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 179 Suffix: nil, 180 Value: []byte("foo"), 181 }}, 182 }, 183 Span{ 184 Start: []byte("c"), 185 End: []byte("d"), 186 Keys: []Key{{ 187 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 188 Suffix: nil, 189 Value: []byte("foo"), 190 }}, 191 }, 192 Span{ 193 Start: []byte("e"), 194 End: []byte("f"), 195 Keys: []Key{{ 196 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 197 Suffix: nil, 198 Value: []byte("foo"), 199 }}, 200 }, 201 }, 202 { 203 Span{ 204 Start: []byte("g"), 205 End: []byte("h"), 206 Keys: []Key{{ 207 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 208 Suffix: nil, 209 Value: []byte("foo"), 210 }}, 211 }, 212 Span{ 213 Start: []byte("i"), 214 End: []byte("j"), 215 Keys: []Key{{ 216 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 217 Suffix: nil, 218 Value: []byte("foo"), 219 }}, 220 }, 221 Span{ 222 Start: []byte("k"), 223 End: []byte("l"), 224 Keys: []Key{{ 225 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 226 Suffix: nil, 227 Value: []byte("foo"), 228 }}, 229 }, 230 }, 231 }, 232 }, 233 }, 234 { 235 "two levels, one with overlapping unset", 236 []level{ 237 { 238 { 239 Span{ 240 Start: []byte("a"), 241 End: []byte("h"), 242 Keys: []Key{{ 243 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeySet), 244 Suffix: nil, 245 Value: []byte("foo"), 246 }}, 247 }, 248 }, 249 { 250 Span{ 251 Start: []byte("l"), 252 End: []byte("u"), 253 Keys: []Key{{ 254 Trailer: base.MakeTrailer(2, base.InternalKeyKindRangeKeyUnset), 255 Suffix: nil, 256 Value: nil, 257 }}, 258 }, 259 }, 260 }, 261 { 262 { 263 Span{ 264 Start: []byte("e"), 265 End: []byte("r"), 266 Keys: []Key{{ 267 Trailer: base.MakeTrailer(1, base.InternalKeyKindRangeKeySet), 268 Suffix: nil, 269 Value: []byte("foo"), 270 }}, 271 }, 272 }, 273 }, 274 }, 275 }, 276 } 277 278 for _, tc := range testCases { 279 var fileIters []FragmentIterator 280 var levelIters []FragmentIterator 281 var iter1, iter2 MergingIter 282 for j, level := range tc.levels { 283 j := j // Copy for use in closures down below. 284 var levelIter LevelIter 285 var metas []*manifest.FileMetadata 286 for k, file := range level { 287 fileIters = append(fileIters, NewIter(base.DefaultComparer.Compare, file)) 288 meta := &manifest.FileMetadata{ 289 FileNum: base.FileNum(k + 1), 290 Size: 1024, 291 SmallestSeqNum: 2, 292 LargestSeqNum: 2, 293 SmallestRangeKey: base.MakeInternalKey(file[0].Start, file[0].SmallestKey().SeqNum(), file[0].SmallestKey().Kind()), 294 LargestRangeKey: base.MakeExclusiveSentinelKey(file[len(file)-1].LargestKey().Kind(), file[len(file)-1].End), 295 HasPointKeys: false, 296 HasRangeKeys: true, 297 } 298 meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, meta.SmallestRangeKey, meta.LargestRangeKey) 299 metas = append(metas, meta) 300 } 301 302 tableNewIters := func(file *manifest.FileMetadata, iterOptions *SpanIterOptions) (FragmentIterator, error) { 303 return NewIter(base.DefaultComparer.Compare, tc.levels[j][file.FileNum-1]), nil 304 } 305 // Add all the fileMetadatas to L6. 306 b := &manifest.BulkVersionEdit{} 307 b.Added[6] = metas 308 v, _, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0) 309 require.NoError(t, err) 310 levelIter.Init(SpanIterOptions{}, base.DefaultComparer.Compare, tableNewIters, v.Levels[6].Iter(), 0, nil, manifest.KeyTypeRange) 311 levelIters = append(levelIters, &levelIter) 312 } 313 314 iter1.Init(base.DefaultComparer.Compare, visibleTransform(base.InternalKeySeqNumMax), fileIters...) 315 iter2.Init(base.DefaultComparer.Compare, visibleTransform(base.InternalKeySeqNumMax), levelIters...) 316 // Check iter1 and iter2 for equivalence. 317 318 require.Equal(t, iter1.First(), iter2.First(), "failed on test case %q", tc.name) 319 valid := true 320 for valid { 321 f1 := iter1.Next() 322 var f2 *Span 323 for { 324 f2 = iter2.Next() 325 // The level iter could produce empty spans that straddle between 326 // files. Ignore those. 327 if f2 == nil || !f2.Empty() { 328 break 329 } 330 } 331 332 require.Equal(t, f1, f2, "failed on test case %q", tc.name) 333 valid = f1 != nil && f2 != nil 334 } 335 } 336 } 337 338 type testLogger struct { 339 t *testing.T 340 } 341 342 // Infof implements the Logger.Infof interface. 343 func (t *testLogger) Infof(format string, args ...interface{}) { 344 _ = log.Output(2, fmt.Sprintf(format, args...)) 345 } 346 347 // Fatalf implements the Logger.Fatalf interface. 348 func (t *testLogger) Fatalf(format string, args ...interface{}) { 349 _ = log.Output(2, fmt.Sprintf(format, args...)) 350 t.t.Fail() 351 } 352 353 func TestLevelIter(t *testing.T) { 354 var level [][]Span 355 var rangedels [][]Span 356 var metas []*manifest.FileMetadata 357 var iter FragmentIterator 358 var extraInfo func() string 359 360 datadriven.RunTest(t, "testdata/level_iter", func(d *datadriven.TestData) string { 361 switch d.Cmd { 362 case "define": 363 level = level[:0] 364 metas = metas[:0] 365 rangedels = rangedels[:0] 366 if iter != nil { 367 iter.Close() 368 iter = nil 369 } 370 var pointKeys []base.InternalKey 371 var currentRangeDels []Span 372 var currentFile []Span 373 for _, key := range strings.Split(d.Input, "\n") { 374 if strings.HasPrefix(key, "file") { 375 // Skip the very first file creation. 376 if len(level) != 0 || len(currentFile) != 0 { 377 meta := &manifest.FileMetadata{ 378 FileNum: base.FileNum(len(level) + 1), 379 } 380 if len(currentFile) > 0 { 381 smallest := base.MakeInternalKey(currentFile[0].Start, currentFile[0].SmallestKey().SeqNum(), currentFile[0].SmallestKey().Kind()) 382 largest := base.MakeExclusiveSentinelKey(currentFile[len(currentFile)-1].LargestKey().Kind(), currentFile[len(currentFile)-1].End) 383 meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, smallest, largest) 384 } 385 if len(pointKeys) != 0 { 386 meta.ExtendPointKeyBounds(base.DefaultComparer.Compare, pointKeys[0], pointKeys[len(pointKeys)-1]) 387 } 388 level = append(level, currentFile) 389 metas = append(metas, meta) 390 rangedels = append(rangedels, currentRangeDels) 391 currentRangeDels = nil 392 currentFile = nil 393 pointKeys = nil 394 } 395 continue 396 } 397 key = strings.TrimSpace(key) 398 if strings.HasPrefix(key, "point:") { 399 key = strings.TrimPrefix(key, "point:") 400 j := strings.Index(key, ":") 401 ikey := base.ParseInternalKey(key[:j]) 402 pointKeys = append(pointKeys, ikey) 403 if ikey.Kind() == base.InternalKeyKindRangeDelete { 404 currentRangeDels = append(currentRangeDels, Span{ 405 Start: ikey.UserKey, End: []byte(key[j+1:]), Keys: []Key{{Trailer: ikey.Trailer}}}) 406 } 407 continue 408 } 409 span := ParseSpan(key) 410 currentFile = append(currentFile, span) 411 } 412 meta := &manifest.FileMetadata{ 413 FileNum: base.FileNum(len(level) + 1), 414 } 415 level = append(level, currentFile) 416 rangedels = append(rangedels, currentRangeDels) 417 if len(currentFile) > 0 { 418 smallest := base.MakeInternalKey(currentFile[0].Start, currentFile[0].SmallestKey().SeqNum(), currentFile[0].SmallestKey().Kind()) 419 largest := base.MakeExclusiveSentinelKey(currentFile[len(currentFile)-1].LargestKey().Kind(), currentFile[len(currentFile)-1].End) 420 meta.ExtendRangeKeyBounds(base.DefaultComparer.Compare, smallest, largest) 421 } 422 if len(pointKeys) != 0 { 423 meta.ExtendPointKeyBounds(base.DefaultComparer.Compare, pointKeys[0], pointKeys[len(pointKeys)-1]) 424 } 425 metas = append(metas, meta) 426 return "" 427 case "num-files": 428 return fmt.Sprintf("%d", len(level)) 429 case "close-iter": 430 _ = iter.Close() 431 iter = nil 432 return "ok" 433 case "iter": 434 keyType := manifest.KeyTypeRange 435 for _, arg := range d.CmdArgs { 436 if strings.Contains(arg.Key, "rangedel") { 437 keyType = manifest.KeyTypePoint 438 } 439 } 440 if iter == nil { 441 var lastFileNum base.FileNum 442 tableNewIters := func(file *manifest.FileMetadata, iterOptions *SpanIterOptions) (FragmentIterator, error) { 443 keyType := keyType 444 spans := level[file.FileNum-1] 445 if keyType == manifest.KeyTypePoint { 446 spans = rangedels[file.FileNum-1] 447 } 448 lastFileNum = file.FileNum 449 return NewIter(base.DefaultComparer.Compare, spans), nil 450 } 451 b := &manifest.BulkVersionEdit{} 452 b.Added[6] = metas 453 v, _, err := b.Apply(nil, base.DefaultComparer.Compare, base.DefaultFormatter, 0, 0) 454 require.NoError(t, err) 455 iter = newLevelIter(SpanIterOptions{}, base.DefaultComparer.Compare, tableNewIters, v.Levels[6].Iter(), 6, &testLogger{t}, keyType) 456 extraInfo = func() string { 457 return fmt.Sprintf("file = %s.sst", lastFileNum) 458 } 459 } 460 461 return runFragmentIteratorCmd(iter, d.Input, extraInfo) 462 463 default: 464 return fmt.Sprintf("unknown command: %s", d.Cmd) 465 } 466 }) 467 468 if iter != nil { 469 iter.Close() 470 } 471 }