github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/leveldb/db_test.go (about) 1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com> 2 // All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 package leveldb 8 9 import ( 10 "bytes" 11 "container/list" 12 crand "crypto/rand" 13 "encoding/binary" 14 "fmt" 15 "math/rand" 16 "os" 17 "path/filepath" 18 "runtime" 19 "strings" 20 "sync" 21 "sync/atomic" 22 "testing" 23 "time" 24 "unsafe" 25 26 "github.com/insionng/yougam/libraries/onsi/gomega" 27 28 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/comparer" 29 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/errors" 30 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/filter" 31 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/iterator" 32 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/opt" 33 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/storage" 34 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/testutil" 35 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/util" 36 ) 37 38 func tkey(i int) []byte { 39 return []byte(fmt.Sprintf("%016d", i)) 40 } 41 42 func tval(seed, n int) []byte { 43 r := rand.New(rand.NewSource(int64(seed))) 44 return randomString(r, n) 45 } 46 47 func testingLogger(t *testing.T) func(log string) { 48 return func(log string) { 49 t.Log(log) 50 } 51 } 52 53 func testingPreserveOnFailed(t *testing.T) func() (preserve bool, err error) { 54 return func() (preserve bool, err error) { 55 preserve = t.Failed() 56 return 57 } 58 } 59 60 type dbHarness struct { 61 t *testing.T 62 63 stor *testutil.Storage 64 db *DB 65 o *opt.Options 66 ro *opt.ReadOptions 67 wo *opt.WriteOptions 68 } 69 70 func newDbHarnessWopt(t *testing.T, o *opt.Options) *dbHarness { 71 h := new(dbHarness) 72 h.init(t, o) 73 return h 74 } 75 76 func newDbHarness(t *testing.T) *dbHarness { 77 return newDbHarnessWopt(t, &opt.Options{DisableLargeBatchTransaction: true}) 78 } 79 80 func (h *dbHarness) init(t *testing.T, o *opt.Options) { 81 gomega.RegisterTestingT(t) 82 h.t = t 83 h.stor = testutil.NewStorage() 84 h.stor.OnLog(testingLogger(t)) 85 h.stor.OnClose(testingPreserveOnFailed(t)) 86 h.o = o 87 h.ro = nil 88 h.wo = nil 89 90 if err := h.openDB0(); err != nil { 91 // So that it will come after fatal message. 92 defer h.stor.Close() 93 h.t.Fatal("Open (init): got error: ", err) 94 } 95 } 96 97 func (h *dbHarness) openDB0() (err error) { 98 h.t.Log("opening DB") 99 h.db, err = Open(h.stor, h.o) 100 return 101 } 102 103 func (h *dbHarness) openDB() { 104 if err := h.openDB0(); err != nil { 105 h.t.Fatal("Open: got error: ", err) 106 } 107 } 108 109 func (h *dbHarness) closeDB0() error { 110 h.t.Log("closing DB") 111 return h.db.Close() 112 } 113 114 func (h *dbHarness) closeDB() { 115 if h.db != nil { 116 if err := h.closeDB0(); err != nil { 117 h.t.Error("Close: got error: ", err) 118 } 119 h.db = nil 120 } 121 h.stor.CloseCheck() 122 runtime.GC() 123 } 124 125 func (h *dbHarness) reopenDB() { 126 if h.db != nil { 127 h.closeDB() 128 } 129 h.openDB() 130 } 131 132 func (h *dbHarness) close() { 133 if h.db != nil { 134 h.closeDB0() 135 h.db = nil 136 } 137 h.stor.Close() 138 h.stor = nil 139 runtime.GC() 140 } 141 142 func (h *dbHarness) openAssert(want bool) { 143 db, err := Open(h.stor, h.o) 144 if err != nil { 145 if want { 146 h.t.Error("Open: assert: got error: ", err) 147 } else { 148 h.t.Log("Open: assert: got error (expected): ", err) 149 } 150 } else { 151 if !want { 152 h.t.Error("Open: assert: expect error") 153 } 154 db.Close() 155 } 156 } 157 158 func (h *dbHarness) write(batch *Batch) { 159 if err := h.db.Write(batch, h.wo); err != nil { 160 h.t.Error("Write: got error: ", err) 161 } 162 } 163 164 func (h *dbHarness) put(key, value string) { 165 if err := h.db.Put([]byte(key), []byte(value), h.wo); err != nil { 166 h.t.Error("Put: got error: ", err) 167 } 168 } 169 170 func (h *dbHarness) putMulti(n int, low, hi string) { 171 for i := 0; i < n; i++ { 172 h.put(low, "begin") 173 h.put(hi, "end") 174 h.compactMem() 175 } 176 } 177 178 func (h *dbHarness) maxNextLevelOverlappingBytes(want int64) { 179 t := h.t 180 db := h.db 181 182 var ( 183 maxOverlaps int64 184 maxLevel int 185 ) 186 v := db.s.version() 187 if len(v.levels) > 2 { 188 for i, tt := range v.levels[1 : len(v.levels)-1] { 189 level := i + 1 190 next := v.levels[level+1] 191 for _, t := range tt { 192 r := next.getOverlaps(nil, db.s.icmp, t.imin.ukey(), t.imax.ukey(), false) 193 sum := r.size() 194 if sum > maxOverlaps { 195 maxOverlaps = sum 196 maxLevel = level 197 } 198 } 199 } 200 } 201 v.release() 202 203 if maxOverlaps > want { 204 t.Errorf("next level most overlapping bytes is more than %d, got=%d level=%d", want, maxOverlaps, maxLevel) 205 } else { 206 t.Logf("next level most overlapping bytes is %d, level=%d want=%d", maxOverlaps, maxLevel, want) 207 } 208 } 209 210 func (h *dbHarness) delete(key string) { 211 t := h.t 212 db := h.db 213 214 err := db.Delete([]byte(key), h.wo) 215 if err != nil { 216 t.Error("Delete: got error: ", err) 217 } 218 } 219 220 func (h *dbHarness) assertNumKeys(want int) { 221 iter := h.db.NewIterator(nil, h.ro) 222 defer iter.Release() 223 got := 0 224 for iter.Next() { 225 got++ 226 } 227 if err := iter.Error(); err != nil { 228 h.t.Error("assertNumKeys: ", err) 229 } 230 if want != got { 231 h.t.Errorf("assertNumKeys: want=%d got=%d", want, got) 232 } 233 } 234 235 func (h *dbHarness) getr(db Reader, key string, expectFound bool) (found bool, v []byte) { 236 t := h.t 237 v, err := db.Get([]byte(key), h.ro) 238 switch err { 239 case ErrNotFound: 240 if expectFound { 241 t.Errorf("Get: key '%s' not found, want found", key) 242 } 243 case nil: 244 found = true 245 if !expectFound { 246 t.Errorf("Get: key '%s' found, want not found", key) 247 } 248 default: 249 t.Error("Get: got error: ", err) 250 } 251 return 252 } 253 254 func (h *dbHarness) get(key string, expectFound bool) (found bool, v []byte) { 255 return h.getr(h.db, key, expectFound) 256 } 257 258 func (h *dbHarness) getValr(db Reader, key, value string) { 259 t := h.t 260 found, r := h.getr(db, key, true) 261 if !found { 262 return 263 } 264 rval := string(r) 265 if rval != value { 266 t.Errorf("Get: invalid value, got '%s', want '%s'", rval, value) 267 } 268 } 269 270 func (h *dbHarness) getVal(key, value string) { 271 h.getValr(h.db, key, value) 272 } 273 274 func (h *dbHarness) allEntriesFor(key, want string) { 275 t := h.t 276 db := h.db 277 s := db.s 278 279 ikey := makeInternalKey(nil, []byte(key), keyMaxSeq, keyTypeVal) 280 iter := db.newRawIterator(nil, nil, nil, nil) 281 if !iter.Seek(ikey) && iter.Error() != nil { 282 t.Error("AllEntries: error during seek, err: ", iter.Error()) 283 return 284 } 285 res := "[ " 286 first := true 287 for iter.Valid() { 288 if ukey, _, kt, kerr := parseInternalKey(iter.Key()); kerr == nil { 289 if s.icmp.uCompare(ikey.ukey(), ukey) != 0 { 290 break 291 } 292 if !first { 293 res += ", " 294 } 295 first = false 296 switch kt { 297 case keyTypeVal: 298 res += string(iter.Value()) 299 case keyTypeDel: 300 res += "DEL" 301 } 302 } else { 303 if !first { 304 res += ", " 305 } 306 first = false 307 res += "CORRUPTED" 308 } 309 iter.Next() 310 } 311 if !first { 312 res += " " 313 } 314 res += "]" 315 if res != want { 316 t.Errorf("AllEntries: assert failed for key %q, got=%q want=%q", key, res, want) 317 } 318 } 319 320 // Return a string that contains all key,value pairs in order, 321 // formatted like "(k1->v1)(k2->v2)". 322 func (h *dbHarness) getKeyVal(want string) { 323 t := h.t 324 db := h.db 325 326 s, err := db.GetSnapshot() 327 if err != nil { 328 t.Fatal("GetSnapshot: got error: ", err) 329 } 330 res := "" 331 iter := s.NewIterator(nil, nil) 332 for iter.Next() { 333 res += fmt.Sprintf("(%s->%s)", string(iter.Key()), string(iter.Value())) 334 } 335 iter.Release() 336 337 if res != want { 338 t.Errorf("GetKeyVal: invalid key/value pair, got=%q want=%q", res, want) 339 } 340 s.Release() 341 } 342 343 func (h *dbHarness) waitCompaction() { 344 t := h.t 345 db := h.db 346 if err := db.compTriggerWait(db.tcompCmdC); err != nil { 347 t.Error("compaction error: ", err) 348 } 349 } 350 351 func (h *dbHarness) waitMemCompaction() { 352 t := h.t 353 db := h.db 354 355 if err := db.compTriggerWait(db.mcompCmdC); err != nil { 356 t.Error("compaction error: ", err) 357 } 358 } 359 360 func (h *dbHarness) compactMem() { 361 t := h.t 362 db := h.db 363 364 t.Log("starting memdb compaction") 365 366 db.writeLockC <- struct{}{} 367 defer func() { 368 <-db.writeLockC 369 }() 370 371 if _, err := db.rotateMem(0, true); err != nil { 372 t.Error("compaction error: ", err) 373 } 374 375 if h.totalTables() == 0 { 376 t.Error("zero tables after mem compaction") 377 } 378 379 t.Log("memdb compaction done") 380 } 381 382 func (h *dbHarness) compactRangeAtErr(level int, min, max string, wanterr bool) { 383 t := h.t 384 db := h.db 385 386 var _min, _max []byte 387 if min != "" { 388 _min = []byte(min) 389 } 390 if max != "" { 391 _max = []byte(max) 392 } 393 394 t.Logf("starting table range compaction: level=%d, min=%q, max=%q", level, min, max) 395 396 if err := db.compTriggerRange(db.tcompCmdC, level, _min, _max); err != nil { 397 if wanterr { 398 t.Log("CompactRangeAt: got error (expected): ", err) 399 } else { 400 t.Error("CompactRangeAt: got error: ", err) 401 } 402 } else if wanterr { 403 t.Error("CompactRangeAt: expect error") 404 } 405 406 t.Log("table range compaction done") 407 } 408 409 func (h *dbHarness) compactRangeAt(level int, min, max string) { 410 h.compactRangeAtErr(level, min, max, false) 411 } 412 413 func (h *dbHarness) compactRange(min, max string) { 414 t := h.t 415 db := h.db 416 417 t.Logf("starting DB range compaction: min=%q, max=%q", min, max) 418 419 var r util.Range 420 if min != "" { 421 r.Start = []byte(min) 422 } 423 if max != "" { 424 r.Limit = []byte(max) 425 } 426 if err := db.CompactRange(r); err != nil { 427 t.Error("CompactRange: got error: ", err) 428 } 429 430 t.Log("DB range compaction done") 431 } 432 433 func (h *dbHarness) sizeOf(start, limit string) int64 { 434 sz, err := h.db.SizeOf([]util.Range{ 435 {[]byte(start), []byte(limit)}, 436 }) 437 if err != nil { 438 h.t.Error("SizeOf: got error: ", err) 439 } 440 return sz.Sum() 441 } 442 443 func (h *dbHarness) sizeAssert(start, limit string, low, hi int64) { 444 sz := h.sizeOf(start, limit) 445 if sz < low || sz > hi { 446 h.t.Errorf("sizeOf %q to %q not in range, want %d - %d, got %d", 447 shorten(start), shorten(limit), low, hi, sz) 448 } 449 } 450 451 func (h *dbHarness) getSnapshot() (s *Snapshot) { 452 s, err := h.db.GetSnapshot() 453 if err != nil { 454 h.t.Fatal("GetSnapshot: got error: ", err) 455 } 456 return 457 } 458 459 func (h *dbHarness) getTablesPerLevel() string { 460 res := "" 461 nz := 0 462 v := h.db.s.version() 463 for level, tables := range v.levels { 464 if level > 0 { 465 res += "," 466 } 467 res += fmt.Sprint(len(tables)) 468 if len(tables) > 0 { 469 nz = len(res) 470 } 471 } 472 v.release() 473 return res[:nz] 474 } 475 476 func (h *dbHarness) tablesPerLevel(want string) { 477 res := h.getTablesPerLevel() 478 if res != want { 479 h.t.Errorf("invalid tables len, want=%s, got=%s", want, res) 480 } 481 } 482 483 func (h *dbHarness) totalTables() (n int) { 484 v := h.db.s.version() 485 for _, tables := range v.levels { 486 n += len(tables) 487 } 488 v.release() 489 return 490 } 491 492 type keyValue interface { 493 Key() []byte 494 Value() []byte 495 } 496 497 func testKeyVal(t *testing.T, kv keyValue, want string) { 498 res := string(kv.Key()) + "->" + string(kv.Value()) 499 if res != want { 500 t.Errorf("invalid key/value, want=%q, got=%q", want, res) 501 } 502 } 503 504 func numKey(num int) string { 505 return fmt.Sprintf("key%06d", num) 506 } 507 508 var testingBloomFilter = filter.NewBloomFilter(10) 509 510 func truno(t *testing.T, o *opt.Options, f func(h *dbHarness)) { 511 for i := 0; i < 4; i++ { 512 func() { 513 switch i { 514 case 0: 515 case 1: 516 if o == nil { 517 o = &opt.Options{ 518 DisableLargeBatchTransaction: true, 519 Filter: testingBloomFilter, 520 } 521 } else { 522 old := o 523 o = &opt.Options{} 524 *o = *old 525 o.Filter = testingBloomFilter 526 } 527 case 2: 528 if o == nil { 529 o = &opt.Options{ 530 DisableLargeBatchTransaction: true, 531 Compression: opt.NoCompression, 532 } 533 } else { 534 old := o 535 o = &opt.Options{} 536 *o = *old 537 o.Compression = opt.NoCompression 538 } 539 } 540 h := newDbHarnessWopt(t, o) 541 defer h.close() 542 switch i { 543 case 3: 544 h.reopenDB() 545 } 546 f(h) 547 }() 548 } 549 } 550 551 func trun(t *testing.T, f func(h *dbHarness)) { 552 truno(t, nil, f) 553 } 554 555 func testAligned(t *testing.T, name string, offset uintptr) { 556 if offset%8 != 0 { 557 t.Errorf("field %s offset is not 64-bit aligned", name) 558 } 559 } 560 561 func Test_FieldsAligned(t *testing.T) { 562 p1 := new(DB) 563 testAligned(t, "DB.seq", unsafe.Offsetof(p1.seq)) 564 p2 := new(session) 565 testAligned(t, "session.stNextFileNum", unsafe.Offsetof(p2.stNextFileNum)) 566 testAligned(t, "session.stJournalNum", unsafe.Offsetof(p2.stJournalNum)) 567 testAligned(t, "session.stPrevJournalNum", unsafe.Offsetof(p2.stPrevJournalNum)) 568 testAligned(t, "session.stSeqNum", unsafe.Offsetof(p2.stSeqNum)) 569 } 570 571 func TestDB_Locking(t *testing.T) { 572 h := newDbHarness(t) 573 defer h.stor.Close() 574 h.openAssert(false) 575 h.closeDB() 576 h.openAssert(true) 577 } 578 579 func TestDB_Empty(t *testing.T) { 580 trun(t, func(h *dbHarness) { 581 h.get("foo", false) 582 583 h.reopenDB() 584 h.get("foo", false) 585 }) 586 } 587 588 func TestDB_ReadWrite(t *testing.T) { 589 trun(t, func(h *dbHarness) { 590 h.put("foo", "v1") 591 h.getVal("foo", "v1") 592 h.put("bar", "v2") 593 h.put("foo", "v3") 594 h.getVal("foo", "v3") 595 h.getVal("bar", "v2") 596 597 h.reopenDB() 598 h.getVal("foo", "v3") 599 h.getVal("bar", "v2") 600 }) 601 } 602 603 func TestDB_PutDeleteGet(t *testing.T) { 604 trun(t, func(h *dbHarness) { 605 h.put("foo", "v1") 606 h.getVal("foo", "v1") 607 h.put("foo", "v2") 608 h.getVal("foo", "v2") 609 h.delete("foo") 610 h.get("foo", false) 611 612 h.reopenDB() 613 h.get("foo", false) 614 }) 615 } 616 617 func TestDB_EmptyBatch(t *testing.T) { 618 h := newDbHarness(t) 619 defer h.close() 620 621 h.get("foo", false) 622 err := h.db.Write(new(Batch), h.wo) 623 if err != nil { 624 t.Error("writing empty batch yield error: ", err) 625 } 626 h.get("foo", false) 627 } 628 629 func TestDB_GetFromFrozen(t *testing.T) { 630 h := newDbHarnessWopt(t, &opt.Options{ 631 DisableLargeBatchTransaction: true, 632 WriteBuffer: 100100, 633 }) 634 defer h.close() 635 636 h.put("foo", "v1") 637 h.getVal("foo", "v1") 638 639 h.stor.Stall(testutil.ModeSync, storage.TypeTable) // Block sync calls 640 h.put("k1", strings.Repeat("x", 100000)) // Fill memtable 641 h.put("k2", strings.Repeat("y", 100000)) // Trigger compaction 642 for i := 0; h.db.getFrozenMem() == nil && i < 100; i++ { 643 time.Sleep(10 * time.Microsecond) 644 } 645 if h.db.getFrozenMem() == nil { 646 h.stor.Release(testutil.ModeSync, storage.TypeTable) 647 t.Fatal("No frozen mem") 648 } 649 h.getVal("foo", "v1") 650 h.stor.Release(testutil.ModeSync, storage.TypeTable) // Release sync calls 651 652 h.reopenDB() 653 h.getVal("foo", "v1") 654 h.get("k1", true) 655 h.get("k2", true) 656 } 657 658 func TestDB_GetFromTable(t *testing.T) { 659 trun(t, func(h *dbHarness) { 660 h.put("foo", "v1") 661 h.compactMem() 662 h.getVal("foo", "v1") 663 }) 664 } 665 666 func TestDB_GetSnapshot(t *testing.T) { 667 trun(t, func(h *dbHarness) { 668 bar := strings.Repeat("b", 200) 669 h.put("foo", "v1") 670 h.put(bar, "v1") 671 672 snap, err := h.db.GetSnapshot() 673 if err != nil { 674 t.Fatal("GetSnapshot: got error: ", err) 675 } 676 677 h.put("foo", "v2") 678 h.put(bar, "v2") 679 680 h.getVal("foo", "v2") 681 h.getVal(bar, "v2") 682 h.getValr(snap, "foo", "v1") 683 h.getValr(snap, bar, "v1") 684 685 h.compactMem() 686 687 h.getVal("foo", "v2") 688 h.getVal(bar, "v2") 689 h.getValr(snap, "foo", "v1") 690 h.getValr(snap, bar, "v1") 691 692 snap.Release() 693 694 h.reopenDB() 695 h.getVal("foo", "v2") 696 h.getVal(bar, "v2") 697 }) 698 } 699 700 func TestDB_GetLevel0Ordering(t *testing.T) { 701 trun(t, func(h *dbHarness) { 702 h.db.memdbMaxLevel = 2 703 704 for i := 0; i < 4; i++ { 705 h.put("bar", fmt.Sprintf("b%d", i)) 706 h.put("foo", fmt.Sprintf("v%d", i)) 707 h.compactMem() 708 } 709 h.getVal("foo", "v3") 710 h.getVal("bar", "b3") 711 712 v := h.db.s.version() 713 t0len := v.tLen(0) 714 v.release() 715 if t0len < 2 { 716 t.Errorf("level-0 tables is less than 2, got %d", t0len) 717 } 718 719 h.reopenDB() 720 h.getVal("foo", "v3") 721 h.getVal("bar", "b3") 722 }) 723 } 724 725 func TestDB_GetOrderedByLevels(t *testing.T) { 726 trun(t, func(h *dbHarness) { 727 h.put("foo", "v1") 728 h.compactMem() 729 h.compactRange("a", "z") 730 h.getVal("foo", "v1") 731 h.put("foo", "v2") 732 h.compactMem() 733 h.getVal("foo", "v2") 734 }) 735 } 736 737 func TestDB_GetPicksCorrectFile(t *testing.T) { 738 trun(t, func(h *dbHarness) { 739 // Arrange to have multiple files in a non-level-0 level. 740 h.put("a", "va") 741 h.compactMem() 742 h.compactRange("a", "b") 743 h.put("x", "vx") 744 h.compactMem() 745 h.compactRange("x", "y") 746 h.put("f", "vf") 747 h.compactMem() 748 h.compactRange("f", "g") 749 750 h.getVal("a", "va") 751 h.getVal("f", "vf") 752 h.getVal("x", "vx") 753 754 h.compactRange("", "") 755 h.getVal("a", "va") 756 h.getVal("f", "vf") 757 h.getVal("x", "vx") 758 }) 759 } 760 761 func TestDB_GetEncountersEmptyLevel(t *testing.T) { 762 trun(t, func(h *dbHarness) { 763 h.db.memdbMaxLevel = 2 764 765 // Arrange for the following to happen: 766 // * sstable A in level 0 767 // * nothing in level 1 768 // * sstable B in level 2 769 // Then do enough Get() calls to arrange for an automatic compaction 770 // of sstable A. A bug would cause the compaction to be marked as 771 // occuring at level 1 (instead of the correct level 0). 772 773 // Step 1: First place sstables in levels 0 and 2 774 for i := 0; ; i++ { 775 if i >= 100 { 776 t.Fatal("could not fill levels-0 and level-2") 777 } 778 v := h.db.s.version() 779 if v.tLen(0) > 0 && v.tLen(2) > 0 { 780 v.release() 781 break 782 } 783 v.release() 784 h.put("a", "begin") 785 h.put("z", "end") 786 h.compactMem() 787 788 h.getVal("a", "begin") 789 h.getVal("z", "end") 790 } 791 792 // Step 2: clear level 1 if necessary. 793 h.compactRangeAt(1, "", "") 794 h.tablesPerLevel("1,0,1") 795 796 h.getVal("a", "begin") 797 h.getVal("z", "end") 798 799 // Step 3: read a bunch of times 800 for i := 0; i < 200; i++ { 801 h.get("missing", false) 802 } 803 804 // Step 4: Wait for compaction to finish 805 h.waitCompaction() 806 807 v := h.db.s.version() 808 if v.tLen(0) > 0 { 809 t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) 810 } 811 v.release() 812 813 h.getVal("a", "begin") 814 h.getVal("z", "end") 815 }) 816 } 817 818 func TestDB_IterMultiWithDelete(t *testing.T) { 819 trun(t, func(h *dbHarness) { 820 h.put("a", "va") 821 h.put("b", "vb") 822 h.put("c", "vc") 823 h.delete("b") 824 h.get("b", false) 825 826 iter := h.db.NewIterator(nil, nil) 827 iter.Seek([]byte("c")) 828 testKeyVal(t, iter, "c->vc") 829 iter.Prev() 830 testKeyVal(t, iter, "a->va") 831 iter.Release() 832 833 h.compactMem() 834 835 iter = h.db.NewIterator(nil, nil) 836 iter.Seek([]byte("c")) 837 testKeyVal(t, iter, "c->vc") 838 iter.Prev() 839 testKeyVal(t, iter, "a->va") 840 iter.Release() 841 }) 842 } 843 844 func TestDB_IteratorPinsRef(t *testing.T) { 845 h := newDbHarness(t) 846 defer h.close() 847 848 h.put("foo", "hello") 849 850 // Get iterator that will yield the current contents of the DB. 851 iter := h.db.NewIterator(nil, nil) 852 853 // Write to force compactions 854 h.put("foo", "newvalue1") 855 for i := 0; i < 100; i++ { 856 h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) 857 } 858 h.put("foo", "newvalue2") 859 860 iter.First() 861 testKeyVal(t, iter, "foo->hello") 862 if iter.Next() { 863 t.Errorf("expect eof") 864 } 865 iter.Release() 866 } 867 868 func TestDB_Recover(t *testing.T) { 869 trun(t, func(h *dbHarness) { 870 h.put("foo", "v1") 871 h.put("baz", "v5") 872 873 h.reopenDB() 874 h.getVal("foo", "v1") 875 876 h.getVal("foo", "v1") 877 h.getVal("baz", "v5") 878 h.put("bar", "v2") 879 h.put("foo", "v3") 880 881 h.reopenDB() 882 h.getVal("foo", "v3") 883 h.put("foo", "v4") 884 h.getVal("foo", "v4") 885 h.getVal("bar", "v2") 886 h.getVal("baz", "v5") 887 }) 888 } 889 890 func TestDB_RecoverWithEmptyJournal(t *testing.T) { 891 trun(t, func(h *dbHarness) { 892 h.put("foo", "v1") 893 h.put("foo", "v2") 894 895 h.reopenDB() 896 h.reopenDB() 897 h.put("foo", "v3") 898 899 h.reopenDB() 900 h.getVal("foo", "v3") 901 }) 902 } 903 904 func TestDB_RecoverDuringMemtableCompaction(t *testing.T) { 905 truno(t, &opt.Options{DisableLargeBatchTransaction: true, WriteBuffer: 1000000}, func(h *dbHarness) { 906 907 h.stor.Stall(testutil.ModeSync, storage.TypeTable) 908 h.put("big1", strings.Repeat("x", 10000000)) 909 h.put("big2", strings.Repeat("y", 1000)) 910 h.put("bar", "v2") 911 h.stor.Release(testutil.ModeSync, storage.TypeTable) 912 913 h.reopenDB() 914 h.getVal("bar", "v2") 915 h.getVal("big1", strings.Repeat("x", 10000000)) 916 h.getVal("big2", strings.Repeat("y", 1000)) 917 }) 918 } 919 920 func TestDB_MinorCompactionsHappen(t *testing.T) { 921 h := newDbHarnessWopt(t, &opt.Options{DisableLargeBatchTransaction: true, WriteBuffer: 10000}) 922 defer h.close() 923 924 n := 500 925 926 key := func(i int) string { 927 return fmt.Sprintf("key%06d", i) 928 } 929 930 for i := 0; i < n; i++ { 931 h.put(key(i), key(i)+strings.Repeat("v", 1000)) 932 } 933 934 for i := 0; i < n; i++ { 935 h.getVal(key(i), key(i)+strings.Repeat("v", 1000)) 936 } 937 938 h.reopenDB() 939 for i := 0; i < n; i++ { 940 h.getVal(key(i), key(i)+strings.Repeat("v", 1000)) 941 } 942 } 943 944 func TestDB_RecoverWithLargeJournal(t *testing.T) { 945 h := newDbHarness(t) 946 defer h.close() 947 948 h.put("big1", strings.Repeat("1", 200000)) 949 h.put("big2", strings.Repeat("2", 200000)) 950 h.put("small3", strings.Repeat("3", 10)) 951 h.put("small4", strings.Repeat("4", 10)) 952 h.tablesPerLevel("") 953 954 // Make sure that if we re-open with a small write buffer size that 955 // we flush table files in the middle of a large journal file. 956 h.o.WriteBuffer = 100000 957 h.reopenDB() 958 h.getVal("big1", strings.Repeat("1", 200000)) 959 h.getVal("big2", strings.Repeat("2", 200000)) 960 h.getVal("small3", strings.Repeat("3", 10)) 961 h.getVal("small4", strings.Repeat("4", 10)) 962 v := h.db.s.version() 963 if v.tLen(0) <= 1 { 964 t.Errorf("tables-0 less than one") 965 } 966 v.release() 967 } 968 969 func TestDB_CompactionsGenerateMultipleFiles(t *testing.T) { 970 h := newDbHarnessWopt(t, &opt.Options{ 971 DisableLargeBatchTransaction: true, 972 WriteBuffer: 10000000, 973 Compression: opt.NoCompression, 974 }) 975 defer h.close() 976 977 v := h.db.s.version() 978 if v.tLen(0) > 0 { 979 t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) 980 } 981 v.release() 982 983 n := 80 984 985 // Write 8MB (80 values, each 100K) 986 for i := 0; i < n; i++ { 987 h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) 988 } 989 990 // Reopening moves updates to level-0 991 h.reopenDB() 992 h.compactRangeAt(0, "", "") 993 994 v = h.db.s.version() 995 if v.tLen(0) > 0 { 996 t.Errorf("level-0 tables more than 0, got %d", v.tLen(0)) 997 } 998 if v.tLen(1) <= 1 { 999 t.Errorf("level-1 tables less than 1, got %d", v.tLen(1)) 1000 } 1001 v.release() 1002 1003 for i := 0; i < n; i++ { 1004 h.getVal(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), 100000/10)) 1005 } 1006 } 1007 1008 func TestDB_RepeatedWritesToSameKey(t *testing.T) { 1009 h := newDbHarnessWopt(t, &opt.Options{DisableLargeBatchTransaction: true, WriteBuffer: 100000}) 1010 defer h.close() 1011 1012 maxTables := h.o.GetWriteL0PauseTrigger() + 7 1013 1014 value := strings.Repeat("v", 2*h.o.GetWriteBuffer()) 1015 for i := 0; i < 5*maxTables; i++ { 1016 h.put("key", value) 1017 n := h.totalTables() 1018 if n > maxTables { 1019 t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i) 1020 } 1021 } 1022 } 1023 1024 func TestDB_RepeatedWritesToSameKeyAfterReopen(t *testing.T) { 1025 h := newDbHarnessWopt(t, &opt.Options{ 1026 DisableLargeBatchTransaction: true, 1027 WriteBuffer: 100000, 1028 }) 1029 defer h.close() 1030 1031 h.reopenDB() 1032 1033 maxTables := h.o.GetWriteL0PauseTrigger() + 7 1034 1035 value := strings.Repeat("v", 2*h.o.GetWriteBuffer()) 1036 for i := 0; i < 5*maxTables; i++ { 1037 h.put("key", value) 1038 n := h.totalTables() 1039 if n > maxTables { 1040 t.Errorf("total tables exceed %d, got=%d, iter=%d", maxTables, n, i) 1041 } 1042 } 1043 } 1044 1045 func TestDB_SparseMerge(t *testing.T) { 1046 h := newDbHarnessWopt(t, &opt.Options{DisableLargeBatchTransaction: true, Compression: opt.NoCompression}) 1047 defer h.close() 1048 1049 h.putMulti(7, "A", "Z") 1050 1051 // Suppose there is: 1052 // small amount of data with prefix A 1053 // large amount of data with prefix B 1054 // small amount of data with prefix C 1055 // and that recent updates have made small changes to all three prefixes. 1056 // Check that we do not do a compaction that merges all of B in one shot. 1057 h.put("A", "va") 1058 value := strings.Repeat("x", 1000) 1059 for i := 0; i < 100000; i++ { 1060 h.put(fmt.Sprintf("B%010d", i), value) 1061 } 1062 h.put("C", "vc") 1063 h.compactMem() 1064 h.compactRangeAt(0, "", "") 1065 h.waitCompaction() 1066 1067 // Make sparse update 1068 h.put("A", "va2") 1069 h.put("B100", "bvalue2") 1070 h.put("C", "vc2") 1071 h.compactMem() 1072 1073 h.waitCompaction() 1074 h.maxNextLevelOverlappingBytes(20 * 1048576) 1075 h.compactRangeAt(0, "", "") 1076 h.waitCompaction() 1077 h.maxNextLevelOverlappingBytes(20 * 1048576) 1078 h.compactRangeAt(1, "", "") 1079 h.waitCompaction() 1080 h.maxNextLevelOverlappingBytes(20 * 1048576) 1081 } 1082 1083 func TestDB_SizeOf(t *testing.T) { 1084 h := newDbHarnessWopt(t, &opt.Options{ 1085 DisableLargeBatchTransaction: true, 1086 Compression: opt.NoCompression, 1087 WriteBuffer: 10000000, 1088 }) 1089 defer h.close() 1090 1091 h.sizeAssert("", "xyz", 0, 0) 1092 h.reopenDB() 1093 h.sizeAssert("", "xyz", 0, 0) 1094 1095 // Write 8MB (80 values, each 100K) 1096 n := 80 1097 s1 := 100000 1098 s2 := 105000 1099 1100 for i := 0; i < n; i++ { 1101 h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), s1/10)) 1102 } 1103 1104 // 0 because SizeOf() does not account for memtable space 1105 h.sizeAssert("", numKey(50), 0, 0) 1106 1107 for r := 0; r < 3; r++ { 1108 h.reopenDB() 1109 1110 for cs := 0; cs < n; cs += 10 { 1111 for i := 0; i < n; i += 10 { 1112 h.sizeAssert("", numKey(i), int64(s1*i), int64(s2*i)) 1113 h.sizeAssert("", numKey(i)+".suffix", int64(s1*(i+1)), int64(s2*(i+1))) 1114 h.sizeAssert(numKey(i), numKey(i+10), int64(s1*10), int64(s2*10)) 1115 } 1116 1117 h.sizeAssert("", numKey(50), int64(s1*50), int64(s2*50)) 1118 h.sizeAssert("", numKey(50)+".suffix", int64(s1*50), int64(s2*50)) 1119 1120 h.compactRangeAt(0, numKey(cs), numKey(cs+9)) 1121 } 1122 1123 v := h.db.s.version() 1124 if v.tLen(0) != 0 { 1125 t.Errorf("level-0 tables was not zero, got %d", v.tLen(0)) 1126 } 1127 if v.tLen(1) == 0 { 1128 t.Error("level-1 tables was zero") 1129 } 1130 v.release() 1131 } 1132 } 1133 1134 func TestDB_SizeOf_MixOfSmallAndLarge(t *testing.T) { 1135 h := newDbHarnessWopt(t, &opt.Options{ 1136 DisableLargeBatchTransaction: true, 1137 Compression: opt.NoCompression, 1138 }) 1139 defer h.close() 1140 1141 sizes := []int64{ 1142 10000, 1143 10000, 1144 100000, 1145 10000, 1146 100000, 1147 10000, 1148 300000, 1149 10000, 1150 } 1151 1152 for i, n := range sizes { 1153 h.put(numKey(i), strings.Repeat(fmt.Sprintf("v%09d", i), int(n)/10)) 1154 } 1155 1156 for r := 0; r < 3; r++ { 1157 h.reopenDB() 1158 1159 var x int64 1160 for i, n := range sizes { 1161 y := x 1162 if i > 0 { 1163 y += 1000 1164 } 1165 h.sizeAssert("", numKey(i), x, y) 1166 x += n 1167 } 1168 1169 h.sizeAssert(numKey(3), numKey(5), 110000, 111000) 1170 1171 h.compactRangeAt(0, "", "") 1172 } 1173 } 1174 1175 func TestDB_Snapshot(t *testing.T) { 1176 trun(t, func(h *dbHarness) { 1177 h.put("foo", "v1") 1178 s1 := h.getSnapshot() 1179 h.put("foo", "v2") 1180 s2 := h.getSnapshot() 1181 h.put("foo", "v3") 1182 s3 := h.getSnapshot() 1183 h.put("foo", "v4") 1184 1185 h.getValr(s1, "foo", "v1") 1186 h.getValr(s2, "foo", "v2") 1187 h.getValr(s3, "foo", "v3") 1188 h.getVal("foo", "v4") 1189 1190 s3.Release() 1191 h.getValr(s1, "foo", "v1") 1192 h.getValr(s2, "foo", "v2") 1193 h.getVal("foo", "v4") 1194 1195 s1.Release() 1196 h.getValr(s2, "foo", "v2") 1197 h.getVal("foo", "v4") 1198 1199 s2.Release() 1200 h.getVal("foo", "v4") 1201 }) 1202 } 1203 1204 func TestDB_SnapshotList(t *testing.T) { 1205 db := &DB{snapsList: list.New()} 1206 e0a := db.acquireSnapshot() 1207 e0b := db.acquireSnapshot() 1208 db.seq = 1 1209 e1 := db.acquireSnapshot() 1210 db.seq = 2 1211 e2 := db.acquireSnapshot() 1212 1213 if db.minSeq() != 0 { 1214 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1215 } 1216 db.releaseSnapshot(e0a) 1217 if db.minSeq() != 0 { 1218 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1219 } 1220 db.releaseSnapshot(e2) 1221 if db.minSeq() != 0 { 1222 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1223 } 1224 db.releaseSnapshot(e0b) 1225 if db.minSeq() != 1 { 1226 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1227 } 1228 e2 = db.acquireSnapshot() 1229 if db.minSeq() != 1 { 1230 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1231 } 1232 db.releaseSnapshot(e1) 1233 if db.minSeq() != 2 { 1234 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1235 } 1236 db.releaseSnapshot(e2) 1237 if db.minSeq() != 2 { 1238 t.Fatalf("invalid sequence number, got=%d", db.minSeq()) 1239 } 1240 } 1241 1242 func TestDB_HiddenValuesAreRemoved(t *testing.T) { 1243 trun(t, func(h *dbHarness) { 1244 s := h.db.s 1245 1246 m := 2 1247 h.db.memdbMaxLevel = m 1248 1249 h.put("foo", "v1") 1250 h.compactMem() 1251 v := s.version() 1252 num := v.tLen(m) 1253 v.release() 1254 if num != 1 { 1255 t.Errorf("invalid level-%d len, want=1 got=%d", m, num) 1256 } 1257 1258 // Place a table at level last-1 to prevent merging with preceding mutation 1259 h.put("a", "begin") 1260 h.put("z", "end") 1261 h.compactMem() 1262 v = s.version() 1263 if v.tLen(m) != 1 { 1264 t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m)) 1265 } 1266 if v.tLen(m-1) != 1 { 1267 t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1)) 1268 } 1269 v.release() 1270 1271 h.delete("foo") 1272 h.put("foo", "v2") 1273 h.allEntriesFor("foo", "[ v2, DEL, v1 ]") 1274 h.compactMem() 1275 h.allEntriesFor("foo", "[ v2, DEL, v1 ]") 1276 h.compactRangeAt(m-2, "", "z") 1277 // DEL eliminated, but v1 remains because we aren't compacting that level 1278 // (DEL can be eliminated because v2 hides v1). 1279 h.allEntriesFor("foo", "[ v2, v1 ]") 1280 h.compactRangeAt(m-1, "", "") 1281 // Merging last-1 w/ last, so we are the base level for "foo", so 1282 // DEL is removed. (as is v1). 1283 h.allEntriesFor("foo", "[ v2 ]") 1284 }) 1285 } 1286 1287 func TestDB_DeletionMarkers2(t *testing.T) { 1288 h := newDbHarness(t) 1289 defer h.close() 1290 s := h.db.s 1291 1292 m := 2 1293 h.db.memdbMaxLevel = m 1294 1295 h.put("foo", "v1") 1296 h.compactMem() 1297 v := s.version() 1298 num := v.tLen(m) 1299 v.release() 1300 if num != 1 { 1301 t.Errorf("invalid level-%d len, want=1 got=%d", m, num) 1302 } 1303 1304 // Place a table at level last-1 to prevent merging with preceding mutation 1305 h.put("a", "begin") 1306 h.put("z", "end") 1307 h.compactMem() 1308 v = s.version() 1309 if v.tLen(m) != 1 { 1310 t.Errorf("invalid level-%d len, want=1 got=%d", m, v.tLen(m)) 1311 } 1312 if v.tLen(m-1) != 1 { 1313 t.Errorf("invalid level-%d len, want=1 got=%d", m-1, v.tLen(m-1)) 1314 } 1315 v.release() 1316 1317 h.delete("foo") 1318 h.allEntriesFor("foo", "[ DEL, v1 ]") 1319 h.compactMem() // Moves to level last-2 1320 h.allEntriesFor("foo", "[ DEL, v1 ]") 1321 h.compactRangeAt(m-2, "", "") 1322 // DEL kept: "last" file overlaps 1323 h.allEntriesFor("foo", "[ DEL, v1 ]") 1324 h.compactRangeAt(m-1, "", "") 1325 // Merging last-1 w/ last, so we are the base level for "foo", so 1326 // DEL is removed. (as is v1). 1327 h.allEntriesFor("foo", "[ ]") 1328 } 1329 1330 func TestDB_CompactionTableOpenError(t *testing.T) { 1331 h := newDbHarnessWopt(t, &opt.Options{ 1332 DisableLargeBatchTransaction: true, 1333 OpenFilesCacheCapacity: -1, 1334 }) 1335 defer h.close() 1336 1337 h.db.memdbMaxLevel = 2 1338 1339 im := 10 1340 jm := 10 1341 for r := 0; r < 2; r++ { 1342 for i := 0; i < im; i++ { 1343 for j := 0; j < jm; j++ { 1344 h.put(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j)) 1345 } 1346 h.compactMem() 1347 } 1348 } 1349 1350 if n := h.totalTables(); n != im*2 { 1351 t.Errorf("total tables is %d, want %d", n, im*2) 1352 } 1353 1354 h.stor.EmulateError(testutil.ModeOpen, storage.TypeTable, errors.New("open error during table compaction")) 1355 go h.db.CompactRange(util.Range{}) 1356 if err := h.db.compTriggerWait(h.db.tcompCmdC); err != nil { 1357 t.Log("compaction error: ", err) 1358 } 1359 h.closeDB0() 1360 h.openDB() 1361 h.stor.EmulateError(testutil.ModeOpen, storage.TypeTable, nil) 1362 1363 for i := 0; i < im; i++ { 1364 for j := 0; j < jm; j++ { 1365 h.getVal(fmt.Sprintf("k%d,%d", i, j), fmt.Sprintf("v%d,%d", i, j)) 1366 } 1367 } 1368 } 1369 1370 func TestDB_OverlapInLevel0(t *testing.T) { 1371 trun(t, func(h *dbHarness) { 1372 h.db.memdbMaxLevel = 2 1373 1374 // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. 1375 h.put("100", "v100") 1376 h.put("999", "v999") 1377 h.compactMem() 1378 h.delete("100") 1379 h.delete("999") 1380 h.compactMem() 1381 h.tablesPerLevel("0,1,1") 1382 1383 // Make files spanning the following ranges in level-0: 1384 // files[0] 200 .. 900 1385 // files[1] 300 .. 500 1386 // Note that files are sorted by min key. 1387 h.put("300", "v300") 1388 h.put("500", "v500") 1389 h.compactMem() 1390 h.put("200", "v200") 1391 h.put("600", "v600") 1392 h.put("900", "v900") 1393 h.compactMem() 1394 h.tablesPerLevel("2,1,1") 1395 1396 // Compact away the placeholder files we created initially 1397 h.compactRangeAt(1, "", "") 1398 h.compactRangeAt(2, "", "") 1399 h.tablesPerLevel("2") 1400 1401 // Do a memtable compaction. Before bug-fix, the compaction would 1402 // not detect the overlap with level-0 files and would incorrectly place 1403 // the deletion in a deeper level. 1404 h.delete("600") 1405 h.compactMem() 1406 h.tablesPerLevel("3") 1407 h.get("600", false) 1408 }) 1409 } 1410 1411 func TestDB_L0_CompactionBug_Issue44_a(t *testing.T) { 1412 h := newDbHarness(t) 1413 defer h.close() 1414 1415 h.reopenDB() 1416 h.put("b", "v") 1417 h.reopenDB() 1418 h.delete("b") 1419 h.delete("a") 1420 h.reopenDB() 1421 h.delete("a") 1422 h.reopenDB() 1423 h.put("a", "v") 1424 h.reopenDB() 1425 h.reopenDB() 1426 h.getKeyVal("(a->v)") 1427 h.waitCompaction() 1428 h.getKeyVal("(a->v)") 1429 } 1430 1431 func TestDB_L0_CompactionBug_Issue44_b(t *testing.T) { 1432 h := newDbHarness(t) 1433 defer h.close() 1434 1435 h.reopenDB() 1436 h.put("", "") 1437 h.reopenDB() 1438 h.delete("e") 1439 h.put("", "") 1440 h.reopenDB() 1441 h.put("c", "cv") 1442 h.reopenDB() 1443 h.put("", "") 1444 h.reopenDB() 1445 h.put("", "") 1446 h.waitCompaction() 1447 h.reopenDB() 1448 h.put("d", "dv") 1449 h.reopenDB() 1450 h.put("", "") 1451 h.reopenDB() 1452 h.delete("d") 1453 h.delete("b") 1454 h.reopenDB() 1455 h.getKeyVal("(->)(c->cv)") 1456 h.waitCompaction() 1457 h.getKeyVal("(->)(c->cv)") 1458 } 1459 1460 func TestDB_SingleEntryMemCompaction(t *testing.T) { 1461 trun(t, func(h *dbHarness) { 1462 for i := 0; i < 10; i++ { 1463 h.put("big", strings.Repeat("v", opt.DefaultWriteBuffer)) 1464 h.compactMem() 1465 h.put("key", strings.Repeat("v", opt.DefaultBlockSize)) 1466 h.compactMem() 1467 h.put("k", "v") 1468 h.compactMem() 1469 h.put("", "") 1470 h.compactMem() 1471 h.put("verybig", strings.Repeat("v", opt.DefaultWriteBuffer*2)) 1472 h.compactMem() 1473 } 1474 }) 1475 } 1476 1477 func TestDB_ManifestWriteError(t *testing.T) { 1478 for i := 0; i < 2; i++ { 1479 func() { 1480 h := newDbHarness(t) 1481 defer h.close() 1482 1483 h.put("foo", "bar") 1484 h.getVal("foo", "bar") 1485 1486 // Mem compaction (will succeed) 1487 h.compactMem() 1488 h.getVal("foo", "bar") 1489 v := h.db.s.version() 1490 if n := v.tLen(0); n != 1 { 1491 t.Errorf("invalid total tables, want=1 got=%d", n) 1492 } 1493 v.release() 1494 1495 if i == 0 { 1496 h.stor.EmulateError(testutil.ModeWrite, storage.TypeManifest, errors.New("manifest write error")) 1497 } else { 1498 h.stor.EmulateError(testutil.ModeSync, storage.TypeManifest, errors.New("manifest sync error")) 1499 } 1500 1501 // Merging compaction (will fail) 1502 h.compactRangeAtErr(0, "", "", true) 1503 1504 h.db.Close() 1505 h.stor.EmulateError(testutil.ModeWrite, storage.TypeManifest, nil) 1506 h.stor.EmulateError(testutil.ModeSync, storage.TypeManifest, nil) 1507 1508 // Should not lose data 1509 h.openDB() 1510 h.getVal("foo", "bar") 1511 }() 1512 } 1513 } 1514 1515 func assertErr(t *testing.T, err error, wanterr bool) { 1516 if err != nil { 1517 if wanterr { 1518 t.Log("AssertErr: got error (expected): ", err) 1519 } else { 1520 t.Error("AssertErr: got error: ", err) 1521 } 1522 } else if wanterr { 1523 t.Error("AssertErr: expect error") 1524 } 1525 } 1526 1527 func TestDB_ClosedIsClosed(t *testing.T) { 1528 h := newDbHarness(t) 1529 db := h.db 1530 1531 var iter, iter2 iterator.Iterator 1532 var snap *Snapshot 1533 func() { 1534 defer h.close() 1535 1536 h.put("k", "v") 1537 h.getVal("k", "v") 1538 1539 iter = db.NewIterator(nil, h.ro) 1540 iter.Seek([]byte("k")) 1541 testKeyVal(t, iter, "k->v") 1542 1543 var err error 1544 snap, err = db.GetSnapshot() 1545 if err != nil { 1546 t.Fatal("GetSnapshot: got error: ", err) 1547 } 1548 1549 h.getValr(snap, "k", "v") 1550 1551 iter2 = snap.NewIterator(nil, h.ro) 1552 iter2.Seek([]byte("k")) 1553 testKeyVal(t, iter2, "k->v") 1554 1555 h.put("foo", "v2") 1556 h.delete("foo") 1557 1558 // closing DB 1559 iter.Release() 1560 iter2.Release() 1561 }() 1562 1563 assertErr(t, db.Put([]byte("x"), []byte("y"), h.wo), true) 1564 _, err := db.Get([]byte("k"), h.ro) 1565 assertErr(t, err, true) 1566 1567 if iter.Valid() { 1568 t.Errorf("iter.Valid should false") 1569 } 1570 assertErr(t, iter.Error(), false) 1571 testKeyVal(t, iter, "->") 1572 if iter.Seek([]byte("k")) { 1573 t.Errorf("iter.Seek should false") 1574 } 1575 assertErr(t, iter.Error(), true) 1576 1577 assertErr(t, iter2.Error(), false) 1578 1579 _, err = snap.Get([]byte("k"), h.ro) 1580 assertErr(t, err, true) 1581 1582 _, err = db.GetSnapshot() 1583 assertErr(t, err, true) 1584 1585 iter3 := db.NewIterator(nil, h.ro) 1586 assertErr(t, iter3.Error(), true) 1587 1588 iter3 = snap.NewIterator(nil, h.ro) 1589 assertErr(t, iter3.Error(), true) 1590 1591 assertErr(t, db.Delete([]byte("k"), h.wo), true) 1592 1593 _, err = db.GetProperty("leveldb.stats") 1594 assertErr(t, err, true) 1595 1596 _, err = db.SizeOf([]util.Range{{[]byte("a"), []byte("z")}}) 1597 assertErr(t, err, true) 1598 1599 assertErr(t, db.CompactRange(util.Range{}), true) 1600 1601 assertErr(t, db.Close(), true) 1602 } 1603 1604 type numberComparer struct{} 1605 1606 func (numberComparer) num(x []byte) (n int) { 1607 fmt.Sscan(string(x[1:len(x)-1]), &n) 1608 return 1609 } 1610 1611 func (numberComparer) Name() string { 1612 return "test.NumberComparer" 1613 } 1614 1615 func (p numberComparer) Compare(a, b []byte) int { 1616 return p.num(a) - p.num(b) 1617 } 1618 1619 func (numberComparer) Separator(dst, a, b []byte) []byte { return nil } 1620 func (numberComparer) Successor(dst, b []byte) []byte { return nil } 1621 1622 func TestDB_CustomComparer(t *testing.T) { 1623 h := newDbHarnessWopt(t, &opt.Options{ 1624 DisableLargeBatchTransaction: true, 1625 Comparer: numberComparer{}, 1626 WriteBuffer: 1000, 1627 }) 1628 defer h.close() 1629 1630 h.put("[10]", "ten") 1631 h.put("[0x14]", "twenty") 1632 for i := 0; i < 2; i++ { 1633 h.getVal("[10]", "ten") 1634 h.getVal("[0xa]", "ten") 1635 h.getVal("[20]", "twenty") 1636 h.getVal("[0x14]", "twenty") 1637 h.get("[15]", false) 1638 h.get("[0xf]", false) 1639 h.compactMem() 1640 h.compactRange("[0]", "[9999]") 1641 } 1642 1643 for n := 0; n < 2; n++ { 1644 for i := 0; i < 100; i++ { 1645 v := fmt.Sprintf("[%d]", i*10) 1646 h.put(v, v) 1647 } 1648 h.compactMem() 1649 h.compactRange("[0]", "[1000000]") 1650 } 1651 } 1652 1653 func TestDB_ManualCompaction(t *testing.T) { 1654 h := newDbHarness(t) 1655 defer h.close() 1656 1657 h.db.memdbMaxLevel = 2 1658 1659 h.putMulti(3, "p", "q") 1660 h.tablesPerLevel("1,1,1") 1661 1662 // Compaction range falls before files 1663 h.compactRange("", "c") 1664 h.tablesPerLevel("1,1,1") 1665 1666 // Compaction range falls after files 1667 h.compactRange("r", "z") 1668 h.tablesPerLevel("1,1,1") 1669 1670 // Compaction range overlaps files 1671 h.compactRange("p1", "p9") 1672 h.tablesPerLevel("0,0,1") 1673 1674 // Populate a different range 1675 h.putMulti(3, "c", "e") 1676 h.tablesPerLevel("1,1,2") 1677 1678 // Compact just the new range 1679 h.compactRange("b", "f") 1680 h.tablesPerLevel("0,0,2") 1681 1682 // Compact all 1683 h.putMulti(1, "a", "z") 1684 h.tablesPerLevel("0,1,2") 1685 h.compactRange("", "") 1686 h.tablesPerLevel("0,0,1") 1687 } 1688 1689 func TestDB_BloomFilter(t *testing.T) { 1690 h := newDbHarnessWopt(t, &opt.Options{ 1691 DisableLargeBatchTransaction: true, 1692 DisableBlockCache: true, 1693 Filter: filter.NewBloomFilter(10), 1694 }) 1695 defer h.close() 1696 1697 key := func(i int) string { 1698 return fmt.Sprintf("key%06d", i) 1699 } 1700 1701 const n = 10000 1702 1703 // Populate multiple layers 1704 for i := 0; i < n; i++ { 1705 h.put(key(i), key(i)) 1706 } 1707 h.compactMem() 1708 h.compactRange("a", "z") 1709 for i := 0; i < n; i += 100 { 1710 h.put(key(i), key(i)) 1711 } 1712 h.compactMem() 1713 1714 // Prevent auto compactions triggered by seeks 1715 h.stor.Stall(testutil.ModeSync, storage.TypeTable) 1716 1717 // Lookup present keys. Should rarely read from small sstable. 1718 h.stor.ResetCounter(testutil.ModeRead, storage.TypeTable) 1719 for i := 0; i < n; i++ { 1720 h.getVal(key(i), key(i)) 1721 } 1722 cnt, _ := h.stor.Counter(testutil.ModeRead, storage.TypeTable) 1723 t.Logf("lookup of %d present keys yield %d sstable I/O reads", n, cnt) 1724 if min, max := n, n+2*n/100; cnt < min || cnt > max { 1725 t.Errorf("num of sstable I/O reads of present keys not in range of %d - %d, got %d", min, max, cnt) 1726 } 1727 1728 // Lookup missing keys. Should rarely read from either sstable. 1729 h.stor.ResetCounter(testutil.ModeRead, storage.TypeTable) 1730 for i := 0; i < n; i++ { 1731 h.get(key(i)+".missing", false) 1732 } 1733 cnt, _ = h.stor.Counter(testutil.ModeRead, storage.TypeTable) 1734 t.Logf("lookup of %d missing keys yield %d sstable I/O reads", n, cnt) 1735 if max := 3 * n / 100; cnt > max { 1736 t.Errorf("num of sstable I/O reads of missing keys was more than %d, got %d", max, cnt) 1737 } 1738 1739 h.stor.Release(testutil.ModeSync, storage.TypeTable) 1740 } 1741 1742 func TestDB_Concurrent(t *testing.T) { 1743 const n, secs, maxkey = 4, 6, 1000 1744 h := newDbHarness(t) 1745 defer h.close() 1746 1747 runtime.GOMAXPROCS(runtime.NumCPU()) 1748 1749 var ( 1750 closeWg sync.WaitGroup 1751 stop uint32 1752 cnt [n]uint32 1753 ) 1754 1755 for i := 0; i < n; i++ { 1756 closeWg.Add(1) 1757 go func(i int) { 1758 var put, get, found uint 1759 defer func() { 1760 t.Logf("goroutine %d stopped after %d ops, put=%d get=%d found=%d missing=%d", 1761 i, cnt[i], put, get, found, get-found) 1762 closeWg.Done() 1763 }() 1764 1765 rnd := rand.New(rand.NewSource(int64(1000 + i))) 1766 for atomic.LoadUint32(&stop) == 0 { 1767 x := cnt[i] 1768 1769 k := rnd.Intn(maxkey) 1770 kstr := fmt.Sprintf("%016d", k) 1771 1772 if (rnd.Int() % 2) > 0 { 1773 put++ 1774 h.put(kstr, fmt.Sprintf("%d.%d.%-1000d", k, i, x)) 1775 } else { 1776 get++ 1777 v, err := h.db.Get([]byte(kstr), h.ro) 1778 if err == nil { 1779 found++ 1780 rk, ri, rx := 0, -1, uint32(0) 1781 fmt.Sscanf(string(v), "%d.%d.%d", &rk, &ri, &rx) 1782 if rk != k { 1783 t.Errorf("invalid key want=%d got=%d", k, rk) 1784 } 1785 if ri < 0 || ri >= n { 1786 t.Error("invalid goroutine number: ", ri) 1787 } else { 1788 tx := atomic.LoadUint32(&(cnt[ri])) 1789 if rx > tx { 1790 t.Errorf("invalid seq number, %d > %d ", rx, tx) 1791 } 1792 } 1793 } else if err != ErrNotFound { 1794 t.Error("Get: got error: ", err) 1795 return 1796 } 1797 } 1798 atomic.AddUint32(&cnt[i], 1) 1799 } 1800 }(i) 1801 } 1802 1803 time.Sleep(secs * time.Second) 1804 atomic.StoreUint32(&stop, 1) 1805 closeWg.Wait() 1806 } 1807 1808 func TestDB_ConcurrentIterator(t *testing.T) { 1809 const n, n2 = 4, 1000 1810 h := newDbHarnessWopt(t, &opt.Options{DisableLargeBatchTransaction: true, WriteBuffer: 30}) 1811 defer h.close() 1812 1813 runtime.GOMAXPROCS(runtime.NumCPU()) 1814 1815 var ( 1816 closeWg sync.WaitGroup 1817 stop uint32 1818 ) 1819 1820 for i := 0; i < n; i++ { 1821 closeWg.Add(1) 1822 go func(i int) { 1823 for k := 0; atomic.LoadUint32(&stop) == 0; k++ { 1824 h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10)) 1825 } 1826 closeWg.Done() 1827 }(i) 1828 } 1829 1830 for i := 0; i < n; i++ { 1831 closeWg.Add(1) 1832 go func(i int) { 1833 for k := 1000000; k < 0 || atomic.LoadUint32(&stop) == 0; k-- { 1834 h.put(fmt.Sprintf("k%d", k), fmt.Sprintf("%d.%d.", k, i)+strings.Repeat("x", 10)) 1835 } 1836 closeWg.Done() 1837 }(i) 1838 } 1839 1840 cmp := comparer.DefaultComparer 1841 for i := 0; i < n2; i++ { 1842 closeWg.Add(1) 1843 go func(i int) { 1844 it := h.db.NewIterator(nil, nil) 1845 var pk []byte 1846 for it.Next() { 1847 kk := it.Key() 1848 if cmp.Compare(kk, pk) <= 0 { 1849 t.Errorf("iter %d: %q is successor of %q", i, pk, kk) 1850 } 1851 pk = append(pk[:0], kk...) 1852 var k, vk, vi int 1853 if n, err := fmt.Sscanf(string(it.Key()), "k%d", &k); err != nil { 1854 t.Errorf("iter %d: Scanf error on key %q: %v", i, it.Key(), err) 1855 } else if n < 1 { 1856 t.Errorf("iter %d: Cannot parse key %q", i, it.Key()) 1857 } 1858 if n, err := fmt.Sscanf(string(it.Value()), "%d.%d", &vk, &vi); err != nil { 1859 t.Errorf("iter %d: Scanf error on value %q: %v", i, it.Value(), err) 1860 } else if n < 2 { 1861 t.Errorf("iter %d: Cannot parse value %q", i, it.Value()) 1862 } 1863 1864 if vk != k { 1865 t.Errorf("iter %d: invalid value i=%d, want=%d got=%d", i, vi, k, vk) 1866 } 1867 } 1868 if err := it.Error(); err != nil { 1869 t.Errorf("iter %d: Got error: %v", i, err) 1870 } 1871 it.Release() 1872 closeWg.Done() 1873 }(i) 1874 } 1875 1876 atomic.StoreUint32(&stop, 1) 1877 closeWg.Wait() 1878 } 1879 1880 func TestDB_ConcurrentWrite(t *testing.T) { 1881 const n, niter = 10, 10000 1882 h := newDbHarness(t) 1883 defer h.close() 1884 1885 runtime.GOMAXPROCS(runtime.NumCPU()) 1886 1887 var wg sync.WaitGroup 1888 for i := 0; i < n; i++ { 1889 wg.Add(1) 1890 go func(i int) { 1891 defer wg.Done() 1892 for k := 0; k < niter; k++ { 1893 kstr := fmt.Sprintf("%d.%d", i, k) 1894 vstr := fmt.Sprintf("v%d", k) 1895 h.put(kstr, vstr) 1896 // Key should immediately available after put returns. 1897 h.getVal(kstr, vstr) 1898 } 1899 }(i) 1900 } 1901 wg.Wait() 1902 } 1903 1904 func TestDB_CreateReopenDbOnFile(t *testing.T) { 1905 dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile-%d", os.Getuid())) 1906 if err := os.RemoveAll(dbpath); err != nil { 1907 t.Fatal("cannot remove old db: ", err) 1908 } 1909 defer os.RemoveAll(dbpath) 1910 1911 for i := 0; i < 3; i++ { 1912 stor, err := storage.OpenFile(dbpath, false) 1913 if err != nil { 1914 t.Fatalf("(%d) cannot open storage: %s", i, err) 1915 } 1916 db, err := Open(stor, nil) 1917 if err != nil { 1918 t.Fatalf("(%d) cannot open db: %s", i, err) 1919 } 1920 if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil { 1921 t.Fatalf("(%d) cannot write to db: %s", i, err) 1922 } 1923 if err := db.Close(); err != nil { 1924 t.Fatalf("(%d) cannot close db: %s", i, err) 1925 } 1926 if err := stor.Close(); err != nil { 1927 t.Fatalf("(%d) cannot close storage: %s", i, err) 1928 } 1929 } 1930 } 1931 1932 func TestDB_CreateReopenDbOnFile2(t *testing.T) { 1933 dbpath := filepath.Join(os.TempDir(), fmt.Sprintf("goleveldbtestCreateReopenDbOnFile2-%d", os.Getuid())) 1934 if err := os.RemoveAll(dbpath); err != nil { 1935 t.Fatal("cannot remove old db: ", err) 1936 } 1937 defer os.RemoveAll(dbpath) 1938 1939 for i := 0; i < 3; i++ { 1940 db, err := OpenFile(dbpath, nil) 1941 if err != nil { 1942 t.Fatalf("(%d) cannot open db: %s", i, err) 1943 } 1944 if err := db.Put([]byte("foo"), []byte("bar"), nil); err != nil { 1945 t.Fatalf("(%d) cannot write to db: %s", i, err) 1946 } 1947 if err := db.Close(); err != nil { 1948 t.Fatalf("(%d) cannot close db: %s", i, err) 1949 } 1950 } 1951 } 1952 1953 func TestDB_DeletionMarkersOnMemdb(t *testing.T) { 1954 h := newDbHarness(t) 1955 defer h.close() 1956 1957 h.put("foo", "v1") 1958 h.compactMem() 1959 h.delete("foo") 1960 h.get("foo", false) 1961 h.getKeyVal("") 1962 } 1963 1964 func TestDB_LeveldbIssue178(t *testing.T) { 1965 nKeys := (opt.DefaultCompactionTableSize / 30) * 5 1966 key1 := func(i int) string { 1967 return fmt.Sprintf("my_key_%d", i) 1968 } 1969 key2 := func(i int) string { 1970 return fmt.Sprintf("my_key_%d_xxx", i) 1971 } 1972 1973 // Disable compression since it affects the creation of layers and the 1974 // code below is trying to test against a very specific scenario. 1975 h := newDbHarnessWopt(t, &opt.Options{ 1976 DisableLargeBatchTransaction: true, 1977 Compression: opt.NoCompression, 1978 }) 1979 defer h.close() 1980 1981 // Create first key range. 1982 batch := new(Batch) 1983 for i := 0; i < nKeys; i++ { 1984 batch.Put([]byte(key1(i)), []byte("value for range 1 key")) 1985 } 1986 h.write(batch) 1987 1988 // Create second key range. 1989 batch.Reset() 1990 for i := 0; i < nKeys; i++ { 1991 batch.Put([]byte(key2(i)), []byte("value for range 2 key")) 1992 } 1993 h.write(batch) 1994 1995 // Delete second key range. 1996 batch.Reset() 1997 for i := 0; i < nKeys; i++ { 1998 batch.Delete([]byte(key2(i))) 1999 } 2000 h.write(batch) 2001 h.waitMemCompaction() 2002 2003 // Run manual compaction. 2004 h.compactRange(key1(0), key1(nKeys-1)) 2005 2006 // Checking the keys. 2007 h.assertNumKeys(nKeys) 2008 } 2009 2010 func TestDB_LeveldbIssue200(t *testing.T) { 2011 h := newDbHarness(t) 2012 defer h.close() 2013 2014 h.put("1", "b") 2015 h.put("2", "c") 2016 h.put("3", "d") 2017 h.put("4", "e") 2018 h.put("5", "f") 2019 2020 iter := h.db.NewIterator(nil, h.ro) 2021 2022 // Add an element that should not be reflected in the iterator. 2023 h.put("25", "cd") 2024 2025 iter.Seek([]byte("5")) 2026 assertBytes(t, []byte("5"), iter.Key()) 2027 iter.Prev() 2028 assertBytes(t, []byte("4"), iter.Key()) 2029 iter.Prev() 2030 assertBytes(t, []byte("3"), iter.Key()) 2031 iter.Next() 2032 assertBytes(t, []byte("4"), iter.Key()) 2033 iter.Next() 2034 assertBytes(t, []byte("5"), iter.Key()) 2035 } 2036 2037 func TestDB_GoleveldbIssue74(t *testing.T) { 2038 h := newDbHarnessWopt(t, &opt.Options{ 2039 DisableLargeBatchTransaction: true, 2040 WriteBuffer: 1 * opt.MiB, 2041 }) 2042 defer h.close() 2043 2044 const n, dur = 10000, 5 * time.Second 2045 2046 runtime.GOMAXPROCS(runtime.NumCPU()) 2047 2048 until := time.Now().Add(dur) 2049 wg := new(sync.WaitGroup) 2050 wg.Add(2) 2051 var done uint32 2052 go func() { 2053 var i int 2054 defer func() { 2055 t.Logf("WRITER DONE #%d", i) 2056 atomic.StoreUint32(&done, 1) 2057 wg.Done() 2058 }() 2059 2060 b := new(Batch) 2061 for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { 2062 iv := fmt.Sprintf("VAL%010d", i) 2063 for k := 0; k < n; k++ { 2064 key := fmt.Sprintf("KEY%06d", k) 2065 b.Put([]byte(key), []byte(key+iv)) 2066 b.Put([]byte(fmt.Sprintf("PTR%06d", k)), []byte(key)) 2067 } 2068 h.write(b) 2069 2070 b.Reset() 2071 snap := h.getSnapshot() 2072 iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil) 2073 var k int 2074 for ; iter.Next(); k++ { 2075 ptrKey := iter.Key() 2076 key := iter.Value() 2077 2078 if _, err := snap.Get(ptrKey, nil); err != nil { 2079 t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, ptrKey, err) 2080 } 2081 if value, err := snap.Get(key, nil); err != nil { 2082 t.Fatalf("WRITER #%d snapshot.Get %q: %v", i, key, err) 2083 } else if string(value) != string(key)+iv { 2084 t.Fatalf("WRITER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+iv, value) 2085 } 2086 2087 b.Delete(key) 2088 b.Delete(ptrKey) 2089 } 2090 h.write(b) 2091 iter.Release() 2092 snap.Release() 2093 if k != n { 2094 t.Fatalf("#%d %d != %d", i, k, n) 2095 } 2096 } 2097 }() 2098 go func() { 2099 var i int 2100 defer func() { 2101 t.Logf("READER DONE #%d", i) 2102 atomic.StoreUint32(&done, 1) 2103 wg.Done() 2104 }() 2105 for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { 2106 snap := h.getSnapshot() 2107 iter := snap.NewIterator(util.BytesPrefix([]byte("PTR")), nil) 2108 var prevValue string 2109 var k int 2110 for ; iter.Next(); k++ { 2111 ptrKey := iter.Key() 2112 key := iter.Value() 2113 2114 if _, err := snap.Get(ptrKey, nil); err != nil { 2115 t.Fatalf("READER #%d snapshot.Get %q: %v", i, ptrKey, err) 2116 } 2117 2118 if value, err := snap.Get(key, nil); err != nil { 2119 t.Fatalf("READER #%d snapshot.Get %q: %v", i, key, err) 2120 } else if prevValue != "" && string(value) != string(key)+prevValue { 2121 t.Fatalf("READER #%d snapshot.Get %q got invalid value, want %q got %q", i, key, string(key)+prevValue, value) 2122 } else { 2123 prevValue = string(value[len(key):]) 2124 } 2125 } 2126 iter.Release() 2127 snap.Release() 2128 if k > 0 && k != n { 2129 t.Fatalf("#%d %d != %d", i, k, n) 2130 } 2131 } 2132 }() 2133 wg.Wait() 2134 } 2135 2136 func TestDB_GetProperties(t *testing.T) { 2137 h := newDbHarness(t) 2138 defer h.close() 2139 2140 _, err := h.db.GetProperty("leveldb.num-files-at-level") 2141 if err == nil { 2142 t.Error("GetProperty() failed to detect missing level") 2143 } 2144 2145 _, err = h.db.GetProperty("leveldb.num-files-at-level0") 2146 if err != nil { 2147 t.Error("got unexpected error", err) 2148 } 2149 2150 _, err = h.db.GetProperty("leveldb.num-files-at-level0x") 2151 if err == nil { 2152 t.Error("GetProperty() failed to detect invalid level") 2153 } 2154 } 2155 2156 func TestDB_GoleveldbIssue72and83(t *testing.T) { 2157 h := newDbHarnessWopt(t, &opt.Options{ 2158 DisableLargeBatchTransaction: true, 2159 WriteBuffer: 1 * opt.MiB, 2160 OpenFilesCacheCapacity: 3, 2161 }) 2162 defer h.close() 2163 2164 const n, wn, dur = 10000, 100, 30 * time.Second 2165 2166 runtime.GOMAXPROCS(runtime.NumCPU()) 2167 2168 randomData := func(prefix byte, i int) []byte { 2169 data := make([]byte, 1+4+32+64+32) 2170 _, err := crand.Reader.Read(data[1 : len(data)-8]) 2171 if err != nil { 2172 panic(err) 2173 } 2174 data[0] = prefix 2175 binary.LittleEndian.PutUint32(data[len(data)-8:], uint32(i)) 2176 binary.LittleEndian.PutUint32(data[len(data)-4:], util.NewCRC(data[:len(data)-4]).Value()) 2177 return data 2178 } 2179 2180 keys := make([][]byte, n) 2181 for i := range keys { 2182 keys[i] = randomData(1, 0) 2183 } 2184 2185 until := time.Now().Add(dur) 2186 wg := new(sync.WaitGroup) 2187 wg.Add(3) 2188 var done uint32 2189 go func() { 2190 i := 0 2191 defer func() { 2192 t.Logf("WRITER DONE #%d", i) 2193 wg.Done() 2194 }() 2195 2196 b := new(Batch) 2197 for ; i < wn && atomic.LoadUint32(&done) == 0; i++ { 2198 b.Reset() 2199 for _, k1 := range keys { 2200 k2 := randomData(2, i) 2201 b.Put(k2, randomData(42, i)) 2202 b.Put(k1, k2) 2203 } 2204 if err := h.db.Write(b, h.wo); err != nil { 2205 atomic.StoreUint32(&done, 1) 2206 t.Fatalf("WRITER #%d db.Write: %v", i, err) 2207 } 2208 } 2209 }() 2210 go func() { 2211 var i int 2212 defer func() { 2213 t.Logf("READER0 DONE #%d", i) 2214 atomic.StoreUint32(&done, 1) 2215 wg.Done() 2216 }() 2217 for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { 2218 snap := h.getSnapshot() 2219 seq := snap.elem.seq 2220 if seq == 0 { 2221 snap.Release() 2222 continue 2223 } 2224 iter := snap.NewIterator(util.BytesPrefix([]byte{1}), nil) 2225 writei := int(seq/(n*2) - 1) 2226 var k int 2227 for ; iter.Next(); k++ { 2228 k1 := iter.Key() 2229 k2 := iter.Value() 2230 k1checksum0 := binary.LittleEndian.Uint32(k1[len(k1)-4:]) 2231 k1checksum1 := util.NewCRC(k1[:len(k1)-4]).Value() 2232 if k1checksum0 != k1checksum1 { 2233 t.Fatalf("READER0 #%d.%d W#%d invalid K1 checksum: %#x != %#x", i, k, k1checksum0, k1checksum0) 2234 } 2235 k2checksum0 := binary.LittleEndian.Uint32(k2[len(k2)-4:]) 2236 k2checksum1 := util.NewCRC(k2[:len(k2)-4]).Value() 2237 if k2checksum0 != k2checksum1 { 2238 t.Fatalf("READER0 #%d.%d W#%d invalid K2 checksum: %#x != %#x", i, k, k2checksum0, k2checksum1) 2239 } 2240 kwritei := int(binary.LittleEndian.Uint32(k2[len(k2)-8:])) 2241 if writei != kwritei { 2242 t.Fatalf("READER0 #%d.%d W#%d invalid write iteration num: %d", i, k, writei, kwritei) 2243 } 2244 if _, err := snap.Get(k2, nil); err != nil { 2245 t.Fatalf("READER0 #%d.%d W#%d snap.Get: %v\nk1: %x\n -> k2: %x", i, k, writei, err, k1, k2) 2246 } 2247 } 2248 if err := iter.Error(); err != nil { 2249 t.Fatalf("READER0 #%d.%d W#%d snap.Iterator: %v", i, k, writei, err) 2250 } 2251 iter.Release() 2252 snap.Release() 2253 if k > 0 && k != n { 2254 t.Fatalf("READER0 #%d W#%d short read, got=%d want=%d", i, writei, k, n) 2255 } 2256 } 2257 }() 2258 go func() { 2259 var i int 2260 defer func() { 2261 t.Logf("READER1 DONE #%d", i) 2262 atomic.StoreUint32(&done, 1) 2263 wg.Done() 2264 }() 2265 for ; time.Now().Before(until) && atomic.LoadUint32(&done) == 0; i++ { 2266 iter := h.db.NewIterator(nil, nil) 2267 seq := iter.(*dbIter).seq 2268 if seq == 0 { 2269 iter.Release() 2270 continue 2271 } 2272 writei := int(seq/(n*2) - 1) 2273 var k int 2274 for ok := iter.Last(); ok; ok = iter.Prev() { 2275 k++ 2276 } 2277 if err := iter.Error(); err != nil { 2278 t.Fatalf("READER1 #%d.%d W#%d db.Iterator: %v", i, k, writei, err) 2279 } 2280 iter.Release() 2281 if m := (writei+1)*n + n; k != m { 2282 t.Fatalf("READER1 #%d W#%d short read, got=%d want=%d", i, writei, k, m) 2283 } 2284 } 2285 }() 2286 2287 wg.Wait() 2288 } 2289 2290 func TestDB_TransientError(t *testing.T) { 2291 h := newDbHarnessWopt(t, &opt.Options{ 2292 DisableLargeBatchTransaction: true, 2293 WriteBuffer: 128 * opt.KiB, 2294 OpenFilesCacheCapacity: 3, 2295 DisableCompactionBackoff: true, 2296 }) 2297 defer h.close() 2298 2299 const ( 2300 nSnap = 20 2301 nKey = 10000 2302 ) 2303 2304 var ( 2305 snaps [nSnap]*Snapshot 2306 b = &Batch{} 2307 ) 2308 for i := range snaps { 2309 vtail := fmt.Sprintf("VAL%030d", i) 2310 b.Reset() 2311 for k := 0; k < nKey; k++ { 2312 key := fmt.Sprintf("KEY%8d", k) 2313 b.Put([]byte(key), []byte(key+vtail)) 2314 } 2315 h.stor.EmulateError(testutil.ModeOpen|testutil.ModeRead, storage.TypeTable, errors.New("table transient read error")) 2316 if err := h.db.Write(b, nil); err != nil { 2317 t.Logf("WRITE #%d error: %v", i, err) 2318 h.stor.EmulateError(testutil.ModeOpen|testutil.ModeRead, storage.TypeTable, nil) 2319 for { 2320 if err := h.db.Write(b, nil); err == nil { 2321 break 2322 } else if errors.IsCorrupted(err) { 2323 t.Fatalf("WRITE #%d corrupted: %v", i, err) 2324 } 2325 } 2326 } 2327 2328 snaps[i] = h.db.newSnapshot() 2329 b.Reset() 2330 for k := 0; k < nKey; k++ { 2331 key := fmt.Sprintf("KEY%8d", k) 2332 b.Delete([]byte(key)) 2333 } 2334 h.stor.EmulateError(testutil.ModeOpen|testutil.ModeRead, storage.TypeTable, errors.New("table transient read error")) 2335 if err := h.db.Write(b, nil); err != nil { 2336 t.Logf("WRITE #%d error: %v", i, err) 2337 h.stor.EmulateError(testutil.ModeOpen|testutil.ModeRead, storage.TypeTable, nil) 2338 for { 2339 if err := h.db.Write(b, nil); err == nil { 2340 break 2341 } else if errors.IsCorrupted(err) { 2342 t.Fatalf("WRITE #%d corrupted: %v", i, err) 2343 } 2344 } 2345 } 2346 } 2347 h.stor.EmulateError(testutil.ModeOpen|testutil.ModeRead, storage.TypeTable, nil) 2348 2349 runtime.GOMAXPROCS(runtime.NumCPU()) 2350 2351 rnd := rand.New(rand.NewSource(0xecafdaed)) 2352 wg := &sync.WaitGroup{} 2353 for i, snap := range snaps { 2354 wg.Add(2) 2355 2356 go func(i int, snap *Snapshot, sk []int) { 2357 defer wg.Done() 2358 2359 vtail := fmt.Sprintf("VAL%030d", i) 2360 for _, k := range sk { 2361 key := fmt.Sprintf("KEY%8d", k) 2362 xvalue, err := snap.Get([]byte(key), nil) 2363 if err != nil { 2364 t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err) 2365 } 2366 value := key + vtail 2367 if !bytes.Equal([]byte(value), xvalue) { 2368 t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue) 2369 } 2370 } 2371 }(i, snap, rnd.Perm(nKey)) 2372 2373 go func(i int, snap *Snapshot) { 2374 defer wg.Done() 2375 2376 vtail := fmt.Sprintf("VAL%030d", i) 2377 iter := snap.NewIterator(nil, nil) 2378 defer iter.Release() 2379 for k := 0; k < nKey; k++ { 2380 if !iter.Next() { 2381 if err := iter.Error(); err != nil { 2382 t.Fatalf("READER_ITER #%d K%d error: %v", i, k, err) 2383 } else { 2384 t.Fatalf("READER_ITER #%d K%d eoi", i, k) 2385 } 2386 } 2387 key := fmt.Sprintf("KEY%8d", k) 2388 xkey := iter.Key() 2389 if !bytes.Equal([]byte(key), xkey) { 2390 t.Fatalf("READER_ITER #%d K%d invalid key: want %q, got %q", i, k, key, xkey) 2391 } 2392 value := key + vtail 2393 xvalue := iter.Value() 2394 if !bytes.Equal([]byte(value), xvalue) { 2395 t.Fatalf("READER_ITER #%d K%d invalid value: want %q, got %q", i, k, value, xvalue) 2396 } 2397 } 2398 }(i, snap) 2399 } 2400 2401 wg.Wait() 2402 } 2403 2404 func TestDB_UkeyShouldntHopAcrossTable(t *testing.T) { 2405 h := newDbHarnessWopt(t, &opt.Options{ 2406 DisableLargeBatchTransaction: true, 2407 WriteBuffer: 112 * opt.KiB, 2408 CompactionTableSize: 90 * opt.KiB, 2409 CompactionExpandLimitFactor: 1, 2410 }) 2411 defer h.close() 2412 2413 const ( 2414 nSnap = 190 2415 nKey = 140 2416 ) 2417 2418 var ( 2419 snaps [nSnap]*Snapshot 2420 b = &Batch{} 2421 ) 2422 for i := range snaps { 2423 vtail := fmt.Sprintf("VAL%030d", i) 2424 b.Reset() 2425 for k := 0; k < nKey; k++ { 2426 key := fmt.Sprintf("KEY%08d", k) 2427 b.Put([]byte(key), []byte(key+vtail)) 2428 } 2429 if err := h.db.Write(b, nil); err != nil { 2430 t.Fatalf("WRITE #%d error: %v", i, err) 2431 } 2432 2433 snaps[i] = h.db.newSnapshot() 2434 b.Reset() 2435 for k := 0; k < nKey; k++ { 2436 key := fmt.Sprintf("KEY%08d", k) 2437 b.Delete([]byte(key)) 2438 } 2439 if err := h.db.Write(b, nil); err != nil { 2440 t.Fatalf("WRITE #%d error: %v", i, err) 2441 } 2442 } 2443 2444 h.compactMem() 2445 2446 h.waitCompaction() 2447 for level, tables := range h.db.s.stVersion.levels { 2448 for _, table := range tables { 2449 t.Logf("L%d@%d %q:%q", level, table.fd.Num, table.imin, table.imax) 2450 } 2451 } 2452 2453 h.compactRangeAt(0, "", "") 2454 h.waitCompaction() 2455 for level, tables := range h.db.s.stVersion.levels { 2456 for _, table := range tables { 2457 t.Logf("L%d@%d %q:%q", level, table.fd.Num, table.imin, table.imax) 2458 } 2459 } 2460 h.compactRangeAt(1, "", "") 2461 h.waitCompaction() 2462 for level, tables := range h.db.s.stVersion.levels { 2463 for _, table := range tables { 2464 t.Logf("L%d@%d %q:%q", level, table.fd.Num, table.imin, table.imax) 2465 } 2466 } 2467 runtime.GOMAXPROCS(runtime.NumCPU()) 2468 2469 wg := &sync.WaitGroup{} 2470 for i, snap := range snaps { 2471 wg.Add(1) 2472 2473 go func(i int, snap *Snapshot) { 2474 defer wg.Done() 2475 2476 vtail := fmt.Sprintf("VAL%030d", i) 2477 for k := 0; k < nKey; k++ { 2478 key := fmt.Sprintf("KEY%08d", k) 2479 xvalue, err := snap.Get([]byte(key), nil) 2480 if err != nil { 2481 t.Fatalf("READER_GET #%d SEQ=%d K%d error: %v", i, snap.elem.seq, k, err) 2482 } 2483 value := key + vtail 2484 if !bytes.Equal([]byte(value), xvalue) { 2485 t.Fatalf("READER_GET #%d SEQ=%d K%d invalid value: want %q, got %q", i, snap.elem.seq, k, value, xvalue) 2486 } 2487 } 2488 }(i, snap) 2489 } 2490 2491 wg.Wait() 2492 } 2493 2494 func TestDB_TableCompactionBuilder(t *testing.T) { 2495 gomega.RegisterTestingT(t) 2496 stor := testutil.NewStorage() 2497 stor.OnLog(testingLogger(t)) 2498 stor.OnClose(testingPreserveOnFailed(t)) 2499 defer stor.Close() 2500 2501 const nSeq = 99 2502 2503 o := &opt.Options{ 2504 DisableLargeBatchTransaction: true, 2505 WriteBuffer: 112 * opt.KiB, 2506 CompactionTableSize: 43 * opt.KiB, 2507 CompactionExpandLimitFactor: 1, 2508 CompactionGPOverlapsFactor: 1, 2509 DisableBlockCache: true, 2510 } 2511 s, err := newSession(stor, o) 2512 if err != nil { 2513 t.Fatal(err) 2514 } 2515 if err := s.create(); err != nil { 2516 t.Fatal(err) 2517 } 2518 defer s.close() 2519 var ( 2520 seq uint64 2521 targetSize = 5 * o.CompactionTableSize 2522 value = bytes.Repeat([]byte{'0'}, 100) 2523 ) 2524 for i := 0; i < 2; i++ { 2525 tw, err := s.tops.create() 2526 if err != nil { 2527 t.Fatal(err) 2528 } 2529 for k := 0; tw.tw.BytesLen() < targetSize; k++ { 2530 key := []byte(fmt.Sprintf("%09d", k)) 2531 seq += nSeq - 1 2532 for x := uint64(0); x < nSeq; x++ { 2533 if err := tw.append(makeInternalKey(nil, key, seq-x, keyTypeVal), value); err != nil { 2534 t.Fatal(err) 2535 } 2536 } 2537 } 2538 tf, err := tw.finish() 2539 if err != nil { 2540 t.Fatal(err) 2541 } 2542 rec := &sessionRecord{} 2543 rec.addTableFile(i, tf) 2544 if err := s.commit(rec); err != nil { 2545 t.Fatal(err) 2546 } 2547 } 2548 2549 // Build grandparent. 2550 v := s.version() 2551 c := newCompaction(s, v, 1, append(tFiles{}, v.levels[1]...)) 2552 rec := &sessionRecord{} 2553 b := &tableCompactionBuilder{ 2554 s: s, 2555 c: c, 2556 rec: rec, 2557 stat1: new(cStatStaging), 2558 minSeq: 0, 2559 strict: true, 2560 tableSize: o.CompactionTableSize/3 + 961, 2561 } 2562 if err := b.run(new(compactionTransactCounter)); err != nil { 2563 t.Fatal(err) 2564 } 2565 for _, t := range c.levels[0] { 2566 rec.delTable(c.sourceLevel, t.fd.Num) 2567 } 2568 if err := s.commit(rec); err != nil { 2569 t.Fatal(err) 2570 } 2571 c.release() 2572 2573 // Build level-1. 2574 v = s.version() 2575 c = newCompaction(s, v, 0, append(tFiles{}, v.levels[0]...)) 2576 rec = &sessionRecord{} 2577 b = &tableCompactionBuilder{ 2578 s: s, 2579 c: c, 2580 rec: rec, 2581 stat1: new(cStatStaging), 2582 minSeq: 0, 2583 strict: true, 2584 tableSize: o.CompactionTableSize, 2585 } 2586 if err := b.run(new(compactionTransactCounter)); err != nil { 2587 t.Fatal(err) 2588 } 2589 for _, t := range c.levels[0] { 2590 rec.delTable(c.sourceLevel, t.fd.Num) 2591 } 2592 // Move grandparent to level-3 2593 for _, t := range v.levels[2] { 2594 rec.delTable(2, t.fd.Num) 2595 rec.addTableFile(3, t) 2596 } 2597 if err := s.commit(rec); err != nil { 2598 t.Fatal(err) 2599 } 2600 c.release() 2601 2602 v = s.version() 2603 for level, want := range []bool{false, true, false, true} { 2604 got := len(v.levels[level]) > 0 2605 if want != got { 2606 t.Fatalf("invalid level-%d tables len: want %v, got %v", level, want, got) 2607 } 2608 } 2609 for i, f := range v.levels[1][:len(v.levels[1])-1] { 2610 nf := v.levels[1][i+1] 2611 if bytes.Equal(f.imax.ukey(), nf.imin.ukey()) { 2612 t.Fatalf("KEY %q hop across table %d .. %d", f.imax.ukey(), f.fd.Num, nf.fd.Num) 2613 } 2614 } 2615 v.release() 2616 2617 // Compaction with transient error. 2618 v = s.version() 2619 c = newCompaction(s, v, 1, append(tFiles{}, v.levels[1]...)) 2620 rec = &sessionRecord{} 2621 b = &tableCompactionBuilder{ 2622 s: s, 2623 c: c, 2624 rec: rec, 2625 stat1: new(cStatStaging), 2626 minSeq: 0, 2627 strict: true, 2628 tableSize: o.CompactionTableSize, 2629 } 2630 stor.EmulateErrorOnce(testutil.ModeSync, storage.TypeTable, errors.New("table sync error (once)")) 2631 stor.EmulateRandomError(testutil.ModeRead|testutil.ModeWrite, storage.TypeTable, 0.01, errors.New("table random IO error")) 2632 for { 2633 if err := b.run(new(compactionTransactCounter)); err != nil { 2634 t.Logf("(expected) b.run: %v", err) 2635 } else { 2636 break 2637 } 2638 } 2639 if err := s.commit(rec); err != nil { 2640 t.Fatal(err) 2641 } 2642 c.release() 2643 2644 stor.EmulateErrorOnce(testutil.ModeSync, storage.TypeTable, nil) 2645 stor.EmulateRandomError(testutil.ModeRead|testutil.ModeWrite, storage.TypeTable, 0, nil) 2646 2647 v = s.version() 2648 if len(v.levels[1]) != len(v.levels[2]) { 2649 t.Fatalf("invalid tables length, want %d, got %d", len(v.levels[1]), len(v.levels[2])) 2650 } 2651 for i, f0 := range v.levels[1] { 2652 f1 := v.levels[2][i] 2653 iter0 := s.tops.newIterator(f0, nil, nil) 2654 iter1 := s.tops.newIterator(f1, nil, nil) 2655 for j := 0; true; j++ { 2656 next0 := iter0.Next() 2657 next1 := iter1.Next() 2658 if next0 != next1 { 2659 t.Fatalf("#%d.%d invalid eoi: want %v, got %v", i, j, next0, next1) 2660 } 2661 key0 := iter0.Key() 2662 key1 := iter1.Key() 2663 if !bytes.Equal(key0, key1) { 2664 t.Fatalf("#%d.%d invalid key: want %q, got %q", i, j, key0, key1) 2665 } 2666 if next0 == false { 2667 break 2668 } 2669 } 2670 iter0.Release() 2671 iter1.Release() 2672 } 2673 v.release() 2674 } 2675 2676 func testDB_IterTriggeredCompaction(t *testing.T, limitDiv int) { 2677 const ( 2678 vSize = 200 * opt.KiB 2679 tSize = 100 * opt.MiB 2680 mIter = 100 2681 n = tSize / vSize 2682 ) 2683 2684 h := newDbHarnessWopt(t, &opt.Options{ 2685 DisableLargeBatchTransaction: true, 2686 Compression: opt.NoCompression, 2687 DisableBlockCache: true, 2688 }) 2689 defer h.close() 2690 2691 h.db.memdbMaxLevel = 2 2692 2693 key := func(x int) string { 2694 return fmt.Sprintf("v%06d", x) 2695 } 2696 2697 // Fill. 2698 value := strings.Repeat("x", vSize) 2699 for i := 0; i < n; i++ { 2700 h.put(key(i), value) 2701 } 2702 h.compactMem() 2703 2704 // Delete all. 2705 for i := 0; i < n; i++ { 2706 h.delete(key(i)) 2707 } 2708 h.compactMem() 2709 2710 var ( 2711 limit = n / limitDiv 2712 2713 startKey = key(0) 2714 limitKey = key(limit) 2715 maxKey = key(n) 2716 slice = &util.Range{Limit: []byte(limitKey)} 2717 2718 initialSize0 = h.sizeOf(startKey, limitKey) 2719 initialSize1 = h.sizeOf(limitKey, maxKey) 2720 ) 2721 2722 t.Logf("inital size %s [rest %s]", shortenb(int(initialSize0)), shortenb(int(initialSize1))) 2723 2724 for r := 0; true; r++ { 2725 if r >= mIter { 2726 t.Fatal("taking too long to compact") 2727 } 2728 2729 // Iterates. 2730 iter := h.db.NewIterator(slice, h.ro) 2731 for iter.Next() { 2732 } 2733 if err := iter.Error(); err != nil { 2734 t.Fatalf("Iter err: %v", err) 2735 } 2736 iter.Release() 2737 2738 // Wait compaction. 2739 h.waitCompaction() 2740 2741 // Check size. 2742 size0 := h.sizeOf(startKey, limitKey) 2743 size1 := h.sizeOf(limitKey, maxKey) 2744 t.Logf("#%03d size %s [rest %s]", r, shortenb(int(size0)), shortenb(int(size1))) 2745 if size0 < initialSize0/10 { 2746 break 2747 } 2748 } 2749 2750 if initialSize1 > 0 { 2751 h.sizeAssert(limitKey, maxKey, initialSize1/4-opt.MiB, initialSize1+opt.MiB) 2752 } 2753 } 2754 2755 func TestDB_IterTriggeredCompaction(t *testing.T) { 2756 testDB_IterTriggeredCompaction(t, 1) 2757 } 2758 2759 func TestDB_IterTriggeredCompactionHalf(t *testing.T) { 2760 testDB_IterTriggeredCompaction(t, 2) 2761 } 2762 2763 func TestDB_ReadOnly(t *testing.T) { 2764 h := newDbHarness(t) 2765 defer h.close() 2766 2767 h.put("foo", "v1") 2768 h.put("bar", "v2") 2769 h.compactMem() 2770 2771 h.put("xfoo", "v1") 2772 h.put("xbar", "v2") 2773 2774 t.Log("Trigger read-only") 2775 if err := h.db.SetReadOnly(); err != nil { 2776 h.close() 2777 t.Fatalf("SetReadOnly error: %v", err) 2778 } 2779 2780 mode := testutil.ModeCreate | testutil.ModeRemove | testutil.ModeRename | testutil.ModeWrite | testutil.ModeSync 2781 h.stor.EmulateError(mode, storage.TypeAll, errors.New("read-only DB shouldn't writes")) 2782 2783 ro := func(key, value, wantValue string) { 2784 if err := h.db.Put([]byte(key), []byte(value), h.wo); err != ErrReadOnly { 2785 t.Fatalf("unexpected error: %v", err) 2786 } 2787 h.getVal(key, wantValue) 2788 } 2789 2790 ro("foo", "vx", "v1") 2791 2792 h.o.ReadOnly = true 2793 h.reopenDB() 2794 2795 ro("foo", "vx", "v1") 2796 ro("bar", "vx", "v2") 2797 h.assertNumKeys(4) 2798 } 2799 2800 func TestDB_BulkInsertDelete(t *testing.T) { 2801 h := newDbHarnessWopt(t, &opt.Options{ 2802 DisableLargeBatchTransaction: true, 2803 Compression: opt.NoCompression, 2804 CompactionTableSize: 128 * opt.KiB, 2805 CompactionTotalSize: 1 * opt.MiB, 2806 WriteBuffer: 256 * opt.KiB, 2807 }) 2808 defer h.close() 2809 2810 const R = 100 2811 const N = 2500 2812 key := make([]byte, 4) 2813 value := make([]byte, 256) 2814 for i := 0; i < R; i++ { 2815 offset := N * i 2816 for j := 0; j < N; j++ { 2817 binary.BigEndian.PutUint32(key, uint32(offset+j)) 2818 h.db.Put(key, value, nil) 2819 } 2820 for j := 0; j < N; j++ { 2821 binary.BigEndian.PutUint32(key, uint32(offset+j)) 2822 h.db.Delete(key, nil) 2823 } 2824 } 2825 2826 if tot := h.totalTables(); tot > 10 { 2827 t.Fatalf("too many uncompacted tables: %d (%s)", tot, h.getTablesPerLevel()) 2828 } 2829 }