go.alphawatch.io/buntdb@v1.1.3/buntdb_test.go (about) 1 package buntdb 2 3 import ( 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 17 func 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 } 23 func testReOpen(t testing.TB, db *DB) *DB { 24 return testReOpenDelay(t, db, 0) 25 } 26 27 func 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 41 func testClose(db *DB) { 42 _ = db.Close() 43 _ = os.RemoveAll("data.db") 44 } 45 46 func 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 } 92 func 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 148 func 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 188 func 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 233 func 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 394 func 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 498 func 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 } 550 func 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 } 602 func 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 1024 func TestNearby(t *testing.T) { 1025 rand.Seed(time.Now().UnixNano()) 1026 N := 100000 1027 db, _ := Open(":memory:") 1028 db.CreateSpatialIndex("points", "*", IndexRect) 1029 db.Update(func(tx *Tx) error { 1030 for i := 0; i < N; i++ { 1031 p := Point( 1032 rand.Float64()*100, 1033 rand.Float64()*100, 1034 rand.Float64()*100, 1035 rand.Float64()*100, 1036 ) 1037 tx.Set(fmt.Sprintf("p:%d", i), p, nil) 1038 } 1039 return nil 1040 }) 1041 var keys, values []string 1042 var dists []float64 1043 var pdist float64 1044 var i int 1045 db.View(func(tx *Tx) error { 1046 tx.Nearby("points", Point(0, 0, 0, 0), func(key, value string, dist float64) bool { 1047 if i != 0 && dist < pdist { 1048 t.Fatal("out of order") 1049 } 1050 keys = append(keys, key) 1051 values = append(values, value) 1052 dists = append(dists, dist) 1053 pdist = dist 1054 i++ 1055 return true 1056 }) 1057 return nil 1058 }) 1059 if len(keys) != N { 1060 t.Fatalf("expected '%v', got '%v'", N, len(keys)) 1061 } 1062 } 1063 1064 func Example_descKeys() { 1065 db, _ := Open(":memory:") 1066 db.CreateIndex("name", "*", IndexString) 1067 db.Update(func(tx *Tx) error { 1068 tx.Set("user:100:first", "Tom", nil) 1069 tx.Set("user:100:last", "Johnson", nil) 1070 tx.Set("user:101:first", "Janet", nil) 1071 tx.Set("user:101:last", "Prichard", nil) 1072 tx.Set("user:102:first", "Alan", nil) 1073 tx.Set("user:102:last", "Cooper", nil) 1074 return nil 1075 }) 1076 db.View(func(tx *Tx) error { 1077 tx.AscendKeys("user:101:*", 1078 func(key, value string) bool { 1079 fmt.Printf("%s: %s\n", key, value) 1080 return true 1081 }) 1082 tx.AscendKeys("user:10?:*", 1083 func(key, value string) bool { 1084 fmt.Printf("%s: %s\n", key, value) 1085 return true 1086 }) 1087 tx.AscendKeys("*2*", 1088 func(key, value string) bool { 1089 fmt.Printf("%s: %s\n", key, value) 1090 return true 1091 }) 1092 tx.DescendKeys("user:101:*", 1093 func(key, value string) bool { 1094 fmt.Printf("%s: %s\n", key, value) 1095 return true 1096 }) 1097 tx.DescendKeys("*", 1098 func(key, value string) bool { 1099 fmt.Printf("%s: %s\n", key, value) 1100 return true 1101 }) 1102 return nil 1103 }) 1104 // Output: 1105 //user:101:first: Janet 1106 //user:101:last: Prichard 1107 //user:100:first: Tom 1108 //user:100:last: Johnson 1109 //user:101:first: Janet 1110 //user:101:last: Prichard 1111 //user:102:first: Alan 1112 //user:102:last: Cooper 1113 //user:102:first: Alan 1114 //user:102:last: Cooper 1115 //user:101:last: Prichard 1116 //user:101:first: Janet 1117 //user:102:last: Cooper 1118 //user:102:first: Alan 1119 //user:101:last: Prichard 1120 //user:101:first: Janet 1121 //user:100:last: Johnson 1122 //user:100:first: Tom 1123 } 1124 1125 func ExampleDesc() { 1126 db, _ := Open(":memory:") 1127 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), Desc(IndexJSON("age"))) 1128 db.Update(func(tx *Tx) error { 1129 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1130 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1131 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1132 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1133 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1134 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1135 return nil 1136 }) 1137 db.View(func(tx *Tx) error { 1138 tx.Ascend("last_name_age", func(key, value string) bool { 1139 fmt.Printf("%s: %s\n", key, value) 1140 return true 1141 }) 1142 return nil 1143 }) 1144 1145 // Output: 1146 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1147 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1148 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1149 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1150 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1151 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1152 } 1153 1154 func ExampleDB_CreateIndex_jSON() { 1155 db, _ := Open(":memory:") 1156 db.CreateIndex("last_name", "*", IndexJSON("name.last")) 1157 db.CreateIndex("age", "*", IndexJSON("age")) 1158 db.Update(func(tx *Tx) error { 1159 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1160 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1161 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1162 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1163 return nil 1164 }) 1165 db.View(func(tx *Tx) error { 1166 fmt.Println("Order by last name") 1167 tx.Ascend("last_name", func(key, value string) bool { 1168 fmt.Printf("%s: %s\n", key, value) 1169 return true 1170 }) 1171 fmt.Println("Order by age") 1172 tx.Ascend("age", func(key, value string) bool { 1173 fmt.Printf("%s: %s\n", key, value) 1174 return true 1175 }) 1176 fmt.Println("Order by age range 30-50") 1177 tx.AscendRange("age", `{"age":30}`, `{"age":50}`, func(key, value string) bool { 1178 fmt.Printf("%s: %s\n", key, value) 1179 return true 1180 }) 1181 return nil 1182 }) 1183 1184 // Output: 1185 // Order by last name 1186 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1187 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1188 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1189 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1190 // Order by age 1191 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1192 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1193 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1194 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1195 // Order by age range 30-50 1196 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1197 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1198 } 1199 1200 func ExampleDB_CreateIndex_strings() { 1201 db, _ := Open(":memory:") 1202 db.CreateIndex("name", "*", IndexString) 1203 db.Update(func(tx *Tx) error { 1204 tx.Set("1", "Tom", nil) 1205 tx.Set("2", "Janet", nil) 1206 tx.Set("3", "Carol", nil) 1207 tx.Set("4", "Alan", nil) 1208 tx.Set("5", "Sam", nil) 1209 tx.Set("6", "Melinda", nil) 1210 return nil 1211 }) 1212 db.View(func(tx *Tx) error { 1213 tx.Ascend("name", func(key, value string) bool { 1214 fmt.Printf("%s: %s\n", key, value) 1215 return true 1216 }) 1217 return nil 1218 }) 1219 1220 // Output: 1221 //4: Alan 1222 //3: Carol 1223 //2: Janet 1224 //6: Melinda 1225 //5: Sam 1226 //1: Tom 1227 } 1228 1229 func ExampleDB_CreateIndex_ints() { 1230 db, _ := Open(":memory:") 1231 db.CreateIndex("age", "*", IndexInt) 1232 db.Update(func(tx *Tx) error { 1233 tx.Set("1", "30", nil) 1234 tx.Set("2", "51", nil) 1235 tx.Set("3", "16", nil) 1236 tx.Set("4", "76", nil) 1237 tx.Set("5", "23", nil) 1238 tx.Set("6", "43", nil) 1239 return nil 1240 }) 1241 db.View(func(tx *Tx) error { 1242 tx.Ascend("age", func(key, value string) bool { 1243 fmt.Printf("%s: %s\n", key, value) 1244 return true 1245 }) 1246 return nil 1247 }) 1248 1249 // Output: 1250 //3: 16 1251 //5: 23 1252 //1: 30 1253 //6: 43 1254 //2: 51 1255 //4: 76 1256 } 1257 func ExampleDB_CreateIndex_multipleFields() { 1258 db, _ := Open(":memory:") 1259 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), IndexJSON("age")) 1260 db.Update(func(tx *Tx) error { 1261 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1262 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1263 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1264 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1265 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1266 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1267 return nil 1268 }) 1269 db.View(func(tx *Tx) error { 1270 tx.Ascend("last_name_age", func(key, value string) bool { 1271 fmt.Printf("%s: %s\n", key, value) 1272 return true 1273 }) 1274 return nil 1275 }) 1276 1277 // Output: 1278 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1279 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1280 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1281 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1282 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1283 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1284 } 1285 1286 func TestNoExpiringItem(t *testing.T) { 1287 item := &dbItem{key: "key", val: "val"} 1288 if !item.expiresAt().Equal(maxTime) { 1289 t.Fatal("item.expiresAt() != maxTime") 1290 } 1291 if min, max := item.Rect(nil); min != nil || max != nil { 1292 t.Fatal("item min,max should both be nil") 1293 } 1294 } 1295 func TestAutoShrink(t *testing.T) { 1296 db := testOpen(t) 1297 defer testClose(db) 1298 for i := 0; i < 1000; i++ { 1299 err := db.Update(func(tx *Tx) error { 1300 for i := 0; i < 20; i++ { 1301 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1302 return err 1303 } 1304 } 1305 return nil 1306 }) 1307 if err != nil { 1308 t.Fatal(err) 1309 } 1310 } 1311 db = testReOpen(t, db) 1312 defer testClose(db) 1313 db.config.AutoShrinkMinSize = 64 * 1024 // 64K 1314 for i := 0; i < 2000; i++ { 1315 err := db.Update(func(tx *Tx) error { 1316 for i := 0; i < 20; i++ { 1317 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1318 return err 1319 } 1320 } 1321 return nil 1322 }) 1323 if err != nil { 1324 t.Fatal(err) 1325 } 1326 } 1327 time.Sleep(time.Second * 3) 1328 db = testReOpen(t, db) 1329 defer testClose(db) 1330 err := db.View(func(tx *Tx) error { 1331 n, err := tx.Len() 1332 if err != nil { 1333 return err 1334 } 1335 if n != 20 { 1336 t.Fatalf("expecting 20, got %v", n) 1337 } 1338 return nil 1339 }) 1340 if err != nil { 1341 t.Fatal(err) 1342 } 1343 } 1344 1345 // test database format loading 1346 func TestDatabaseFormat(t *testing.T) { 1347 // should succeed 1348 func() { 1349 resp := strings.Join([]string{ 1350 "*3\r\n$3\r\nset\r\n$4\r\nvar1\r\n$4\r\n1234\r\n", 1351 "*3\r\n$3\r\nset\r\n$4\r\nvar2\r\n$4\r\n1234\r\n", 1352 "*2\r\n$3\r\ndel\r\n$4\r\nvar1\r\n", 1353 "*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", 1354 }, "") 1355 if err := os.RemoveAll("data.db"); err != nil { 1356 t.Fatal(err) 1357 } 1358 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1359 t.Fatal(err) 1360 } 1361 db := testOpen(t) 1362 defer testClose(db) 1363 }() 1364 testBadFormat := func(resp string) { 1365 if err := os.RemoveAll("data.db"); err != nil { 1366 t.Fatal(err) 1367 } 1368 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1369 t.Fatal(err) 1370 } 1371 db, err := Open("data.db") 1372 if err == nil { 1373 if err := db.Close(); err != nil { 1374 t.Fatal(err) 1375 } 1376 if err := os.RemoveAll("data.db"); err != nil { 1377 t.Fatal(err) 1378 } 1379 t.Fatalf("invalid database should not be allowed") 1380 } 1381 } 1382 testBadFormat("*3\r") 1383 testBadFormat("*3\n") 1384 testBadFormat("*a\r\n") 1385 testBadFormat("*2\r\n") 1386 testBadFormat("*2\r\n%3") 1387 testBadFormat("*2\r\n$") 1388 testBadFormat("*2\r\n$3\r\n") 1389 testBadFormat("*2\r\n$3\r\ndel") 1390 testBadFormat("*2\r\n$3\r\ndel\r\r") 1391 testBadFormat("*0\r\n*2\r\n$3\r\ndel\r\r") 1392 testBadFormat("*1\r\n$3\r\nnop\r\n") 1393 testBadFormat("*1\r\n$3\r\ndel\r\n") 1394 testBadFormat("*1\r\n$3\r\nset\r\n") 1395 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") 1396 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") 1397 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") 1398 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") 1399 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") 1400 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") 1401 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") 1402 } 1403 1404 func TestInsertsAndDeleted(t *testing.T) { 1405 db := testOpen(t) 1406 defer testClose(db) 1407 if err := db.CreateIndex("any", "*", IndexString); err != nil { 1408 t.Fatal(err) 1409 } 1410 if err := db.CreateSpatialIndex("rect", "*", IndexRect); err != nil { 1411 t.Fatal(err) 1412 } 1413 if err := db.Update(func(tx *Tx) error { 1414 if _, _, err := tx.Set("item1", "value1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1415 return err 1416 } 1417 if _, _, err := tx.Set("item2", "value2", nil); err != nil { 1418 return err 1419 } 1420 if _, _, err := tx.Set("item3", "value3", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1421 return err 1422 } 1423 return nil 1424 }); err != nil { 1425 t.Fatal(err) 1426 } 1427 1428 // test replacing items in the database 1429 if err := db.Update(func(tx *Tx) error { 1430 if _, _, err := tx.Set("item1", "nvalue1", nil); err != nil { 1431 return err 1432 } 1433 if _, _, err := tx.Set("item2", "nvalue2", nil); err != nil { 1434 return err 1435 } 1436 if _, err := tx.Delete("item3"); err != nil { 1437 return err 1438 } 1439 return nil 1440 }); err != nil { 1441 t.Fatal(err) 1442 } 1443 } 1444 1445 // test index compare functions 1446 func TestIndexCompare(t *testing.T) { 1447 if !IndexFloat("1.5", "1.6") { 1448 t.Fatalf("expected true, got false") 1449 } 1450 if !IndexInt("-1", "2") { 1451 t.Fatalf("expected true, got false") 1452 } 1453 if !IndexUint("10", "25") { 1454 t.Fatalf("expected true, got false") 1455 } 1456 if !IndexBinary("Hello", "hello") { 1457 t.Fatalf("expected true, got false") 1458 } 1459 if IndexString("hello", "hello") { 1460 t.Fatalf("expected false, got true") 1461 } 1462 if IndexString("Hello", "hello") { 1463 t.Fatalf("expected false, got true") 1464 } 1465 if IndexString("hello", "Hello") { 1466 t.Fatalf("expected false, got true") 1467 } 1468 if !IndexString("gello", "Hello") { 1469 t.Fatalf("expected true, got false") 1470 } 1471 if IndexString("Hello", "gello") { 1472 t.Fatalf("expected false, got true") 1473 } 1474 if Rect(IndexRect("[1 2 3 4],[5 6 7 8]")) != "[1 2 3 4],[5 6 7 8]" { 1475 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4],[5 6 7 8]", Rect(IndexRect("[1 2 3 4],[5 6 7 8]"))) 1476 } 1477 if Rect(IndexRect("[1 2 3 4]")) != "[1 2 3 4]" { 1478 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4]", Rect(IndexRect("[1 2 3 4]"))) 1479 } 1480 if Rect(nil, nil) != "[]" { 1481 t.Fatalf("expected '%v', got '%v'", "", Rect(nil, nil)) 1482 } 1483 if Point(1, 2, 3) != "[1 2 3]" { 1484 t.Fatalf("expected '%v', got '%v'", "[1 2 3]", Point(1, 2, 3)) 1485 } 1486 } 1487 1488 // test opening a folder. 1489 func TestOpeningAFolder(t *testing.T) { 1490 if err := os.RemoveAll("dir.tmp"); err != nil { 1491 t.Fatal(err) 1492 } 1493 if err := os.Mkdir("dir.tmp", 0700); err != nil { 1494 t.Fatal(err) 1495 } 1496 defer func() { _ = os.RemoveAll("dir.tmp") }() 1497 db, err := Open("dir.tmp") 1498 if err == nil { 1499 if err := db.Close(); err != nil { 1500 t.Fatal(err) 1501 } 1502 t.Fatalf("opening a directory should not be allowed") 1503 } 1504 } 1505 1506 // test opening an invalid resp file. 1507 func TestOpeningInvalidDatabaseFile(t *testing.T) { 1508 if err := os.RemoveAll("data.db"); err != nil { 1509 t.Fatal(err) 1510 } 1511 if err := ioutil.WriteFile("data.db", []byte("invalid\r\nfile"), 0666); err != nil { 1512 t.Fatal(err) 1513 } 1514 defer func() { _ = os.RemoveAll("data.db") }() 1515 db, err := Open("data.db") 1516 if err == nil { 1517 if err := db.Close(); err != nil { 1518 t.Fatal(err) 1519 } 1520 t.Fatalf("invalid database should not be allowed") 1521 } 1522 } 1523 1524 // test closing a closed database. 1525 func TestOpeningClosedDatabase(t *testing.T) { 1526 if err := os.RemoveAll("data.db"); err != nil { 1527 t.Fatal(err) 1528 } 1529 db, err := Open("data.db") 1530 if err != nil { 1531 t.Fatal(err) 1532 } 1533 defer func() { _ = os.RemoveAll("data.db") }() 1534 if err := db.Close(); err != nil { 1535 t.Fatal(err) 1536 } 1537 if err := db.Close(); err != ErrDatabaseClosed { 1538 t.Fatal("should not be able to close a closed database") 1539 } 1540 db, err = Open(":memory:") 1541 if err != nil { 1542 t.Fatal(err) 1543 } 1544 if err := db.Close(); err != nil { 1545 t.Fatal(err) 1546 } 1547 if err := db.Close(); err != ErrDatabaseClosed { 1548 t.Fatal("should not be able to close a closed database") 1549 } 1550 } 1551 1552 // test shrinking a database. 1553 func TestShrink(t *testing.T) { 1554 db := testOpen(t) 1555 defer testClose(db) 1556 if err := db.Shrink(); err != nil { 1557 t.Fatal(err) 1558 } 1559 fi, err := os.Stat("data.db") 1560 if err != nil { 1561 t.Fatal(err) 1562 } 1563 if fi.Size() != 0 { 1564 t.Fatalf("expected %v, got %v", 0, fi.Size()) 1565 } 1566 // add 10 items 1567 err = db.Update(func(tx *Tx) error { 1568 for i := 0; i < 10; i++ { 1569 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1570 return err 1571 } 1572 } 1573 return nil 1574 }) 1575 if err != nil { 1576 t.Fatal(err) 1577 } 1578 // add the same 10 items 1579 // this will create 10 duplicate log entries 1580 err = db.Update(func(tx *Tx) error { 1581 for i := 0; i < 10; i++ { 1582 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1583 return err 1584 } 1585 } 1586 return nil 1587 }) 1588 if err != nil { 1589 t.Fatal(err) 1590 } 1591 fi, err = os.Stat("data.db") 1592 if err != nil { 1593 t.Fatal(err) 1594 } 1595 sz1 := fi.Size() 1596 if sz1 == 0 { 1597 t.Fatalf("expected > 0, got %v", sz1) 1598 } 1599 if err := db.Shrink(); err != nil { 1600 t.Fatal(err) 1601 } 1602 fi, err = os.Stat("data.db") 1603 if err != nil { 1604 t.Fatal(err) 1605 } 1606 sz2 := fi.Size() 1607 if sz2 >= sz1 { 1608 t.Fatalf("expected < %v, got %v", sz1, sz2) 1609 } 1610 if err := db.Close(); err != nil { 1611 t.Fatal(err) 1612 } 1613 if err := db.Shrink(); err != ErrDatabaseClosed { 1614 t.Fatal("shrink on a closed databse should not be allowed") 1615 } 1616 // Now we will open a db that does not persist 1617 db, err = Open(":memory:") 1618 if err != nil { 1619 t.Fatal(err) 1620 } 1621 defer func() { _ = db.Close() }() 1622 // add 10 items 1623 err = db.Update(func(tx *Tx) error { 1624 for i := 0; i < 10; i++ { 1625 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1626 return err 1627 } 1628 } 1629 return nil 1630 }) 1631 if err != nil { 1632 t.Fatal(err) 1633 } 1634 // add the same 10 items 1635 // this will create 10 duplicate log entries 1636 err = db.Update(func(tx *Tx) error { 1637 for i := 0; i < 10; i++ { 1638 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1639 return err 1640 } 1641 } 1642 return nil 1643 }) 1644 if err != nil { 1645 t.Fatal(err) 1646 } 1647 err = db.View(func(tx *Tx) error { 1648 n, err := tx.Len() 1649 if err != nil { 1650 t.Fatal(err) 1651 } 1652 if n != 10 { 1653 t.Fatalf("expecting %v, got %v", 10, n) 1654 } 1655 return nil 1656 }) 1657 if err != nil { 1658 t.Fatal(err) 1659 } 1660 // this should succeed even though it's basically a noop. 1661 if err := db.Shrink(); err != nil { 1662 t.Fatal(err) 1663 } 1664 } 1665 1666 func TestVariousIndexOperations(t *testing.T) { 1667 db := testOpen(t) 1668 defer testClose(db) 1669 // test creating an index with no index name. 1670 err := db.CreateIndex("", "", nil) 1671 if err == nil { 1672 t.Fatal("should not be able to create an index with no name") 1673 } 1674 // test creating an index with a name that has already been used. 1675 err = db.CreateIndex("hello", "", nil) 1676 if err != nil { 1677 t.Fatal(err) 1678 } 1679 err = db.CreateIndex("hello", "", nil) 1680 if err == nil { 1681 t.Fatal("should not be able to create a duplicate index") 1682 } 1683 err = db.Update(func(tx *Tx) error { 1684 1685 if _, _, err := tx.Set("user:1", "tom", nil); err != nil { 1686 return err 1687 } 1688 if _, _, err := tx.Set("user:2", "janet", nil); err != nil { 1689 return err 1690 } 1691 if _, _, err := tx.Set("alt:1", "from", nil); err != nil { 1692 return err 1693 } 1694 if _, _, err := tx.Set("alt:2", "there", nil); err != nil { 1695 return err 1696 } 1697 if _, _, err := tx.Set("rect:1", "[1 2],[3 4]", nil); err != nil { 1698 return err 1699 } 1700 if _, _, err := tx.Set("rect:2", "[5 6],[7 8]", nil); err != nil { 1701 return err 1702 } 1703 return nil 1704 }) 1705 if err != nil { 1706 t.Fatal(err) 1707 } 1708 // test creating an index after adding items. use pattern matching. have some items in the match and some not. 1709 if err := db.CreateIndex("string", "user:*", IndexString); err != nil { 1710 t.Fatal(err) 1711 } 1712 // test creating a spatial index after adding items. use pattern matching. have some items in the match and some not. 1713 if err := db.CreateSpatialIndex("rect", "rect:*", IndexRect); err != nil { 1714 t.Fatal(err) 1715 } 1716 // test dropping an index 1717 if err := db.DropIndex("hello"); err != nil { 1718 t.Fatal(err) 1719 } 1720 // test dropping an index with no name 1721 if err := db.DropIndex(""); err == nil { 1722 t.Fatal("should not be allowed to drop an index with no name") 1723 } 1724 // test dropping an index with no name 1725 if err := db.DropIndex("na"); err == nil { 1726 t.Fatal("should not be allowed to drop an index that does not exist") 1727 } 1728 // test retrieving index names 1729 names, err := db.Indexes() 1730 if err != nil { 1731 t.Fatal(err) 1732 } 1733 if strings.Join(names, ",") != "rect,string" { 1734 t.Fatalf("expecting '%v', got '%v'", "rect,string", strings.Join(names, ",")) 1735 } 1736 // test creating an index after closing database 1737 if err := db.Close(); err != nil { 1738 t.Fatal(err) 1739 } 1740 if err := db.CreateIndex("new-index", "", nil); err != ErrDatabaseClosed { 1741 t.Fatal("should not be able to create an index on a closed database") 1742 } 1743 // test getting index names after closing database 1744 if _, err := db.Indexes(); err != ErrDatabaseClosed { 1745 t.Fatal("should not be able to get index names on a closed database") 1746 } 1747 // test dropping an index after closing database 1748 if err := db.DropIndex("rect"); err != ErrDatabaseClosed { 1749 t.Fatal("should not be able to drop an index on a closed database") 1750 } 1751 } 1752 1753 func test(t *testing.T, a, b bool) { 1754 if a != b { 1755 t.Fatal("failed, bummer...") 1756 } 1757 } 1758 1759 func TestBasic(t *testing.T) { 1760 rand.Seed(time.Now().UnixNano()) 1761 db := testOpen(t) 1762 defer testClose(db) 1763 1764 // create a simple index 1765 if err := db.CreateIndex("users", "fun:user:*", IndexString); err != nil { 1766 t.Fatal(err) 1767 } 1768 1769 // create a spatial index 1770 if err := db.CreateSpatialIndex("rects", "rect:*", IndexRect); err != nil { 1771 t.Fatal(err) 1772 } 1773 if true { 1774 err := db.Update(func(tx *Tx) error { 1775 if _, _, err := tx.Set("fun:user:0", "tom", nil); err != nil { 1776 return err 1777 } 1778 if _, _, err := tx.Set("fun:user:1", "Randi", nil); err != nil { 1779 return err 1780 } 1781 if _, _, err := tx.Set("fun:user:2", "jane", nil); err != nil { 1782 return err 1783 } 1784 if _, _, err := tx.Set("fun:user:4", "Janet", nil); err != nil { 1785 return err 1786 } 1787 if _, _, err := tx.Set("fun:user:5", "Paula", nil); err != nil { 1788 return err 1789 } 1790 if _, _, err := tx.Set("fun:user:6", "peter", nil); err != nil { 1791 return err 1792 } 1793 if _, _, err := tx.Set("fun:user:7", "Terri", nil); err != nil { 1794 return err 1795 } 1796 return nil 1797 }) 1798 if err != nil { 1799 t.Fatal(err) 1800 } 1801 // add some random items 1802 start := time.Now() 1803 if err := db.Update(func(tx *Tx) error { 1804 for _, i := range rand.Perm(100) { 1805 if _, _, err := tx.Set(fmt.Sprintf("tag:%d", i+100), fmt.Sprintf("val:%d", rand.Int()%100+100), nil); err != nil { 1806 return err 1807 } 1808 } 1809 return nil 1810 }); err != nil { 1811 t.Fatal(err) 1812 } 1813 if false { 1814 println(time.Now().Sub(start).String(), db.keys.Len()) 1815 } 1816 // add some random rects 1817 if err := db.Update(func(tx *Tx) error { 1818 if _, _, err := tx.Set("rect:1", Rect([]float64{10, 10}, []float64{20, 20}), nil); err != nil { 1819 return err 1820 } 1821 if _, _, err := tx.Set("rect:2", Rect([]float64{15, 15}, []float64{24, 24}), nil); err != nil { 1822 return err 1823 } 1824 if _, _, err := tx.Set("rect:3", Rect([]float64{17, 17}, []float64{27, 27}), nil); err != nil { 1825 return err 1826 } 1827 return nil 1828 }); err != nil { 1829 t.Fatal(err) 1830 } 1831 } 1832 // verify the data has been created 1833 buf := &bytes.Buffer{} 1834 err := db.View(func(tx *Tx) error { 1835 err := tx.Ascend("users", func(key, val string) bool { 1836 fmt.Fprintf(buf, "%s %s\n", key, val) 1837 return true 1838 }) 1839 if err != nil { 1840 t.Fatal(err) 1841 } 1842 err = tx.AscendRange("", "tag:170", "tag:172", func(key, val string) bool { 1843 fmt.Fprintf(buf, "%s\n", key) 1844 return true 1845 }) 1846 if err != nil { 1847 t.Fatal(err) 1848 } 1849 err = tx.AscendGreaterOrEqual("", "tag:195", func(key, val string) bool { 1850 fmt.Fprintf(buf, "%s\n", key) 1851 return true 1852 }) 1853 if err != nil { 1854 t.Fatal(err) 1855 } 1856 err = tx.AscendGreaterOrEqual("", "rect:", func(key, val string) bool { 1857 if !strings.HasPrefix(key, "rect:") { 1858 return false 1859 } 1860 min, max := IndexRect(val) 1861 fmt.Fprintf(buf, "%s: %v,%v\n", key, min, max) 1862 return true 1863 }) 1864 expect := make([]string, 2) 1865 n := 0 1866 err = tx.Intersects("rects", "[0 0],[15 15]", func(key, val string) bool { 1867 if n == 2 { 1868 t.Fatalf("too many rects where received, expecting only two") 1869 } 1870 min, max := IndexRect(val) 1871 s := fmt.Sprintf("%s: %v,%v\n", key, min, max) 1872 if key == "rect:1" { 1873 expect[0] = s 1874 } else if key == "rect:2" { 1875 expect[1] = s 1876 } 1877 n++ 1878 return true 1879 }) 1880 if err != nil { 1881 t.Fatal(err) 1882 } 1883 for _, s := range expect { 1884 if _, err := buf.WriteString(s); err != nil { 1885 return err 1886 } 1887 } 1888 return nil 1889 }) 1890 if err != nil { 1891 t.Fatal(err) 1892 } 1893 res := ` 1894 fun:user:2 jane 1895 fun:user:4 Janet 1896 fun:user:5 Paula 1897 fun:user:6 peter 1898 fun:user:1 Randi 1899 fun:user:7 Terri 1900 fun:user:0 tom 1901 tag:170 1902 tag:171 1903 tag:195 1904 tag:196 1905 tag:197 1906 tag:198 1907 tag:199 1908 rect:1: [10 10],[20 20] 1909 rect:2: [15 15],[24 24] 1910 rect:3: [17 17],[27 27] 1911 rect:1: [10 10],[20 20] 1912 rect:2: [15 15],[24 24] 1913 ` 1914 res = strings.Replace(res, "\r", "", -1) 1915 if strings.TrimSpace(buf.String()) != strings.TrimSpace(res) { 1916 t.Fatalf("expected [%v], got [%v]", strings.TrimSpace(res), strings.TrimSpace(buf.String())) 1917 } 1918 } 1919 1920 func TestIndexAscend(t *testing.T) { 1921 rand.Seed(time.Now().UnixNano()) 1922 db := testOpen(t) 1923 defer testClose(db) 1924 1925 // create a simple index 1926 if err := db.CreateIndex("usr", "usr:*", IndexInt); err != nil { 1927 t.Fatal(err) 1928 } 1929 if err := db.Update(func(tx *Tx) error { 1930 for i := 10; i > 0; i-- { 1931 tx.Set(fmt.Sprintf("usr:%d", i), fmt.Sprintf("%d", 10-i), nil) 1932 } 1933 return nil 1934 }); err != nil { 1935 t.Fatal(err) 1936 } 1937 1938 buf := &bytes.Buffer{} 1939 err := db.View(func(tx *Tx) error { 1940 tx.Ascend("usr", func(key, value string) bool { 1941 fmt.Fprintf(buf, "%s %s\n", key, value) 1942 return true 1943 }) 1944 fmt.Fprintln(buf) 1945 1946 tx.AscendGreaterOrEqual("usr", "8", func(key, value string) bool { 1947 fmt.Fprintf(buf, "%s %s\n", key, value) 1948 return true 1949 }) 1950 fmt.Fprintln(buf) 1951 1952 tx.AscendLessThan("usr", "3", func(key, value string) bool { 1953 fmt.Fprintf(buf, "%s %s\n", key, value) 1954 return true 1955 }) 1956 fmt.Fprintln(buf) 1957 1958 tx.AscendRange("usr", "4", "8", func(key, value string) bool { 1959 fmt.Fprintf(buf, "%s %s\n", key, value) 1960 return true 1961 }) 1962 return nil 1963 }) 1964 1965 if err != nil { 1966 t.Fatal(err) 1967 } 1968 1969 res := ` 1970 usr:10 0 1971 usr:9 1 1972 usr:8 2 1973 usr:7 3 1974 usr:6 4 1975 usr:5 5 1976 usr:4 6 1977 usr:3 7 1978 usr:2 8 1979 usr:1 9 1980 1981 usr:2 8 1982 usr:1 9 1983 1984 usr:10 0 1985 usr:9 1 1986 usr:8 2 1987 1988 usr:6 4 1989 usr:5 5 1990 usr:4 6 1991 usr:3 7 1992 ` 1993 res = strings.Replace(res, "\r", "", -1) 1994 s1 := strings.TrimSpace(buf.String()) 1995 s2 := strings.TrimSpace(res) 1996 if s1 != s2 { 1997 t.Fatalf("expected [%v], got [%v]", s1, s2) 1998 } 1999 } 2000 2001 func testRectStringer(min, max []float64) error { 2002 nmin, nmax := IndexRect(Rect(min, max)) 2003 if len(nmin) != len(min) { 2004 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 2005 } 2006 for i := 0; i < len(min); i++ { 2007 if min[i] != nmin[i] || max[i] != nmax[i] { 2008 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 2009 } 2010 } 2011 return nil 2012 } 2013 func TestRectStrings(t *testing.T) { 2014 test(t, Rect(IndexRect(Point(1))) == "[1]", true) 2015 test(t, Rect(IndexRect(Point(1, 2, 3, 4))) == "[1 2 3 4]", true) 2016 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[1 2]")))) == "[1 2]", true) 2017 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2]")))) == "[1 2],[2 2]", true) 2018 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2],[3]")))) == "[1 2],[2 2]", true) 2019 test(t, Rect(IndexRect(Rect(IndexRect("[1 2]")))) == "[1 2]", true) 2020 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6]")))) == "[1.5 2 4.5 5.6]", true) 2021 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6 -1],[]")))) == "[1.5 2 4.5 5.6 -1]", true) 2022 test(t, Rect(IndexRect(Rect(IndexRect("[]")))) == "[]", true) 2023 test(t, Rect(IndexRect(Rect(IndexRect("")))) == "[]", true) 2024 if err := testRectStringer(nil, nil); err != nil { 2025 t.Fatal(err) 2026 } 2027 if err := testRectStringer([]float64{}, []float64{}); err != nil { 2028 t.Fatal(err) 2029 } 2030 if err := testRectStringer([]float64{1}, []float64{2}); err != nil { 2031 t.Fatal(err) 2032 } 2033 if err := testRectStringer([]float64{1, 2}, []float64{3, 4}); err != nil { 2034 t.Fatal(err) 2035 } 2036 if err := testRectStringer([]float64{1, 2, 3}, []float64{4, 5, 6}); err != nil { 2037 t.Fatal(err) 2038 } 2039 if err := testRectStringer([]float64{1, 2, 3, 4}, []float64{5, 6, 7, 8}); err != nil { 2040 t.Fatal(err) 2041 } 2042 if err := testRectStringer([]float64{1, 2, 3, 4, 5}, []float64{6, 7, 8, 9, 10}); err != nil { 2043 t.Fatal(err) 2044 } 2045 } 2046 2047 // TestTTLReOpen test setting a TTL and then immediately closing the database and 2048 // then waiting the TTL before reopening. The key should not be accessible. 2049 func TestTTLReOpen(t *testing.T) { 2050 ttl := time.Second * 3 2051 db := testOpen(t) 2052 defer testClose(db) 2053 err := db.Update(func(tx *Tx) error { 2054 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: ttl}); err != nil { 2055 return err 2056 } 2057 return nil 2058 }) 2059 if err != nil { 2060 t.Fatal(err) 2061 } 2062 db = testReOpenDelay(t, db, ttl/4) 2063 err = db.View(func(tx *Tx) error { 2064 val, err := tx.Get("key1") 2065 if err != nil { 2066 return err 2067 } 2068 if val != "val1" { 2069 t.Fatalf("expecting '%v', got '%v'", "val1", val) 2070 } 2071 return nil 2072 }) 2073 if err != nil { 2074 t.Fatal(err) 2075 } 2076 db = testReOpenDelay(t, db, ttl-ttl/4) 2077 defer testClose(db) 2078 err = db.View(func(tx *Tx) error { 2079 val, err := tx.Get("key1") 2080 if err == nil || err != ErrNotFound || val != "" { 2081 t.Fatal("expecting not found") 2082 } 2083 2084 return nil 2085 }) 2086 if err != nil { 2087 t.Fatal(err) 2088 } 2089 } 2090 2091 func TestTTL(t *testing.T) { 2092 db := testOpen(t) 2093 defer testClose(db) 2094 err := db.Update(func(tx *Tx) error { 2095 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 2096 return err 2097 } 2098 if _, _, err := tx.Set("key2", "val2", nil); err != nil { 2099 return err 2100 } 2101 return nil 2102 }) 2103 if err != nil { 2104 t.Fatal(err) 2105 } 2106 err = db.View(func(tx *Tx) error { 2107 dur1, err := tx.TTL("key1") 2108 if err != nil { 2109 t.Fatal(err) 2110 } 2111 if dur1 > time.Second || dur1 <= 0 { 2112 t.Fatalf("expecting between zero and one second, got '%v'", dur1) 2113 } 2114 dur1, err = tx.TTL("key2") 2115 if err != nil { 2116 t.Fatal(err) 2117 } 2118 if dur1 >= 0 { 2119 t.Fatalf("expecting a negative value, got '%v'", dur1) 2120 } 2121 return nil 2122 }) 2123 if err != nil { 2124 t.Fatal(err) 2125 } 2126 } 2127 2128 func TestConfig(t *testing.T) { 2129 db := testOpen(t) 2130 defer testClose(db) 2131 2132 err := db.SetConfig(Config{SyncPolicy: SyncPolicy(-1)}) 2133 if err == nil { 2134 t.Fatal("expecting a config syncpolicy error") 2135 } 2136 err = db.SetConfig(Config{SyncPolicy: SyncPolicy(3)}) 2137 if err == nil { 2138 t.Fatal("expecting a config syncpolicy error") 2139 } 2140 err = db.SetConfig(Config{SyncPolicy: Never}) 2141 if err != nil { 2142 t.Fatal(err) 2143 } 2144 err = db.SetConfig(Config{SyncPolicy: EverySecond}) 2145 if err != nil { 2146 t.Fatal(err) 2147 } 2148 err = db.SetConfig(Config{AutoShrinkMinSize: 100, AutoShrinkPercentage: 200, SyncPolicy: Always}) 2149 if err != nil { 2150 t.Fatal(err) 2151 } 2152 2153 var c Config 2154 if err := db.ReadConfig(&c); err != nil { 2155 t.Fatal(err) 2156 } 2157 if c.AutoShrinkMinSize != 100 || c.AutoShrinkPercentage != 200 && c.SyncPolicy != Always { 2158 t.Fatalf("expecting %v, %v, and %v, got %v, %v, and %v", 100, 200, Always, c.AutoShrinkMinSize, c.AutoShrinkPercentage, c.SyncPolicy) 2159 } 2160 } 2161 func testUint64Hex(n uint64) string { 2162 s := strconv.FormatUint(n, 16) 2163 s = "0000000000000000" + s 2164 return s[len(s)-16:] 2165 } 2166 func textHexUint64(s string) uint64 { 2167 n, _ := strconv.ParseUint(s, 16, 64) 2168 return n 2169 } 2170 func benchClose(t *testing.B, persist bool, db *DB) { 2171 if persist { 2172 if err := os.RemoveAll("data.db"); err != nil { 2173 t.Fatal(err) 2174 } 2175 } 2176 if err := db.Close(); err != nil { 2177 t.Fatal(err) 2178 } 2179 } 2180 2181 func benchOpenFillData(t *testing.B, N int, 2182 set, persist, random bool, 2183 geo bool, 2184 batch int) (db *DB, keys, vals []string) { 2185 /// 2186 t.StopTimer() 2187 rand.Seed(time.Now().UnixNano()) 2188 var err error 2189 if persist { 2190 if err := os.RemoveAll("data.db"); err != nil { 2191 t.Fatal(err) 2192 } 2193 db, err = Open("data.db") 2194 } else { 2195 db, err = Open(":memory:") 2196 } 2197 if err != nil { 2198 t.Fatal(err) 2199 } 2200 keys = make([]string, N) 2201 vals = make([]string, N) 2202 perm := rand.Perm(N) 2203 for i := 0; i < N; i++ { 2204 if random && set { 2205 keys[perm[i]] = testUint64Hex(uint64(i)) 2206 vals[perm[i]] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2207 } else { 2208 keys[i] = testUint64Hex(uint64(i)) 2209 vals[i] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2210 } 2211 } 2212 if set { 2213 t.StartTimer() 2214 } 2215 for i := 0; i < N; { 2216 err := db.Update(func(tx *Tx) error { 2217 var err error 2218 for j := 0; j < batch && i < N; j++ { 2219 _, _, err = tx.Set(keys[i], vals[i], nil) 2220 i++ 2221 } 2222 return err 2223 }) 2224 if err != nil { 2225 t.Fatal(err) 2226 } 2227 } 2228 if set { 2229 t.StopTimer() 2230 } 2231 var n uint64 2232 err = db.View(func(tx *Tx) error { 2233 err := tx.Ascend("", func(key, value string) bool { 2234 n2 := textHexUint64(key) 2235 if n2 != n { 2236 t.Fatalf("expecting '%v', got '%v'", n2, n) 2237 } 2238 n++ 2239 return true 2240 }) 2241 return err 2242 }) 2243 if err != nil { 2244 t.Fatal(err) 2245 } 2246 if n != uint64(N) { 2247 t.Fatalf("expecting '%v', got '%v'", N, n) 2248 } 2249 t.StartTimer() 2250 return db, keys, vals 2251 } 2252 2253 func benchSetGet(t *testing.B, set, persist, random bool, batch int) { 2254 N := t.N 2255 for N > 0 { 2256 n := 0 2257 if N >= 100000 { 2258 n = 100000 2259 } else { 2260 n = N 2261 } 2262 func() { 2263 db, keys, _ := benchOpenFillData(t, n, set, persist, random, false, batch) 2264 defer benchClose(t, persist, db) 2265 if !set { 2266 for i := 0; i < n; { 2267 err := db.View(func(tx *Tx) error { 2268 var err error 2269 for j := 0; j < batch && i < n; j++ { 2270 _, err = tx.Get(keys[i]) 2271 i++ 2272 } 2273 return err 2274 }) 2275 if err != nil { 2276 t.Fatal(err) 2277 } 2278 } 2279 } 2280 }() 2281 N -= n 2282 } 2283 } 2284 2285 // Set Persist 2286 func Benchmark_Set_Persist_Random_1(t *testing.B) { 2287 benchSetGet(t, true, true, true, 1) 2288 } 2289 func Benchmark_Set_Persist_Random_10(t *testing.B) { 2290 benchSetGet(t, true, true, true, 10) 2291 } 2292 func Benchmark_Set_Persist_Random_100(t *testing.B) { 2293 benchSetGet(t, true, true, true, 100) 2294 } 2295 func Benchmark_Set_Persist_Sequential_1(t *testing.B) { 2296 benchSetGet(t, true, true, false, 1) 2297 } 2298 func Benchmark_Set_Persist_Sequential_10(t *testing.B) { 2299 benchSetGet(t, true, true, false, 10) 2300 } 2301 func Benchmark_Set_Persist_Sequential_100(t *testing.B) { 2302 benchSetGet(t, true, true, false, 100) 2303 } 2304 2305 // Set NoPersist 2306 func Benchmark_Set_NoPersist_Random_1(t *testing.B) { 2307 benchSetGet(t, true, false, true, 1) 2308 } 2309 func Benchmark_Set_NoPersist_Random_10(t *testing.B) { 2310 benchSetGet(t, true, false, true, 10) 2311 } 2312 func Benchmark_Set_NoPersist_Random_100(t *testing.B) { 2313 benchSetGet(t, true, false, true, 100) 2314 } 2315 func Benchmark_Set_NoPersist_Sequential_1(t *testing.B) { 2316 benchSetGet(t, true, false, false, 1) 2317 } 2318 func Benchmark_Set_NoPersist_Sequential_10(t *testing.B) { 2319 benchSetGet(t, true, false, false, 10) 2320 } 2321 func Benchmark_Set_NoPersist_Sequential_100(t *testing.B) { 2322 benchSetGet(t, true, false, false, 100) 2323 } 2324 2325 // Get 2326 func Benchmark_Get_1(t *testing.B) { 2327 benchSetGet(t, false, false, false, 1) 2328 } 2329 func Benchmark_Get_10(t *testing.B) { 2330 benchSetGet(t, false, false, false, 10) 2331 } 2332 func Benchmark_Get_100(t *testing.B) { 2333 benchSetGet(t, false, false, false, 100) 2334 } 2335 2336 func benchScan(t *testing.B, asc bool, count int) { 2337 N := count 2338 db, _, _ := benchOpenFillData(t, N, false, false, false, false, 100) 2339 defer benchClose(t, false, db) 2340 for i := 0; i < t.N; i++ { 2341 count := 0 2342 err := db.View(func(tx *Tx) error { 2343 if asc { 2344 return tx.Ascend("", func(key, val string) bool { 2345 count++ 2346 return true 2347 }) 2348 } 2349 return tx.Descend("", func(key, val string) bool { 2350 count++ 2351 return true 2352 }) 2353 2354 }) 2355 if err != nil { 2356 t.Fatal(err) 2357 } 2358 if count != N { 2359 t.Fatalf("expecting '%v', got '%v'", N, count) 2360 } 2361 } 2362 } 2363 2364 func Benchmark_Ascend_1(t *testing.B) { 2365 benchScan(t, true, 1) 2366 } 2367 func Benchmark_Ascend_10(t *testing.B) { 2368 benchScan(t, true, 10) 2369 } 2370 func Benchmark_Ascend_100(t *testing.B) { 2371 benchScan(t, true, 100) 2372 } 2373 func Benchmark_Ascend_1000(t *testing.B) { 2374 benchScan(t, true, 1000) 2375 } 2376 func Benchmark_Ascend_10000(t *testing.B) { 2377 benchScan(t, true, 10000) 2378 } 2379 2380 func Benchmark_Descend_1(t *testing.B) { 2381 benchScan(t, false, 1) 2382 } 2383 func Benchmark_Descend_10(t *testing.B) { 2384 benchScan(t, false, 10) 2385 } 2386 func Benchmark_Descend_100(t *testing.B) { 2387 benchScan(t, false, 100) 2388 } 2389 func Benchmark_Descend_1000(t *testing.B) { 2390 benchScan(t, false, 1000) 2391 } 2392 func Benchmark_Descend_10000(t *testing.B) { 2393 benchScan(t, false, 10000) 2394 } 2395 2396 /* 2397 func Benchmark_Spatial_2D(t *testing.B) { 2398 N := 100000 2399 db, _, _ := benchOpenFillData(t, N, true, true, false, true, 100) 2400 defer benchClose(t, false, db) 2401 2402 } 2403 */ 2404 func TestCoverCloseAlreadyClosed(t *testing.T) { 2405 db := testOpen(t) 2406 defer testClose(db) 2407 _ = db.file.Close() 2408 if err := db.Close(); err == nil { 2409 t.Fatal("expecting an error") 2410 } 2411 } 2412 2413 func TestCoverConfigClosed(t *testing.T) { 2414 db := testOpen(t) 2415 defer testClose(db) 2416 _ = db.Close() 2417 var config Config 2418 if err := db.ReadConfig(&config); err != ErrDatabaseClosed { 2419 t.Fatal("expecting database closed error") 2420 } 2421 if err := db.SetConfig(config); err != ErrDatabaseClosed { 2422 t.Fatal("expecting database closed error") 2423 } 2424 } 2425 func TestCoverShrinkShrink(t *testing.T) { 2426 db := testOpen(t) 2427 defer testClose(db) 2428 if err := db.Update(func(tx *Tx) error { 2429 for i := 0; i < 10000; i++ { 2430 _, _, err := tx.Set(fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), nil) 2431 if err != nil { 2432 return err 2433 } 2434 } 2435 return nil 2436 }); err != nil { 2437 t.Fatal(err) 2438 } 2439 if err := db.Update(func(tx *Tx) error { 2440 for i := 250; i < 250+100; i++ { 2441 _, err := tx.Delete(fmt.Sprintf("%d", i)) 2442 if err != nil { 2443 return err 2444 } 2445 } 2446 return nil 2447 }); err != nil { 2448 t.Fatal(err) 2449 } 2450 var err1, err2 error 2451 var wg sync.WaitGroup 2452 wg.Add(2) 2453 go func() { 2454 defer wg.Done() 2455 err1 = db.Shrink() 2456 }() 2457 go func() { 2458 defer wg.Done() 2459 err2 = db.Shrink() 2460 }() 2461 wg.Wait() 2462 //println(123) 2463 //fmt.Printf("%v\n%v\n", err1, err2) 2464 if err1 != ErrShrinkInProcess && err2 != ErrShrinkInProcess { 2465 t.Fatal("expecting a shrink in process error") 2466 } 2467 db = testReOpen(t, db) 2468 defer testClose(db) 2469 if err := db.View(func(tx *Tx) error { 2470 n, err := tx.Len() 2471 if err != nil { 2472 return err 2473 } 2474 if n != 9900 { 2475 t.Fatal("expecting 9900 items") 2476 } 2477 return nil 2478 }); err != nil { 2479 t.Fatal(err) 2480 } 2481 } 2482 2483 func TestPreviousItem(t *testing.T) { 2484 db := testOpen(t) 2485 defer testClose(db) 2486 err := db.Update(func(tx *Tx) error { 2487 _, _, err := tx.Set("hello", "world", nil) 2488 if err != nil { 2489 return err 2490 } 2491 prev, replaced, err := tx.Set("hello", "planet", nil) 2492 if err != nil { 2493 return err 2494 } 2495 if !replaced { 2496 t.Fatal("should be replaced") 2497 } 2498 if prev != "world" { 2499 t.Fatalf("expecting '%v', got '%v'", "world", prev) 2500 } 2501 return nil 2502 }) 2503 if err != nil { 2504 t.Fatal(err) 2505 } 2506 } 2507 2508 func TestJSONIndex(t *testing.T) { 2509 db := testOpen(t) 2510 defer testClose(db) 2511 2512 _ = db.CreateIndex("last_name", "*", IndexJSON("name.last")) 2513 _ = db.CreateIndex("last_name_cs", "*", IndexJSONCaseSensitive("name.last")) 2514 _ = db.CreateIndex("age", "*", IndexJSON("age")) 2515 _ = db.CreateIndex("student", "*", IndexJSON("student")) 2516 _ = db.Update(func(tx *Tx) error { 2517 _, _, _ = tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38,"student":false}`, nil) 2518 _, _, _ = tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47,"student":true}`, nil) 2519 _, _, _ = tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52,"student":true}`, nil) 2520 _, _, _ = tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28,"student":false}`, nil) 2521 _, _, _ = tx.Set("5", `{"name":{"first":"bill","last":"frank"},"age":21,"student":true}`, nil) 2522 _, _, _ = tx.Set("6", `{"name":{"first":"sally","last":"randall"},"age":68,"student":false}`, nil) 2523 return nil 2524 }) 2525 var keys []string 2526 _ = db.View(func(tx *Tx) error { 2527 _ = tx.Ascend("last_name_cs", func(key, value string) bool { 2528 //fmt.Printf("%s: %s\n", key, value) 2529 keys = append(keys, key) 2530 return true 2531 }) 2532 _ = tx.Ascend("last_name", func(key, value string) bool { 2533 //fmt.Printf("%s: %s\n", key, value) 2534 keys = append(keys, key) 2535 return true 2536 }) 2537 _ = tx.Ascend("age", func(key, value string) bool { 2538 //fmt.Printf("%s: %s\n", key, value) 2539 keys = append(keys, key) 2540 return true 2541 }) 2542 _ = tx.Ascend("student", func(key, value string) bool { 2543 //fmt.Printf("%s: %s\n", key, value) 2544 keys = append(keys, key) 2545 return true 2546 }) 2547 return nil 2548 }) 2549 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" 2550 if strings.Join(keys, ",") != expect { 2551 t.Fatalf("expected %v, got %v", expect, strings.Join(keys, ",")) 2552 } 2553 } 2554 2555 func TestOnExpiredSync(t *testing.T) { 2556 db := testOpen(t) 2557 defer testClose(db) 2558 2559 var config Config 2560 if err := db.ReadConfig(&config); err != nil { 2561 t.Fatal(err) 2562 } 2563 hits := make(chan int, 3) 2564 config.OnExpiredSync = func(key, value string, tx *Tx) error { 2565 n, err := strconv.Atoi(value) 2566 if err != nil { 2567 return err 2568 } 2569 defer func() { hits <- n }() 2570 if n >= 2 { 2571 _, err = tx.Delete(key) 2572 if err != ErrNotFound { 2573 return err 2574 } 2575 return nil 2576 } 2577 n++ 2578 _, _, err = tx.Set(key, strconv.Itoa(n), &SetOptions{Expires: true, TTL: time.Millisecond * 100}) 2579 return err 2580 } 2581 if err := db.SetConfig(config); err != nil { 2582 t.Fatal(err) 2583 } 2584 err := db.Update(func(tx *Tx) error { 2585 _, _, err := tx.Set("K", "0", &SetOptions{Expires: true, TTL: time.Millisecond * 100}) 2586 return err 2587 }) 2588 if err != nil { 2589 t.Fail() 2590 } 2591 2592 done := make(chan struct{}) 2593 go func() { 2594 ticks := time.NewTicker(time.Millisecond * 50) 2595 defer ticks.Stop() 2596 for { 2597 select { 2598 case <-done: 2599 return 2600 case <-ticks.C: 2601 err := db.View(func(tx *Tx) error { 2602 v, err := tx.Get("K", true) 2603 if err != nil { 2604 return err 2605 } 2606 n, err := strconv.Atoi(v) 2607 if err != nil { 2608 return err 2609 } 2610 if n < 0 || n > 2 { 2611 t.Fail() 2612 } 2613 return nil 2614 }) 2615 if err != nil { 2616 t.Fail() 2617 } 2618 } 2619 } 2620 }() 2621 2622 OUTER1: 2623 for { 2624 select { 2625 case <-time.After(time.Second * 2): 2626 t.Fail() 2627 case v := <-hits: 2628 if v >= 2 { 2629 break OUTER1 2630 } 2631 } 2632 } 2633 err = db.View(func(tx *Tx) error { 2634 defer close(done) 2635 v, err := tx.Get("K") 2636 if err != nil { 2637 t.Fail() 2638 return err 2639 } 2640 if v != "2" { 2641 t.Fail() 2642 } 2643 return nil 2644 }) 2645 if err != nil { 2646 t.Fail() 2647 } 2648 }