1package buntdb 2 3import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "math/rand" 9 "os" 10 "strconv" 11 "strings" 12 "sync" 13 "testing" 14 "time" 15) 16 17func testOpen(t testing.TB) *DB { 18 if err := os.RemoveAll("data.db"); err != nil { 19 t.Fatal(err) 20 } 21 return testReOpen(t, nil) 22} 23func testReOpen(t testing.TB, db *DB) *DB { 24 return testReOpenDelay(t, db, 0) 25} 26 27func testReOpenDelay(t testing.TB, db *DB, dur time.Duration) *DB { 28 if db != nil { 29 if err := db.Close(); err != nil { 30 t.Fatal(err) 31 } 32 } 33 time.Sleep(dur) 34 db, err := Open("data.db") 35 if err != nil { 36 t.Fatal(err) 37 } 38 return db 39} 40 41func testClose(db *DB) { 42 _ = db.Close() 43 _ = os.RemoveAll("data.db") 44} 45 46func TestBackgroudOperations(t *testing.T) { 47 db := testOpen(t) 48 defer testClose(db) 49 for i := 0; i < 1000; i++ { 50 if err := db.Update(func(tx *Tx) error { 51 for j := 0; j < 200; j++ { 52 if _, _, err := tx.Set(fmt.Sprintf("hello%d", j), "planet", nil); err != nil { 53 return err 54 } 55 } 56 if _, _, err := tx.Set("hi", "world", &SetOptions{Expires: true, TTL: time.Second / 2}); err != nil { 57 return err 58 } 59 return nil 60 }); err != nil { 61 t.Fatal(err) 62 } 63 } 64 n := 0 65 err := db.View(func(tx *Tx) error { 66 var err error 67 n, err = tx.Len() 68 return err 69 }) 70 if err != nil { 71 t.Fatal(err) 72 } 73 if n != 201 { 74 t.Fatalf("expecting '%v', got '%v'", 201, n) 75 } 76 time.Sleep(time.Millisecond * 1500) 77 db = testReOpen(t, db) 78 defer testClose(db) 79 n = 0 80 err = db.View(func(tx *Tx) error { 81 var err error 82 n, err = tx.Len() 83 return err 84 }) 85 if err != nil { 86 t.Fatal(err) 87 } 88 if n != 200 { 89 t.Fatalf("expecting '%v', got '%v'", 200, n) 90 } 91} 92func TestSaveLoad(t *testing.T) { 93 db, _ := Open(":memory:") 94 defer db.Close() 95 if err := db.Update(func(tx *Tx) error { 96 for i := 0; i < 20; i++ { 97 _, _, err := tx.Set(fmt.Sprintf("key:%d", i), fmt.Sprintf("planet:%d", i), nil) 98 if err != nil { 99 return err 100 } 101 } 102 return nil 103 }); err != nil { 104 t.Fatal(err) 105 } 106 f, err := os.Create("temp.db") 107 if err != nil { 108 t.Fatal(err) 109 } 110 defer func() { 111 f.Close() 112 os.RemoveAll("temp.db") 113 }() 114 if err := db.Save(f); err != nil { 115 t.Fatal(err) 116 } 117 if err := f.Close(); err != nil { 118 t.Fatal(err) 119 } 120 db.Close() 121 db, _ = Open(":memory:") 122 defer db.Close() 123 f, err = os.Open("temp.db") 124 if err != nil { 125 t.Fatal(err) 126 } 127 defer f.Close() 128 if err := db.Load(f); err != nil { 129 t.Fatal(err) 130 } 131 if err := db.View(func(tx *Tx) error { 132 for i := 0; i < 20; i++ { 133 ex := fmt.Sprintf("planet:%d", i) 134 val, err := tx.Get(fmt.Sprintf("key:%d", i)) 135 if err != nil { 136 return err 137 } 138 if ex != val { 139 t.Fatalf("expected %s, got %s", ex, val) 140 } 141 } 142 return nil 143 }); err != nil { 144 t.Fatal(err) 145 } 146} 147 148func TestMutatingIterator(t *testing.T) { 149 db := testOpen(t) 150 defer testClose(db) 151 count := 1000 152 if err := db.CreateIndex("ages", "user:*:age", IndexInt); err != nil { 153 t.Fatal(err) 154 } 155 156 for i := 0; i < 10; i++ { 157 if err := db.Update(func(tx *Tx) error { 158 for j := 0; j < count; j++ { 159 key := fmt.Sprintf("user:%d:age", j) 160 val := fmt.Sprintf("%d", rand.Intn(100)) 161 if _, _, err := tx.Set(key, val, nil); err != nil { 162 return err 163 } 164 } 165 return nil 166 }); err != nil { 167 t.Fatal(err) 168 } 169 170 if err := db.Update(func(tx *Tx) error { 171 return tx.Ascend("ages", func(key, val string) bool { 172 _, err := tx.Delete(key) 173 if err != ErrTxIterating { 174 t.Fatal("should not be able to call Delete while iterating.") 175 } 176 _, _, err = tx.Set(key, "", nil) 177 if err != ErrTxIterating { 178 t.Fatal("should not be able to call Set while iterating.") 179 } 180 return true 181 }) 182 }); err != nil { 183 t.Fatal(err) 184 } 185 } 186} 187 188func TestCaseInsensitiveIndex(t *testing.T) { 189 db := testOpen(t) 190 defer testClose(db) 191 count := 1000 192 if err := db.Update(func(tx *Tx) error { 193 opts := &IndexOptions{ 194 CaseInsensitiveKeyMatching: true, 195 } 196 return tx.CreateIndexOptions("ages", "User:*:age", opts, IndexInt) 197 }); err != nil { 198 t.Fatal(err) 199 } 200 201 if err := db.Update(func(tx *Tx) error { 202 for j := 0; j < count; j++ { 203 key := fmt.Sprintf("user:%d:age", j) 204 val := fmt.Sprintf("%d", rand.Intn(100)) 205 if _, _, err := tx.Set(key, val, nil); err != nil { 206 return err 207 } 208 } 209 return nil 210 }); err != nil { 211 t.Fatal(err) 212 } 213 214 if err := db.View(func(tx *Tx) error { 215 var vals []string 216 err := tx.Ascend("ages", func(key, value string) bool { 217 vals = append(vals, value) 218 return true 219 }) 220 if err != nil { 221 return err 222 } 223 if len(vals) != count { 224 return fmt.Errorf("expected '%v', got '%v'", count, len(vals)) 225 } 226 return nil 227 }); err != nil { 228 t.Fatal(err) 229 } 230 231} 232 233func TestIndexTransaction(t *testing.T) { 234 db := testOpen(t) 235 defer testClose(db) 236 var errFine = errors.New("this is fine") 237 ascend := func(tx *Tx, index string) ([]string, error) { 238 var vals []string 239 if err := tx.Ascend(index, func(key, val string) bool { 240 vals = append(vals, key, val) 241 return true 242 }); err != nil { 243 return nil, err 244 } 245 return vals, nil 246 } 247 ascendEqual := func(tx *Tx, index string, vals []string) error { 248 vals2, err := ascend(tx, index) 249 if err != nil { 250 return err 251 } 252 if len(vals) != len(vals2) { 253 return errors.New("invalid size match") 254 } 255 for i := 0; i < len(vals); i++ { 256 if vals[i] != vals2[i] { 257 return errors.New("invalid order") 258 } 259 } 260 return nil 261 } 262 // test creating an index and adding items 263 if err := db.Update(func(tx *Tx) error { 264 tx.Set("1", "3", nil) 265 tx.Set("2", "2", nil) 266 tx.Set("3", "1", nil) 267 if err := tx.CreateIndex("idx1", "*", IndexInt); err != nil { 268 return err 269 } 270 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 271 return err 272 } 273 return nil 274 }); err != nil { 275 t.Fatal(err) 276 } 277 278 // test to see if the items persisted from previous transaction 279 // test add item. 280 // test force rollback. 281 if err := db.Update(func(tx *Tx) error { 282 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 283 return err 284 } 285 tx.Set("4", "0", nil) 286 if err := ascendEqual(tx, "idx1", []string{"4", "0", "3", "1", "2", "2", "1", "3"}); err != nil { 287 return err 288 } 289 return errFine 290 }); err != errFine { 291 t.Fatalf("expected '%v', got '%v'", errFine, err) 292 } 293 294 // test to see if the rollback happened 295 if err := db.View(func(tx *Tx) error { 296 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 297 return err 298 } 299 return nil 300 }); err != nil { 301 t.Fatalf("expected '%v', got '%v'", nil, err) 302 } 303 304 // del item, drop index, rollback 305 if err := db.Update(func(tx *Tx) error { 306 if err := tx.DropIndex("idx1"); err != nil { 307 return err 308 } 309 return errFine 310 }); err != errFine { 311 t.Fatalf("expected '%v', got '%v'", errFine, err) 312 } 313 314 // test to see if the rollback happened 315 if err := db.View(func(tx *Tx) error { 316 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 317 return err 318 } 319 return nil 320 }); err != nil { 321 t.Fatalf("expected '%v', got '%v'", nil, err) 322 } 323 324 various := func(reterr error) error { 325 // del item 3, add index 2, add item 4, test index 1 and 2. 326 // flushdb, test index 1 and 2. 327 // add item 1 and 2, add index 2 and 3, test index 2 and 3 328 return db.Update(func(tx *Tx) error { 329 tx.Delete("3") 330 tx.CreateIndex("idx2", "*", IndexInt) 331 tx.Set("4", "0", nil) 332 if err := ascendEqual(tx, "idx1", []string{"4", "0", "2", "2", "1", "3"}); err != nil { 333 return fmt.Errorf("err: %v", err) 334 } 335 if err := ascendEqual(tx, "idx2", []string{"4", "0", "2", "2", "1", "3"}); err != nil { 336 return fmt.Errorf("err: %v", err) 337 } 338 tx.DeleteAll() 339 if err := ascendEqual(tx, "idx1", []string{}); err != nil { 340 return fmt.Errorf("err: %v", err) 341 } 342 if err := ascendEqual(tx, "idx2", []string{}); err != nil { 343 return fmt.Errorf("err: %v", err) 344 } 345 tx.Set("1", "3", nil) 346 tx.Set("2", "2", nil) 347 tx.CreateIndex("idx1", "*", IndexInt) 348 tx.CreateIndex("idx2", "*", IndexInt) 349 if err := ascendEqual(tx, "idx1", []string{"2", "2", "1", "3"}); err != nil { 350 return fmt.Errorf("err: %v", err) 351 } 352 if err := ascendEqual(tx, "idx2", []string{"2", "2", "1", "3"}); err != nil { 353 return fmt.Errorf("err: %v", err) 354 } 355 return reterr 356 }) 357 } 358 // various rollback 359 if err := various(errFine); err != errFine { 360 t.Fatalf("expected '%v', got '%v'", errFine, err) 361 } 362 // test to see if the rollback happened 363 if err := db.View(func(tx *Tx) error { 364 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 365 return fmt.Errorf("err: %v", err) 366 } 367 if err := ascendEqual(tx, "idx2", []string{"3", "1", "2", "2", "1", "3"}); err != ErrNotFound { 368 return fmt.Errorf("err: %v", err) 369 } 370 return nil 371 }); err != nil { 372 t.Fatalf("expected '%v', got '%v'", nil, err) 373 } 374 375 // various commit 376 if err := various(nil); err != nil { 377 t.Fatalf("expected '%v', got '%v'", nil, err) 378 } 379 380 // test to see if the commit happened 381 if err := db.View(func(tx *Tx) error { 382 if err := ascendEqual(tx, "idx1", []string{"2", "2", "1", "3"}); err != nil { 383 return fmt.Errorf("err: %v", err) 384 } 385 if err := ascendEqual(tx, "idx2", []string{"2", "2", "1", "3"}); err != nil { 386 return fmt.Errorf("err: %v", err) 387 } 388 return nil 389 }); err != nil { 390 t.Fatalf("expected '%v', got '%v'", nil, err) 391 } 392} 393 394func TestDeleteAll(t *testing.T) { 395 db := testOpen(t) 396 defer testClose(db) 397 398 db.Update(func(tx *Tx) error { 399 tx.Set("hello1", "planet1", nil) 400 tx.Set("hello2", "planet2", nil) 401 tx.Set("hello3", "planet3", nil) 402 return nil 403 }) 404 db.CreateIndex("all", "*", IndexString) 405 db.Update(func(tx *Tx) error { 406 tx.Set("hello1", "planet1.1", nil) 407 tx.DeleteAll() 408 tx.Set("bb", "11", nil) 409 tx.Set("aa", "**", nil) 410 tx.Delete("aa") 411 tx.Set("aa", "22", nil) 412 return nil 413 }) 414 var res string 415 var res2 string 416 db.View(func(tx *Tx) error { 417 tx.Ascend("", func(key, val string) bool { 418 res += key + ":" + val + "\n" 419 return true 420 }) 421 tx.Ascend("all", func(key, val string) bool { 422 res2 += key + ":" + val + "\n" 423 return true 424 }) 425 return nil 426 }) 427 if res != "aa:22\nbb:11\n" { 428 t.Fatal("fail") 429 } 430 if res2 != "bb:11\naa:22\n" { 431 t.Fatal("fail") 432 } 433 db = testReOpen(t, db) 434 defer testClose(db) 435 res = "" 436 res2 = "" 437 db.CreateIndex("all", "*", IndexString) 438 db.View(func(tx *Tx) error { 439 tx.Ascend("", func(key, val string) bool { 440 res += key + ":" + val + "\n" 441 return true 442 }) 443 tx.Ascend("all", func(key, val string) bool { 444 res2 += key + ":" + val + "\n" 445 return true 446 }) 447 return nil 448 }) 449 if res != "aa:22\nbb:11\n" { 450 t.Fatal("fail") 451 } 452 if res2 != "bb:11\naa:22\n" { 453 t.Fatal("fail") 454 } 455 db.Update(func(tx *Tx) error { 456 tx.Set("1", "1", nil) 457 tx.Set("2", "2", nil) 458 tx.Set("3", "3", nil) 459 tx.Set("4", "4", nil) 460 return nil 461 }) 462 err := db.Update(func(tx *Tx) error { 463 tx.Set("1", "a", nil) 464 tx.Set("5", "5", nil) 465 tx.Delete("2") 466 tx.Set("6", "6", nil) 467 tx.DeleteAll() 468 tx.Set("7", "7", nil) 469 tx.Set("8", "8", nil) 470 tx.Set("6", "c", nil) 471 return errors.New("please rollback") 472 }) 473 if err == nil || err.Error() != "please rollback" { 474 t.Fatal("expecteding 'please rollback' error") 475 } 476 477 res = "" 478 res2 = "" 479 db.View(func(tx *Tx) error { 480 tx.Ascend("", func(key, val string) bool { 481 res += key + ":" + val + "\n" 482 return true 483 }) 484 tx.Ascend("all", func(key, val string) bool { 485 res2 += key + ":" + val + "\n" 486 return true 487 }) 488 return nil 489 }) 490 if res != "1:1\n2:2\n3:3\n4:4\naa:22\nbb:11\n" { 491 t.Fatal("fail") 492 } 493 if res2 != "1:1\nbb:11\n2:2\naa:22\n3:3\n4:4\n" { 494 t.Fatal("fail") 495 } 496} 497 498func TestAscendEqual(t *testing.T) { 499 db := testOpen(t) 500 defer testClose(db) 501 if err := db.Update(func(tx *Tx) error { 502 for i := 0; i < 300; i++ { 503 _, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil) 504 if err != nil { 505 return err 506 } 507 _, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil) 508 if err != nil { 509 return err 510 } 511 } 512 return tx.CreateIndex("num", "*", IndexInt) 513 }); err != nil { 514 t.Fatal(err) 515 } 516 var res []string 517 if err := db.View(func(tx *Tx) error { 518 return tx.AscendEqual("", "key:00055A", func(key, value string) bool { 519 res = append(res, key) 520 return true 521 }) 522 }); err != nil { 523 t.Fatal(err) 524 } 525 if len(res) != 1 { 526 t.Fatalf("expected %v, got %v", 1, len(res)) 527 } 528 if res[0] != "key:00055A" { 529 t.Fatalf("expected %v, got %v", "key:00055A", res[0]) 530 } 531 res = nil 532 if err := db.View(func(tx *Tx) error { 533 return tx.AscendEqual("num", "1125", func(key, value string) bool { 534 res = append(res, key) 535 return true 536 }) 537 }); err != nil { 538 t.Fatal(err) 539 } 540 if len(res) != 2 { 541 t.Fatalf("expected %v, got %v", 2, len(res)) 542 } 543 if res[0] != "key:00125A" { 544 t.Fatalf("expected %v, got %v", "key:00125A", res[0]) 545 } 546 if res[1] != "key:00125B" { 547 t.Fatalf("expected %v, got %v", "key:00125B", res[1]) 548 } 549} 550func TestDescendEqual(t *testing.T) { 551 db := testOpen(t) 552 defer testClose(db) 553 if err := db.Update(func(tx *Tx) error { 554 for i := 0; i < 300; i++ { 555 _, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil) 556 if err != nil { 557 return err 558 } 559 _, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil) 560 if err != nil { 561 return err 562 } 563 } 564 return tx.CreateIndex("num", "*", IndexInt) 565 }); err != nil { 566 t.Fatal(err) 567 } 568 var res []string 569 if err := db.View(func(tx *Tx) error { 570 return tx.DescendEqual("", "key:00055A", func(key, value string) bool { 571 res = append(res, key) 572 return true 573 }) 574 }); err != nil { 575 t.Fatal(err) 576 } 577 if len(res) != 1 { 578 t.Fatalf("expected %v, got %v", 1, len(res)) 579 } 580 if res[0] != "key:00055A" { 581 t.Fatalf("expected %v, got %v", "key:00055A", res[0]) 582 } 583 res = nil 584 if err := db.View(func(tx *Tx) error { 585 return tx.DescendEqual("num", "1125", func(key, value string) bool { 586 res = append(res, key) 587 return true 588 }) 589 }); err != nil { 590 t.Fatal(err) 591 } 592 if len(res) != 2 { 593 t.Fatalf("expected %v, got %v", 2, len(res)) 594 } 595 if res[0] != "key:00125B" { 596 t.Fatalf("expected %v, got %v", "key:00125B", res[0]) 597 } 598 if res[1] != "key:00125A" { 599 t.Fatalf("expected %v, got %v", "key:00125A", res[1]) 600 } 601} 602func TestVariousTx(t *testing.T) { 603 db := testOpen(t) 604 defer testClose(db) 605 if err := db.Update(func(tx *Tx) error { 606 _, _, err := tx.Set("hello", "planet", nil) 607 return err 608 }); err != nil { 609 t.Fatal(err) 610 } 611 errBroken := errors.New("broken") 612 if err := db.Update(func(tx *Tx) error { 613 _, _, _ = tx.Set("hello", "world", nil) 614 return errBroken 615 }); err != errBroken { 616 t.Fatalf("did not correctly receive the user-defined transaction error.") 617 } 618 var val string 619 err := db.View(func(tx *Tx) error { 620 var err error 621 val, err = tx.Get("hello") 622 return err 623 }) 624 if err != nil { 625 t.Fatal(err) 626 } 627 if val == "world" { 628 t.Fatal("a rollbacked transaction got through") 629 } 630 if val != "planet" { 631 t.Fatalf("expecting '%v', got '%v'", "planet", val) 632 } 633 if err := db.Update(func(tx *Tx) error { 634 tx.db = nil 635 if _, _, err := tx.Set("hello", "planet", nil); err != ErrTxClosed { 636 t.Fatal("expecting a tx closed error") 637 } 638 if _, err := tx.Delete("hello"); err != ErrTxClosed { 639 t.Fatal("expecting a tx closed error") 640 } 641 if _, err := tx.Get("hello"); err != ErrTxClosed { 642 t.Fatal("expecting a tx closed error") 643 } 644 tx.db = db 645 tx.writable = false 646 if _, _, err := tx.Set("hello", "planet", nil); err != ErrTxNotWritable { 647 t.Fatal("expecting a tx not writable error") 648 } 649 if _, err := tx.Delete("hello"); err != ErrTxNotWritable { 650 t.Fatal("expecting a tx not writable error") 651 } 652 tx.writable = true 653 if _, err := tx.Get("something"); err != ErrNotFound { 654 t.Fatalf("expecting not found error") 655 } 656 if _, err := tx.Delete("something"); err != ErrNotFound { 657 t.Fatalf("expecting not found error") 658 } 659 if _, _, err := tx.Set("var", "val", &SetOptions{Expires: true, TTL: 0}); err != nil { 660 t.Fatal(err) 661 } 662 if _, err := tx.Get("var"); err != ErrNotFound { 663 t.Fatalf("expecting not found error") 664 } 665 if _, err := tx.Delete("var"); err != ErrNotFound { 666 tx.unlock() 667 t.Fatalf("expecting not found error") 668 } 669 return nil 670 }); err != nil { 671 t.Fatal(err) 672 } 673 674 // test non-managed transactions 675 tx, err := db.Begin(true) 676 if err != nil { 677 t.Fatal(err) 678 } 679 defer tx.Rollback() 680 _, _, err = tx.Set("howdy", "world", nil) 681 if err != nil { 682 t.Fatal(err) 683 } 684 if err := tx.Commit(); err != nil { 685 t.Fatal(err) 686 } 687 tx, err = db.Begin(false) 688 if err != nil { 689 t.Fatal(err) 690 } 691 defer tx.Rollback() 692 v, err := tx.Get("howdy") 693 if err != nil { 694 t.Fatal(err) 695 } 696 if v != "world" { 697 t.Fatalf("expecting '%v', got '%v'", "world", v) 698 } 699 if err := tx.Rollback(); err != nil { 700 t.Fatal(err) 701 } 702 tx, err = db.Begin(true) 703 if err != nil { 704 t.Fatal(err) 705 } 706 defer tx.Rollback() 707 v, err = tx.Get("howdy") 708 if err != nil { 709 t.Fatal(err) 710 } 711 if v != "world" { 712 t.Fatalf("expecting '%v', got '%v'", "world", v) 713 } 714 _, err = tx.Delete("howdy") 715 if err != nil { 716 t.Fatal(err) 717 } 718 if err := tx.Commit(); err != nil { 719 t.Fatal(err) 720 } 721 722 // test for invalid commits 723 if err := db.Update(func(tx *Tx) error { 724 // we are going to do some hackery 725 defer func() { 726 if v := recover(); v != nil { 727 if v.(string) != "managed tx commit not allowed" { 728 t.Fatal(v.(string)) 729 } 730 } 731 }() 732 return tx.Commit() 733 }); err != nil { 734 t.Fatal(err) 735 } 736 737 // test for invalid commits 738 if err := db.Update(func(tx *Tx) error { 739 // we are going to do some hackery 740 defer func() { 741 if v := recover(); v != nil { 742 if v.(string) != "managed tx rollback not allowed" { 743 t.Fatal(v.(string)) 744 } 745 } 746 }() 747 return tx.Rollback() 748 }); err != nil { 749 t.Fatal(err) 750 } 751 752 // test for closed transactions 753 if err := db.Update(func(tx *Tx) error { 754 tx.db = nil 755 return nil 756 }); err != ErrTxClosed { 757 t.Fatal("expecting tx closed error") 758 } 759 db.mu.Unlock() 760 761 // test for invalid writes 762 if err := db.Update(func(tx *Tx) error { 763 tx.writable = false 764 return nil 765 }); err != ErrTxNotWritable { 766 t.Fatal("expecting tx not writable error") 767 } 768 db.mu.Unlock() 769 // test for closed transactions 770 if err := db.View(func(tx *Tx) error { 771 tx.db = nil 772 return nil 773 }); err != ErrTxClosed { 774 t.Fatal("expecting tx closed error") 775 } 776 db.mu.RUnlock() 777 // flush to unwritable file 778 if err := db.Update(func(tx *Tx) error { 779 _, _, err := tx.Set("var1", "val1", nil) 780 if err != nil { 781 t.Fatal(err) 782 } 783 return tx.db.file.Close() 784 }); err == nil { 785 t.Fatal("should not be able to commit when the file is closed") 786 } 787 db.file, err = os.OpenFile("data.db", os.O_CREATE|os.O_RDWR, 0666) 788 if err != nil { 789 t.Fatal(err) 790 } 791 if _, err := db.file.Seek(0, 2); err != nil { 792 t.Fatal(err) 793 } 794 db.buf = nil 795 if err := db.CreateIndex("blank", "*", nil); err != nil { 796 t.Fatal(err) 797 } 798 if err := db.CreateIndex("real", "*", IndexInt); err != nil { 799 t.Fatal(err) 800 } 801 // test scanning 802 if err := db.Update(func(tx *Tx) error { 803 less, err := tx.GetLess("junk") 804 if err != ErrNotFound { 805 t.Fatalf("expecting a not found, got %v", err) 806 } 807 if less != nil { 808 t.Fatal("expecting nil, got a less function") 809 } 810 less, err = tx.GetLess("blank") 811 if err != ErrNotFound { 812 t.Fatalf("expecting a not found, got %v", err) 813 } 814 if less != nil { 815 t.Fatal("expecting nil, got a less function") 816 } 817 less, err = tx.GetLess("real") 818 if err != nil { 819 return err 820 } 821 if less == nil { 822 t.Fatal("expecting a less function, got nil") 823 } 824 _, _, err = tx.Set("nothing", "here", nil) 825 return err 826 }); err != nil { 827 t.Fatal(err) 828 } 829 if err := db.View(func(tx *Tx) error { 830 s := "" 831 err := tx.Ascend("", func(key, val string) bool { 832 s += key + ":" + val + "\n" 833 return true 834 }) 835 if err != nil { 836 return err 837 } 838 if s != "hello:planet\nnothing:here\n" { 839 t.Fatal("invalid scan") 840 } 841 tx.db = nil 842 err = tx.Ascend("", func(key, val string) bool { return true }) 843 if err != ErrTxClosed { 844 tx.unlock() 845 t.Fatal("expecting tx closed error") 846 } 847 tx.db = db 848 err = tx.Ascend("na", func(key, val string) bool { return true }) 849 if err != ErrNotFound { 850 t.Fatal("expecting not found error") 851 } 852 err = tx.Ascend("blank", func(key, val string) bool { return true }) 853 if err != nil { 854 t.Fatal(err) 855 } 856 s = "" 857 err = tx.AscendLessThan("", "liger", func(key, val string) bool { 858 s += key + ":" + val + "\n" 859 return true 860 }) 861 if err != nil { 862 return err 863 } 864 if s != "hello:planet\n" { 865 t.Fatal("invalid scan") 866 } 867 868 s = "" 869 err = tx.Descend("", func(key, val string) bool { 870 s += key + ":" + val + "\n" 871 return true 872 }) 873 if err != nil { 874 return err 875 } 876 if s != "nothing:here\nhello:planet\n" { 877 t.Fatal("invalid scan") 878 } 879 880 s = "" 881 err = tx.DescendLessOrEqual("", "liger", func(key, val string) bool { 882 s += key + ":" + val + "\n" 883 return true 884 }) 885 if err != nil { 886 return err 887 } 888 889 if s != "hello:planet\n" { 890 t.Fatal("invalid scan") 891 } 892 893 s = "" 894 err = tx.DescendGreaterThan("", "liger", func(key, val string) bool { 895 s += key + ":" + val + "\n" 896 return true 897 }) 898 if err != nil { 899 return err 900 } 901 902 if s != "nothing:here\n" { 903 t.Fatal("invalid scan") 904 } 905 s = "" 906 err = tx.DescendRange("", "liger", "apple", func(key, val string) bool { 907 s += key + ":" + val + "\n" 908 return true 909 }) 910 if err != nil { 911 return err 912 } 913 if s != "hello:planet\n" { 914 t.Fatal("invalid scan") 915 } 916 return nil 917 }); err != nil { 918 t.Fatal(err) 919 } 920 921 // test some spatial stuff 922 if err := db.CreateSpatialIndex("spat", "rect:*", IndexRect); err != nil { 923 t.Fatal(err) 924 } 925 if err := db.CreateSpatialIndex("junk", "rect:*", nil); err != nil { 926 t.Fatal(err) 927 } 928 err = db.Update(func(tx *Tx) error { 929 rect, err := tx.GetRect("spat") 930 if err != nil { 931 return err 932 } 933 if rect == nil { 934 t.Fatal("expecting a rect function, got nil") 935 } 936 rect, err = tx.GetRect("junk") 937 if err != ErrNotFound { 938 t.Fatalf("expecting a not found, got %v", err) 939 } 940 if rect != nil { 941 t.Fatal("expecting nil, got a rect function") 942 } 943 rect, err = tx.GetRect("na") 944 if err != ErrNotFound { 945 t.Fatalf("expecting a not found, got %v", err) 946 } 947 if rect != nil { 948 t.Fatal("expecting nil, got a rect function") 949 } 950 if _, _, err := tx.Set("rect:1", "[10 10],[20 20]", nil); err != nil { 951 return err 952 } 953 if _, _, err := tx.Set("rect:2", "[15 15],[25 25]", nil); err != nil { 954 return err 955 } 956 if _, _, err := tx.Set("shape:1", "[12 12],[25 25]", nil); err != nil { 957 return err 958 } 959 s := "" 960 err = tx.Intersects("spat", "[5 5],[13 13]", func(key, val string) bool { 961 s += key + ":" + val + "\n" 962 return true 963 }) 964 if err != nil { 965 return err 966 } 967 if s != "rect:1:[10 10],[20 20]\n" { 968 t.Fatal("invalid scan") 969 } 970 tx.db = nil 971 err = tx.Intersects("spat", "[5 5],[13 13]", func(key, val string) bool { 972 return true 973 }) 974 if err != ErrTxClosed { 975 t.Fatal("expecting tx closed error") 976 } 977 tx.db = db 978 err = tx.Intersects("", "[5 5],[13 13]", func(key, val string) bool { 979 return true 980 }) 981 if err != nil { 982 t.Fatal(err) 983 } 984 err = tx.Intersects("na", "[5 5],[13 13]", func(key, val string) bool { 985 return true 986 }) 987 if err != ErrNotFound { 988 t.Fatal("expecting not found error") 989 } 990 err = tx.Intersects("junk", "[5 5],[13 13]", func(key, val string) bool { 991 return true 992 }) 993 if err != nil { 994 t.Fatal(err) 995 } 996 n, err := tx.Len() 997 if err != nil { 998 t.Fatal(err) 999 } 1000 if n != 5 { 1001 t.Fatalf("expecting %v, got %v", 5, n) 1002 } 1003 tx.db = nil 1004 _, err = tx.Len() 1005 if err != ErrTxClosed { 1006 t.Fatal("expecting tx closed error") 1007 } 1008 tx.db = db 1009 return nil 1010 }) 1011 if err != nil { 1012 t.Fatal(err) 1013 } 1014 // test after closing 1015 if err := db.Close(); err != nil { 1016 t.Fatal(err) 1017 } 1018 1019 if err := db.Update(func(tx *Tx) error { return nil }); err != ErrDatabaseClosed { 1020 t.Fatalf("should not be able to perform transactionso on a closed database.") 1021 } 1022} 1023 1024func Example_descKeys() { 1025 db, _ := Open(":memory:") 1026 db.CreateIndex("name", "*", IndexString) 1027 db.Update(func(tx *Tx) error { 1028 tx.Set("user:100:first", "Tom", nil) 1029 tx.Set("user:100:last", "Johnson", nil) 1030 tx.Set("user:101:first", "Janet", nil) 1031 tx.Set("user:101:last", "Prichard", nil) 1032 tx.Set("user:102:first", "Alan", nil) 1033 tx.Set("user:102:last", "Cooper", nil) 1034 return nil 1035 }) 1036 db.View(func(tx *Tx) error { 1037 tx.AscendKeys("user:101:*", 1038 func(key, value string) bool { 1039 fmt.Printf("%s: %s\n", key, value) 1040 return true 1041 }) 1042 tx.AscendKeys("user:10?:*", 1043 func(key, value string) bool { 1044 fmt.Printf("%s: %s\n", key, value) 1045 return true 1046 }) 1047 tx.AscendKeys("*2*", 1048 func(key, value string) bool { 1049 fmt.Printf("%s: %s\n", key, value) 1050 return true 1051 }) 1052 tx.DescendKeys("user:101:*", 1053 func(key, value string) bool { 1054 fmt.Printf("%s: %s\n", key, value) 1055 return true 1056 }) 1057 tx.DescendKeys("*", 1058 func(key, value string) bool { 1059 fmt.Printf("%s: %s\n", key, value) 1060 return true 1061 }) 1062 return nil 1063 }) 1064 // Output: 1065 //user:101:first: Janet 1066 //user:101:last: Prichard 1067 //user:100:first: Tom 1068 //user:100:last: Johnson 1069 //user:101:first: Janet 1070 //user:101:last: Prichard 1071 //user:102:first: Alan 1072 //user:102:last: Cooper 1073 //user:102:first: Alan 1074 //user:102:last: Cooper 1075 //user:101:last: Prichard 1076 //user:101:first: Janet 1077 //user:102:last: Cooper 1078 //user:102:first: Alan 1079 //user:101:last: Prichard 1080 //user:101:first: Janet 1081 //user:100:last: Johnson 1082 //user:100:first: Tom 1083} 1084 1085func ExampleDesc() { 1086 db, _ := Open(":memory:") 1087 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), Desc(IndexJSON("age"))) 1088 db.Update(func(tx *Tx) error { 1089 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1090 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1091 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1092 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1093 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1094 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1095 return nil 1096 }) 1097 db.View(func(tx *Tx) error { 1098 tx.Ascend("last_name_age", func(key, value string) bool { 1099 fmt.Printf("%s: %s\n", key, value) 1100 return true 1101 }) 1102 return nil 1103 }) 1104 1105 // Output: 1106 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1107 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1108 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1109 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1110 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1111 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1112} 1113 1114func ExampleDB_CreateIndex_jSON() { 1115 db, _ := Open(":memory:") 1116 db.CreateIndex("last_name", "*", IndexJSON("name.last")) 1117 db.CreateIndex("age", "*", IndexJSON("age")) 1118 db.Update(func(tx *Tx) error { 1119 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1120 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1121 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1122 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1123 return nil 1124 }) 1125 db.View(func(tx *Tx) error { 1126 fmt.Println("Order by last name") 1127 tx.Ascend("last_name", func(key, value string) bool { 1128 fmt.Printf("%s: %s\n", key, value) 1129 return true 1130 }) 1131 fmt.Println("Order by age") 1132 tx.Ascend("age", func(key, value string) bool { 1133 fmt.Printf("%s: %s\n", key, value) 1134 return true 1135 }) 1136 fmt.Println("Order by age range 30-50") 1137 tx.AscendRange("age", `{"age":30}`, `{"age":50}`, func(key, value string) bool { 1138 fmt.Printf("%s: %s\n", key, value) 1139 return true 1140 }) 1141 return nil 1142 }) 1143 1144 // Output: 1145 // Order by last name 1146 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1147 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1148 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1149 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1150 // Order by age 1151 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1152 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1153 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1154 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1155 // Order by age range 30-50 1156 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1157 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1158} 1159 1160func ExampleDB_CreateIndex_strings() { 1161 db, _ := Open(":memory:") 1162 db.CreateIndex("name", "*", IndexString) 1163 db.Update(func(tx *Tx) error { 1164 tx.Set("1", "Tom", nil) 1165 tx.Set("2", "Janet", nil) 1166 tx.Set("3", "Carol", nil) 1167 tx.Set("4", "Alan", nil) 1168 tx.Set("5", "Sam", nil) 1169 tx.Set("6", "Melinda", nil) 1170 return nil 1171 }) 1172 db.View(func(tx *Tx) error { 1173 tx.Ascend("name", func(key, value string) bool { 1174 fmt.Printf("%s: %s\n", key, value) 1175 return true 1176 }) 1177 return nil 1178 }) 1179 1180 // Output: 1181 //4: Alan 1182 //3: Carol 1183 //2: Janet 1184 //6: Melinda 1185 //5: Sam 1186 //1: Tom 1187} 1188 1189func ExampleDB_CreateIndex_ints() { 1190 db, _ := Open(":memory:") 1191 db.CreateIndex("age", "*", IndexInt) 1192 db.Update(func(tx *Tx) error { 1193 tx.Set("1", "30", nil) 1194 tx.Set("2", "51", nil) 1195 tx.Set("3", "16", nil) 1196 tx.Set("4", "76", nil) 1197 tx.Set("5", "23", nil) 1198 tx.Set("6", "43", nil) 1199 return nil 1200 }) 1201 db.View(func(tx *Tx) error { 1202 tx.Ascend("age", func(key, value string) bool { 1203 fmt.Printf("%s: %s\n", key, value) 1204 return true 1205 }) 1206 return nil 1207 }) 1208 1209 // Output: 1210 //3: 16 1211 //5: 23 1212 //1: 30 1213 //6: 43 1214 //2: 51 1215 //4: 76 1216} 1217func ExampleDB_CreateIndex_multipleFields() { 1218 db, _ := Open(":memory:") 1219 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), IndexJSON("age")) 1220 db.Update(func(tx *Tx) error { 1221 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1222 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1223 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1224 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1225 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1226 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1227 return nil 1228 }) 1229 db.View(func(tx *Tx) error { 1230 tx.Ascend("last_name_age", func(key, value string) bool { 1231 fmt.Printf("%s: %s\n", key, value) 1232 return true 1233 }) 1234 return nil 1235 }) 1236 1237 // Output: 1238 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1239 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1240 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1241 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1242 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1243 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1244} 1245 1246func TestNoExpiringItem(t *testing.T) { 1247 item := &dbItem{key: "key", val: "val"} 1248 if !item.expiresAt().Equal(maxTime) { 1249 t.Fatal("item.expiresAt() != maxTime") 1250 } 1251 if min, max := item.Rect(nil); min != nil || max != nil { 1252 t.Fatal("item min,max should both be nil") 1253 } 1254} 1255func TestAutoShrink(t *testing.T) { 1256 db := testOpen(t) 1257 defer testClose(db) 1258 for i := 0; i < 1000; i++ { 1259 err := db.Update(func(tx *Tx) error { 1260 for i := 0; i < 20; i++ { 1261 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1262 return err 1263 } 1264 } 1265 return nil 1266 }) 1267 if err != nil { 1268 t.Fatal(err) 1269 } 1270 } 1271 db = testReOpen(t, db) 1272 defer testClose(db) 1273 db.config.AutoShrinkMinSize = 64 * 1024 // 64K 1274 for i := 0; i < 2000; i++ { 1275 err := db.Update(func(tx *Tx) error { 1276 for i := 0; i < 20; i++ { 1277 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1278 return err 1279 } 1280 } 1281 return nil 1282 }) 1283 if err != nil { 1284 t.Fatal(err) 1285 } 1286 } 1287 time.Sleep(time.Second * 3) 1288 db = testReOpen(t, db) 1289 defer testClose(db) 1290 err := db.View(func(tx *Tx) error { 1291 n, err := tx.Len() 1292 if err != nil { 1293 return err 1294 } 1295 if n != 20 { 1296 t.Fatalf("expecting 20, got %v", n) 1297 } 1298 return nil 1299 }) 1300 if err != nil { 1301 t.Fatal(err) 1302 } 1303} 1304 1305// test database format loading 1306func TestDatabaseFormat(t *testing.T) { 1307 // should succeed 1308 func() { 1309 resp := strings.Join([]string{ 1310 "*3\r\n$3\r\nset\r\n$4\r\nvar1\r\n$4\r\n1234\r\n", 1311 "*3\r\n$3\r\nset\r\n$4\r\nvar2\r\n$4\r\n1234\r\n", 1312 "*2\r\n$3\r\ndel\r\n$4\r\nvar1\r\n", 1313 "*5\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\n10\r\n", 1314 }, "") 1315 if err := os.RemoveAll("data.db"); err != nil { 1316 t.Fatal(err) 1317 } 1318 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1319 t.Fatal(err) 1320 } 1321 db := testOpen(t) 1322 defer testClose(db) 1323 }() 1324 testBadFormat := func(resp string) { 1325 if err := os.RemoveAll("data.db"); err != nil { 1326 t.Fatal(err) 1327 } 1328 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1329 t.Fatal(err) 1330 } 1331 db, err := Open("data.db") 1332 if err == nil { 1333 if err := db.Close(); err != nil { 1334 t.Fatal(err) 1335 } 1336 if err := os.RemoveAll("data.db"); err != nil { 1337 t.Fatal(err) 1338 } 1339 t.Fatalf("invalid database should not be allowed") 1340 } 1341 } 1342 testBadFormat("*3\r") 1343 testBadFormat("*3\n") 1344 testBadFormat("*a\r\n") 1345 testBadFormat("*2\r\n") 1346 testBadFormat("*2\r\n%3") 1347 testBadFormat("*2\r\n$") 1348 testBadFormat("*2\r\n$3\r\n") 1349 testBadFormat("*2\r\n$3\r\ndel") 1350 testBadFormat("*2\r\n$3\r\ndel\r\r") 1351 testBadFormat("*0\r\n*2\r\n$3\r\ndel\r\r") 1352 testBadFormat("*1\r\n$3\r\nnop\r\n") 1353 testBadFormat("*1\r\n$3\r\ndel\r\n") 1354 testBadFormat("*1\r\n$3\r\nset\r\n") 1355 testBadFormat("*5\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nxx\r\n$2\r\n10\r\n") 1356 testBadFormat("*5\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1357 testBadFormat("*15\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1358 testBadFormat("*1A\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1359 testBadFormat("*5\r\n$13\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1360 testBadFormat("*5\r\n$1A\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1361 testBadFormat("*5\r\n$3\r\nset\r\n$5000\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\naa\r\n") 1362} 1363 1364func TestInsertsAndDeleted(t *testing.T) { 1365 db := testOpen(t) 1366 defer testClose(db) 1367 if err := db.CreateIndex("any", "*", IndexString); err != nil { 1368 t.Fatal(err) 1369 } 1370 if err := db.CreateSpatialIndex("rect", "*", IndexRect); err != nil { 1371 t.Fatal(err) 1372 } 1373 if err := db.Update(func(tx *Tx) error { 1374 if _, _, err := tx.Set("item1", "value1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1375 return err 1376 } 1377 if _, _, err := tx.Set("item2", "value2", nil); err != nil { 1378 return err 1379 } 1380 if _, _, err := tx.Set("item3", "value3", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1381 return err 1382 } 1383 return nil 1384 }); err != nil { 1385 t.Fatal(err) 1386 } 1387 1388 // test replacing items in the database 1389 if err := db.Update(func(tx *Tx) error { 1390 if _, _, err := tx.Set("item1", "nvalue1", nil); err != nil { 1391 return err 1392 } 1393 if _, _, err := tx.Set("item2", "nvalue2", nil); err != nil { 1394 return err 1395 } 1396 if _, err := tx.Delete("item3"); err != nil { 1397 return err 1398 } 1399 return nil 1400 }); err != nil { 1401 t.Fatal(err) 1402 } 1403} 1404 1405// test index compare functions 1406func TestIndexCompare(t *testing.T) { 1407 if !IndexFloat("1.5", "1.6") { 1408 t.Fatalf("expected true, got false") 1409 } 1410 if !IndexInt("-1", "2") { 1411 t.Fatalf("expected true, got false") 1412 } 1413 if !IndexUint("10", "25") { 1414 t.Fatalf("expected true, got false") 1415 } 1416 if !IndexBinary("Hello", "hello") { 1417 t.Fatalf("expected true, got false") 1418 } 1419 if IndexString("hello", "hello") { 1420 t.Fatalf("expected false, got true") 1421 } 1422 if IndexString("Hello", "hello") { 1423 t.Fatalf("expected false, got true") 1424 } 1425 if IndexString("hello", "Hello") { 1426 t.Fatalf("expected false, got true") 1427 } 1428 if !IndexString("gello", "Hello") { 1429 t.Fatalf("expected true, got false") 1430 } 1431 if IndexString("Hello", "gello") { 1432 t.Fatalf("expected false, got true") 1433 } 1434 if Rect(IndexRect("[1 2 3 4],[5 6 7 8]")) != "[1 2 3 4],[5 6 7 8]" { 1435 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4],[5 6 7 8]", Rect(IndexRect("[1 2 3 4],[5 6 7 8]"))) 1436 } 1437 if Rect(IndexRect("[1 2 3 4]")) != "[1 2 3 4]" { 1438 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4]", Rect(IndexRect("[1 2 3 4]"))) 1439 } 1440 if Rect(nil, nil) != "[]" { 1441 t.Fatalf("expected '%v', got '%v'", "", Rect(nil, nil)) 1442 } 1443 if Point(1, 2, 3) != "[1 2 3]" { 1444 t.Fatalf("expected '%v', got '%v'", "[1 2 3]", Point(1, 2, 3)) 1445 } 1446} 1447 1448// test opening a folder. 1449func TestOpeningAFolder(t *testing.T) { 1450 if err := os.RemoveAll("dir.tmp"); err != nil { 1451 t.Fatal(err) 1452 } 1453 if err := os.Mkdir("dir.tmp", 0700); err != nil { 1454 t.Fatal(err) 1455 } 1456 defer func() { _ = os.RemoveAll("dir.tmp") }() 1457 db, err := Open("dir.tmp") 1458 if err == nil { 1459 if err := db.Close(); err != nil { 1460 t.Fatal(err) 1461 } 1462 t.Fatalf("opening a directory should not be allowed") 1463 } 1464} 1465 1466// test opening an invalid resp file. 1467func TestOpeningInvalidDatabaseFile(t *testing.T) { 1468 if err := os.RemoveAll("data.db"); err != nil { 1469 t.Fatal(err) 1470 } 1471 if err := ioutil.WriteFile("data.db", []byte("invalid\r\nfile"), 0666); err != nil { 1472 t.Fatal(err) 1473 } 1474 defer func() { _ = os.RemoveAll("data.db") }() 1475 db, err := Open("data.db") 1476 if err == nil { 1477 if err := db.Close(); err != nil { 1478 t.Fatal(err) 1479 } 1480 t.Fatalf("invalid database should not be allowed") 1481 } 1482} 1483 1484// test closing a closed database. 1485func TestOpeningClosedDatabase(t *testing.T) { 1486 if err := os.RemoveAll("data.db"); err != nil { 1487 t.Fatal(err) 1488 } 1489 db, err := Open("data.db") 1490 if err != nil { 1491 t.Fatal(err) 1492 } 1493 defer func() { _ = os.RemoveAll("data.db") }() 1494 if err := db.Close(); err != nil { 1495 t.Fatal(err) 1496 } 1497 if err := db.Close(); err != ErrDatabaseClosed { 1498 t.Fatal("should not be able to close a closed database") 1499 } 1500 db, err = Open(":memory:") 1501 if err != nil { 1502 t.Fatal(err) 1503 } 1504 if err := db.Close(); err != nil { 1505 t.Fatal(err) 1506 } 1507 if err := db.Close(); err != ErrDatabaseClosed { 1508 t.Fatal("should not be able to close a closed database") 1509 } 1510} 1511 1512// test shrinking a database. 1513func TestShrink(t *testing.T) { 1514 db := testOpen(t) 1515 defer testClose(db) 1516 if err := db.Shrink(); err != nil { 1517 t.Fatal(err) 1518 } 1519 fi, err := os.Stat("data.db") 1520 if err != nil { 1521 t.Fatal(err) 1522 } 1523 if fi.Size() != 0 { 1524 t.Fatalf("expected %v, got %v", 0, fi.Size()) 1525 } 1526 // add 10 items 1527 err = db.Update(func(tx *Tx) error { 1528 for i := 0; i < 10; i++ { 1529 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1530 return err 1531 } 1532 } 1533 return nil 1534 }) 1535 if err != nil { 1536 t.Fatal(err) 1537 } 1538 // add the same 10 items 1539 // this will create 10 duplicate log entries 1540 err = db.Update(func(tx *Tx) error { 1541 for i := 0; i < 10; i++ { 1542 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1543 return err 1544 } 1545 } 1546 return nil 1547 }) 1548 if err != nil { 1549 t.Fatal(err) 1550 } 1551 fi, err = os.Stat("data.db") 1552 if err != nil { 1553 t.Fatal(err) 1554 } 1555 sz1 := fi.Size() 1556 if sz1 == 0 { 1557 t.Fatalf("expected > 0, got %v", sz1) 1558 } 1559 if err := db.Shrink(); err != nil { 1560 t.Fatal(err) 1561 } 1562 fi, err = os.Stat("data.db") 1563 if err != nil { 1564 t.Fatal(err) 1565 } 1566 sz2 := fi.Size() 1567 if sz2 >= sz1 { 1568 t.Fatalf("expected < %v, got %v", sz1, sz2) 1569 } 1570 if err := db.Close(); err != nil { 1571 t.Fatal(err) 1572 } 1573 if err := db.Shrink(); err != ErrDatabaseClosed { 1574 t.Fatal("shrink on a closed databse should not be allowed") 1575 } 1576 // Now we will open a db that does not persist 1577 db, err = Open(":memory:") 1578 if err != nil { 1579 t.Fatal(err) 1580 } 1581 defer func() { _ = db.Close() }() 1582 // add 10 items 1583 err = db.Update(func(tx *Tx) error { 1584 for i := 0; i < 10; i++ { 1585 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1586 return err 1587 } 1588 } 1589 return nil 1590 }) 1591 if err != nil { 1592 t.Fatal(err) 1593 } 1594 // add the same 10 items 1595 // this will create 10 duplicate log entries 1596 err = db.Update(func(tx *Tx) error { 1597 for i := 0; i < 10; i++ { 1598 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1599 return err 1600 } 1601 } 1602 return nil 1603 }) 1604 if err != nil { 1605 t.Fatal(err) 1606 } 1607 err = db.View(func(tx *Tx) error { 1608 n, err := tx.Len() 1609 if err != nil { 1610 t.Fatal(err) 1611 } 1612 if n != 10 { 1613 t.Fatalf("expecting %v, got %v", 10, n) 1614 } 1615 return nil 1616 }) 1617 if err != nil { 1618 t.Fatal(err) 1619 } 1620 // this should succeed even though it's basically a noop. 1621 if err := db.Shrink(); err != nil { 1622 t.Fatal(err) 1623 } 1624} 1625 1626func TestVariousIndexOperations(t *testing.T) { 1627 db := testOpen(t) 1628 defer testClose(db) 1629 // test creating an index with no index name. 1630 err := db.CreateIndex("", "", nil) 1631 if err == nil { 1632 t.Fatal("should not be able to create an index with no name") 1633 } 1634 // test creating an index with a name that has already been used. 1635 err = db.CreateIndex("hello", "", nil) 1636 if err != nil { 1637 t.Fatal(err) 1638 } 1639 err = db.CreateIndex("hello", "", nil) 1640 if err == nil { 1641 t.Fatal("should not be able to create a duplicate index") 1642 } 1643 err = db.Update(func(tx *Tx) error { 1644 1645 if _, _, err := tx.Set("user:1", "tom", nil); err != nil { 1646 return err 1647 } 1648 if _, _, err := tx.Set("user:2", "janet", nil); err != nil { 1649 return err 1650 } 1651 if _, _, err := tx.Set("alt:1", "from", nil); err != nil { 1652 return err 1653 } 1654 if _, _, err := tx.Set("alt:2", "there", nil); err != nil { 1655 return err 1656 } 1657 if _, _, err := tx.Set("rect:1", "[1 2],[3 4]", nil); err != nil { 1658 return err 1659 } 1660 if _, _, err := tx.Set("rect:2", "[5 6],[7 8]", nil); err != nil { 1661 return err 1662 } 1663 return nil 1664 }) 1665 if err != nil { 1666 t.Fatal(err) 1667 } 1668 // test creating an index after adding items. use pattern matching. have some items in the match and some not. 1669 if err := db.CreateIndex("string", "user:*", IndexString); err != nil { 1670 t.Fatal(err) 1671 } 1672 // test creating a spatial index after adding items. use pattern matching. have some items in the match and some not. 1673 if err := db.CreateSpatialIndex("rect", "rect:*", IndexRect); err != nil { 1674 t.Fatal(err) 1675 } 1676 // test dropping an index 1677 if err := db.DropIndex("hello"); err != nil { 1678 t.Fatal(err) 1679 } 1680 // test dropping an index with no name 1681 if err := db.DropIndex(""); err == nil { 1682 t.Fatal("should not be allowed to drop an index with no name") 1683 } 1684 // test dropping an index with no name 1685 if err := db.DropIndex("na"); err == nil { 1686 t.Fatal("should not be allowed to drop an index that does not exist") 1687 } 1688 // test retrieving index names 1689 names, err := db.Indexes() 1690 if err != nil { 1691 t.Fatal(err) 1692 } 1693 if strings.Join(names, ",") != "rect,string" { 1694 t.Fatalf("expecting '%v', got '%v'", "rect,string", strings.Join(names, ",")) 1695 } 1696 // test creating an index after closing database 1697 if err := db.Close(); err != nil { 1698 t.Fatal(err) 1699 } 1700 if err := db.CreateIndex("new-index", "", nil); err != ErrDatabaseClosed { 1701 t.Fatal("should not be able to create an index on a closed database") 1702 } 1703 // test getting index names after closing database 1704 if _, err := db.Indexes(); err != ErrDatabaseClosed { 1705 t.Fatal("should not be able to get index names on a closed database") 1706 } 1707 // test dropping an index after closing database 1708 if err := db.DropIndex("rect"); err != ErrDatabaseClosed { 1709 t.Fatal("should not be able to drop an index on a closed database") 1710 } 1711} 1712 1713func test(t *testing.T, a, b bool) { 1714 if a != b { 1715 t.Fatal("failed, bummer...") 1716 } 1717} 1718 1719func TestBasic(t *testing.T) { 1720 rand.Seed(time.Now().UnixNano()) 1721 db := testOpen(t) 1722 defer testClose(db) 1723 1724 // create a simple index 1725 if err := db.CreateIndex("users", "fun:user:*", IndexString); err != nil { 1726 t.Fatal(err) 1727 } 1728 1729 // create a spatial index 1730 if err := db.CreateSpatialIndex("rects", "rect:*", IndexRect); err != nil { 1731 t.Fatal(err) 1732 } 1733 if true { 1734 err := db.Update(func(tx *Tx) error { 1735 if _, _, err := tx.Set("fun:user:0", "tom", nil); err != nil { 1736 return err 1737 } 1738 if _, _, err := tx.Set("fun:user:1", "Randi", nil); err != nil { 1739 return err 1740 } 1741 if _, _, err := tx.Set("fun:user:2", "jane", nil); err != nil { 1742 return err 1743 } 1744 if _, _, err := tx.Set("fun:user:4", "Janet", nil); err != nil { 1745 return err 1746 } 1747 if _, _, err := tx.Set("fun:user:5", "Paula", nil); err != nil { 1748 return err 1749 } 1750 if _, _, err := tx.Set("fun:user:6", "peter", nil); err != nil { 1751 return err 1752 } 1753 if _, _, err := tx.Set("fun:user:7", "Terri", nil); err != nil { 1754 return err 1755 } 1756 return nil 1757 }) 1758 if err != nil { 1759 t.Fatal(err) 1760 } 1761 // add some random items 1762 start := time.Now() 1763 if err := db.Update(func(tx *Tx) error { 1764 for _, i := range rand.Perm(100) { 1765 if _, _, err := tx.Set(fmt.Sprintf("tag:%d", i+100), fmt.Sprintf("val:%d", rand.Int()%100+100), nil); err != nil { 1766 return err 1767 } 1768 } 1769 return nil 1770 }); err != nil { 1771 t.Fatal(err) 1772 } 1773 if false { 1774 println(time.Now().Sub(start).String(), db.keys.Len()) 1775 } 1776 // add some random rects 1777 if err := db.Update(func(tx *Tx) error { 1778 if _, _, err := tx.Set("rect:1", Rect([]float64{10, 10}, []float64{20, 20}), nil); err != nil { 1779 return err 1780 } 1781 if _, _, err := tx.Set("rect:2", Rect([]float64{15, 15}, []float64{24, 24}), nil); err != nil { 1782 return err 1783 } 1784 if _, _, err := tx.Set("rect:3", Rect([]float64{17, 17}, []float64{27, 27}), nil); err != nil { 1785 return err 1786 } 1787 return nil 1788 }); err != nil { 1789 t.Fatal(err) 1790 } 1791 } 1792 // verify the data has been created 1793 buf := &bytes.Buffer{} 1794 err := db.View(func(tx *Tx) error { 1795 err := tx.Ascend("users", func(key, val string) bool { 1796 fmt.Fprintf(buf, "%s %s\n", key, val) 1797 return true 1798 }) 1799 if err != nil { 1800 t.Fatal(err) 1801 } 1802 err = tx.AscendRange("", "tag:170", "tag:172", func(key, val string) bool { 1803 fmt.Fprintf(buf, "%s\n", key) 1804 return true 1805 }) 1806 if err != nil { 1807 t.Fatal(err) 1808 } 1809 err = tx.AscendGreaterOrEqual("", "tag:195", func(key, val string) bool { 1810 fmt.Fprintf(buf, "%s\n", key) 1811 return true 1812 }) 1813 if err != nil { 1814 t.Fatal(err) 1815 } 1816 err = tx.AscendGreaterOrEqual("", "rect:", func(key, val string) bool { 1817 if !strings.HasPrefix(key, "rect:") { 1818 return false 1819 } 1820 min, max := IndexRect(val) 1821 fmt.Fprintf(buf, "%s: %v,%v\n", key, min, max) 1822 return true 1823 }) 1824 expect := make([]string, 2) 1825 n := 0 1826 err = tx.Intersects("rects", "[0 0],[15 15]", func(key, val string) bool { 1827 if n == 2 { 1828 t.Fatalf("too many rects where received, expecting only two") 1829 } 1830 min, max := IndexRect(val) 1831 s := fmt.Sprintf("%s: %v,%v\n", key, min, max) 1832 if key == "rect:1" { 1833 expect[0] = s 1834 } else if key == "rect:2" { 1835 expect[1] = s 1836 } 1837 n++ 1838 return true 1839 }) 1840 if err != nil { 1841 t.Fatal(err) 1842 } 1843 for _, s := range expect { 1844 if _, err := buf.WriteString(s); err != nil { 1845 return err 1846 } 1847 } 1848 return nil 1849 }) 1850 if err != nil { 1851 t.Fatal(err) 1852 } 1853 res := ` 1854fun:user:2 jane 1855fun:user:4 Janet 1856fun:user:5 Paula 1857fun:user:6 peter 1858fun:user:1 Randi 1859fun:user:7 Terri 1860fun:user:0 tom 1861tag:170 1862tag:171 1863tag:195 1864tag:196 1865tag:197 1866tag:198 1867tag:199 1868rect:1: [10 10],[20 20] 1869rect:2: [15 15],[24 24] 1870rect:3: [17 17],[27 27] 1871rect:1: [10 10],[20 20] 1872rect:2: [15 15],[24 24] 1873` 1874 res = strings.Replace(res, "\r", "", -1) 1875 if strings.TrimSpace(buf.String()) != strings.TrimSpace(res) { 1876 t.Fatalf("expected [%v], got [%v]", strings.TrimSpace(res), strings.TrimSpace(buf.String())) 1877 } 1878} 1879 1880func TestIndexAscend(t *testing.T) { 1881 rand.Seed(time.Now().UnixNano()) 1882 db := testOpen(t) 1883 defer testClose(db) 1884 1885 // create a simple index 1886 if err := db.CreateIndex("usr", "usr:*", IndexInt); err != nil { 1887 t.Fatal(err) 1888 } 1889 if err := db.Update(func(tx *Tx) error { 1890 for i := 10; i > 0; i-- { 1891 tx.Set(fmt.Sprintf("usr:%d", i), fmt.Sprintf("%d", 10-i), nil) 1892 } 1893 return nil 1894 }); err != nil { 1895 t.Fatal(err) 1896 } 1897 1898 buf := &bytes.Buffer{} 1899 err := db.View(func(tx *Tx) error { 1900 tx.Ascend("usr", func(key, value string) bool { 1901 fmt.Fprintf(buf, "%s %s\n", key, value) 1902 return true 1903 }) 1904 fmt.Fprintln(buf) 1905 1906 tx.AscendGreaterOrEqual("usr", "8", func(key, value string) bool { 1907 fmt.Fprintf(buf, "%s %s\n", key, value) 1908 return true 1909 }) 1910 fmt.Fprintln(buf) 1911 1912 tx.AscendLessThan("usr", "3", func(key, value string) bool { 1913 fmt.Fprintf(buf, "%s %s\n", key, value) 1914 return true 1915 }) 1916 fmt.Fprintln(buf) 1917 1918 tx.AscendRange("usr", "4", "8", func(key, value string) bool { 1919 fmt.Fprintf(buf, "%s %s\n", key, value) 1920 return true 1921 }) 1922 return nil 1923 }) 1924 1925 if err != nil { 1926 t.Fatal(err) 1927 } 1928 1929 res := ` 1930usr:10 0 1931usr:9 1 1932usr:8 2 1933usr:7 3 1934usr:6 4 1935usr:5 5 1936usr:4 6 1937usr:3 7 1938usr:2 8 1939usr:1 9 1940 1941usr:2 8 1942usr:1 9 1943 1944usr:10 0 1945usr:9 1 1946usr:8 2 1947 1948usr:6 4 1949usr:5 5 1950usr:4 6 1951usr:3 7 1952` 1953 res = strings.Replace(res, "\r", "", -1) 1954 s1 := strings.TrimSpace(buf.String()) 1955 s2 := strings.TrimSpace(res) 1956 if s1 != s2 { 1957 t.Fatalf("expected [%v], got [%v]", s1, s2) 1958 } 1959} 1960 1961func testRectStringer(min, max []float64) error { 1962 nmin, nmax := IndexRect(Rect(min, max)) 1963 if len(nmin) != len(min) { 1964 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 1965 } 1966 for i := 0; i < len(min); i++ { 1967 if min[i] != nmin[i] || max[i] != nmax[i] { 1968 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 1969 } 1970 } 1971 return nil 1972} 1973func TestRectStrings(t *testing.T) { 1974 test(t, Rect(IndexRect(Point(1))) == "[1]", true) 1975 test(t, Rect(IndexRect(Point(1, 2, 3, 4))) == "[1 2 3 4]", true) 1976 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[1 2]")))) == "[1 2]", true) 1977 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2]")))) == "[1 2],[2 2]", true) 1978 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2],[3]")))) == "[1 2],[2 2]", true) 1979 test(t, Rect(IndexRect(Rect(IndexRect("[1 2]")))) == "[1 2]", true) 1980 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6]")))) == "[1.5 2 4.5 5.6]", true) 1981 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6 -1],[]")))) == "[1.5 2 4.5 5.6 -1]", true) 1982 test(t, Rect(IndexRect(Rect(IndexRect("[]")))) == "[]", true) 1983 test(t, Rect(IndexRect(Rect(IndexRect("")))) == "[]", true) 1984 if err := testRectStringer(nil, nil); err != nil { 1985 t.Fatal(err) 1986 } 1987 if err := testRectStringer([]float64{}, []float64{}); err != nil { 1988 t.Fatal(err) 1989 } 1990 if err := testRectStringer([]float64{1}, []float64{2}); err != nil { 1991 t.Fatal(err) 1992 } 1993 if err := testRectStringer([]float64{1, 2}, []float64{3, 4}); err != nil { 1994 t.Fatal(err) 1995 } 1996 if err := testRectStringer([]float64{1, 2, 3}, []float64{4, 5, 6}); err != nil { 1997 t.Fatal(err) 1998 } 1999 if err := testRectStringer([]float64{1, 2, 3, 4}, []float64{5, 6, 7, 8}); err != nil { 2000 t.Fatal(err) 2001 } 2002 if err := testRectStringer([]float64{1, 2, 3, 4, 5}, []float64{6, 7, 8, 9, 10}); err != nil { 2003 t.Fatal(err) 2004 } 2005} 2006 2007// TestTTLReOpen test setting a TTL and then immediately closing the database and 2008// then waiting the TTL before reopening. The key should not be accessible. 2009func TestTTLReOpen(t *testing.T) { 2010 ttl := time.Second * 3 2011 db := testOpen(t) 2012 defer testClose(db) 2013 err := db.Update(func(tx *Tx) error { 2014 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: ttl}); err != nil { 2015 return err 2016 } 2017 return nil 2018 }) 2019 if err != nil { 2020 t.Fatal(err) 2021 } 2022 db = testReOpenDelay(t, db, ttl/4) 2023 err = db.View(func(tx *Tx) error { 2024 val, err := tx.Get("key1") 2025 if err != nil { 2026 return err 2027 } 2028 if val != "val1" { 2029 t.Fatalf("expecting '%v', got '%v'", "val1", val) 2030 } 2031 return nil 2032 }) 2033 if err != nil { 2034 t.Fatal(err) 2035 } 2036 db = testReOpenDelay(t, db, ttl-ttl/4) 2037 defer testClose(db) 2038 err = db.View(func(tx *Tx) error { 2039 val, err := tx.Get("key1") 2040 if err == nil || err != ErrNotFound || val != "" { 2041 t.Fatal("expecting not found") 2042 } 2043 2044 return nil 2045 }) 2046 if err != nil { 2047 t.Fatal(err) 2048 } 2049} 2050 2051func TestTTL(t *testing.T) { 2052 db := testOpen(t) 2053 defer testClose(db) 2054 err := db.Update(func(tx *Tx) error { 2055 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 2056 return err 2057 } 2058 if _, _, err := tx.Set("key2", "val2", nil); err != nil { 2059 return err 2060 } 2061 return nil 2062 }) 2063 if err != nil { 2064 t.Fatal(err) 2065 } 2066 err = db.View(func(tx *Tx) error { 2067 dur1, err := tx.TTL("key1") 2068 if err != nil { 2069 t.Fatal(err) 2070 } 2071 if dur1 > time.Second || dur1 <= 0 { 2072 t.Fatalf("expecting between zero and one second, got '%v'", dur1) 2073 } 2074 dur1, err = tx.TTL("key2") 2075 if err != nil { 2076 t.Fatal(err) 2077 } 2078 if dur1 >= 0 { 2079 t.Fatalf("expecting a negative value, got '%v'", dur1) 2080 } 2081 return nil 2082 }) 2083 if err != nil { 2084 t.Fatal(err) 2085 } 2086} 2087 2088func TestConfig(t *testing.T) { 2089 db := testOpen(t) 2090 defer testClose(db) 2091 2092 err := db.SetConfig(Config{SyncPolicy: SyncPolicy(-1)}) 2093 if err == nil { 2094 t.Fatal("expecting a config syncpolicy error") 2095 } 2096 err = db.SetConfig(Config{SyncPolicy: SyncPolicy(3)}) 2097 if err == nil { 2098 t.Fatal("expecting a config syncpolicy error") 2099 } 2100 err = db.SetConfig(Config{SyncPolicy: Never}) 2101 if err != nil { 2102 t.Fatal(err) 2103 } 2104 err = db.SetConfig(Config{SyncPolicy: EverySecond}) 2105 if err != nil { 2106 t.Fatal(err) 2107 } 2108 err = db.SetConfig(Config{AutoShrinkMinSize: 100, AutoShrinkPercentage: 200, SyncPolicy: Always}) 2109 if err != nil { 2110 t.Fatal(err) 2111 } 2112 2113 var c Config 2114 if err := db.ReadConfig(&c); err != nil { 2115 t.Fatal(err) 2116 } 2117 if c.AutoShrinkMinSize != 100 || c.AutoShrinkPercentage != 200 && c.SyncPolicy != Always { 2118 t.Fatalf("expecting %v, %v, and %v, got %v, %v, and %v", 100, 200, Always, c.AutoShrinkMinSize, c.AutoShrinkPercentage, c.SyncPolicy) 2119 } 2120} 2121func testUint64Hex(n uint64) string { 2122 s := strconv.FormatUint(n, 16) 2123 s = "0000000000000000" + s 2124 return s[len(s)-16:] 2125} 2126func textHexUint64(s string) uint64 { 2127 n, _ := strconv.ParseUint(s, 16, 64) 2128 return n 2129} 2130func benchClose(t *testing.B, persist bool, db *DB) { 2131 if persist { 2132 if err := os.RemoveAll("data.db"); err != nil { 2133 t.Fatal(err) 2134 } 2135 } 2136 if err := db.Close(); err != nil { 2137 t.Fatal(err) 2138 } 2139} 2140 2141func benchOpenFillData(t *testing.B, N int, 2142 set, persist, random bool, 2143 geo bool, 2144 batch int) (db *DB, keys, vals []string) { 2145 /// 2146 t.StopTimer() 2147 rand.Seed(time.Now().UnixNano()) 2148 var err error 2149 if persist { 2150 if err := os.RemoveAll("data.db"); err != nil { 2151 t.Fatal(err) 2152 } 2153 db, err = Open("data.db") 2154 } else { 2155 db, err = Open(":memory:") 2156 } 2157 if err != nil { 2158 t.Fatal(err) 2159 } 2160 keys = make([]string, N) 2161 vals = make([]string, N) 2162 perm := rand.Perm(N) 2163 for i := 0; i < N; i++ { 2164 if random && set { 2165 keys[perm[i]] = testUint64Hex(uint64(i)) 2166 vals[perm[i]] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2167 } else { 2168 keys[i] = testUint64Hex(uint64(i)) 2169 vals[i] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2170 } 2171 } 2172 if set { 2173 t.StartTimer() 2174 } 2175 for i := 0; i < N; { 2176 err := db.Update(func(tx *Tx) error { 2177 var err error 2178 for j := 0; j < batch && i < N; j++ { 2179 _, _, err = tx.Set(keys[i], vals[i], nil) 2180 i++ 2181 } 2182 return err 2183 }) 2184 if err != nil { 2185 t.Fatal(err) 2186 } 2187 } 2188 if set { 2189 t.StopTimer() 2190 } 2191 var n uint64 2192 err = db.View(func(tx *Tx) error { 2193 err := tx.Ascend("", func(key, value string) bool { 2194 n2 := textHexUint64(key) 2195 if n2 != n { 2196 t.Fatalf("expecting '%v', got '%v'", n2, n) 2197 } 2198 n++ 2199 return true 2200 }) 2201 return err 2202 }) 2203 if err != nil { 2204 t.Fatal(err) 2205 } 2206 if n != uint64(N) { 2207 t.Fatalf("expecting '%v', got '%v'", N, n) 2208 } 2209 t.StartTimer() 2210 return db, keys, vals 2211} 2212 2213func benchSetGet(t *testing.B, set, persist, random bool, batch int) { 2214 N := t.N 2215 for N > 0 { 2216 n := 0 2217 if N >= 100000 { 2218 n = 100000 2219 } else { 2220 n = N 2221 } 2222 func() { 2223 db, keys, _ := benchOpenFillData(t, n, set, persist, random, false, batch) 2224 defer benchClose(t, persist, db) 2225 if !set { 2226 for i := 0; i < n; { 2227 err := db.View(func(tx *Tx) error { 2228 var err error 2229 for j := 0; j < batch && i < n; j++ { 2230 _, err = tx.Get(keys[i]) 2231 i++ 2232 } 2233 return err 2234 }) 2235 if err != nil { 2236 t.Fatal(err) 2237 } 2238 } 2239 } 2240 }() 2241 N -= n 2242 } 2243} 2244 2245// Set Persist 2246func Benchmark_Set_Persist_Random_1(t *testing.B) { 2247 benchSetGet(t, true, true, true, 1) 2248} 2249func Benchmark_Set_Persist_Random_10(t *testing.B) { 2250 benchSetGet(t, true, true, true, 10) 2251} 2252func Benchmark_Set_Persist_Random_100(t *testing.B) { 2253 benchSetGet(t, true, true, true, 100) 2254} 2255func Benchmark_Set_Persist_Sequential_1(t *testing.B) { 2256 benchSetGet(t, true, true, false, 1) 2257} 2258func Benchmark_Set_Persist_Sequential_10(t *testing.B) { 2259 benchSetGet(t, true, true, false, 10) 2260} 2261func Benchmark_Set_Persist_Sequential_100(t *testing.B) { 2262 benchSetGet(t, true, true, false, 100) 2263} 2264 2265// Set NoPersist 2266func Benchmark_Set_NoPersist_Random_1(t *testing.B) { 2267 benchSetGet(t, true, false, true, 1) 2268} 2269func Benchmark_Set_NoPersist_Random_10(t *testing.B) { 2270 benchSetGet(t, true, false, true, 10) 2271} 2272func Benchmark_Set_NoPersist_Random_100(t *testing.B) { 2273 benchSetGet(t, true, false, true, 100) 2274} 2275func Benchmark_Set_NoPersist_Sequential_1(t *testing.B) { 2276 benchSetGet(t, true, false, false, 1) 2277} 2278func Benchmark_Set_NoPersist_Sequential_10(t *testing.B) { 2279 benchSetGet(t, true, false, false, 10) 2280} 2281func Benchmark_Set_NoPersist_Sequential_100(t *testing.B) { 2282 benchSetGet(t, true, false, false, 100) 2283} 2284 2285// Get 2286func Benchmark_Get_1(t *testing.B) { 2287 benchSetGet(t, false, false, false, 1) 2288} 2289func Benchmark_Get_10(t *testing.B) { 2290 benchSetGet(t, false, false, false, 10) 2291} 2292func Benchmark_Get_100(t *testing.B) { 2293 benchSetGet(t, false, false, false, 100) 2294} 2295 2296func benchScan(t *testing.B, asc bool, count int) { 2297 N := count 2298 db, _, _ := benchOpenFillData(t, N, false, false, false, false, 100) 2299 defer benchClose(t, false, db) 2300 for i := 0; i < t.N; i++ { 2301 count := 0 2302 err := db.View(func(tx *Tx) error { 2303 if asc { 2304 return tx.Ascend("", func(key, val string) bool { 2305 count++ 2306 return true 2307 }) 2308 } 2309 return tx.Descend("", func(key, val string) bool { 2310 count++ 2311 return true 2312 }) 2313 2314 }) 2315 if err != nil { 2316 t.Fatal(err) 2317 } 2318 if count != N { 2319 t.Fatalf("expecting '%v', got '%v'", N, count) 2320 } 2321 } 2322} 2323 2324func Benchmark_Ascend_1(t *testing.B) { 2325 benchScan(t, true, 1) 2326} 2327func Benchmark_Ascend_10(t *testing.B) { 2328 benchScan(t, true, 10) 2329} 2330func Benchmark_Ascend_100(t *testing.B) { 2331 benchScan(t, true, 100) 2332} 2333func Benchmark_Ascend_1000(t *testing.B) { 2334 benchScan(t, true, 1000) 2335} 2336func Benchmark_Ascend_10000(t *testing.B) { 2337 benchScan(t, true, 10000) 2338} 2339 2340func Benchmark_Descend_1(t *testing.B) { 2341 benchScan(t, false, 1) 2342} 2343func Benchmark_Descend_10(t *testing.B) { 2344 benchScan(t, false, 10) 2345} 2346func Benchmark_Descend_100(t *testing.B) { 2347 benchScan(t, false, 100) 2348} 2349func Benchmark_Descend_1000(t *testing.B) { 2350 benchScan(t, false, 1000) 2351} 2352func Benchmark_Descend_10000(t *testing.B) { 2353 benchScan(t, false, 10000) 2354} 2355 2356/* 2357func Benchmark_Spatial_2D(t *testing.B) { 2358 N := 100000 2359 db, _, _ := benchOpenFillData(t, N, true, true, false, true, 100) 2360 defer benchClose(t, false, db) 2361 2362} 2363*/ 2364func TestCoverCloseAlreadyClosed(t *testing.T) { 2365 db := testOpen(t) 2366 defer testClose(db) 2367 _ = db.file.Close() 2368 if err := db.Close(); err == nil { 2369 t.Fatal("expecting an error") 2370 } 2371} 2372 2373func TestCoverConfigClosed(t *testing.T) { 2374 db := testOpen(t) 2375 defer testClose(db) 2376 _ = db.Close() 2377 var config Config 2378 if err := db.ReadConfig(&config); err != ErrDatabaseClosed { 2379 t.Fatal("expecting database closed error") 2380 } 2381 if err := db.SetConfig(config); err != ErrDatabaseClosed { 2382 t.Fatal("expecting database closed error") 2383 } 2384} 2385func TestCoverShrinkShrink(t *testing.T) { 2386 db := testOpen(t) 2387 defer testClose(db) 2388 if err := db.Update(func(tx *Tx) error { 2389 for i := 0; i < 10000; i++ { 2390 _, _, err := tx.Set(fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), nil) 2391 if err != nil { 2392 return err 2393 } 2394 } 2395 return nil 2396 }); err != nil { 2397 t.Fatal(err) 2398 } 2399 if err := db.Update(func(tx *Tx) error { 2400 for i := 250; i < 250+100; i++ { 2401 _, err := tx.Delete(fmt.Sprintf("%d", i)) 2402 if err != nil { 2403 return err 2404 } 2405 } 2406 return nil 2407 }); err != nil { 2408 t.Fatal(err) 2409 } 2410 var err1, err2 error 2411 var wg sync.WaitGroup 2412 wg.Add(2) 2413 go func() { 2414 defer wg.Done() 2415 err1 = db.Shrink() 2416 }() 2417 go func() { 2418 defer wg.Done() 2419 err2 = db.Shrink() 2420 }() 2421 wg.Wait() 2422 //println(123) 2423 //fmt.Printf("%v\n%v\n", err1, err2) 2424 if err1 != ErrShrinkInProcess && err2 != ErrShrinkInProcess { 2425 t.Fatal("expecting a shrink in process error") 2426 } 2427 db = testReOpen(t, db) 2428 defer testClose(db) 2429 if err := db.View(func(tx *Tx) error { 2430 n, err := tx.Len() 2431 if err != nil { 2432 return err 2433 } 2434 if n != 9900 { 2435 t.Fatal("expecting 9900 items") 2436 } 2437 return nil 2438 }); err != nil { 2439 t.Fatal(err) 2440 } 2441} 2442 2443func TestPreviousItem(t *testing.T) { 2444 db := testOpen(t) 2445 defer testClose(db) 2446 err := db.Update(func(tx *Tx) error { 2447 _, _, err := tx.Set("hello", "world", nil) 2448 if err != nil { 2449 return err 2450 } 2451 prev, replaced, err := tx.Set("hello", "planet", nil) 2452 if err != nil { 2453 return err 2454 } 2455 if !replaced { 2456 t.Fatal("should be replaced") 2457 } 2458 if prev != "world" { 2459 t.Fatalf("expecting '%v', got '%v'", "world", prev) 2460 } 2461 return nil 2462 }) 2463 if err != nil { 2464 t.Fatal(err) 2465 } 2466} 2467 2468func TestJSONIndex(t *testing.T) { 2469 db := testOpen(t) 2470 defer testClose(db) 2471 2472 _ = db.CreateIndex("last_name", "*", IndexJSON("name.last")) 2473 _ = db.CreateIndex("last_name_cs", "*", IndexJSONCaseSensitive("name.last")) 2474 _ = db.CreateIndex("age", "*", IndexJSON("age")) 2475 _ = db.CreateIndex("student", "*", IndexJSON("student")) 2476 _ = db.Update(func(tx *Tx) error { 2477 _, _, _ = tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38,"student":false}`, nil) 2478 _, _, _ = tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47,"student":true}`, nil) 2479 _, _, _ = tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52,"student":true}`, nil) 2480 _, _, _ = tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28,"student":false}`, nil) 2481 _, _, _ = tx.Set("5", `{"name":{"first":"bill","last":"frank"},"age":21,"student":true}`, nil) 2482 _, _, _ = tx.Set("6", `{"name":{"first":"sally","last":"randall"},"age":68,"student":false}`, nil) 2483 return nil 2484 }) 2485 var keys []string 2486 _ = db.View(func(tx *Tx) error { 2487 _ = tx.Ascend("last_name_cs", func(key, value string) bool { 2488 //fmt.Printf("%s: %s\n", key, value) 2489 keys = append(keys, key) 2490 return true 2491 }) 2492 _ = tx.Ascend("last_name", func(key, value string) bool { 2493 //fmt.Printf("%s: %s\n", key, value) 2494 keys = append(keys, key) 2495 return true 2496 }) 2497 _ = tx.Ascend("age", func(key, value string) bool { 2498 //fmt.Printf("%s: %s\n", key, value) 2499 keys = append(keys, key) 2500 return true 2501 }) 2502 _ = tx.Ascend("student", func(key, value string) bool { 2503 //fmt.Printf("%s: %s\n", key, value) 2504 keys = append(keys, key) 2505 return true 2506 }) 2507 return nil 2508 }) 2509 expect := "3,4,1,2,5,6,3,4,5,1,2,6,5,4,1,2,3,6,1,4,6,2,3,5" 2510 if strings.Join(keys, ",") != expect { 2511 t.Fatalf("expected %v, got %v", expect, strings.Join(keys, ",")) 2512 } 2513} 2514