github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/get_iter_test.go (about) 1 // Copyright 2018 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 pebble 6 7 import ( 8 "context" 9 "strings" 10 "testing" 11 12 "github.com/cockroachdb/errors" 13 "github.com/cockroachdb/pebble/internal/base" 14 "github.com/cockroachdb/pebble/internal/keyspan" 15 "github.com/cockroachdb/pebble/internal/manifest" 16 "github.com/cockroachdb/pebble/internal/testkeys" 17 ) 18 19 func TestGetIter(t *testing.T) { 20 // testTable is a table to insert into a version. 21 // Each element of data is a string of the form "internalKey value". 22 type testTable struct { 23 level int 24 fileNum FileNum 25 data []string 26 } 27 28 testCases := []struct { 29 description string 30 // badOrdering is whether this test case has a table ordering violation. 31 badOrdering bool 32 // tables are the tables to populate the version with. 33 tables []testTable 34 // queries are the queries to run against the version. Each element has 35 // the form "internalKey wantedValue". The internalKey is passed to the 36 // version.get method, wantedValue may be "ErrNotFound" if the query 37 // should return that error. 38 queries []string 39 }{ 40 { 41 description: "empty: an empty version", 42 queries: []string{ 43 "abc.SEPARATOR.101 ErrNotFound", 44 }, 45 }, 46 47 { 48 description: "single-0: one level-0 table", 49 tables: []testTable{ 50 { 51 level: 0, 52 fileNum: 10, 53 data: []string{ 54 "the.SET.101 a", 55 "cat.SET.102 b", 56 "on_.SET.103 c", 57 "the.SET.104 d", 58 "mat.SET.105 e", 59 "the.DEL.106 ", 60 "the.MERGE.107 g", 61 }, 62 }, 63 }, 64 queries: []string{ 65 "aaa.SEPARATOR.105 ErrNotFound", 66 "cat.SEPARATOR.105 b", 67 "hat.SEPARATOR.105 ErrNotFound", 68 "mat.SEPARATOR.105 e", 69 "the.SEPARATOR.108 g", 70 "the.SEPARATOR.107 g", 71 "the.SEPARATOR.106 ErrNotFound", 72 "the.SEPARATOR.105 d", 73 "the.SEPARATOR.104 d", 74 "the.SEPARATOR.104 d", 75 "the.SEPARATOR.103 a", 76 "the.SEPARATOR.102 a", 77 "the.SEPARATOR.101 a", 78 "the.SEPARATOR.100 ErrNotFound", 79 "zzz.SEPARATOR.105 ErrNotFound", 80 }, 81 }, 82 83 { 84 description: "triple-0: three level-0 tables", 85 tables: []testTable{ 86 { 87 level: 0, 88 fileNum: 10, 89 data: []string{ 90 "the.SET.101 a", 91 "cat.SET.102 b", 92 "on_.SET.103 c", 93 "the.SET.104 d", 94 "mat.SET.105 e", 95 "the.DEL.106 ", 96 "the.SET.107 g", 97 }, 98 }, 99 { 100 level: 0, 101 fileNum: 11, 102 data: []string{ 103 "awk.SET.111 w", 104 "cat.SET.112 x", 105 "man.SET.113 y", 106 "sed.SET.114 z", 107 }, 108 }, 109 { 110 level: 0, 111 fileNum: 12, 112 data: []string{ 113 "the.DEL.121 ", 114 "cat.DEL.122 ", 115 "man.DEL.123 ", 116 "was.SET.124 D", 117 "not.SET.125 E", 118 "the.SET.126 F", 119 "man.SET.127 G", 120 }, 121 }, 122 }, 123 queries: []string{ 124 "aaa.SEPARATOR.105 ErrNotFound", 125 "awk.SEPARATOR.135 w", 126 "awk.SEPARATOR.125 w", 127 "awk.SEPARATOR.115 w", 128 "awk.SEPARATOR.105 ErrNotFound", 129 "cat.SEPARATOR.135 ErrNotFound", 130 "cat.SEPARATOR.125 ErrNotFound", 131 "cat.SEPARATOR.115 x", 132 "cat.SEPARATOR.105 b", 133 "man.SEPARATOR.135 G", 134 "man.SEPARATOR.125 ErrNotFound", 135 "man.SEPARATOR.115 y", 136 "man.SEPARATOR.105 ErrNotFound", 137 "on_.SEPARATOR.135 c", 138 "on_.SEPARATOR.125 c", 139 "on_.SEPARATOR.115 c", 140 "on_.SEPARATOR.105 c", 141 "the.SEPARATOR.135 F", 142 "the.SEPARATOR.127 F", 143 "the.SEPARATOR.126 F", 144 "the.SEPARATOR.125 ErrNotFound", 145 "the.SEPARATOR.122 ErrNotFound", 146 "the.SEPARATOR.121 ErrNotFound", 147 "the.SEPARATOR.120 g", 148 "the.SEPARATOR.115 g", 149 "the.SEPARATOR.114 g", 150 "the.SEPARATOR.111 g", 151 "the.SEPARATOR.110 g", 152 "the.SEPARATOR.108 g", 153 "the.SEPARATOR.107 g", 154 "the.SEPARATOR.106 ErrNotFound", 155 "the.SEPARATOR.105 d", 156 "the.SEPARATOR.104 d", 157 "the.SEPARATOR.104 d", 158 "the.SEPARATOR.103 a", 159 "the.SEPARATOR.102 a", 160 "the.SEPARATOR.101 a", 161 "the.SEPARATOR.100 ErrNotFound", 162 "zzz.SEPARATOR.105 ErrNotFound", 163 }, 164 }, 165 166 { 167 description: "quad-4: four level-4 tables", 168 tables: []testTable{ 169 { 170 level: 4, 171 fileNum: 11, 172 data: []string{ 173 "aardvark.SET.101 a1", 174 "alpaca__.SET.201 a2", 175 "anteater.SET.301 a3", 176 }, 177 }, 178 { 179 level: 4, 180 fileNum: 22, 181 data: []string{ 182 "baboon__.SET.102 b1", 183 "baboon__.DEL.202 ", 184 "baboon__.SET.302 b3", 185 "bear____.SET.402 b4", 186 "bear____.DEL.502 ", 187 "buffalo_.SET.602 b6", 188 }, 189 }, 190 { 191 level: 4, 192 fileNum: 33, 193 data: []string{ 194 "buffalo_.SET.103 B1", 195 }, 196 }, 197 { 198 level: 4, 199 fileNum: 44, 200 data: []string{ 201 "chipmunk.SET.104 c1", 202 "chipmunk.SET.204 c2", 203 }, 204 }, 205 }, 206 queries: []string{ 207 "a_______.SEPARATOR.999 ErrNotFound", 208 "aardvark.SEPARATOR.999 a1", 209 "aardvark.SEPARATOR.102 a1", 210 "aardvark.SEPARATOR.101 a1", 211 "aardvark.SEPARATOR.100 ErrNotFound", 212 "alpaca__.SEPARATOR.999 a2", 213 "alpaca__.SEPARATOR.200 ErrNotFound", 214 "anteater.SEPARATOR.999 a3", 215 "anteater.SEPARATOR.302 a3", 216 "anteater.SEPARATOR.301 a3", 217 "anteater.SEPARATOR.300 ErrNotFound", 218 "anteater.SEPARATOR.000 ErrNotFound", 219 "b_______.SEPARATOR.999 ErrNotFound", 220 "baboon__.SEPARATOR.999 b3", 221 "baboon__.SEPARATOR.302 b3", 222 "baboon__.SEPARATOR.301 ErrNotFound", 223 "baboon__.SEPARATOR.202 ErrNotFound", 224 "baboon__.SEPARATOR.201 b1", 225 "baboon__.SEPARATOR.102 b1", 226 "baboon__.SEPARATOR.101 ErrNotFound", 227 "bear____.SEPARATOR.999 ErrNotFound", 228 "bear____.SEPARATOR.500 b4", 229 "bear____.SEPARATOR.000 ErrNotFound", 230 "buffalo_.SEPARATOR.999 b6", 231 "buffalo_.SEPARATOR.603 b6", 232 "buffalo_.SEPARATOR.602 b6", 233 "buffalo_.SEPARATOR.601 B1", 234 "buffalo_.SEPARATOR.104 B1", 235 "buffalo_.SEPARATOR.103 B1", 236 "buffalo_.SEPARATOR.102 ErrNotFound", 237 "buffalo_.SEPARATOR.000 ErrNotFound", 238 "c_______.SEPARATOR.999 ErrNotFound", 239 "chipmunk.SEPARATOR.999 c2", 240 "chipmunk.SEPARATOR.205 c2", 241 "chipmunk.SEPARATOR.204 c2", 242 "chipmunk.SEPARATOR.203 c1", 243 "chipmunk.SEPARATOR.105 c1", 244 "chipmunk.SEPARATOR.104 c1", 245 "chipmunk.SEPARATOR.103 ErrNotFound", 246 "chipmunk.SEPARATOR.000 ErrNotFound", 247 "d_______.SEPARATOR.999 ErrNotFound", 248 }, 249 }, 250 251 { 252 description: "complex: many tables at many levels", 253 tables: []testTable{ 254 { 255 level: 0, 256 fileNum: 50, 257 data: []string{ 258 "alfalfa__.SET.501 p1", 259 "asparagus.SET.502 p2", 260 "cabbage__.DEL.503 ", 261 "spinach__.MERGE.504 p3", 262 }, 263 }, 264 { 265 level: 0, 266 fileNum: 51, 267 data: []string{ 268 "asparagus.SET.511 q1", 269 "asparagus.SET.512 q2", 270 "asparagus.SET.513 q3", 271 "beans____.SET.514 q4", 272 "broccoli_.SET.515 q5", 273 "cabbage__.SET.516 q6", 274 "celery___.SET.517 q7", 275 "spinach__.MERGE.518 q8", 276 }, 277 }, 278 { 279 level: 1, 280 fileNum: 40, 281 data: []string{ 282 "alfalfa__.SET.410 r1", 283 "asparagus.SET.420 r2", 284 "arugula__.SET.430 r3", 285 }, 286 }, 287 { 288 level: 1, 289 fileNum: 41, 290 data: []string{ 291 "beans____.SET.411 s1", 292 "beans____.SET.421 s2", 293 "bokchoy__.DEL.431 ", 294 "broccoli_.SET.441 s4", 295 }, 296 }, 297 { 298 level: 1, 299 fileNum: 42, 300 data: []string{ 301 "cabbage__.SET.412 t1", 302 "corn_____.DEL.422 ", 303 "spinach__.MERGE.432 t2", 304 }, 305 }, 306 { 307 level: 2, 308 fileNum: 30, 309 data: []string{ 310 "alfalfa__.SET.310 u1", 311 "bokchoy__.SET.320 u2", 312 "celery___.SET.330 u3", 313 "corn_____.SET.340 u4", 314 "spinach__.MERGE.350 u5", 315 }, 316 }, 317 }, 318 queries: []string{ 319 "a________.SEPARATOR.999 ErrNotFound", 320 "alfalfa__.SEPARATOR.520 p1", 321 "alfalfa__.SEPARATOR.510 p1", 322 "alfalfa__.SEPARATOR.500 r1", 323 "alfalfa__.SEPARATOR.400 u1", 324 "alfalfa__.SEPARATOR.300 ErrNotFound", 325 "asparagus.SEPARATOR.520 q3", 326 "asparagus.SEPARATOR.510 p2", 327 "asparagus.SEPARATOR.500 r2", 328 "asparagus.SEPARATOR.400 ErrNotFound", 329 "asparagus.SEPARATOR.300 ErrNotFound", 330 "arugula__.SEPARATOR.520 r3", 331 "arugula__.SEPARATOR.510 r3", 332 "arugula__.SEPARATOR.500 r3", 333 "arugula__.SEPARATOR.400 ErrNotFound", 334 "arugula__.SEPARATOR.300 ErrNotFound", 335 "beans____.SEPARATOR.520 q4", 336 "beans____.SEPARATOR.510 s2", 337 "beans____.SEPARATOR.500 s2", 338 "beans____.SEPARATOR.400 ErrNotFound", 339 "beans____.SEPARATOR.300 ErrNotFound", 340 "bokchoy__.SEPARATOR.520 ErrNotFound", 341 "bokchoy__.SEPARATOR.510 ErrNotFound", 342 "bokchoy__.SEPARATOR.500 ErrNotFound", 343 "bokchoy__.SEPARATOR.400 u2", 344 "bokchoy__.SEPARATOR.300 ErrNotFound", 345 "broccoli_.SEPARATOR.520 q5", 346 "broccoli_.SEPARATOR.510 s4", 347 "broccoli_.SEPARATOR.500 s4", 348 "broccoli_.SEPARATOR.400 ErrNotFound", 349 "broccoli_.SEPARATOR.300 ErrNotFound", 350 "cabbage__.SEPARATOR.520 q6", 351 "cabbage__.SEPARATOR.510 ErrNotFound", 352 "cabbage__.SEPARATOR.500 t1", 353 "cabbage__.SEPARATOR.400 ErrNotFound", 354 "cabbage__.SEPARATOR.300 ErrNotFound", 355 "celery___.SEPARATOR.520 q7", 356 "celery___.SEPARATOR.510 u3", 357 "celery___.SEPARATOR.500 u3", 358 "celery___.SEPARATOR.400 u3", 359 "celery___.SEPARATOR.300 ErrNotFound", 360 "corn_____.SEPARATOR.520 ErrNotFound", 361 "corn_____.SEPARATOR.510 ErrNotFound", 362 "corn_____.SEPARATOR.500 ErrNotFound", 363 "corn_____.SEPARATOR.400 u4", 364 "corn_____.SEPARATOR.300 ErrNotFound", 365 "d________.SEPARATOR.999 ErrNotFound", 366 "spinach__.SEPARATOR.999 u5t2p3q8", 367 "spinach__.SEPARATOR.518 u5t2p3q8", 368 "spinach__.SEPARATOR.517 u5t2p3", 369 "spinach__.SEPARATOR.504 u5t2p3", 370 "spinach__.SEPARATOR.503 u5t2", 371 "spinach__.SEPARATOR.432 u5t2", 372 "spinach__.SEPARATOR.431 u5", 373 "spinach__.SEPARATOR.350 u5", 374 "spinach__.SEPARATOR.349 ErrNotFound", 375 }, 376 }, 377 378 { 379 description: "broken invariants 0: non-increasing level 0 sequence numbers", 380 badOrdering: true, 381 tables: []testTable{ 382 { 383 level: 0, 384 fileNum: 19, 385 data: []string{ 386 "a.SET.101 a", 387 "b.SET.102 b", 388 }, 389 }, 390 { 391 level: 0, 392 fileNum: 20, 393 data: []string{ 394 "c.SET.101 c", 395 }, 396 }, 397 }, 398 }, 399 400 { 401 description: "broken invariants 1: non-increasing level 0 sequence numbers", 402 badOrdering: true, 403 tables: []testTable{ 404 { 405 level: 0, 406 fileNum: 19, 407 data: []string{ 408 "a.SET.101 a", 409 "b.SET.102 b", 410 }, 411 }, 412 { 413 level: 0, 414 fileNum: 20, 415 data: []string{ 416 "c.SET.100 c", 417 "d.SET.101 d", 418 }, 419 }, 420 }, 421 }, 422 423 { 424 description: "broken invariants 2: matching level 0 sequence numbers, considered acceptable", 425 badOrdering: false, 426 tables: []testTable{ 427 { 428 level: 0, 429 fileNum: 19, 430 data: []string{ 431 "a.SET.101 a", 432 }, 433 }, 434 { 435 level: 0, 436 fileNum: 20, 437 data: []string{ 438 "a.SET.101 a", 439 }, 440 }, 441 }, 442 }, 443 444 { 445 description: "broken invariants 3: level non-0 overlapping internal key ranges", 446 badOrdering: true, 447 tables: []testTable{ 448 { 449 level: 5, 450 fileNum: 11, 451 data: []string{ 452 "bat.SET.101 xxx", 453 "dog.SET.102 xxx", 454 }, 455 }, 456 { 457 level: 5, 458 fileNum: 12, 459 data: []string{ 460 "cow.SET.103 xxx", 461 "pig.SET.104 xxx", 462 }, 463 }, 464 }, 465 }, 466 } 467 468 cmp := testkeys.Comparer.Compare 469 for _, tc := range testCases { 470 desc := tc.description[:strings.Index(tc.description, ":")] 471 472 // m is a map from file numbers to DBs. 473 m := map[FileNum]*memTable{} 474 newIter := func( 475 _ context.Context, file *manifest.FileMetadata, _ *IterOptions, _ internalIterOpts, 476 ) (internalIterator, keyspan.FragmentIterator, error) { 477 d, ok := m[file.FileNum] 478 if !ok { 479 return nil, nil, errors.New("no such file") 480 } 481 return d.newIter(nil), nil, nil 482 } 483 484 var files [numLevels][]*fileMetadata 485 for _, tt := range tc.tables { 486 d := newMemTable(memTableOptions{}) 487 m[tt.fileNum] = d 488 489 meta := &fileMetadata{ 490 FileNum: tt.fileNum, 491 } 492 meta.InitPhysicalBacking() 493 for i, datum := range tt.data { 494 s := strings.Split(datum, " ") 495 ikey := base.ParseInternalKey(s[0]) 496 err := d.set(ikey, []byte(s[1])) 497 if err != nil { 498 t.Fatalf("desc=%q: memtable Set: %v", desc, err) 499 } 500 501 meta.ExtendPointKeyBounds(cmp, ikey, ikey) 502 if i == 0 { 503 meta.SmallestSeqNum = ikey.SeqNum() 504 meta.LargestSeqNum = ikey.SeqNum() 505 } else { 506 if meta.SmallestSeqNum > ikey.SeqNum() { 507 meta.SmallestSeqNum = ikey.SeqNum() 508 } 509 if meta.LargestSeqNum < ikey.SeqNum() { 510 meta.LargestSeqNum = ikey.SeqNum() 511 } 512 } 513 } 514 515 files[tt.level] = append(files[tt.level], meta) 516 } 517 v := manifest.NewVersion(cmp, base.DefaultFormatter, 10<<20, files) 518 err := v.CheckOrdering(cmp, base.DefaultFormatter, manifest.AllowSplitUserKeys) 519 if tc.badOrdering && err == nil { 520 t.Errorf("desc=%q: want bad ordering, got nil error", desc) 521 continue 522 } else if !tc.badOrdering && err != nil { 523 t.Errorf("desc=%q: bad ordering: %v", desc, err) 524 continue 525 } 526 527 get := func(v *version, ikey InternalKey) ([]byte, error) { 528 var buf struct { 529 dbi Iterator 530 get getIter 531 } 532 533 get := &buf.get 534 get.comparer = testkeys.Comparer 535 get.newIters = newIter 536 get.key = ikey.UserKey 537 get.l0 = v.L0SublevelFiles 538 get.version = v 539 get.snapshot = ikey.SeqNum() + 1 540 541 i := &buf.dbi 542 i.comparer = *testkeys.Comparer 543 i.merge = DefaultMerger.Merge 544 i.iter = get 545 546 defer i.Close() 547 if !i.First() { 548 err := i.Error() 549 if err != nil { 550 return nil, err 551 } 552 return nil, ErrNotFound 553 } 554 return i.Value(), nil 555 } 556 557 for _, query := range tc.queries { 558 s := strings.Split(query, " ") 559 ikey := base.ParseInternalKey(s[0]) 560 value, err := get(v, ikey) 561 got, want := "", s[1] 562 if err != nil { 563 if err != ErrNotFound { 564 t.Errorf("desc=%q: query=%q: %v", desc, s[0], err) 565 continue 566 } 567 got = "ErrNotFound" 568 } else { 569 got = string(value) 570 } 571 if got != want { 572 t.Errorf("desc=%q: query=%q: got %q, want %q", desc, s[0], got, want) 573 } 574 } 575 } 576 }