github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/strs_test.go (about) 1 package rosedb 2 3 import ( 4 "bytes" 5 "errors" 6 "math" 7 "math/rand" 8 "path/filepath" 9 "reflect" 10 "sort" 11 "strconv" 12 "testing" 13 "time" 14 15 "github.com/stretchr/testify/assert" 16 ) 17 18 func TestRoseDB_Set(t *testing.T) { 19 t.Run("default", func(t *testing.T) { 20 testRoseDBSet(t, FileIO, KeyOnlyMemMode) 21 }) 22 23 t.Run("mmap", func(t *testing.T) { 24 testRoseDBSet(t, MMap, KeyOnlyMemMode) 25 }) 26 27 t.Run("key-val-mem-mode", func(t *testing.T) { 28 testRoseDBSet(t, FileIO, KeyValueMemMode) 29 }) 30 } 31 32 func TestRoseDB_Set_LogFileThreshold(t *testing.T) { 33 path := filepath.Join("/tmp", "rosedb") 34 opts := DefaultOptions(path) 35 opts.IoType = MMap 36 opts.LogFileSizeThreshold = 32 << 20 37 db, err := Open(opts) 38 assert.Nil(t, err) 39 defer destroyDB(db) 40 41 for i := 0; i < 600000; i++ { 42 err := db.Set(GetKey(i), GetValue128B()) 43 assert.Nil(t, err) 44 } 45 } 46 47 func TestRoseDB_Get(t *testing.T) { 48 t.Run("default", func(t *testing.T) { 49 testRoseDBGet(t, FileIO, KeyOnlyMemMode) 50 }) 51 52 t.Run("mmap", func(t *testing.T) { 53 testRoseDBGet(t, MMap, KeyOnlyMemMode) 54 }) 55 56 t.Run("key-val-mem-mode", func(t *testing.T) { 57 testRoseDBGet(t, MMap, KeyValueMemMode) 58 }) 59 } 60 61 func TestRoseDB_Get_LogFileThreshold(t *testing.T) { 62 path := filepath.Join("/tmp", "rosedb") 63 opts := DefaultOptions(path) 64 opts.IoType = MMap 65 opts.LogFileSizeThreshold = 32 << 20 66 db, err := Open(opts) 67 assert.Nil(t, err) 68 defer destroyDB(db) 69 70 writeCount := 600000 71 for i := 0; i <= writeCount; i++ { 72 err := db.Set(GetKey(i), GetValue128B()) 73 assert.Nil(t, err) 74 } 75 76 rand.Seed(time.Now().Unix()) 77 for i := 0; i < 10000; i++ { 78 key := GetKey(rand.Intn(writeCount)) 79 v, err := db.Get(key) 80 assert.Nil(t, err) 81 assert.NotNil(t, v) 82 } 83 } 84 85 func testRoseDBSet(t *testing.T, ioType IOType, mode DataIndexMode) { 86 path := filepath.Join("/tmp", "rosedb") 87 opts := DefaultOptions(path) 88 opts.IoType = ioType 89 opts.IndexMode = mode 90 db, err := Open(opts) 91 assert.Nil(t, err) 92 defer destroyDB(db) 93 94 type args struct { 95 key []byte 96 value []byte 97 } 98 tests := []struct { 99 name string 100 db *RoseDB 101 args args 102 wantErr bool 103 }{ 104 { 105 "nil-key", db, args{key: nil, value: []byte("val-1")}, false, 106 }, 107 { 108 "nil-value", db, args{key: []byte("key-1"), value: nil}, false, 109 }, 110 { 111 "normal", db, args{key: []byte("key-1111"), value: []byte("value-1111")}, false, 112 }, 113 } 114 for _, tt := range tests { 115 t.Run(tt.name, func(t *testing.T) { 116 if err := tt.db.Set(tt.args.key, tt.args.value); (err != nil) != tt.wantErr { 117 t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) 118 } 119 }) 120 } 121 } 122 123 func testRoseDBGet(t *testing.T, ioType IOType, mode DataIndexMode) { 124 path := filepath.Join("/tmp", "rosedb") 125 opts := DefaultOptions(path) 126 opts.IoType = ioType 127 opts.IndexMode = mode 128 db, err := Open(opts) 129 assert.Nil(t, err) 130 defer destroyDB(db) 131 132 db.Set(nil, []byte("v-1111")) 133 db.Set([]byte("k-1"), []byte("v-1")) 134 db.Set([]byte("k-2"), []byte("v-2")) 135 db.Set([]byte("k-3"), []byte("v-3")) 136 db.Set([]byte("k-3"), []byte("v-333")) 137 138 type args struct { 139 key []byte 140 } 141 tests := []struct { 142 name string 143 db *RoseDB 144 args args 145 want []byte 146 wantErr bool 147 }{ 148 { 149 "nil-key", db, args{key: nil}, nil, true, 150 }, 151 { 152 "normal", db, args{key: []byte("k-1")}, []byte("v-1"), false, 153 }, 154 { 155 "normal-rewrite", db, args{key: []byte("k-3")}, []byte("v-333"), false, 156 }, 157 } 158 for _, tt := range tests { 159 t.Run(tt.name, func(t *testing.T) { 160 got, err := tt.db.Get(tt.args.key) 161 if (err != nil) != tt.wantErr { 162 t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr) 163 return 164 } 165 if !reflect.DeepEqual(got, tt.want) { 166 t.Errorf("Get() got = %v, want %v", got, tt.want) 167 } 168 }) 169 } 170 } 171 172 func TestRoseDB_MGet(t *testing.T) { 173 t.Run("default", func(t *testing.T) { 174 testRoseDBMGet(t, FileIO, KeyOnlyMemMode) 175 }) 176 177 t.Run("mmap", func(t *testing.T) { 178 testRoseDBMGet(t, MMap, KeyOnlyMemMode) 179 }) 180 181 t.Run("key-val-mem-mode", func(t *testing.T) { 182 testRoseDBMGet(t, MMap, KeyValueMemMode) 183 }) 184 } 185 186 func testRoseDBMGet(t *testing.T, ioType IOType, mode DataIndexMode) { 187 path := filepath.Join("/tmp", "rosedb") 188 opts := DefaultOptions(path) 189 opts.IoType = ioType 190 opts.IndexMode = mode 191 db, err := Open(opts) 192 assert.Nil(t, err) 193 defer destroyDB(db) 194 195 db.Set(nil, []byte("v-1111")) 196 db.Set([]byte("k-1"), []byte("v-1")) 197 db.Set([]byte("k-2"), []byte("v-2")) 198 db.Set([]byte("k-3"), []byte("v-3")) 199 db.Set([]byte("k-3"), []byte("v-333")) 200 db.Set([]byte("k-4"), []byte("v-4")) 201 db.Set([]byte("k-5"), []byte("v-5")) 202 203 type args struct { 204 keys [][]byte 205 } 206 207 tests := []struct { 208 name string 209 db *RoseDB 210 args args 211 want [][]byte 212 wantErr bool 213 }{ 214 { 215 name: "nil-key", 216 db: db, 217 args: args{keys: [][]byte{nil}}, 218 want: [][]byte{nil}, 219 wantErr: false, 220 }, 221 { 222 name: "normal", 223 db: db, 224 args: args{keys: [][]byte{[]byte("k-1")}}, 225 want: [][]byte{[]byte("v-1")}, 226 wantErr: false, 227 }, 228 { 229 name: "normal-rewrite", 230 db: db, 231 args: args{keys: [][]byte{[]byte("k-1"), []byte("k-3")}}, 232 want: [][]byte{[]byte("v-1"), []byte("v-333")}, 233 wantErr: false, 234 }, 235 { 236 name: "multiple key", 237 db: db, 238 args: args{keys: [][]byte{ 239 []byte("k-1"), 240 []byte("k-2"), 241 []byte("k-4"), 242 []byte("k-5"), 243 }}, 244 want: [][]byte{ 245 []byte("v-1"), 246 []byte("v-2"), 247 []byte("v-4"), 248 []byte("v-5"), 249 }, 250 wantErr: false, 251 }, 252 { 253 name: "missed one key", 254 db: db, 255 args: args{keys: [][]byte{[]byte("missed-k")}}, 256 want: [][]byte{nil}, 257 wantErr: false, 258 }, 259 { 260 name: "missed multiple keys", 261 db: db, 262 args: args{keys: [][]byte{ 263 []byte("missed-k-1"), 264 []byte("missed-k-2"), 265 []byte("missed-k-3"), 266 }}, 267 want: [][]byte{nil, nil, nil}, 268 wantErr: false, 269 }, 270 { 271 name: "missed one key in multiple keys", 272 db: db, 273 args: args{keys: [][]byte{ 274 []byte("k-1"), 275 []byte("missed-k-1"), 276 []byte("k-2"), 277 }}, 278 want: [][]byte{[]byte("v-1"), nil, []byte("v-2")}, 279 wantErr: false, 280 }, 281 { 282 name: "nil key in multiple keys", 283 db: db, 284 args: args{keys: [][]byte{nil, []byte("k-1")}}, 285 want: [][]byte{nil, []byte("v-1")}, 286 wantErr: false, 287 }, 288 { 289 name: "empty key", 290 db: db, 291 args: args{keys: [][]byte{}}, 292 wantErr: true, 293 }, 294 } 295 296 for _, tt := range tests { 297 t.Run(tt.name, func(t *testing.T) { 298 got, err := tt.db.MGet(tt.args.keys) 299 if (err != nil) != tt.wantErr { 300 t.Errorf("MGet() error = %v, wantErr %v", err, tt.wantErr) 301 return 302 } 303 if !reflect.DeepEqual(got, tt.want) { 304 t.Errorf("MGet() got = %v, want %v", got, tt.want) 305 } 306 }) 307 } 308 } 309 310 func TestRoseDB_GetRange(t *testing.T) { 311 t.Run("default", func(t *testing.T) { 312 testRoseDBGetRange(t, FileIO, KeyOnlyMemMode) 313 }) 314 315 t.Run("mmap", func(t *testing.T) { 316 testRoseDBGetRange(t, MMap, KeyOnlyMemMode) 317 }) 318 319 t.Run("key-val-mem-mode", func(t *testing.T) { 320 testRoseDBGetRange(t, MMap, KeyValueMemMode) 321 }) 322 } 323 324 func testRoseDBGetRange(t *testing.T, ioType IOType, mode DataIndexMode) { 325 path := filepath.Join("/tmp", "rosedb") 326 opts := DefaultOptions(path) 327 opts.IoType = ioType 328 opts.IndexMode = mode 329 db, err := Open(opts) 330 assert.Nil(t, err) 331 defer destroyDB(db) 332 333 key := []byte("key") 334 val := []byte("test-val") 335 db.Set(key, val) 336 337 keyEmpty := []byte("key-empty") 338 valEmpty := []byte("") 339 db.Set(keyEmpty, valEmpty) 340 341 type args struct { 342 key []byte 343 start int 344 end int 345 } 346 tests := []struct { 347 name string 348 args args 349 want []byte 350 wantErr bool 351 }{ 352 { 353 name: "key not found", 354 args: args{key: []byte("missing key"), start: 0, end: 7}, 355 want: nil, 356 wantErr: true, 357 }, 358 { 359 name: "empty", 360 args: args{key: keyEmpty, start: 0, end: 0}, 361 want: valEmpty, 362 wantErr: false, 363 }, 364 { 365 name: "all strings", 366 args: args{key: key, start: 0, end: 7}, 367 want: val, 368 wantErr: false, 369 }, 370 { 371 name: "trim 1 length", 372 args: args{key: key, start: 1, end: 6}, 373 want: []byte("est-va"), 374 wantErr: false, 375 }, 376 { 377 name: "all strings with end neg", 378 args: args{key: key, start: 0, end: -1}, 379 want: val, 380 wantErr: false, 381 }, 382 { 383 name: "start neg", 384 args: args{key: key, start: -1, end: 7}, 385 want: []byte("l"), 386 wantErr: false, 387 }, 388 { 389 name: "over start neg limit", 390 args: args{key: key, start: -9, end: 0}, 391 want: []byte("t"), 392 wantErr: false, 393 }, 394 { 395 name: "end neg", 396 args: args{key: key, start: 7, end: -1}, 397 want: []byte("l"), 398 wantErr: false, 399 }, 400 { 401 name: "over end neg limit", 402 args: args{key: key, start: 0, end: -9}, 403 want: []byte("t"), 404 wantErr: false, 405 }, 406 { 407 name: "over end limit", 408 args: args{key: key, start: 0, end: 8}, 409 want: val, 410 wantErr: false, 411 }, 412 { 413 name: "over start limit", 414 args: args{key: key, start: 8, end: 8}, 415 want: []byte{}, 416 wantErr: false, 417 }, 418 { 419 name: "start over end", 420 args: args{key: key, start: 1, end: 0}, 421 want: []byte{}, 422 wantErr: false, 423 }, 424 { 425 name: "start and end both are positive numbers, and start > end", 426 args: args{key: key, start: 3, end: 1}, 427 want: []byte{}, 428 wantErr: false, 429 }, 430 } 431 for _, tt := range tests { 432 t.Run(tt.name, func(t *testing.T) { 433 got, err := db.GetRange(tt.args.key, tt.args.start, tt.args.end) 434 if (err != nil) != tt.wantErr { 435 t.Errorf("GetRange() error = %v, wantErr %v", err, tt.wantErr) 436 return 437 } 438 if !reflect.DeepEqual(got, tt.want) { 439 t.Errorf("GetRange() got = %v, want %v", got, tt.want) 440 } 441 }) 442 } 443 } 444 445 func TestRoseDB_Delete(t *testing.T) { 446 t.Run("default", func(t *testing.T) { 447 testRoseDBDelete(t, FileIO, KeyOnlyMemMode) 448 }) 449 450 t.Run("mmap", func(t *testing.T) { 451 testRoseDBDelete(t, MMap, KeyOnlyMemMode) 452 }) 453 454 t.Run("key-val-mem-mode", func(t *testing.T) { 455 testRoseDBDelete(t, MMap, KeyValueMemMode) 456 }) 457 } 458 459 func TestRoseDB_Delete_MultiFiles(t *testing.T) { 460 path := filepath.Join("/tmp", "rosedb") 461 opts := DefaultOptions(path) 462 opts.IoType = FileIO 463 opts.LogFileSizeThreshold = 32 << 20 464 db, err := Open(opts) 465 assert.Nil(t, err) 466 defer destroyDB(db) 467 468 writeCount := 600000 469 for i := 0; i <= writeCount; i++ { 470 err := db.Set(GetKey(i), GetValue128B()) 471 assert.Nil(t, err) 472 } 473 474 var deletedKeys [][]byte 475 rand.Seed(time.Now().Unix()) 476 for i := 0; i < 10000; i++ { 477 key := GetKey(rand.Intn(writeCount)) 478 err := db.Delete(key) 479 assert.Nil(t, err) 480 deletedKeys = append(deletedKeys, key) 481 } 482 for _, k := range deletedKeys { 483 _, err := db.Get(k) 484 assert.Equal(t, ErrKeyNotFound, err) 485 } 486 } 487 488 func testRoseDBDelete(t *testing.T, ioType IOType, mode DataIndexMode) { 489 path := filepath.Join("/tmp", "rosedb") 490 opts := DefaultOptions(path) 491 opts.IoType = ioType 492 opts.IndexMode = mode 493 db, err := Open(opts) 494 assert.Nil(t, err) 495 defer destroyDB(db) 496 497 db.Set(nil, []byte("v-1111")) 498 db.Set([]byte("k-1"), []byte("v-1")) 499 db.Set([]byte("k-3"), []byte("v-3")) 500 db.Set([]byte("k-3"), []byte("v-333")) 501 502 type args struct { 503 key []byte 504 } 505 tests := []struct { 506 name string 507 db *RoseDB 508 args args 509 wantErr bool 510 }{ 511 { 512 "nil", db, args{key: nil}, false, 513 }, 514 { 515 "normal-1", db, args{key: []byte("k-1")}, false, 516 }, 517 { 518 "normal-2", db, args{key: []byte("k-3")}, false, 519 }, 520 } 521 for _, tt := range tests { 522 t.Run(tt.name, func(t *testing.T) { 523 if err := tt.db.Delete(tt.args.key); (err != nil) != tt.wantErr { 524 t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr) 525 } 526 }) 527 } 528 } 529 530 func TestRoseDB_SetEx(t *testing.T) { 531 t.Run("key-only", func(t *testing.T) { 532 testRoseDBSetEx(t, KeyOnlyMemMode) 533 }) 534 535 t.Run("key-value", func(t *testing.T) { 536 testRoseDBSetEx(t, KeyValueMemMode) 537 }) 538 } 539 540 func testRoseDBSetEx(t *testing.T, mode DataIndexMode) { 541 path := filepath.Join("/tmp", "rosedb") 542 opts := DefaultOptions(path) 543 opts.IndexMode = mode 544 db, err := Open(opts) 545 assert.Nil(t, err) 546 defer destroyDB(db) 547 548 err = db.SetEX(GetKey(1), GetValue16B(), time.Millisecond*200) 549 assert.Nil(t, err) 550 time.Sleep(time.Millisecond * 205) 551 v, err := db.Get(GetKey(1)) 552 assert.Equal(t, 0, len(v)) 553 assert.Equal(t, ErrKeyNotFound, err) 554 555 err = db.SetEX(GetKey(2), GetValue16B(), time.Second*200) 556 assert.Nil(t, err) 557 time.Sleep(time.Millisecond * 200) 558 v1, err := db.Get(GetKey(2)) 559 assert.NotNil(t, v1) 560 assert.Nil(t, err) 561 562 // set an existed key. 563 err = db.Set(GetKey(3), GetValue16B()) 564 assert.Nil(t, err) 565 566 err = db.SetEX(GetKey(3), GetValue16B(), time.Millisecond*200) 567 assert.Nil(t, err) 568 time.Sleep(time.Millisecond * 205) 569 v2, err := db.Get(GetKey(3)) 570 assert.Equal(t, 0, len(v2)) 571 assert.Equal(t, ErrKeyNotFound, err) 572 } 573 574 func TestRoseDB_SetNX(t *testing.T) { 575 t.Run("default", func(t *testing.T) { 576 testRoseDBSetNX(t, FileIO, KeyOnlyMemMode) 577 }) 578 579 t.Run("mmap", func(t *testing.T) { 580 testRoseDBSetNX(t, MMap, KeyOnlyMemMode) 581 }) 582 583 t.Run("key-val-mem-mode", func(t *testing.T) { 584 testRoseDBSetNX(t, FileIO, KeyValueMemMode) 585 }) 586 } 587 588 func testRoseDBSetNX(t *testing.T, ioType IOType, mode DataIndexMode) { 589 path := filepath.Join("/tmp", "rosedb") 590 opts := DefaultOptions(path) 591 opts.IoType = ioType 592 opts.IndexMode = mode 593 db, err := Open(opts) 594 assert.Nil(t, err) 595 defer destroyDB(db) 596 597 type args struct { 598 key []byte 599 value []byte 600 wantErr bool 601 } 602 tests := []struct { 603 name string 604 db *RoseDB 605 args []args 606 }{ 607 { 608 name: "nil-key", 609 db: db, 610 args: []args{{key: nil, value: []byte("val-1")}}, 611 }, 612 { 613 name: "nil-value", 614 db: db, 615 args: []args{{key: []byte("key-1"), value: nil}}, 616 }, 617 { 618 name: "not exist in db", 619 db: db, 620 args: []args{ 621 { 622 key: []byte("key-1"), 623 value: []byte("val-1"), 624 wantErr: false, 625 }, 626 }, 627 }, 628 { 629 name: "exist in db", 630 db: db, 631 args: []args{ 632 { 633 key: []byte("key-1"), 634 value: []byte("val-1"), 635 wantErr: false, 636 }, 637 { 638 key: []byte("key-1"), 639 value: []byte("val-1"), 640 wantErr: false, 641 }, 642 }, 643 }, 644 { 645 name: "not exist in multiple valued db", 646 db: db, 647 args: []args{ 648 { 649 key: []byte("key-1"), 650 value: []byte("value-1"), 651 wantErr: false, 652 }, 653 { 654 key: []byte("key-2"), 655 value: []byte("value-2"), 656 wantErr: false, 657 }, 658 }, 659 }, 660 } 661 for _, tt := range tests { 662 t.Run(tt.name, func(t *testing.T) { 663 for _, arg := range tt.args { 664 if err := tt.db.SetNX(arg.key, arg.value); (err != nil) != arg.wantErr { 665 t.Errorf("Set() error = %v, wantErr %v", err, arg.wantErr) 666 } 667 } 668 }) 669 } 670 } 671 672 func TestRoseDB_MSet(t *testing.T) { 673 t.Run("default", func(t *testing.T) { 674 testRoseDBMSet(t, FileIO, KeyOnlyMemMode) 675 }) 676 677 t.Run("mmap", func(t *testing.T) { 678 testRoseDBMSet(t, MMap, KeyOnlyMemMode) 679 }) 680 681 t.Run("key-val-mem-mode", func(t *testing.T) { 682 testRoseDBMSet(t, FileIO, KeyValueMemMode) 683 }) 684 } 685 686 func testRoseDBMSet(t *testing.T, ioType IOType, mode DataIndexMode) { 687 path := filepath.Join("/tmp", "rosedb") 688 opts := DefaultOptions(path) 689 opts.IoType = ioType 690 opts.IndexMode = mode 691 db, err := Open(opts) 692 assert.Nil(t, err) 693 defer destroyDB(db) 694 695 tests := []struct { 696 name string 697 db *RoseDB 698 args [][]byte 699 wantErr bool 700 }{ 701 { 702 name: "nil-key", 703 db: db, 704 args: [][]byte{nil, []byte("val-1")}, 705 wantErr: false, 706 }, 707 { 708 name: "nil-value", 709 db: db, 710 args: [][]byte{[]byte("key-1"), nil}, 711 wantErr: false, 712 }, 713 { 714 name: "empty pair", 715 db: db, 716 args: [][]byte{}, 717 wantErr: true, 718 }, 719 { 720 name: "one pair", 721 db: db, 722 args: [][]byte{[]byte("key-1"), []byte("value-1")}, 723 wantErr: false, 724 }, 725 { 726 name: "multiple pair", 727 db: db, 728 args: [][]byte{ 729 []byte("key-1"), []byte("value-1"), 730 []byte("key-2"), []byte("value-2"), 731 []byte("key-3"), []byte("value-3"), 732 }, 733 wantErr: false, 734 }, 735 { 736 name: "wrong number of key-value", 737 db: db, 738 args: [][]byte{ 739 []byte("key-1"), []byte("value-1"), 740 []byte("key-2"), []byte("value-2"), 741 []byte("key-3"), 742 }, 743 wantErr: true, 744 }, 745 } 746 for _, tt := range tests { 747 t.Run(tt.name, func(t *testing.T) { 748 err := tt.db.MSet(tt.args...) 749 if (err != nil) != tt.wantErr { 750 t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) 751 } 752 if tt.wantErr == true && !errors.Is(err, ErrWrongNumberOfArgs) { 753 t.Errorf("Set() error = %v, expected error = %v", err, ErrWrongNumberOfArgs) 754 } 755 }) 756 } 757 } 758 759 func TestRoseDB_Append(t *testing.T) { 760 t.Run("default", func(t *testing.T) { 761 testRoseDBAppend(t, FileIO, KeyOnlyMemMode) 762 }) 763 764 t.Run("mmap", func(t *testing.T) { 765 testRoseDBAppend(t, MMap, KeyOnlyMemMode) 766 }) 767 768 t.Run("key-val-mem-mode", func(t *testing.T) { 769 testRoseDBAppend(t, FileIO, KeyValueMemMode) 770 }) 771 } 772 773 func testRoseDBAppend(t *testing.T, ioType IOType, mode DataIndexMode) { 774 path := filepath.Join("/tmp", "rosedb") 775 opts := DefaultOptions(path) 776 opts.IoType = ioType 777 opts.IndexMode = mode 778 db, err := Open(opts) 779 assert.Nil(t, err) 780 defer destroyDB(db) 781 782 type args struct { 783 key []byte 784 value []byte 785 } 786 tests := []struct { 787 name string 788 db *RoseDB 789 args args 790 wantErr bool 791 }{ 792 { 793 "nil-key", db, args{key: nil, value: []byte("val-1")}, false, 794 }, 795 { 796 "nil-value", db, args{key: []byte("key-1"), value: nil}, false, 797 }, 798 { 799 "not exist in db", db, args{key: []byte("key-2"), value: []byte("val-2")}, false, 800 }, 801 { 802 "exist in db", db, args{key: []byte("key-2"), value: []byte("val-2")}, false, 803 }, 804 } 805 for _, tt := range tests { 806 t.Run(tt.name, func(t *testing.T) { 807 if err := tt.db.Append(tt.args.key, tt.args.value); (err != nil) != tt.wantErr { 808 t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) 809 } 810 }) 811 } 812 } 813 814 func TestRoseDB_MSetNX(t *testing.T) { 815 t.Run("default", func(t *testing.T) { 816 testRoseDBMSetNX(t, FileIO, KeyOnlyMemMode) 817 }) 818 819 t.Run("mmap", func(t *testing.T) { 820 testRoseDBMSetNX(t, MMap, KeyOnlyMemMode) 821 }) 822 823 t.Run("key-val-mem-mode", func(t *testing.T) { 824 testRoseDBMSetNX(t, FileIO, KeyValueMemMode) 825 }) 826 } 827 828 func testRoseDBMSetNX(t *testing.T, ioType IOType, mode DataIndexMode) { 829 path := filepath.Join("/tmp", "rosedb") 830 opts := DefaultOptions(path) 831 opts.IoType = ioType 832 opts.IndexMode = mode 833 db, err := Open(opts) 834 assert.Nil(t, err) 835 defer destroyDB(db) 836 837 _ = db.Set([]byte("key-10"), []byte("value-10")) 838 tests := []struct { 839 name string 840 db *RoseDB 841 args [][]byte 842 expDuplicateKey []byte 843 expDuplicateVal []byte 844 wantErr bool 845 }{ 846 { 847 name: "nil-key", 848 db: db, 849 args: [][]byte{nil, []byte("val-1")}, 850 wantErr: false, 851 }, 852 { 853 name: "nil-value", 854 db: db, 855 args: [][]byte{[]byte("key-1"), nil}, 856 wantErr: false, 857 }, 858 { 859 name: "empty pair", 860 db: db, 861 args: [][]byte{}, 862 wantErr: true, 863 }, 864 { 865 name: "one pair", 866 db: db, 867 args: [][]byte{[]byte("key-1"), []byte("value-1")}, 868 wantErr: false, 869 }, 870 { 871 name: "multiple pair - no duplicate", 872 db: db, 873 args: [][]byte{ 874 []byte("key-1"), []byte("value-1"), 875 []byte("key-2"), []byte("value-2"), 876 []byte("key-3"), []byte("value-3"), 877 }, 878 wantErr: false, 879 }, 880 { 881 name: "multiple pair - duplicate exists", 882 db: db, 883 args: [][]byte{ 884 []byte("key-11"), []byte("value-1"), 885 []byte("key-12"), []byte("value-2"), 886 []byte("key-12"), []byte("value-3")}, 887 expDuplicateKey: []byte("key-12"), 888 expDuplicateVal: []byte("value-2"), 889 wantErr: false, 890 }, 891 { 892 name: "multiple pair - already exists", 893 db: db, 894 args: [][]byte{ 895 []byte("key-1"), []byte("value-1"), 896 []byte("key-2"), []byte("value-2"), 897 []byte("key-10"), []byte("value-20"), 898 }, 899 expDuplicateKey: []byte("key-10"), 900 expDuplicateVal: []byte("value-10"), 901 wantErr: false, 902 }, 903 { 904 name: "wrong number of key-value", 905 db: db, 906 args: [][]byte{ 907 []byte("key-1"), []byte("value-1"), 908 []byte("key-2"), []byte("value-2"), 909 []byte("key-3"), 910 }, 911 wantErr: true, 912 }, 913 } 914 for _, tt := range tests { 915 t.Run(tt.name, func(t *testing.T) { 916 err = tt.db.MSetNX(tt.args...) 917 if (err != nil) != tt.wantErr { 918 t.Errorf("MSetNX() error = %v, wantErr %v", err, tt.wantErr) 919 } 920 if tt.wantErr == true && !errors.Is(err, ErrWrongNumberOfArgs) { 921 t.Errorf("MSetNX() error = %v, expected error = %v", err, ErrWrongNumberOfArgs) 922 } 923 if tt.expDuplicateVal != nil { 924 val, _ := tt.db.Get(tt.expDuplicateKey) 925 if !bytes.Equal(val, tt.expDuplicateVal) { 926 t.Errorf("expected duplicate value = %v, got = %v", string(tt.expDuplicateVal), string(val)) 927 } 928 } 929 }) 930 } 931 } 932 933 func TestRoseDB_Decr(t *testing.T) { 934 t.Run("default", func(t *testing.T) { 935 testRoseDBDecr(t, FileIO, KeyOnlyMemMode) 936 }) 937 938 t.Run("mmap", func(t *testing.T) { 939 testRoseDBDecr(t, MMap, KeyOnlyMemMode) 940 }) 941 942 t.Run("key-val-mem-mode", func(t *testing.T) { 943 testRoseDBDecr(t, FileIO, KeyValueMemMode) 944 }) 945 } 946 947 func testRoseDBDecr(t *testing.T, ioType IOType, mode DataIndexMode) { 948 path := filepath.Join("/tmp", "rosedb") 949 opts := DefaultOptions(path) 950 opts.IoType = ioType 951 opts.IndexMode = mode 952 db, err := Open(opts) 953 assert.Nil(t, err) 954 defer destroyDB(db) 955 956 _ = db.MSet([]byte("nil-value"), nil, 957 []byte("ten"), []byte("10"), 958 []byte("min"), []byte(strconv.Itoa(math.MinInt64)), 959 []byte("str-key"), []byte("str-val")) 960 tests := []struct { 961 name string 962 db *RoseDB 963 key []byte 964 expVal int64 965 expByte []byte 966 expErr error 967 wantErr bool 968 }{ 969 { 970 name: "nil value", 971 db: db, 972 key: []byte("nil-value"), 973 expVal: -1, 974 expByte: []byte("-1"), 975 wantErr: false, 976 }, 977 { 978 name: "exist key", 979 db: db, 980 key: []byte("ten"), 981 expVal: 9, 982 expByte: []byte("9"), 983 wantErr: false, 984 }, 985 { 986 name: "non-exist key", 987 db: db, 988 key: []byte("zero"), 989 expVal: -1, 990 expByte: []byte("-1"), 991 wantErr: false, 992 }, 993 { 994 name: "overflow value", 995 db: db, 996 key: []byte("min"), 997 expVal: 0, 998 expByte: []byte(strconv.Itoa(math.MinInt64)), 999 expErr: ErrIntegerOverflow, 1000 wantErr: true, 1001 }, 1002 { 1003 name: "wrong type", 1004 db: db, 1005 key: []byte("str-key"), 1006 expVal: 0, 1007 expErr: ErrWrongValueType, 1008 wantErr: true, 1009 }, 1010 } 1011 1012 for _, tt := range tests { 1013 t.Run(tt.name, func(t *testing.T) { 1014 newVal, err := tt.db.Decr(tt.key) 1015 if (err != nil) != tt.wantErr || err != tt.expErr { 1016 t.Errorf("Decr() error = %v, wantErr = %v", err, tt.expErr) 1017 } 1018 if newVal != tt.expVal { 1019 t.Errorf("Decr() expected value = %v, actual value = %v", tt.expVal, newVal) 1020 } 1021 val, _ := tt.db.Get(tt.key) 1022 if tt.expByte != nil && !bytes.Equal(val, tt.expByte) { 1023 t.Errorf("Decr() expected value = %v, actual = %v", tt.expByte, val) 1024 } 1025 }) 1026 } 1027 } 1028 1029 func TestRoseDB_DecrBy(t *testing.T) { 1030 t.Run("default", func(t *testing.T) { 1031 testRoseDBDecrBy(t, FileIO, KeyOnlyMemMode) 1032 }) 1033 1034 t.Run("mmap", func(t *testing.T) { 1035 testRoseDBDecrBy(t, MMap, KeyOnlyMemMode) 1036 }) 1037 1038 t.Run("key-val-mem-mode", func(t *testing.T) { 1039 testRoseDBDecrBy(t, FileIO, KeyValueMemMode) 1040 }) 1041 } 1042 1043 func testRoseDBDecrBy(t *testing.T, ioType IOType, mode DataIndexMode) { 1044 path := filepath.Join("/tmp", "rosedb") 1045 opts := DefaultOptions(path) 1046 opts.IoType = ioType 1047 opts.IndexMode = mode 1048 db, err := Open(opts) 1049 assert.Nil(t, err) 1050 defer destroyDB(db) 1051 1052 _ = db.MSet([]byte("nil-value"), nil, 1053 []byte("ten"), []byte("10"), 1054 []byte("min"), []byte(strconv.Itoa(math.MinInt64)), 1055 []byte("max"), []byte(strconv.Itoa(math.MaxInt64)), 1056 []byte("str-key"), []byte("str-val"), 1057 []byte("neg"), []byte("11")) 1058 tests := []struct { 1059 name string 1060 db *RoseDB 1061 key []byte 1062 decr int64 1063 expVal int64 1064 expByte []byte 1065 expErr error 1066 wantErr bool 1067 }{ 1068 { 1069 name: "nil value", 1070 db: db, 1071 key: []byte("nil-value"), 1072 decr: 10, 1073 expVal: -10, 1074 expByte: []byte("-10"), 1075 wantErr: false, 1076 }, 1077 { 1078 name: "exist key", 1079 db: db, 1080 key: []byte("ten"), 1081 decr: 25, 1082 expVal: -15, 1083 expByte: []byte("-15"), 1084 wantErr: false, 1085 }, 1086 { 1087 name: "non-exist key", 1088 db: db, 1089 key: []byte("zero"), 1090 decr: 3, 1091 expVal: -3, 1092 expByte: []byte("-3"), 1093 wantErr: false, 1094 }, 1095 { 1096 name: "overflow value-min", 1097 db: db, 1098 key: []byte("min"), 1099 decr: 3, 1100 expVal: 0, 1101 expByte: []byte(strconv.Itoa(math.MinInt64)), 1102 expErr: ErrIntegerOverflow, 1103 wantErr: true, 1104 }, 1105 { 1106 name: "overflow value-max", 1107 db: db, 1108 key: []byte("max"), 1109 decr: -10, 1110 expVal: 0, 1111 expByte: []byte(strconv.Itoa(math.MaxInt64)), 1112 expErr: ErrIntegerOverflow, 1113 wantErr: true, 1114 }, 1115 { 1116 name: "wrong type", 1117 db: db, 1118 key: []byte("str-key"), 1119 decr: 5, 1120 expVal: 0, 1121 expErr: ErrWrongValueType, 1122 wantErr: true, 1123 }, 1124 { 1125 name: "negative incr", 1126 db: db, 1127 key: []byte("neg"), 1128 decr: -4, 1129 expVal: 15, 1130 expByte: []byte("15"), 1131 wantErr: false, 1132 }, 1133 } 1134 1135 for _, tt := range tests { 1136 t.Run(tt.name, func(t *testing.T) { 1137 newVal, err := tt.db.DecrBy(tt.key, tt.decr) 1138 if (err != nil) != tt.wantErr || err != tt.expErr { 1139 t.Errorf("DecrBy() error = %v, wantErr = %v", err, tt.expErr) 1140 } 1141 if newVal != tt.expVal { 1142 t.Errorf("DecrBy() expected value = %v, actual value = %v", tt.expVal, newVal) 1143 } 1144 val, _ := tt.db.Get(tt.key) 1145 if tt.expByte != nil && !bytes.Equal(val, tt.expByte) { 1146 t.Errorf("DecrBy() expected value = %v, actual = %v", tt.expByte, val) 1147 } 1148 }) 1149 } 1150 } 1151 1152 func TestRoseDB_Incr(t *testing.T) { 1153 t.Run("default", func(t *testing.T) { 1154 testRoseDBIncr(t, FileIO, KeyOnlyMemMode) 1155 }) 1156 1157 t.Run("mmap", func(t *testing.T) { 1158 testRoseDBIncr(t, MMap, KeyOnlyMemMode) 1159 }) 1160 1161 t.Run("key-val-mem-mode", func(t *testing.T) { 1162 testRoseDBIncr(t, FileIO, KeyValueMemMode) 1163 }) 1164 } 1165 1166 func testRoseDBIncr(t *testing.T, ioType IOType, mode DataIndexMode) { 1167 path := filepath.Join("/tmp", "rosedb") 1168 opts := DefaultOptions(path) 1169 opts.IoType = ioType 1170 opts.IndexMode = mode 1171 db, err := Open(opts) 1172 assert.Nil(t, err) 1173 defer destroyDB(db) 1174 1175 _ = db.MSet([]byte("nil-value"), nil, 1176 []byte("ten"), []byte("10"), 1177 []byte("max"), []byte(strconv.Itoa(math.MaxInt64)), 1178 []byte("str-key"), []byte("str-val")) 1179 tests := []struct { 1180 name string 1181 db *RoseDB 1182 key []byte 1183 expVal int64 1184 expByte []byte 1185 expErr error 1186 wantErr bool 1187 }{ 1188 { 1189 name: "nil value", 1190 db: db, 1191 key: []byte("nil-value"), 1192 expVal: 1, 1193 expByte: []byte("1"), 1194 wantErr: false, 1195 }, 1196 { 1197 name: "exist key", 1198 db: db, 1199 key: []byte("ten"), 1200 expVal: 11, 1201 expByte: []byte("11"), 1202 wantErr: false, 1203 }, 1204 { 1205 name: "non-exist key", 1206 db: db, 1207 key: []byte("zero"), 1208 expVal: 1, 1209 expByte: []byte("1"), 1210 wantErr: false, 1211 }, 1212 { 1213 name: "overflow value-max", 1214 db: db, 1215 key: []byte("max"), 1216 expVal: 0, 1217 expByte: []byte(strconv.Itoa(math.MaxInt64)), 1218 expErr: ErrIntegerOverflow, 1219 wantErr: true, 1220 }, 1221 { 1222 name: "wrong type", 1223 db: db, 1224 key: []byte("str-key"), 1225 expVal: 0, 1226 expErr: ErrWrongValueType, 1227 wantErr: true, 1228 }, 1229 } 1230 1231 for _, tt := range tests { 1232 t.Run(tt.name, func(t *testing.T) { 1233 newVal, err := tt.db.Incr(tt.key) 1234 if (err != nil) != tt.wantErr || err != tt.expErr { 1235 t.Errorf("Incr() error = %v, wantErr = %v", err, tt.expErr) 1236 } 1237 if newVal != tt.expVal { 1238 t.Errorf("Incr() expected value = %v, actual value = %v", tt.expVal, newVal) 1239 } 1240 val, _ := tt.db.Get(tt.key) 1241 if tt.expByte != nil && !bytes.Equal(val, tt.expByte) { 1242 t.Errorf("Incr() expected value = %v, actual = %v", tt.expByte, val) 1243 } 1244 }) 1245 } 1246 } 1247 1248 func TestRoseDB_IncrBy(t *testing.T) { 1249 t.Run("default", func(t *testing.T) { 1250 testRoseDBIncrBy(t, FileIO, KeyOnlyMemMode) 1251 }) 1252 1253 t.Run("mmap", func(t *testing.T) { 1254 testRoseDBIncrBy(t, MMap, KeyOnlyMemMode) 1255 }) 1256 1257 t.Run("key-val-mem-mode", func(t *testing.T) { 1258 testRoseDBIncrBy(t, FileIO, KeyValueMemMode) 1259 }) 1260 } 1261 1262 func testRoseDBIncrBy(t *testing.T, ioType IOType, mode DataIndexMode) { 1263 path := filepath.Join("/tmp", "rosedb") 1264 opts := DefaultOptions(path) 1265 opts.IoType = ioType 1266 opts.IndexMode = mode 1267 db, err := Open(opts) 1268 assert.Nil(t, err) 1269 defer destroyDB(db) 1270 1271 _ = db.MSet([]byte("nil-value"), nil, 1272 []byte("ten"), []byte("10"), 1273 []byte("min"), []byte(strconv.Itoa(math.MinInt64)), 1274 []byte("max"), []byte(strconv.Itoa(math.MaxInt64)), 1275 []byte("str-key"), []byte("str-val"), 1276 []byte("neg"), []byte("11")) 1277 tests := []struct { 1278 name string 1279 db *RoseDB 1280 key []byte 1281 incr int64 1282 expVal int64 1283 expByte []byte 1284 expErr error 1285 wantErr bool 1286 }{ 1287 { 1288 name: "nil value", 1289 db: db, 1290 key: []byte("nil-value"), 1291 incr: 10, 1292 expVal: 10, 1293 expByte: []byte("10"), 1294 wantErr: false, 1295 }, 1296 { 1297 name: "exist key", 1298 db: db, 1299 key: []byte("ten"), 1300 incr: 25, 1301 expVal: 35, 1302 expByte: []byte("35"), 1303 wantErr: false, 1304 }, 1305 { 1306 name: "non-exist key", 1307 db: db, 1308 key: []byte("zero"), 1309 incr: 3, 1310 expVal: 3, 1311 expByte: []byte("3"), 1312 wantErr: false, 1313 }, 1314 { 1315 name: "overflow value-min", 1316 db: db, 1317 key: []byte("min"), 1318 incr: -3, 1319 expVal: 0, 1320 expByte: []byte(strconv.Itoa(math.MinInt64)), 1321 expErr: ErrIntegerOverflow, 1322 wantErr: true, 1323 }, 1324 { 1325 name: "overflow value-max", 1326 db: db, 1327 key: []byte("max"), 1328 incr: 10, 1329 expVal: 0, 1330 expByte: []byte(strconv.Itoa(math.MaxInt64)), 1331 expErr: ErrIntegerOverflow, 1332 wantErr: true, 1333 }, 1334 { 1335 name: "wrong type", 1336 db: db, 1337 key: []byte("str-key"), 1338 incr: 5, 1339 expVal: 0, 1340 expErr: ErrWrongValueType, 1341 wantErr: true, 1342 }, 1343 { 1344 name: "negative incr", 1345 db: db, 1346 key: []byte("neg"), 1347 incr: -4, 1348 expVal: 7, 1349 expByte: []byte("7"), 1350 wantErr: false, 1351 }, 1352 } 1353 1354 for _, tt := range tests { 1355 t.Run(tt.name, func(t *testing.T) { 1356 newVal, err := tt.db.IncrBy(tt.key, tt.incr) 1357 if (err != nil) != tt.wantErr || err != tt.expErr { 1358 t.Errorf("IncrBy() error = %v, wantErr = %v", err, tt.expErr) 1359 } 1360 if newVal != tt.expVal { 1361 t.Errorf("IncrBy() expected value = %v, actual value = %v", tt.expVal, newVal) 1362 } 1363 val, _ := tt.db.Get(tt.key) 1364 if tt.expByte != nil && !bytes.Equal(val, tt.expByte) { 1365 t.Errorf("IncrBy() expected value = %v, actual = %v", tt.expByte, val) 1366 } 1367 }) 1368 } 1369 } 1370 1371 func TestRoseDB_StrLen(t *testing.T) { 1372 t.Run("default", func(t *testing.T) { 1373 testRoseDBStrLen(t, FileIO, KeyOnlyMemMode) 1374 }) 1375 1376 t.Run("mmap", func(t *testing.T) { 1377 testRoseDBStrLen(t, MMap, KeyOnlyMemMode) 1378 }) 1379 1380 t.Run("key-val-mem-mode", func(t *testing.T) { 1381 testRoseDBStrLen(t, FileIO, KeyValueMemMode) 1382 }) 1383 } 1384 1385 func testRoseDBStrLen(t *testing.T, ioType IOType, mode DataIndexMode) { 1386 path := filepath.Join("/tmp", "rosedb") 1387 opts := DefaultOptions(path) 1388 opts.IoType = ioType 1389 opts.IndexMode = mode 1390 db, err := Open(opts) 1391 assert.Nil(t, err) 1392 defer destroyDB(db) 1393 1394 _ = db.MSet([]byte("string"), []byte("value"), []byte("empty"), []byte("")) 1395 1396 tests := []struct { 1397 name string 1398 db *RoseDB 1399 key []byte 1400 expLen int 1401 }{ 1402 { 1403 name: "Empty", 1404 db: db, 1405 key: []byte("empty"), 1406 expLen: 0, 1407 }, 1408 { 1409 name: "not exist", 1410 db: db, 1411 key: []byte("not-exist-key"), 1412 expLen: 0, 1413 }, 1414 { 1415 name: "normal string", 1416 db: db, 1417 key: []byte("string"), 1418 expLen: 5, 1419 }, 1420 } 1421 1422 for _, tt := range tests { 1423 t.Run(tt.name, func(t *testing.T) { 1424 strLen := tt.db.StrLen(tt.key) 1425 if strLen != tt.expLen { 1426 t.Errorf("StrLen() expected length = %v, actual length = %v", tt.expLen, strLen) 1427 } 1428 }) 1429 } 1430 } 1431 1432 func TestRoseDB_GetDel(t *testing.T) { 1433 t.Run("default", func(t *testing.T) { 1434 testRoseDBGetDel(t, FileIO, KeyOnlyMemMode) 1435 }) 1436 1437 t.Run("mmap", func(t *testing.T) { 1438 testRoseDBGetDel(t, MMap, KeyOnlyMemMode) 1439 }) 1440 1441 t.Run("key-val-mem-mode", func(t *testing.T) { 1442 testRoseDBGetDel(t, FileIO, KeyValueMemMode) 1443 }) 1444 } 1445 1446 func testRoseDBGetDel(t *testing.T, ioType IOType, mode DataIndexMode) { 1447 path := filepath.Join("/tmp", "rosedb") 1448 opts := DefaultOptions(path) 1449 opts.IoType = ioType 1450 opts.IndexMode = mode 1451 db, err := Open(opts) 1452 assert.Nil(t, err) 1453 defer destroyDB(db) 1454 1455 _ = db.MSet( 1456 []byte("nil-value"), nil, 1457 []byte("key-1"), []byte("value-1"), 1458 []byte("key-2"), []byte("value-2"), 1459 []byte("key-3"), []byte("value-3"), 1460 []byte("key-4"), []byte("value-4"), 1461 ) 1462 tests := []struct { 1463 name string 1464 db *RoseDB 1465 key []byte 1466 expVal []byte 1467 expErr error 1468 }{ 1469 { 1470 name: "nil value", 1471 db: db, 1472 key: []byte("nil-value"), 1473 expVal: nil, 1474 expErr: nil, 1475 }, 1476 { 1477 name: "not exist in db", 1478 db: db, 1479 key: []byte("not-exist-key"), 1480 expVal: nil, 1481 expErr: nil, 1482 }, 1483 { 1484 name: "exist in db", 1485 db: db, 1486 key: []byte("key-1"), 1487 expVal: []byte("value-1"), 1488 expErr: nil, 1489 }, 1490 } 1491 1492 for _, tt := range tests { 1493 t.Run(tt.name, func(t *testing.T) { 1494 val, err := tt.db.GetDel(tt.key) 1495 if err != tt.expErr { 1496 t.Errorf("GetDel(): expected error: %+v, actual error: %+v", tt.expErr, err) 1497 } 1498 if !bytes.Equal(val, tt.expVal) { 1499 t.Errorf("GetDel(): expected val: %v, actual val: %v", tt.expVal, val) 1500 } 1501 1502 val, _ = tt.db.Get(tt.key) 1503 if val != nil { 1504 t.Errorf("GetDel(): expected val(after Get()): <nil>, actual val(after Get()): %v", val) 1505 } 1506 }) 1507 } 1508 } 1509 1510 func TestRoseDB_DiscardStat_Strs(t *testing.T) { 1511 helper := func(isDelete bool) { 1512 path := filepath.Join("/tmp", "rosedb") 1513 opts := DefaultOptions(path) 1514 opts.LogFileSizeThreshold = 64 << 20 1515 db, err := Open(opts) 1516 assert.Nil(t, err) 1517 defer destroyDB(db) 1518 1519 writeCount := 500000 1520 for i := 0; i < writeCount/2; i++ { 1521 err := db.Set(GetKey(i), GetValue128B()) 1522 assert.Nil(t, err) 1523 } 1524 1525 if isDelete { 1526 for i := 0; i < writeCount/2; i++ { 1527 err := db.Delete(GetKey(i)) 1528 assert.Nil(t, err) 1529 } 1530 } else { 1531 for i := 0; i < writeCount/2; i++ { 1532 err := db.Set(GetKey(i), GetValue128B()) 1533 assert.Nil(t, err) 1534 } 1535 } 1536 _ = db.Sync() 1537 ccl, err := db.discards[String].getCCL(10, 0.5) 1538 assert.Nil(t, err) 1539 assert.Equal(t, 1, len(ccl)) 1540 } 1541 1542 t.Run("rewrite", func(t *testing.T) { 1543 helper(false) 1544 }) 1545 1546 t.Run("delete", func(t *testing.T) { 1547 helper(true) 1548 }) 1549 } 1550 1551 func TestRoseDB_StrsGC(t *testing.T) { 1552 path := filepath.Join("/tmp", "rosedb") 1553 opts := DefaultOptions(path) 1554 opts.LogFileSizeThreshold = 64 << 20 1555 db, err := Open(opts) 1556 assert.Nil(t, err) 1557 defer destroyDB(db) 1558 1559 writeCount := 1000000 1560 for i := 0; i < writeCount; i++ { 1561 err := db.Set(GetKey(i), GetValue16B()) 1562 assert.Nil(t, err) 1563 } 1564 for i := 0; i < writeCount/4; i++ { 1565 err := db.Delete(GetKey(i)) 1566 assert.Nil(t, err) 1567 } 1568 1569 err = db.RunLogFileGC(String, 0, 0.6) 1570 assert.Nil(t, err) 1571 size := db.strIndex.idxTree.Size() 1572 assert.Equal(t, writeCount-writeCount/4, size) 1573 } 1574 1575 func TestRoseDB_Count(t *testing.T) { 1576 path := filepath.Join("/tmp", "rosedb") 1577 opts := DefaultOptions(path) 1578 db, err := Open(opts) 1579 assert.Nil(t, err) 1580 defer destroyDB(db) 1581 1582 c1 := db.Count() 1583 assert.Equal(t, 0, c1) 1584 1585 for i := 0; i < 100; i++ { 1586 err = db.Set(GetKey(i), GetValue16B()) 1587 assert.Nil(t, err) 1588 } 1589 c2 := db.Count() 1590 assert.Equal(t, 100, c2) 1591 } 1592 1593 func TestRoseDB_Scan(t *testing.T) { 1594 t.Run("fileio", func(t *testing.T) { 1595 testRoseDBScan(t, FileIO, KeyOnlyMemMode) 1596 }) 1597 1598 t.Run("mmap", func(t *testing.T) { 1599 testRoseDBScan(t, MMap, KeyValueMemMode) 1600 }) 1601 } 1602 1603 func testRoseDBScan(t *testing.T, ioType IOType, mode DataIndexMode) { 1604 path := filepath.Join("/tmp", "rosedb") 1605 opts := DefaultOptions(path) 1606 opts.IoType = ioType 1607 opts.IndexMode = mode 1608 db, err := Open(opts) 1609 assert.Nil(t, err) 1610 defer destroyDB(db) 1611 1612 for i := 0; i < 100; i++ { 1613 err = db.Set(GetKey(i), GetValue16B()) 1614 assert.Nil(t, err) 1615 } 1616 1617 values, err := db.Scan(nil, "", 10) 1618 assert.Nil(t, err) 1619 assert.Equal(t, 20, len(values)) 1620 1621 db.Set([]byte("aba"), GetValue16B()) 1622 db.Set([]byte("aab"), GetValue16B()) 1623 db.Set([]byte("aac"), GetValue16B()) 1624 db.Set([]byte("abc"), GetValue16B()) 1625 1626 values, err = db.Scan([]byte("ab"), "", 20) 1627 assert.Nil(t, err) 1628 assert.Equal(t, 4, len(values)) 1629 1630 db.Set([]byte("1223"), GetValue16B()) 1631 db.Set([]byte("55"), GetValue16B()) 1632 db.Set([]byte("9001"), GetValue16B()) 1633 1634 values, err = db.Scan(nil, "^[0-9]*$", 3) 1635 assert.Nil(t, err) 1636 assert.Equal(t, 6, len(values)) 1637 } 1638 1639 func TestRoseDB_Expire(t *testing.T) { 1640 t.Run("fileio", func(t *testing.T) { 1641 testRoseDBExpire(t, FileIO, KeyOnlyMemMode) 1642 }) 1643 1644 t.Run("mmap", func(t *testing.T) { 1645 testRoseDBExpire(t, MMap, KeyValueMemMode) 1646 }) 1647 } 1648 1649 func testRoseDBExpire(t *testing.T, ioType IOType, mode DataIndexMode) { 1650 path := filepath.Join("/tmp", "rosedb") 1651 opts := DefaultOptions(path) 1652 opts.IoType = ioType 1653 opts.IndexMode = mode 1654 db, err := Open(opts) 1655 assert.Nil(t, err) 1656 defer destroyDB(db) 1657 1658 t.Run("normal", func(t *testing.T) { 1659 err = db.Expire(GetKey(31), time.Second*2) 1660 assert.Equal(t, ErrKeyNotFound, err) 1661 1662 err = db.Set(GetKey(55), GetValue16B()) 1663 assert.Nil(t, err) 1664 err = db.Expire(GetKey(55), time.Second*1) 1665 assert.Nil(t, err) 1666 1667 time.Sleep(time.Second) 1668 _, err = db.Get(GetKey(55)) 1669 assert.Equal(t, ErrKeyNotFound, err) 1670 }) 1671 1672 t.Run("set-twice", func(t *testing.T) { 1673 err := db.Set(GetKey(66), GetValue16B()) 1674 assert.Nil(t, err) 1675 1676 db.Expire(GetKey(66), time.Second*100) 1677 db.Expire(GetKey(66), time.Second*1) 1678 time.Sleep(time.Second) 1679 _, err = db.Get(GetKey(66)) 1680 assert.Equal(t, ErrKeyNotFound, err) 1681 }) 1682 } 1683 1684 func TestRoseDB_TTL(t *testing.T) { 1685 path := filepath.Join("/tmp", "rosedb") 1686 opts := DefaultOptions(path) 1687 db, err := Open(opts) 1688 assert.Nil(t, err) 1689 defer destroyDB(db) 1690 1691 t1, err := db.TTL(GetKey(111)) 1692 assert.Equal(t, int64(0), t1) 1693 assert.Equal(t, ErrKeyNotFound, err) 1694 1695 err = db.SetEX(GetKey(123), GetValue16B(), time.Second*30) 1696 assert.Nil(t, err) 1697 1698 t2, err := db.TTL(GetKey(123)) 1699 assert.Equal(t, int64(30), t2) 1700 assert.Nil(t, err) 1701 1702 err = db.Set(GetKey(007), GetValue16B()) 1703 assert.Nil(t, err) 1704 db.Expire(GetKey(007), time.Second*50) 1705 1706 t3, err := db.TTL(GetKey(007)) 1707 assert.Equal(t, int64(50), t3) 1708 assert.Nil(t, err) 1709 1710 db.SetEX(GetKey(999), GetValue16B(), time.Second*5) 1711 db.Expire(GetKey(999), time.Second*100) 1712 db.Expire(GetKey(999), time.Second*10) 1713 1714 t4, err := db.TTL(GetKey(999)) 1715 assert.Equal(t, int64(10), t4) 1716 assert.Nil(t, err) 1717 } 1718 1719 func TestRoseDB_Persist(t *testing.T) { 1720 t.Run("fileio", func(t *testing.T) { 1721 testRoseDBPersist(t, FileIO, KeyOnlyMemMode) 1722 }) 1723 1724 t.Run("mmap", func(t *testing.T) { 1725 testRoseDBPersist(t, MMap, KeyValueMemMode) 1726 }) 1727 } 1728 1729 func testRoseDBPersist(t *testing.T, ioType IOType, mode DataIndexMode) { 1730 path := filepath.Join("/tmp", "rosedb") 1731 opts := DefaultOptions(path) 1732 opts.IoType = ioType 1733 opts.IndexMode = mode 1734 db, err := Open(opts) 1735 assert.Nil(t, err) 1736 defer destroyDB(db) 1737 1738 err = db.SetEX(GetKey(900), GetValue16B(), time.Second*1) 1739 assert.Nil(t, err) 1740 err = db.Persist(GetKey(900)) 1741 assert.Nil(t, err) 1742 1743 time.Sleep(time.Second) 1744 1745 val, err := db.Get(GetKey(900)) 1746 assert.Nil(t, err) 1747 assert.NotNil(t, val) 1748 } 1749 1750 func TestRoseDB_GetStrsKeys(t *testing.T) { 1751 t.Run("fileio", func(t *testing.T) { 1752 testRoseDBGetStrsKeys(t, FileIO, KeyOnlyMemMode) 1753 }) 1754 1755 t.Run("mmap", func(t *testing.T) { 1756 testRoseDBGetStrsKeys(t, MMap, KeyValueMemMode) 1757 }) 1758 } 1759 1760 func testRoseDBGetStrsKeys(t *testing.T, ioType IOType, mode DataIndexMode) { 1761 path := filepath.Join("/tmp", "rosedb") 1762 opts := DefaultOptions(path) 1763 opts.IoType = ioType 1764 opts.IndexMode = mode 1765 db, err := Open(opts) 1766 assert.Nil(t, err) 1767 defer destroyDB(db) 1768 1769 keys1, err := db.GetStrsKeys() 1770 assert.Nil(t, err) 1771 assert.Equal(t, 0, len(keys1)) 1772 1773 var keys [][]byte 1774 for i := 0; i < 100; i++ { 1775 keys = append(keys, GetKey(i)) 1776 err := db.Set(GetKey(i), GetValue16B()) 1777 assert.Nil(t, err) 1778 } 1779 sort.Slice(keys, func(i, j int) bool { 1780 return bytes.Compare(keys[i], keys[j]) < 0 1781 }) 1782 1783 keys2, err := db.GetStrsKeys() 1784 assert.Nil(t, err) 1785 assert.Equal(t, keys2, keys) 1786 1787 db.Expire(GetKey(19), time.Millisecond*200) 1788 db.Expire(GetKey(33), time.Millisecond*400) 1789 db.Expire(GetKey(99), time.Millisecond*500) 1790 time.Sleep(time.Second) 1791 1792 keys3, err := db.GetStrsKeys() 1793 assert.Nil(t, err) 1794 assert.Equal(t, 97, len(keys3)) 1795 }