1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009 Oracle. All rights reserved. 5 * 6 */ 7using System; 8using System.Collections; 9using System.Collections.Generic; 10using System.IO; 11using System.Text; 12using System.Threading; 13using System.Xml; 14using NUnit.Framework; 15using BerkeleyDB; 16 17namespace CsharpAPITest 18{ 19 [TestFixture] 20 public class SecondaryCursorTest 21 { 22 private string testFixtureHome; 23 private string testFixtureName; 24 private string testName; 25 private string testHome; 26 27 [TestFixtureSetUp] 28 public void RunBeforeTests() 29 { 30 testFixtureName = "SecondaryCursorTest"; 31 testFixtureHome = "./TestOut/" + testFixtureName; 32 33 /* 34 * Delete existing test ouput directory and files specified 35 * for the current test fixture and then create a new one. 36 */ 37 Configuration.ClearDir(testFixtureHome); 38 } 39 40 [Test] 41 public void TestDuplicate() 42 { 43 testName = "TestDuplicate"; 44 testHome = testFixtureHome + "/" + testName; 45 string dbFileName = testHome + "/" + testName + ".db"; 46 string dbSecFileName = testHome + "/" + testName + 47 "_sec.db"; 48 49 Configuration.ClearDir(testHome); 50 51 // Open a primary database. 52 BTreeDatabaseConfig dbConfig = 53 new BTreeDatabaseConfig(); 54 dbConfig.Creation = CreatePolicy.IF_NEEDED; 55 BTreeDatabase db = BTreeDatabase.Open( 56 dbFileName, dbConfig); 57 58 // Open a secondary database. 59 SecondaryBTreeDatabaseConfig secConfig = 60 new SecondaryBTreeDatabaseConfig(db, 61 new SecondaryKeyGenDelegate(SecondaryKeyGen)); 62 secConfig.Creation = CreatePolicy.IF_NEEDED; 63 secConfig.Duplicates = DuplicatesPolicy.UNSORTED; 64 SecondaryBTreeDatabase secDB = 65 SecondaryBTreeDatabase.Open(dbSecFileName, 66 secConfig); 67 68 // Put a pair of key and data into the database. 69 DatabaseEntry key, data; 70 key = new DatabaseEntry( 71 ASCIIEncoding.ASCII.GetBytes("key")); 72 data = new DatabaseEntry( 73 ASCIIEncoding.ASCII.GetBytes("data")); 74 db.Put(key, data); 75 76 // Create a cursor. 77 SecondaryCursor cursor = secDB.SecondaryCursor(); 78 cursor.Move(key, true); 79 80 // Duplicate the cursor. 81 SecondaryCursor dupCursor; 82 dupCursor = cursor.Duplicate(true); 83 84 /* 85 * Confirm that the duplicate cursor has the same 86 * position as the original one. 87 */ 88 Assert.AreEqual(cursor.Current.Key, 89 dupCursor.Current.Key); 90 Assert.AreEqual(cursor.Current.Value, 91 dupCursor.Current.Value); 92 93 // Close the cursor and the duplicate cursor. 94 dupCursor.Close(); 95 cursor.Close(); 96 97 // Close secondary and primary database. 98 secDB.Close(); 99 db.Close(); 100 } 101 102 [Test] 103 public void TestDelete() 104 { 105 testName = "TestDelete"; 106 testHome = testFixtureHome + "/" + testName; 107 string dbFileName = testHome + "/" + testName + ".db"; 108 string dbSecFileName = testHome + "/" + testName + 109 "_sec.db"; 110 111 Configuration.ClearDir(testHome); 112 113 // Open a primary database and its secondary database. 114 BTreeDatabase db; 115 SecondaryBTreeDatabase secDB; 116 OpenSecDB(dbFileName, dbSecFileName, out db, out secDB); 117 118 // Put a pair of key and data into database. 119 DatabaseEntry key, data; 120 key = new DatabaseEntry( 121 ASCIIEncoding.ASCII.GetBytes("key")); 122 data = new DatabaseEntry( 123 ASCIIEncoding.ASCII.GetBytes("data")); 124 db.Put(key, data); 125 126 // Delete the pair with cursor. 127 SecondaryCursor secCursor = secDB.SecondaryCursor(); 128 Assert.IsTrue(secCursor.MoveFirst()); 129 secCursor.Delete(); 130 131 // Confirm that the pair is deleted. 132 Assert.IsFalse(db.Exists(key)); 133 134 // Close all databases. 135 secDB.Close(); 136 db.Close(); 137 } 138 139 [Test] 140 public void TestCurrent() 141 { 142 testName = "TestCurrent"; 143 testHome = testFixtureHome + "/" + testName; 144 string dbFileName = testHome + "/" + testName + ".db"; 145 string dbSecFileName = testHome + "/" + testName + 146 "_sec.db"; 147 148 Configuration.ClearDir(testHome); 149 150 // Open a primary database and its secondary database. 151 BTreeDatabase db; 152 SecondaryBTreeDatabase secDB; 153 OpenSecDB(dbFileName, dbSecFileName, out db, out secDB); 154 155 // Put a pair of key and data into database. 156 DatabaseEntry key, data; 157 key = new DatabaseEntry( 158 ASCIIEncoding.ASCII.GetBytes("key")); 159 data = new DatabaseEntry( 160 ASCIIEncoding.ASCII.GetBytes("data")); 161 db.Put(key, data); 162 163 // Delete the pair with cursor. 164 SecondaryCursor secCursor = secDB.SecondaryCursor(); 165 Assert.IsTrue(secCursor.Move(data, true)); 166 167 // Confirm that the current is the one we put into database. 168 Assert.AreEqual(data.Data, secCursor.Current.Key.Data); 169 170 // Close all databases. 171 secDB.Close(); 172 db.Close(); 173 } 174 175 [Test] 176 public void TestGetEnumerator() 177 { 178 testName = "TestGetEnumerator"; 179 testHome = testFixtureHome + "/" + testName; 180 string dbFileName = testHome + "/" + testName + ".db"; 181 string dbSecFileName = testHome + "/" + testName + 182 "_sec.db"; 183 184 Configuration.ClearDir(testHome); 185 186 // Open a primary database and its secondary database. 187 BTreeDatabase db; 188 SecondaryBTreeDatabase secDB; 189 OpenSecDB(dbFileName, dbSecFileName, out db, 190 out secDB); 191 192 // Write ten records into the database. 193 WriteRecords(db); 194 195 /* 196 * Get all records from the secondary database and see 197 * if the records with key other than 10 have the same as 198 * their primary key. 199 */ 200 SecondaryCursor secCursor = secDB.SecondaryCursor(); 201 foreach (KeyValuePair<DatabaseEntry, KeyValuePair< 202 DatabaseEntry, DatabaseEntry>> secData in secCursor) 203 { 204 if (BitConverter.ToInt32(secData.Key.Data, 0) != 10) 205 Assert.AreEqual(secData.Value.Key.Data, 206 secData.Value.Value.Data); 207 } 208 209 // Close all cursors and databases. 210 secCursor.Close(); 211 secDB.Close(); 212 db.Close(); 213 } 214 215 [Test] 216 public void TestMoveToKey() 217 { 218 testName = "TestMoveToKey"; 219 testHome = testFixtureHome + "/" + testName; 220 string dbFileName = testHome + "/" + testName + ".db"; 221 string dbSecFileName = testHome + "/" + testName + 222 "_sec.db"; 223 224 Configuration.ClearDir(testHome); 225 226 MoveToPos(dbFileName, dbSecFileName, false); 227 } 228 229 [Test] 230 public void TestMoveToPair() 231 { 232 testName = "TestMoveToPair"; 233 testHome = testFixtureHome + "/" + testName; 234 string dbFileName = testHome + "/" + testName + ".db"; 235 string dbSecFileName = testHome + "/" + testName + 236 "_sec.db"; 237 238 Configuration.ClearDir(testHome); 239 240 MoveToPos(dbFileName, dbSecFileName, true); 241 } 242 243 public void MoveToPos(string dbFileName, 244 string dbSecFileName, bool ifPair) 245 { 246 // Open a primary database and its secondary database. 247 BTreeDatabase db; 248 SecondaryBTreeDatabase secDB; 249 OpenSecDB(dbFileName, dbSecFileName, out db, 250 out secDB); 251 252 // Write ten records into the database. 253 WriteRecords(db); 254 255 SecondaryCursor secCursor = secDB.SecondaryCursor(); 256 DatabaseEntry key = new DatabaseEntry( 257 BitConverter.GetBytes((int)0)); 258 DatabaseEntry notExistingKey = new DatabaseEntry( 259 BitConverter.GetBytes((int)100)); 260 if (ifPair == false) 261 { 262 Assert.IsTrue(secCursor.Move(key, true)); 263 Assert.IsFalse(secCursor.Move(notExistingKey, true)); 264 } 265 else 266 { 267 KeyValuePair<DatabaseEntry, KeyValuePair< 268 DatabaseEntry, DatabaseEntry>> pair = 269 new KeyValuePair<DatabaseEntry, 270 KeyValuePair<DatabaseEntry, DatabaseEntry>>(key, 271 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 272 key, key)); 273 274 KeyValuePair<DatabaseEntry, KeyValuePair< 275 DatabaseEntry, DatabaseEntry>> notExistingPair; 276 277 notExistingPair = new KeyValuePair<DatabaseEntry, 278 KeyValuePair<DatabaseEntry, DatabaseEntry>>( 279 notExistingKey, new KeyValuePair< 280 DatabaseEntry, DatabaseEntry>( 281 notExistingKey, notExistingKey)); 282 Assert.IsTrue(secCursor.Move(pair, true)); 283 Assert.IsFalse(secCursor.Move(notExistingPair, true)); 284 } 285 286 secCursor.Close(); 287 secDB.Close(); 288 db.Close(); 289 } 290 291 [Test] 292 public void TestMoveToKeyWithLockingInfo() 293 { 294 testName = "TestMoveToKeyWithLockingInfo"; 295 testHome = testFixtureHome + "/" + testName; 296 string dbFileName = testName + ".db"; 297 string dbSecFileName = testName + "_sec.db"; 298 299 Configuration.ClearDir(testHome); 300 301 MoveToPosWithLockingInfo(testHome, dbFileName, 302 dbSecFileName, false); 303 } 304 305 [Test] 306 public void TestMoveToPairWithLockingInfo() 307 { 308 testName = "TestMoveToPairWithLockingInfo"; 309 testHome = testFixtureHome + "/" + testName; 310 string dbFileName = testName + ".db"; 311 string dbSecFileName = testName + "_sec.db"; 312 313 Configuration.ClearDir(testHome); 314 315 MoveToPosWithLockingInfo(testHome, dbFileName, 316 dbSecFileName, true); 317 } 318 319 public void MoveToPosWithLockingInfo(string home, 320 string dbFileName, string dbSecFileName, bool ifPair) 321 { 322 // Open a primary database and its secondary database. 323 BTreeDatabase db; 324 DatabaseEnvironment env; 325 SecondaryBTreeDatabase secDB; 326 OpenSecDBInTxn(home, dbFileName, dbSecFileName, 327 out env, out db, out secDB); 328 329 // Write ten records into the database. 330 WriteRecordsInTxn(db, env); 331 332 // Create an secondary cursor. 333 Transaction cursorTxn = env.BeginTransaction(); 334 SecondaryCursor secCursor = secDB.SecondaryCursor( 335 cursorTxn); 336 DatabaseEntry key = new DatabaseEntry( 337 BitConverter.GetBytes((int)0)); 338 LockingInfo lockingInfo = new LockingInfo(); 339 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 340 lockingInfo.ReadModifyWrite = true; 341 if (ifPair == false) 342 { 343 Assert.IsTrue(secCursor.Move(key, true, lockingInfo)); 344 } 345 else 346 { 347 KeyValuePair<DatabaseEntry, KeyValuePair< 348 DatabaseEntry, DatabaseEntry>> pair; 349 350 pair = new KeyValuePair<DatabaseEntry, 351 KeyValuePair<DatabaseEntry, DatabaseEntry>>(key, 352 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 353 key, key)); 354 Assert.IsTrue(secCursor.Move(pair, true, lockingInfo)); 355 } 356 secCursor.Close(); 357 cursorTxn.Commit(); 358 359 secDB.Close(); 360 db.Close(); 361 env.Close(); 362 } 363 364 [Test] 365 public void TestMoveFirst() 366 { 367 testName = "TestMoveFirst"; 368 testHome = testFixtureHome + "/" + testName; 369 string dbFileName = testHome + "/" + testName + ".db"; 370 string dbSecFileName = testHome + "/" + testName + 371 "_sec.db"; 372 373 Configuration.ClearDir(testHome); 374 375 // Open primary and secondary database. 376 BTreeDatabase db; 377 SecondaryBTreeDatabase secDB; 378 OpenSecDB(dbFileName, dbSecFileName, out db, 379 out secDB); 380 381 382 // Write ten records into the database. 383 WriteRecords(db); 384 385 // Move the cursor to the first record(0,0). 386 SecondaryCursor cursor = secDB.SecondaryCursor(); 387 Assert.IsTrue(cursor.MoveFirst()); 388 Assert.AreEqual(BitConverter.GetBytes((int)0), 389 cursor.Current.Key.Data); 390 391 // Close all. 392 cursor.Close(); 393 secDB.Close(); 394 db.Close(); 395 } 396 397 [Test] 398 public void TestMoveLast() 399 { 400 testName = "TestMoveLast"; 401 testHome = testFixtureHome + "/" + testName; 402 string dbFileName = testHome + "/" + testName + ".db"; 403 string dbSecFileName = testHome + "/" + testName + 404 "_sec.db"; 405 406 Configuration.ClearDir(testHome); 407 408 BTreeDatabase db; 409 SecondaryBTreeDatabase secDB; 410 OpenSecDB(dbFileName, dbSecFileName, out db, 411 out secDB); 412 WriteRecords(db); 413 414 SecondaryCursor cursor = secDB.SecondaryCursor(); 415 Assert.IsTrue(cursor.MoveLast()); 416 Assert.AreEqual(BitConverter.GetBytes((int)10), 417 cursor.Current.Key.Data); 418 419 cursor.Close(); 420 secDB.Close(); 421 db.Close(); 422 } 423 424 [Test] 425 public void TestMoveNext() 426 { 427 testName = "TestMoveNext"; 428 testHome = testFixtureHome + "/" + testName; 429 string dbFileName = testHome + "/" + testName + ".db"; 430 string dbSecFileName = testHome + "/" + testName + 431 "_sec.db"; 432 433 Configuration.ClearDir(testHome); 434 435 BTreeDatabase db; 436 SecondaryBTreeDatabase secDB; 437 OpenSecDB(dbFileName, dbSecFileName, out db, 438 out secDB); 439 WriteRecords(db); 440 441 SecondaryCursor cursor = secDB.SecondaryCursor(); 442 cursor.MoveFirst(); 443 for (int i = 0; i < 5; i++) 444 Assert.IsTrue(cursor.MoveNext()); 445 446 cursor.Close(); 447 secDB.Close(); 448 db.Close(); 449 } 450 451 [Test] 452 public void TestMoveNextDuplicate() 453 { 454 testName = "TestMoveNextDuplicate"; 455 testHome = testFixtureHome + "/" + testName; 456 string dbFileName = testHome + "/" + testName + ".db"; 457 string dbSecFileName = testHome + "/" + testName + 458 "_sec.db"; 459 460 Configuration.ClearDir(testHome); 461 462 BTreeDatabase db; 463 SecondaryBTreeDatabase secDB; 464 OpenSecDB(dbFileName, dbSecFileName, out db, 465 out secDB); 466 WriteRecords(db); 467 468 // Create a cursor and move the cursor to duplicate record. 469 SecondaryCursor cursor = secDB.SecondaryCursor(); 470 cursor.Move(new DatabaseEntry( 471 BitConverter.GetBytes((int)10)), true); 472 Assert.IsTrue(cursor.MoveNextDuplicate()); 473 Assert.AreEqual(BitConverter.GetBytes((int)10), 474 cursor.Current.Key.Data); 475 476 cursor.Close(); 477 secDB.Close(); 478 db.Close(); 479 } 480 481 [Test] 482 public void TestMoveNextUnique() 483 { 484 testName = "TestMoveNextUnique"; 485 testHome = testFixtureHome + "/" + testName; 486 string dbFileName = testHome + "/" + testName + ".db"; 487 string dbSecFileName = testHome + "/" + testName + 488 "_sec.db"; 489 490 Configuration.ClearDir(testHome); 491 492 BTreeDatabase db; 493 SecondaryBTreeDatabase secDB; 494 OpenSecDB(dbFileName, dbSecFileName, out db, 495 out secDB); 496 WriteRecords(db); 497 498 /* 499 * Move cursor to duplicate record. Since the duplicate 500 * record has the largest key, moving to the next 501 * unique record should fail. 502 */ 503 SecondaryCursor cursor = secDB.SecondaryCursor(); 504 cursor.Move(new DatabaseEntry( 505 BitConverter.GetBytes((int)10)), true); 506 Assert.IsFalse(cursor.MoveNextUnique()); 507 508 cursor.Close(); 509 secDB.Close(); 510 db.Close(); 511 } 512 513 [Test] 514 public void TestMovePrev() 515 { 516 testName = "TestMovePrev"; 517 testHome = testFixtureHome + "/" + testName; 518 string dbFileName = testHome + "/" + testName + ".db"; 519 string dbSecFileName = testHome + "/" + testName + 520 "_sec.db"; 521 522 Configuration.ClearDir(testHome); 523 524 BTreeDatabase db; 525 SecondaryBTreeDatabase secDB; 526 OpenSecDB(dbFileName, dbSecFileName, out db, 527 out secDB); 528 WriteRecords(db); 529 530 SecondaryCursor cursor = secDB.SecondaryCursor(); 531 cursor.MoveLast(); 532 for (int i = 0; i < 5; i++) 533 Assert.IsTrue(cursor.MovePrev()); 534 535 cursor.Close(); 536 secDB.Close(); 537 db.Close(); 538 } 539 540 [Test] 541 public void TestMovePrevDuplicate() 542 { 543 testName = "TestMovePrevDuplicate"; 544 testHome = testFixtureHome + "/" + testName; 545 string dbFileName = testHome + "/" + testName + ".db"; 546 string dbSecFileName = testHome + "/" + testName + 547 "_sec.db"; 548 549 Configuration.ClearDir(testHome); 550 551 BTreeDatabase db; 552 SecondaryBTreeDatabase secDB; 553 OpenSecDB(dbFileName, dbSecFileName, out db, 554 out secDB); 555 WriteRecords(db); 556 557 SecondaryCursor cursor = secDB.SecondaryCursor(); 558 KeyValuePair<DatabaseEntry, KeyValuePair< 559 DatabaseEntry, DatabaseEntry>> pair; 560 DatabaseEntry pKey, pData; 561 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 562 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 563 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 564 DatabaseEntry, DatabaseEntry>>(pData, 565 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 566 pKey, pData)); 567 cursor.Move(pair, true); 568 Assert.IsTrue(cursor.MovePrevDuplicate()); 569 Assert.AreEqual(BitConverter.GetBytes((int)10), 570 cursor.Current.Key.Data); 571 572 cursor.Close(); 573 secDB.Close(); 574 db.Close(); 575 } 576 577 578 [Test] 579 public void TestMovePrevUnique() 580 { 581 testName = "TestMovePrevUnique"; 582 testHome = testFixtureHome + "/" + testName; 583 string dbFileName = testHome + "/" + testName + ".db"; 584 string dbSecFileName = testHome + "/" + testName + 585 "_sec.db"; 586 587 Configuration.ClearDir(testHome); 588 589 BTreeDatabase db; 590 SecondaryBTreeDatabase secDB; 591 OpenSecDB(dbFileName, dbSecFileName, out db, 592 out secDB); 593 WriteRecords(db); 594 595 SecondaryCursor cursor = secDB.SecondaryCursor(); 596 KeyValuePair<DatabaseEntry, KeyValuePair< 597 DatabaseEntry, DatabaseEntry>> pair; 598 DatabaseEntry pKey, pData; 599 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 600 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 601 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 602 DatabaseEntry, DatabaseEntry>>(pData, 603 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 604 pKey, pData)); 605 cursor.Move(pair, true); 606 Assert.IsTrue(cursor.MovePrevUnique()); 607 Assert.AreNotEqual(BitConverter.GetBytes((int)10), 608 cursor.Current.Key.Data); 609 610 cursor.Close(); 611 secDB.Close(); 612 db.Close(); 613 } 614 615 [Test] 616 public void TestRefresh() 617 { 618 testName = "TestRefresh"; 619 testHome = testFixtureHome + "/" + testName; 620 string dbFileName = testHome + "/" + testName + ".db"; 621 string dbSecFileName = testHome + "/" + testName + 622 "_sec.db"; 623 624 Configuration.ClearDir(testHome); 625 626 BTreeDatabase db; 627 SecondaryBTreeDatabase secDB; 628 OpenSecDB(dbFileName, dbSecFileName, out db, 629 out secDB); 630 WriteRecords(db); 631 632 SecondaryCursor cursor = secDB.SecondaryCursor(); 633 KeyValuePair<DatabaseEntry, KeyValuePair< 634 DatabaseEntry, DatabaseEntry>> pair; 635 DatabaseEntry pKey, pData; 636 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 637 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 638 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 639 DatabaseEntry, DatabaseEntry>>(pData, 640 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 641 pKey, pData)); 642 cursor.Move(pair, true); 643 Assert.IsTrue(cursor.Refresh()); 644 Assert.AreEqual(pData.Data, cursor.Current.Key.Data); 645 Assert.AreEqual(pKey.Data, cursor.Current.Value.Key.Data); 646 647 cursor.Close(); 648 secDB.Close(); 649 db.Close(); 650 } 651 652 [Test] 653 public void TestMoveFirstWithLockingInfo() 654 { 655 testName = "TestMoveFirstWithLockingInfo"; 656 testHome = testFixtureHome + "/" + testName; 657 string dbFileName = testName + ".db"; 658 string dbSecFileName = testName + "_sec.db"; 659 660 Configuration.ClearDir(testHome); 661 662 /* 663 * Open environment, primary database and 664 * secondary database. 665 */ 666 BTreeDatabase db; 667 DatabaseEnvironment env; 668 SecondaryBTreeDatabase secDB; 669 OpenSecDBInTxn(testHome, dbFileName, dbSecFileName, 670 out env, out db, out secDB); 671 672 // Write ten records into the database. 673 WriteRecordsInTxn(db, env); 674 675 // Move the cursor to the first record(0, 0). 676 Transaction cursorTxn = env.BeginTransaction(); 677 SecondaryCursor cursor = 678 secDB.SecondaryCursor(cursorTxn); 679 LockingInfo lockingInfo = new LockingInfo(); 680 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 681 lockingInfo.ReadModifyWrite = true; 682 Assert.IsTrue(cursor.MoveFirst(lockingInfo)); 683 Assert.AreEqual(BitConverter.GetBytes((int)0), 684 cursor.Current.Key.Data); 685 cursor.Close(); 686 cursorTxn.Commit(); 687 688 // Close all. 689 secDB.Close(); 690 db.Close(); 691 env.Close(); 692 } 693 694 [Test] 695 public void TestMoveLastWithLockingInfo() 696 { 697 testName = "TestMoveLastWithLockingInfo"; 698 testHome = testFixtureHome + "/" + testName; 699 string dbFileName = testName + ".db"; 700 string dbSecFileName = testName + "_sec.db"; 701 702 Configuration.ClearDir(testHome); 703 704 /* 705 * Open environment, primary database and 706 * secondary database. 707 */ 708 BTreeDatabase db; 709 DatabaseEnvironment env; 710 SecondaryBTreeDatabase secDB; 711 OpenSecDBInTxn(testHome, dbFileName, dbSecFileName, 712 out env, out db, out secDB); 713 714 // Write ten records into the database. 715 WriteRecordsInTxn(db, env); 716 717 /* 718 * Move the cursor to the last record(10, 6), that is 719 * record(6, 10) in primary database. 720 */ 721 Transaction cursorTxn = env.BeginTransaction(); 722 SecondaryCursor cursor = 723 secDB.SecondaryCursor(cursorTxn); 724 LockingInfo lockingInfo = new LockingInfo(); 725 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 726 lockingInfo.ReadModifyWrite = true; 727 Assert.IsTrue(cursor.MoveLast(lockingInfo)); 728 Assert.AreEqual(BitConverter.GetBytes((int)10), 729 cursor.Current.Key.Data); 730 cursor.Close(); 731 cursorTxn.Commit(); 732 733 // Close all. 734 secDB.Close(); 735 db.Close(); 736 env.Close(); 737 } 738 739 [Test] 740 public void TestMoveNextWithLockingInfo() 741 { 742 testName = "TestMoveNextWithLockingInfo"; 743 testHome = testFixtureHome + "/" + testName; 744 string dbFileName = testName + ".db"; 745 string dbSecFileName = testName + "_sec.db"; 746 747 Configuration.ClearDir(testHome); 748 749 /* 750 * Open environment, primary database and 751 * secondary database. 752 */ 753 BTreeDatabase db; 754 DatabaseEnvironment env; 755 SecondaryBTreeDatabase secDB; 756 OpenSecDBInTxn(testHome, dbFileName, dbSecFileName, 757 out env, out db, out secDB); 758 759 // Write ten records into the database. 760 WriteRecordsInTxn(db, env); 761 762 /* 763 * Move cursor to the first record and move to next 764 * record for five times. 765 */ 766 Transaction cursorTxn = env.BeginTransaction(); 767 SecondaryCursor cursor = 768 secDB.SecondaryCursor(cursorTxn); 769 LockingInfo lockingInfo = new LockingInfo(); 770 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 771 lockingInfo.ReadModifyWrite = true; 772 cursor.MoveFirst(lockingInfo); 773 for (int i = 0; i < 5; i++) 774 Assert.IsTrue(cursor.MoveNext(lockingInfo)); 775 cursor.Close(); 776 cursorTxn.Commit(); 777 778 // Close all. 779 secDB.Close(); 780 db.Close(); 781 env.Close(); 782 } 783 784 [Test] 785 public void TestMoveNextDuplicateWithLockingInfo() 786 { 787 testName = "TestMoveNextDuplicateWithLockingInfo"; 788 testHome = testFixtureHome + "/" + testName; 789 string dbFileName = testName + ".db"; 790 string dbSecFileName = testName + "_sec.db"; 791 792 Configuration.ClearDir(testHome); 793 794 /* 795 * Open environment, primary database and 796 * secondary database. 797 */ 798 BTreeDatabase db; 799 DatabaseEnvironment env; 800 SecondaryBTreeDatabase secDB; 801 OpenSecDBInTxn(testHome, dbFileName, 802 dbSecFileName, out env, out db, out secDB); 803 804 // Write ten records into the database. 805 WriteRecordsInTxn(db, env); 806 807 /* 808 * Create a cursor and move the cursor to duplicate 809 * record(10, 5), that is record(5,10) in primary database. 810 * Then move the cursor to the next duplicate record 811 * (10, 6), that is record(6,10) in primary database. 812 */ 813 Transaction cursorTxn = env.BeginTransaction(); 814 SecondaryCursor cursor = 815 secDB.SecondaryCursor(cursorTxn); 816 LockingInfo lockingInfo = new LockingInfo(); 817 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 818 lockingInfo.ReadModifyWrite = true; 819 cursor.Move(new DatabaseEntry( 820 BitConverter.GetBytes((int)10)), true, lockingInfo); 821 Assert.IsTrue(cursor.MoveNextDuplicate(lockingInfo)); 822 Assert.AreEqual(BitConverter.GetBytes((int)10), 823 cursor.Current.Key.Data); 824 cursor.Close(); 825 cursorTxn.Commit(); 826 827 // Close all. 828 secDB.Close(); 829 db.Close(); 830 env.Close(); 831 } 832 833 [Test] 834 public void TestMoveNextUniqueWithLockingInfo() 835 { 836 testName = "TestMoveNextUniqueWithLockingInfo"; 837 testHome = testFixtureHome + "/" + testName; 838 string dbFileName = testName + ".db"; 839 string dbSecFileName = testName + "_sec.db"; 840 841 Configuration.ClearDir(testHome); 842 843 /* 844 * Open environment, primary database and 845 * secondary database. 846 */ 847 BTreeDatabase db; 848 DatabaseEnvironment env; 849 SecondaryBTreeDatabase secDB; 850 OpenSecDBInTxn(testHome, dbFileName, 851 dbSecFileName, out env, out db, out secDB); 852 853 // Write ten records into the database. 854 WriteRecordsInTxn(db, env); 855 856 /* 857 * Move cursor to duplicate record. Since the duplicate 858 * record has the largest key, moving to the next 859 * unique record should fail. 860 */ 861 Transaction cursorTxn = env.BeginTransaction(); 862 SecondaryCursor cursor = 863 secDB.SecondaryCursor(cursorTxn); 864 LockingInfo lockingInfo = new LockingInfo(); 865 lockingInfo.IsolationDegree = Isolation.DEGREE_THREE; 866 lockingInfo.ReadModifyWrite = true; 867 cursor.Move(new DatabaseEntry( 868 BitConverter.GetBytes((int)10)), true); 869 Assert.IsFalse(cursor.MoveNextUnique()); 870 cursor.Close(); 871 cursorTxn.Commit(); 872 873 // Close all. 874 secDB.Close(); 875 db.Close(); 876 env.Close(); 877 } 878 879 [Test] 880 public void TestMovePrevWithLockingInfo() 881 { 882 testName = "TestMovePrevWithLockingInfo"; 883 testHome = testFixtureHome + "/" + testName; 884 string dbFileName = testName + ".db"; 885 string dbSecFileName = testName + "_sec.db"; 886 887 Configuration.ClearDir(testHome); 888 889 /* 890 * Open environment, primary database and 891 * secondary database. 892 */ 893 BTreeDatabase db; 894 DatabaseEnvironment env; 895 SecondaryBTreeDatabase secDB; 896 OpenSecDBInTxn(testHome, dbFileName, 897 dbSecFileName, out env, out db, out secDB); 898 899 // Write ten records into the database. 900 WriteRecordsInTxn(db, env); 901 902 /* 903 * Move the cursor to the last record and move to its 904 * previous record for five times. 905 */ 906 Transaction cursorTxn = env.BeginTransaction(); 907 SecondaryCursor cursor = 908 secDB.SecondaryCursor(cursorTxn); 909 LockingInfo lockingInfo = new LockingInfo(); 910 lockingInfo.IsolationDegree = Isolation.DEGREE_TWO; 911 lockingInfo.ReadModifyWrite = true; 912 cursor.MoveLast(lockingInfo); 913 for (int i = 0; i < 5; i++) 914 Assert.IsTrue(cursor.MovePrev(lockingInfo)); 915 cursor.Close(); 916 cursorTxn.Commit(); 917 918 // Close all. 919 secDB.Close(); 920 db.Close(); 921 env.Close(); 922 } 923 924 [Test] 925 public void TestMovePrevDuplicateWithLockingInfo() 926 { 927 testName = "TestMovePrevDuplicateWithLockingInfo"; 928 testHome = testFixtureHome + "/" + testName; 929 string dbFileName = testName + ".db"; 930 string dbSecFileName = testName + "_sec.db"; 931 932 Configuration.ClearDir(testHome); 933 934 /* 935 * Open environment, primary database and 936 * secondary database. 937 */ 938 BTreeDatabase db; 939 DatabaseEnvironment env; 940 SecondaryBTreeDatabase secDB; 941 OpenSecDBInTxn(testHome, dbFileName, 942 dbSecFileName, out env, out db, out secDB); 943 944 // Write ten records into the database. 945 WriteRecordsInTxn(db, env); 946 947 Transaction cursorTxn = env.BeginTransaction(); 948 SecondaryCursor cursor = 949 secDB.SecondaryCursor(cursorTxn); 950 LockingInfo lockingInfo = new LockingInfo(); 951 lockingInfo.IsolationDegree = Isolation.DEGREE_TWO; 952 lockingInfo.ReadModifyWrite = true; 953 954 /* 955 * Move the cursor to the record(10,6), that is the 956 * record(6, 10) in the primary database. Move to 957 * its previous duplicate record, that is (10,5). 958 */ 959 KeyValuePair<DatabaseEntry, KeyValuePair< 960 DatabaseEntry, DatabaseEntry>> pair; 961 DatabaseEntry pKey, pData; 962 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 963 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 964 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 965 DatabaseEntry, DatabaseEntry>>(pData, 966 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 967 pKey, pData)); 968 cursor.Move(pair, true, lockingInfo); 969 Assert.IsTrue(cursor.MovePrevDuplicate(lockingInfo)); 970 Assert.AreEqual(BitConverter.GetBytes((int)10), 971 cursor.Current.Key.Data); 972 973 cursor.Close(); 974 cursorTxn.Commit(); 975 976 // Close all. 977 secDB.Close(); 978 db.Close(); 979 env.Close(); 980 } 981 982 983 [Test] 984 public void TestMovePrevUniqueWithLockingInfo() 985 { 986 testName = "TestMovePrevUniqueWithLockingInfo"; 987 testHome = testFixtureHome + "/" + testName; 988 string dbFileName = testName + ".db"; 989 string dbSecFileName = testName + "_sec.db"; 990 991 Configuration.ClearDir(testHome); 992 993 /* 994 * Open environment, primary database and 995 * secondary database. 996 */ 997 BTreeDatabase db; 998 DatabaseEnvironment env; 999 SecondaryBTreeDatabase secDB; 1000 OpenSecDBInTxn(testHome, dbFileName, 1001 dbSecFileName, out env, out db, out secDB); 1002 1003 // Write ten records into the database. 1004 WriteRecordsInTxn(db, env); 1005 1006 Transaction cursorTxn = env.BeginTransaction(); 1007 SecondaryCursor cursor = 1008 secDB.SecondaryCursor(cursorTxn); 1009 LockingInfo lockingInfo = new LockingInfo(); 1010 lockingInfo.IsolationDegree = Isolation.DEGREE_TWO; 1011 lockingInfo.ReadModifyWrite = true; 1012 1013 /* 1014 * Move the cursor to the record(10, 6) and move to the 1015 * previous unique record which has different key from 1016 * the record(10,6). 1017 */ 1018 KeyValuePair<DatabaseEntry, KeyValuePair< 1019 DatabaseEntry, DatabaseEntry>> pair; 1020 DatabaseEntry pKey, pData; 1021 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 1022 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 1023 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 1024 DatabaseEntry, DatabaseEntry>>(pData, 1025 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 1026 pKey, pData)); 1027 cursor.Move(pair, true, lockingInfo); 1028 Assert.IsTrue(cursor.MovePrevUnique(lockingInfo)); 1029 Assert.AreNotEqual(BitConverter.GetBytes((int)10), 1030 cursor.Current.Key.Data); 1031 1032 cursor.Close(); 1033 cursorTxn.Commit(); 1034 1035 // Close all. 1036 secDB.Close(); 1037 db.Close(); 1038 env.Close(); 1039 } 1040 1041 [Test] 1042 public void TestRefreshWithLockingInfo() 1043 { 1044 testName = "TestRefreshWithLockingInfo"; 1045 testHome = testFixtureHome + "/" + testName; 1046 string dbFileName = testName + ".db"; 1047 string dbSecFileName = testName + "_sec.db"; 1048 1049 Configuration.ClearDir(testHome); 1050 1051 /* 1052 * Open environment, primary database and 1053 * secondary database. 1054 */ 1055 BTreeDatabase db; 1056 DatabaseEnvironment env; 1057 SecondaryBTreeDatabase secDB; 1058 OpenSecDBInTxn(testHome, dbFileName, 1059 dbSecFileName, out env, out db, out secDB); 1060 1061 // Write ten records into the database. 1062 WriteRecordsInTxn(db, env); 1063 1064 Transaction cursorTxn = env.BeginTransaction(); 1065 SecondaryCursor cursor = 1066 secDB.SecondaryCursor(cursorTxn); 1067 LockingInfo lockingInfo = new LockingInfo(); 1068 lockingInfo.IsolationDegree = Isolation.DEGREE_TWO; 1069 lockingInfo.ReadModifyWrite = true; 1070 1071 // Move cursor to a record and refresh it. 1072 KeyValuePair<DatabaseEntry, KeyValuePair< 1073 DatabaseEntry, DatabaseEntry>> pair; 1074 DatabaseEntry pKey, pData; 1075 pKey = new DatabaseEntry(BitConverter.GetBytes((int)6)); 1076 pData = new DatabaseEntry(BitConverter.GetBytes((int)10)); 1077 pair = new KeyValuePair<DatabaseEntry, KeyValuePair< 1078 DatabaseEntry, DatabaseEntry>>(pData, 1079 new KeyValuePair<DatabaseEntry, DatabaseEntry>( 1080 pKey, pData)); 1081 cursor.Move(pair, true, lockingInfo); 1082 Assert.IsTrue(cursor.Refresh(lockingInfo)); 1083 Assert.AreEqual(pData.Data, cursor.Current.Key.Data); 1084 Assert.AreEqual(pKey.Data, cursor.Current.Value.Key.Data); 1085 1086 cursor.Close(); 1087 cursorTxn.Commit(); 1088 1089 // Close all. 1090 secDB.Close(); 1091 db.Close(); 1092 env.Close(); 1093 } 1094 1095 public void OpenSecDBInTxn(string home, string dbFileName, 1096 string dbSecFileName, out DatabaseEnvironment env, 1097 out BTreeDatabase db, out SecondaryBTreeDatabase secDB) 1098 { 1099 // Open environment. 1100 DatabaseEnvironmentConfig envCfg = 1101 new DatabaseEnvironmentConfig(); 1102 envCfg.Create = true; 1103 envCfg.UseLocking = true; 1104 envCfg.UseLogging = true; 1105 envCfg.UseMPool = true; 1106 envCfg.UseTxns = true; 1107 env = DatabaseEnvironment.Open( 1108 home, envCfg); 1109 1110 // Open primary and secondary database in a transaction. 1111 Transaction openTxn = env.BeginTransaction(); 1112 BTreeDatabaseConfig dbConfig = 1113 new BTreeDatabaseConfig(); 1114 dbConfig.Creation = CreatePolicy.IF_NEEDED; 1115 dbConfig.Env = env; 1116 dbConfig.PageSize = 4096; 1117 dbConfig.Duplicates = DuplicatesPolicy.NONE; 1118 dbConfig.ReadUncommitted = true; 1119 db = BTreeDatabase.Open(dbFileName, dbConfig, 1120 openTxn); 1121 openTxn.Commit(); 1122 1123 openTxn = env.BeginTransaction(); 1124 SecondaryBTreeDatabaseConfig secConfig = 1125 new SecondaryBTreeDatabaseConfig(db, 1126 new SecondaryKeyGenDelegate(SecondaryKeyGen)); 1127 secConfig.Creation = CreatePolicy.IF_NEEDED; 1128 secConfig.Duplicates = DuplicatesPolicy.SORTED; 1129 secConfig.Env = env; 1130 secConfig.ReadUncommitted = true; 1131 secDB = SecondaryBTreeDatabase.Open(dbSecFileName, 1132 secConfig, openTxn); 1133 openTxn.Commit(); 1134 } 1135 1136 public void WriteRecords(BTreeDatabase db) 1137 { 1138 /* 1139 * Write ten records into the database. The records 1140 * from 1st to 5th and 8th to 10th are unique in the 1141 * database. The data in the 6th and 7th records 1142 * are the same. 1143 */ 1144 for (int i = 0; i < 10; i++) 1145 { 1146 if (i == 5 || i == 6) 1147 db.Put(new DatabaseEntry( 1148 BitConverter.GetBytes(i)), 1149 new DatabaseEntry( 1150 BitConverter.GetBytes((int)10))); 1151 else 1152 db.Put(new DatabaseEntry( 1153 BitConverter.GetBytes(i)), 1154 new DatabaseEntry(BitConverter.GetBytes(i))); 1155 } 1156 } 1157 1158 public void WriteRecordsInTxn(BTreeDatabase db, 1159 DatabaseEnvironment env) 1160 { 1161 Transaction txn = env.BeginTransaction(); 1162 /* 1163 * Write ten records into the database. The records 1164 * from 1st to 5th and 8th to 10th are unique in the 1165 * database. The data in the 6th and 7th records 1166 * are the same. 1167 */ 1168 for (int i = 0; i < 10; i++) 1169 { 1170 if (i == 5 || i == 6) 1171 db.Put(new DatabaseEntry( 1172 BitConverter.GetBytes(i)), 1173 new DatabaseEntry( 1174 BitConverter.GetBytes((int)10)), txn); 1175 else 1176 db.Put(new DatabaseEntry( 1177 BitConverter.GetBytes(i)), 1178 new DatabaseEntry(BitConverter.GetBytes(i)), txn); 1179 } 1180 1181 txn.Commit(); 1182 } 1183 1184 1185 public void OpenSecDB(string dbFileName, 1186 string dbSecFileName, out BTreeDatabase db, 1187 out SecondaryBTreeDatabase secDB) 1188 { 1189 // Open a primary database. 1190 BTreeDatabaseConfig dbConfig = 1191 new BTreeDatabaseConfig(); 1192 dbConfig.Creation = CreatePolicy.IF_NEEDED; 1193 db = BTreeDatabase.Open(dbFileName, dbConfig); 1194 1195 // Open a secondary database. 1196 SecondaryBTreeDatabaseConfig secConfig = 1197 new SecondaryBTreeDatabaseConfig(db, 1198 new SecondaryKeyGenDelegate(SecondaryKeyGen)); 1199 secConfig.Creation = CreatePolicy.IF_NEEDED; 1200 secConfig.Duplicates = DuplicatesPolicy.SORTED; 1201 secDB = SecondaryBTreeDatabase.Open(dbSecFileName, 1202 secConfig); 1203 } 1204 1205 1206 public DatabaseEntry SecondaryKeyGen( 1207 DatabaseEntry key, DatabaseEntry data) 1208 { 1209 DatabaseEntry dbtGen; 1210 dbtGen = new DatabaseEntry(data.Data); 1211 return dbtGen; 1212 } 1213 } 1214} 1215