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 NUnit.Framework; 14using BerkeleyDB; 15 16namespace CsharpAPITest 17{ 18 [TestFixture] 19 public class BTreeCursorTest 20 { 21 private string testFixtureName; 22 private string testFixtureHome; 23 private string testName; 24 private string testHome; 25 26 private DatabaseEnvironment paramEnv; 27 private BTreeDatabase paramDB; 28 private EventWaitHandle signal; 29 30 private delegate void BTCursorMoveFuncDelegate( 31 BTreeCursor cursor, LockingInfo lockingInfo); 32 private BTCursorMoveFuncDelegate btCursorFunc; 33 34 [TestFixtureSetUp] 35 public void RunBeforeTests() 36 { 37 testFixtureName = "BTreeCursorTest"; 38 testFixtureHome = "./TestOut/" + testFixtureName; 39 } 40 41 [Test] 42 public void TestAddKeyFirst() 43 { 44 BTreeDatabase db; 45 BTreeCursor cursor; 46 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 47 48 testName = "TestAddKeyFirst"; 49 testHome = testFixtureHome + "/" + testName; 50 51 Configuration.ClearDir(testHome); 52 53 // Add record("key", "data") into database. 54 CursorTest.GetCursorInBtreeDBWithoutEnv( 55 testHome, testName, out db, out cursor); 56 CursorTest.AddOneByCursor(db, cursor); 57 58 // Add record("key","data1") as the first of the data item of "key". 59 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 60 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), 61 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1"))); 62 cursor.Add(pair, Cursor.InsertLocation.FIRST); 63 64 // Confirm the record is added as the first of the data item of "key". 65 cursor.Move(new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), true); 66 Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), 67 cursor.Current.Value.Data); 68 69 cursor.Close(); 70 db.Close(); 71 } 72 73 [Test] 74 public void TestAddKeyLast() 75 { 76 BTreeDatabase db; 77 BTreeCursor cursor; 78 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 79 80 testName = "TestAddKeyLast"; 81 testHome = testFixtureHome + "/" + testName; 82 83 Configuration.ClearDir(testHome); 84 85 // Add record("key", "data") into database. 86 CursorTest.GetCursorInBtreeDBWithoutEnv(testHome, testName, 87 out db, out cursor); 88 CursorTest.AddOneByCursor(db, cursor); 89 90 // Add new record("key","data1") as the last of the data item of "key". 91 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 92 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), 93 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1"))); 94 cursor.Add(pair, Cursor.InsertLocation.LAST); 95 96 // Confirm the record is added as the first of the data item of "key". 97 cursor.Move(new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), true); 98 Assert.AreNotEqual(ASCIIEncoding.ASCII.GetBytes("data1"), 99 cursor.Current.Value.Data); 100 101 cursor.Close(); 102 db.Close(); 103 } 104 105 [Test] 106 public void TestAddUnique() 107 { 108 BTreeDatabase db; 109 BTreeCursor cursor; 110 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 111 112 testName = "TestAddUnique"; 113 testHome = testFixtureHome + "/" + testName; 114 115 Configuration.ClearDir(testHome); 116 117 // Open a database and cursor. 118 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 119 dbConfig.Creation = CreatePolicy.IF_NEEDED; 120 121 // To put no duplicate data, the database should be set to be sorted. 122 dbConfig.Duplicates = DuplicatesPolicy.SORTED; 123 db = BTreeDatabase.Open(testHome + "/" + testName + ".db", dbConfig); 124 cursor = db.Cursor(); 125 126 // Add record("key", "data") into database. 127 CursorTest.AddOneByCursor(db, cursor); 128 129 // Fail to add duplicate record("key","data"). 130 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 131 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), 132 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); 133 try 134 { 135 cursor.AddUnique(pair); 136 } 137 catch (KeyExistException) 138 { 139 } 140 finally 141 { 142 cursor.Close(); 143 db.Close(); 144 } 145 } 146 147 [Test] 148 public void TestDuplicateWithSamePos() 149 { 150 BTreeDatabase db; 151 BTreeDatabaseConfig dbConfig; 152 BTreeCursor cursor, dupCursor; 153 DatabaseEnvironment env; 154 DatabaseEnvironmentConfig envConfig; 155 DatabaseEntry key, data; 156 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 157 Transaction txn; 158 159 testName = "TestDuplicateWithSamePos"; 160 testHome = testFixtureHome + "/" + testName; 161 162 Configuration.ClearDir(testHome); 163 164 envConfig = new DatabaseEnvironmentConfig(); 165 envConfig.Create = true; 166 envConfig.UseMPool = true; 167 envConfig.UseTxns = true; 168 envConfig.NoMMap = false; 169 env = DatabaseEnvironment.Open(testHome, envConfig); 170 171 txn = env.BeginTransaction(); 172 dbConfig = new BTreeDatabaseConfig(); 173 dbConfig.Creation = CreatePolicy.IF_NEEDED; 174 dbConfig.Env = env; 175 db = BTreeDatabase.Open(testName + ".db", dbConfig, txn); 176 key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); 177 data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); 178 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 179 db.Put(key, data, txn); 180 txn.Commit(); 181 182 txn = env.BeginTransaction(); 183 cursor = db.Cursor(txn); 184 cursor.Move(key, true); 185 186 //Duplicate a new cursor to the same position. 187 dupCursor = cursor.Duplicate(true); 188 189 // Overwrite the record. 190 dupCursor.Overwrite(new DatabaseEntry( 191 ASCIIEncoding.ASCII.GetBytes("newdata"))); 192 193 // Confirm that the original data doesn't exist. 194 Assert.IsFalse(dupCursor.Move(pair, true)); 195 196 dupCursor.Close(); 197 cursor.Close(); 198 txn.Commit(); 199 db.Close(); 200 env.Close(); 201 } 202 203 [Test, ExpectedException(typeof(ExpectedTestException))] 204 public void TestDuplicateToDifferentPos() 205 { 206 BTreeDatabase db; 207 BTreeDatabaseConfig dbConfig; 208 BTreeCursor cursor, dupCursor; 209 DatabaseEnvironment env; 210 DatabaseEnvironmentConfig envConfig; 211 DatabaseEntry key, data; 212 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 213 Transaction txn; 214 215 testName = "TestDuplicateToDifferentPos"; 216 testHome = testFixtureHome + "/" + testName; 217 218 Configuration.ClearDir(testHome); 219 220 envConfig = new DatabaseEnvironmentConfig(); 221 envConfig.Create = true; 222 envConfig.UseMPool = true; 223 envConfig.UseTxns = true; 224 envConfig.NoMMap = false; 225 env = DatabaseEnvironment.Open(testHome, envConfig); 226 227 txn = env.BeginTransaction(); 228 dbConfig = new BTreeDatabaseConfig(); 229 dbConfig.Creation = CreatePolicy.IF_NEEDED; 230 dbConfig.Env = env; 231 db = BTreeDatabase.Open(testName + ".db", dbConfig, txn); 232 key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); 233 data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); 234 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 235 db.Put(key, data, txn); 236 txn.Commit(); 237 238 txn = env.BeginTransaction(); 239 cursor = db.Cursor(txn); 240 cursor.Move(key, true); 241 242 //Duplicate a new cursor to the same position. 243 dupCursor = cursor.Duplicate(false); 244 245 /* 246 * The duplicate cursor points to nothing so overwriting the 247 * record is not allowed. 248 */ 249 try 250 { 251 dupCursor.Overwrite(new DatabaseEntry( 252 ASCIIEncoding.ASCII.GetBytes("newdata"))); 253 } 254 catch (DatabaseException) 255 { 256 throw new ExpectedTestException(); 257 } 258 finally 259 { 260 dupCursor.Close(); 261 cursor.Close(); 262 txn.Commit(); 263 db.Close(); 264 env.Close(); 265 } 266 } 267 268 [Test] 269 public void TestInsertAfter() 270 { 271 BTreeDatabase db; 272 BTreeCursor cursor; 273 DatabaseEntry data; 274 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 275 276 testName = "TestInsertAfter"; 277 testHome = testFixtureHome + "/" + testName; 278 279 Configuration.ClearDir(testHome); 280 281 // Add record("key", "data") into database. 282 CursorTest.GetCursorInBtreeDBWithoutEnv(testHome, testName, 283 out db, out cursor); 284 CursorTest.AddOneByCursor(db, cursor); 285 286 // Insert the new record("key","data1") after the record("key", "data"). 287 data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1")); 288 cursor.Insert(data, Cursor.InsertLocation.AFTER); 289 290 /* 291 * Move the cursor to the record("key", "data") and confirm that 292 * the next record is the one just inserted. 293 */ 294 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 295 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), 296 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); 297 Assert.IsTrue(cursor.Move(pair, true)); 298 Assert.IsTrue(cursor.MoveNext()); 299 Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("key"), cursor.Current.Key.Data); 300 Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); 301 302 cursor.Close(); 303 db.Close(); 304 } 305 306 [Test] 307 public void TestMoveFirstMultipleAndMultipleKey() 308 { 309 testName = "TestMoveFirstMultipleAndMultipleKey"; 310 testHome = testFixtureHome + "/" + testName; 311 string btreeDBFileName = testHome + "/" + 312 testName + ".db"; 313 BTreeDatabase db; 314 BTreeCursor cursor; 315 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pair; 316 MultipleKeyDatabaseEntry multiPair; 317 int cnt; 318 int[] size = new int[2]; 319 size[0] = 0; 320 size[1] = 1024; 321 322 Configuration.ClearDir(testHome); 323 324 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 325 dbConfig.Creation = CreatePolicy.ALWAYS; 326 dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; 327 dbConfig.PageSize = 1024; 328 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 329 330 for (int i = 0; i < 2; i++) { 331 cnt = 0; 332 if (size[i] == 0) 333 cursor.MoveFirstMultiple(); 334 else 335 cursor.MoveFirstMultiple(size[i]); 336 pair = cursor.CurrentMultiple; 337 foreach (DatabaseEntry dbt in pair.Value) 338 cnt++; 339 Assert.AreEqual(1, cnt); 340 } 341 342 for (int i = 0; i < 2; i++) { 343 cnt = 0; 344 if (size[i] == 0) 345 cursor.MoveFirstMultipleKey(); 346 else 347 cursor.MoveFirstMultipleKey(size[i]); 348 multiPair = cursor.CurrentMultipleKey; 349 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 350 dbt in multiPair) 351 cnt++; 352 Assert.Less(1, cnt); 353 } 354 355 cursor.Close(); 356 db.Close(); 357 } 358 359 [Test] 360 public void TestMoveMultiple() 361 { 362 testName = "TestMoveMultiple"; 363 testHome = testFixtureHome + "/" + testName; 364 string btreeDBFileName = testHome + "/" + 365 testName + ".db"; 366 BTreeDatabase db; 367 BTreeCursor cursor; 368 DatabaseEntry key; 369 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pair; 370 int cnt; 371 372 Configuration.ClearDir(testHome); 373 374 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 375 dbConfig.Creation = CreatePolicy.ALWAYS; 376 dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; 377 dbConfig.PageSize = 1024; 378 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 379 380 // Move cursor to pairs with exact 99 as its key. 381 cnt = 0; 382 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 383 cursor.MoveMultiple(key, true); 384 pair = cursor.CurrentMultiple; 385 Assert.AreEqual(99, BitConverter.ToInt32(pair.Key.Data, 0)); 386 foreach (DatabaseEntry dbt in pair.Value) 387 cnt++; 388 Assert.AreEqual(2, cnt); 389 390 // Move cursor to pairs with the smallest key larger than 100. 391 cnt = 0; 392 key = new DatabaseEntry(BitConverter.GetBytes((int)100)); 393 cursor.MoveMultiple(key, false); 394 pair = cursor.CurrentMultiple; 395 Assert.AreEqual(101, BitConverter.ToInt32(pair.Key.Data, 0)); 396 foreach (DatabaseEntry dbt in pair.Value) 397 cnt++; 398 Assert.AreEqual(1, cnt); 399 400 cursor.Close(); 401 db.Close(); 402 } 403 404 [Test] 405 public void TestMoveMultipleKey() 406 { 407 testName = "TestMoveMultipleKey"; 408 testHome = testFixtureHome + "/" + testName; 409 string btreeDBFileName = testHome + "/" + 410 testName + ".db"; 411 BTreeDatabase db; 412 BTreeCursor cursor; 413 DatabaseEntry key; 414 MultipleKeyDatabaseEntry mulPair; ; 415 int cnt; 416 417 Configuration.ClearDir(testHome); 418 419 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 420 dbConfig.Creation = CreatePolicy.ALWAYS; 421 dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; 422 dbConfig.PageSize = 1024; 423 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 424 425 /* 426 * Bulk retrieve key/value pair from the pair whose key 427 * is exact 99. 428 */ 429 cnt = 0; 430 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 431 cursor.MoveMultipleKey(key, true); 432 mulPair = cursor.CurrentMultipleKey; 433 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 434 pair in mulPair) { 435 Assert.GreaterOrEqual(3, 436 BitConverter.ToInt32(pair.Key.Data, 0) - 98); 437 cnt++; 438 } 439 Assert.AreEqual(3, cnt); 440 441 /* 442 * Bulk retrieve key/value pair from the pair whose key 443 * is the smallest one larger than 100. 444 */ 445 cnt = 0; 446 key = new DatabaseEntry(BitConverter.GetBytes((int)100)); 447 cursor.MoveMultipleKey(key, false); 448 mulPair = cursor.CurrentMultipleKey; 449 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 450 pair in mulPair) { 451 Assert.AreEqual(101, 452 BitConverter.ToInt32(pair.Key.Data, 0)); 453 cnt++; 454 } 455 Assert.LessOrEqual(1, cnt); 456 457 cnt = 0; 458 key = new DatabaseEntry(BitConverter.GetBytes((int)100)); 459 cursor.MoveMultipleKey(key, false, 1024); 460 mulPair = cursor.CurrentMultipleKey; 461 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 462 pair in mulPair) { 463 Assert.AreEqual(101, 464 BitConverter.ToInt32(pair.Key.Data, 0)); 465 Assert.AreEqual(101, 466 BitConverter.ToInt32(pair.Value.Data, 0)); 467 cnt++; 468 } 469 Assert.LessOrEqual(1, cnt); 470 471 cursor.Close(); 472 db.Close(); 473 } 474 475 [Test] 476 public void TestMoveMultipleKeyWithRecno() 477 { 478 testName = "TestMoveMultipleKeyWithRecno"; 479 testHome = testFixtureHome + "/" + testName; 480 string btreeDBFileName = testHome + "/" + 481 testName + ".db"; 482 BTreeDatabase db; 483 BTreeCursor cursor; 484 MultipleKeyDatabaseEntry multiDBT; 485 int cnt; 486 487 Configuration.ClearDir(testHome); 488 489 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 490 dbConfig.UseRecordNumbers = true; 491 dbConfig.Creation = CreatePolicy.IF_NEEDED; 492 dbConfig.PageSize = 1024; 493 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 494 495 cnt = 0; 496 cursor.MoveMultipleKey(98); 497 multiDBT = cursor.CurrentMultipleKey; 498 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 499 pair in multiDBT) 500 cnt++; 501 Assert.AreEqual(3, cnt); 502 503 cnt = 0; 504 cursor.MoveMultipleKey(98, 1024); 505 multiDBT = cursor.CurrentMultipleKey; 506 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 507 pair in multiDBT) 508 cnt++; 509 Assert.AreEqual(3, cnt); 510 511 cursor.Close(); 512 db.Close(); 513 } 514 515 [Test] 516 public void TestMoveMultiplePairs() 517 { 518 testName = "TestMoveMultiplePairs"; 519 testHome = testFixtureHome + "/" + testName; 520 string btreeDBFileName = testHome + "/" + 521 testName + ".db"; 522 BTreeDatabase db; 523 BTreeCursor cursor; 524 DatabaseEntry key, data; 525 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 526 MultipleKeyDatabaseEntry multiKeyDBTs1, multiKeyDBTs2; 527 int cnt; 528 529 Configuration.ClearDir(testHome); 530 531 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 532 dbConfig.Creation = CreatePolicy.ALWAYS; 533 dbConfig.Duplicates = DuplicatesPolicy.SORTED; 534 dbConfig.PageSize = 1024; 535 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 536 537 /* 538 * Bulk retrieve pairs from the pair whose key/data 539 * is exact 99/99. 540 */ 541 cnt = 0; 542 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 543 data = new DatabaseEntry(BitConverter.GetBytes((int)99)); 544 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 545 cursor.MoveMultipleKey(pair, true); 546 multiKeyDBTs1 = cursor.CurrentMultipleKey; 547 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 548 p in multiKeyDBTs1) 549 cnt++; 550 Assert.AreEqual(3, cnt); 551 552 // Bulk retrieve pairs from the pair whose key is exact 99. 553 cnt = 0; 554 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 555 data = new DatabaseEntry(BitConverter.GetBytes((int)98)); 556 cursor.MoveMultipleKey(pair, true); 557 multiKeyDBTs2 = cursor.CurrentMultipleKey; 558 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 559 dbts in multiKeyDBTs2) 560 cnt++; 561 Assert.AreEqual(3, cnt); 562 563 /* 564 * Bulk retrieve pairs from the pair whose key is 565 * exact 99 in buffer size of 1024k. 566 */ 567 cnt = 0; 568 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 569 data = new DatabaseEntry(BitConverter.GetBytes((int)102)); 570 cursor.MoveMultipleKey(pair, true, 1024); 571 multiKeyDBTs2 = cursor.CurrentMultipleKey; 572 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> 573 dbts in multiKeyDBTs2) 574 cnt++; 575 Assert.AreEqual(3, cnt); 576 577 cursor.Close(); 578 db.Close(); 579 } 580 581 [Test] 582 public void TestMoveMultiplePairWithKey() 583 { 584 testName = "TestMoveMultiplePairWithKey"; 585 testHome = testFixtureHome + "/" + testName; 586 string btreeDBFileName = testHome + "/" + 587 testName + ".db"; 588 BTreeDatabase db; 589 BTreeCursor cursor; 590 DatabaseEntry key, data; 591 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 592 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> mulPair; 593 int cnt; 594 595 Configuration.ClearDir(testHome); 596 597 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 598 dbConfig.Creation = CreatePolicy.ALWAYS; 599 dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; 600 dbConfig.PageSize = 1024; 601 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 602 603 /* 604 * Move the cursor to pairs with exact 99 as its key 605 * and 99 as its data. 606 */ 607 cnt = 0; 608 key = new DatabaseEntry(BitConverter.GetBytes((int)99)); 609 data = new DatabaseEntry(BitConverter.GetBytes((int)99)); 610 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 611 cursor.MoveMultiple(pair, true); 612 mulPair = cursor.CurrentMultiple; 613 Assert.AreEqual(99, BitConverter.ToInt32(mulPair.Key.Data, 0)); 614 foreach (DatabaseEntry dbt in mulPair.Value) { 615 Assert.AreEqual(99, BitConverter.ToInt32(dbt.Data, 0)); 616 cnt++; 617 } 618 Assert.AreEqual(1, cnt); 619 620 // Move cursor to pairs with the smallest key larger than 100. 621 cnt = 0; 622 key = new DatabaseEntry(BitConverter.GetBytes((int)100)); 623 data = new DatabaseEntry(BitConverter.GetBytes((int)100)); 624 cursor.MoveMultiple(pair, false); 625 mulPair = cursor.CurrentMultiple; 626 Assert.AreEqual(99, BitConverter.ToInt32(mulPair.Key.Data, 0)); 627 foreach (DatabaseEntry dbt in mulPair.Value) { 628 Assert.GreaterOrEqual(1, 629 BitConverter.ToInt32(dbt.Data, 0) - 99); 630 cnt++; 631 } 632 Assert.AreEqual(1, cnt); 633 634 cursor.Close(); 635 db.Close(); 636 } 637 638 [Test] 639 public void TestMoveMultipleWithRecno() 640 { 641 testName = "TestMoveMultipleWithRecno"; 642 testHome = testFixtureHome + "/" + testName; 643 string btreeDBFileName = testHome + "/" + 644 testName + ".db"; 645 BTreeDatabase db; 646 BTreeCursor cursor; 647 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pair; 648 int cnt; 649 650 Configuration.ClearDir(testHome); 651 652 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 653 dbConfig.Creation = CreatePolicy.ALWAYS; 654 dbConfig.PageSize = 1024; 655 dbConfig.UseRecordNumbers = true; 656 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 657 658 // Move cursor to the No.100 record. 659 cnt = 0; 660 cursor.MoveMultiple(100); 661 pair = cursor.CurrentMultiple; 662 Assert.AreEqual(100, BitConverter.ToInt32(pair.Key.Data, 0)); 663 foreach (DatabaseEntry dbt in pair.Value) 664 cnt++; 665 Assert.AreEqual(1, cnt); 666 667 // Move cursor to the No.100 record with buffer size of 1024k. 668 cnt = 0; 669 cursor.MoveMultiple(100, 1024); 670 pair = cursor.CurrentMultiple; 671 Assert.AreEqual(100, BitConverter.ToInt32(pair.Key.Data, 0)); 672 foreach (DatabaseEntry dbt in pair.Value) 673 cnt++; 674 Assert.AreEqual(1, cnt); 675 676 cursor.Close(); 677 db.Close(); 678 } 679 680 [Test] 681 public void TestMoveNextDuplicateMultipleAndMultipleKey() 682 { 683 testName = "TestMoveNextDuplicateMultipleAndMultipleKey"; 684 testHome = testFixtureHome + "/" + testName; 685 string btreeDBFileName = testHome + "/" + 686 testName + ".db"; 687 BTreeDatabase db; 688 BTreeCursor cursor; 689 DatabaseEntry key, data; 690 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 691 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pairs; 692 MultipleKeyDatabaseEntry multiPair; 693 int cnt; 694 int[] size = new int[2]; 695 size[0] = 0; 696 size[1] = 1024; 697 698 Configuration.ClearDir(testHome); 699 700 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 701 dbConfig.Creation = CreatePolicy.ALWAYS; 702 dbConfig.Duplicates = DuplicatesPolicy.SORTED; 703 dbConfig.PageSize = 1024; 704 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 705 706 key = new DatabaseEntry(BitConverter.GetBytes(99)); 707 data = new DatabaseEntry(BitConverter.GetBytes(99)); 708 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 709 710 for (int j = 0; j < 2; j++) { 711 for (int i = 0; i < 2; i++) { 712 cnt = 0; 713 cursor.Move(pair, true); 714 if (j == 0) { 715 if (size[i] == 0) 716 Assert.IsTrue(cursor.MoveNextDuplicateMultiple()); 717 else 718 Assert.IsTrue(cursor.MoveNextDuplicateMultiple(size[i])); 719 pairs = cursor.CurrentMultiple; 720 foreach (DatabaseEntry dbt in pairs.Value) { 721 Assert.AreEqual(100, BitConverter.ToInt32(dbt.Data, 0)); 722 cnt++; 723 } 724 Assert.AreEqual(1, cnt); 725 } else { 726 if (size[i] == 0) 727 Assert.IsTrue(cursor.MoveNextDuplicateMultipleKey()); 728 else 729 Assert.IsTrue(cursor.MoveNextDuplicateMultipleKey(size[i])); 730 multiPair = cursor.CurrentMultipleKey; 731 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> p in multiPair) { 732 Assert.AreEqual(100, BitConverter.ToInt32(p.Value.Data, 0)); 733 cnt++; 734 } 735 Assert.AreEqual(1, cnt); 736 } 737 } 738 } 739 740 cursor.Close(); 741 db.Close(); 742 } 743 744 [Test] 745 public void TestMoveNextUniqueMultipleAndMultipleKey() 746 { 747 testName = "TestMoveNextUniqueMultipleAndMultipleKey"; 748 testHome = testFixtureHome + "/" + testName; 749 string btreeDBFileName = testHome + "/" + 750 testName + ".db"; 751 BTreeDatabase db; 752 BTreeCursor cursor; 753 DatabaseEntry key, data; 754 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 755 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pairs; 756 MultipleKeyDatabaseEntry multiPair; 757 int cnt; 758 int[] size = new int[2]; 759 size[0] = 0; 760 size[1] = 1024; 761 762 Configuration.ClearDir(testHome); 763 764 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 765 dbConfig.Creation = CreatePolicy.ALWAYS; 766 dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; 767 dbConfig.PageSize = 1024; 768 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 769 770 key = new DatabaseEntry(BitConverter.GetBytes(99)); 771 data = new DatabaseEntry(BitConverter.GetBytes(99)); 772 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 773 774 for (int j = 0; j < 2; j++) { 775 for (int i = 0; i < 2; i++) { 776 cnt = 0; 777 cursor.Move(pair, true); 778 if (j == 0) { 779 if (size[i] == 0) 780 Assert.IsTrue(cursor.MoveNextUniqueMultiple()); 781 else 782 Assert.IsTrue(cursor.MoveNextUniqueMultiple(size[i])); 783 pairs = cursor.CurrentMultiple; 784 foreach (DatabaseEntry dbt in pairs.Value) { 785 Assert.AreEqual(101, BitConverter.ToInt32(dbt.Data, 0)); 786 cnt++; 787 } 788 Assert.AreEqual(1, cnt); 789 } else { 790 if (size[i] == 0) 791 Assert.IsTrue(cursor.MoveNextUniqueMultipleKey()); 792 else 793 Assert.IsTrue(cursor.MoveNextUniqueMultipleKey(size[i])); 794 multiPair = cursor.CurrentMultipleKey; 795 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> p in multiPair) { 796 Assert.AreEqual(101, BitConverter.ToInt32(p.Value.Data, 0)); 797 cnt++; 798 } 799 Assert.AreEqual(1, cnt); 800 } 801 } 802 } 803 804 cursor.Close(); 805 db.Close(); 806 } 807 808 [Test] 809 public void TestRefreshMultipleAndMultipleKey() 810 { 811 testName = "TestRefreshMultipleAndMultipleKey"; 812 testHome = testFixtureHome + "/" + testName; 813 string btreeDBFileName = testHome + "/" + 814 testName + ".db"; 815 BTreeDatabase db; 816 BTreeCursor cursor; 817 DatabaseEntry key, data; 818 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 819 KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> pairs; 820 MultipleKeyDatabaseEntry multiPair; 821 int cnt; 822 int[] size = new int[2]; 823 size[0] = 0; 824 size[1] = 1024; 825 826 Configuration.ClearDir(testHome); 827 828 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 829 dbConfig.Creation = CreatePolicy.ALWAYS; 830 dbConfig.Duplicates = DuplicatesPolicy.SORTED; 831 dbConfig.PageSize = 1024; 832 GetMultipleDB(btreeDBFileName, dbConfig, out db, out cursor); 833 834 key = new DatabaseEntry(BitConverter.GetBytes(99)); 835 data = new DatabaseEntry(BitConverter.GetBytes(99)); 836 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 837 838 for (int j = 0; j < 2; j++) { 839 for (int i = 0; i < 2; i++) { 840 cnt = 0; 841 cursor.Move(pair, true); 842 if (j == 0) { 843 if (size[i] == 0) 844 Assert.IsTrue(cursor.RefreshMultiple()); 845 else 846 Assert.IsTrue(cursor.RefreshMultiple(size[i])); 847 pairs = cursor.CurrentMultiple; 848 foreach (DatabaseEntry dbt in pairs.Value) 849 cnt++; 850 Assert.AreEqual(2, cnt); 851 } else { 852 if (size[i] == 0) 853 Assert.IsTrue(cursor.RefreshMultipleKey()); 854 else 855 Assert.IsTrue(cursor.RefreshMultipleKey(size[i])); 856 multiPair = cursor.CurrentMultipleKey; 857 foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> p in multiPair) 858 cnt++; 859 Assert.AreEqual(3, cnt); 860 } 861 } 862 } 863 864 cursor.Close(); 865 db.Close(); 866 } 867 868 private void GetMultipleDB(string dbFileName, BTreeDatabaseConfig dbConfig, 869 out BTreeDatabase db, out BTreeCursor cursor) 870 { 871 db = BTreeDatabase.Open(dbFileName, dbConfig); 872 cursor = db.Cursor(); 873 874 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 875 DatabaseEntry key, data; 876 for (int i = 1; i < 100; i++) { 877 key = new DatabaseEntry(BitConverter.GetBytes(i)); 878 data = new DatabaseEntry(BitConverter.GetBytes(i)); 879 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 880 cursor.Add(pair); 881 } 882 883 if (dbConfig.UseRecordNumbers == true) { 884 byte[] bytes = new byte[512]; 885 for (int i = 0; i < 512; i++) 886 bytes[i] = (byte)i; 887 key = new DatabaseEntry(BitConverter.GetBytes(100)); 888 data = new DatabaseEntry(bytes); 889 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 890 cursor.Add(pair); 891 } else { 892 if (dbConfig.Duplicates == DuplicatesPolicy.UNSORTED || 893 dbConfig.Duplicates == DuplicatesPolicy.SORTED) { 894 key = new DatabaseEntry(BitConverter.GetBytes(99)); 895 data = new DatabaseEntry(BitConverter.GetBytes(100)); 896 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 897 cursor.Add(pair); 898 } 899 900 key = new DatabaseEntry(BitConverter.GetBytes(101)); 901 data = new DatabaseEntry(BitConverter.GetBytes(101)); 902 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data); 903 cursor.Add(pair); 904 } 905 } 906 907 [Test] 908 public void TestInsertBefore() 909 { 910 BTreeDatabase db; 911 BTreeCursor cursor; 912 DatabaseEntry data; 913 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 914 915 testName = "TestInsertBefore"; 916 testHome = testFixtureHome + "/" + testName; 917 918 Configuration.ClearDir(testHome); 919 920 // Add record("key", "data") into database. 921 CursorTest.GetCursorInBtreeDBWithoutEnv( 922 testHome, testName, out db, out cursor); 923 CursorTest.AddOneByCursor(db, cursor); 924 925 // Insert the new record("key","data1") before the record("key", "data"). 926 data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1")); 927 cursor.Insert(data, Cursor.InsertLocation.BEFORE); 928 929 /* 930 * Move the cursor to the record("key", "data") and confirm 931 * that the previous record is the one just inserted. 932 */ 933 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 934 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), 935 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); 936 Assert.IsTrue(cursor.Move(pair, true)); 937 Assert.IsTrue(cursor.MovePrev()); 938 Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("key"),cursor.Current.Key.Data); 939 Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); 940 941 cursor.Close(); 942 db.Close(); 943 } 944 945 [Test] 946 public void TestMoveToRecno() 947 { 948 BTreeDatabase db; 949 BTreeCursor cursor; 950 951 testName = "TestMoveToRecno"; 952 testHome = testFixtureHome + "/" + testName; 953 954 Configuration.ClearDir(testHome); 955 956 GetCursorInBtreeDBUsingRecno(testHome, testName, 957 out db, out cursor); 958 for (int i = 0; i < 10; i++) 959 db.Put( 960 new DatabaseEntry(BitConverter.GetBytes(i)), 961 new DatabaseEntry(BitConverter.GetBytes(i))); 962 963 MoveCursorToRecno(cursor, null); 964 cursor.Close(); 965 db.Close(); 966 } 967 968 [Test] 969 public void TestMoveToRecnoWithRMW() 970 { 971 testName = "TestMoveToRecnoWithRMW"; 972 testHome = testFixtureHome + "/" + testName; 973 Configuration.ClearDir(testHome); 974 975 btCursorFunc = new BTCursorMoveFuncDelegate( 976 MoveCursorToRecno); 977 978 // Move to a specified key and a key/data pair. 979 MoveWithRMW(testHome, testName); 980 } 981 982 [Test] 983 public void TestRecno() 984 { 985 BTreeDatabase db; 986 BTreeCursor cursor; 987 988 testName = "TestRecno"; 989 testHome = testFixtureHome + "/" + testName; 990 991 Configuration.ClearDir(testHome); 992 993 GetCursorInBtreeDBUsingRecno(testHome, testName, 994 out db, out cursor); 995 for (int i = 0; i < 10; i++) 996 db.Put( 997 new DatabaseEntry(BitConverter.GetBytes(i)), 998 new DatabaseEntry(BitConverter.GetBytes(i))); 999 1000 ReturnRecno(cursor, null); 1001 cursor.Close(); 1002 db.Close(); 1003 } 1004 1005 [Test] 1006 public void TestRecnoWithRMW() 1007 { 1008 testName = "TestRecnoWithRMW"; 1009 testHome = testFixtureHome + "/" + testName; 1010 Configuration.ClearDir(testHome); 1011 1012 // Use MoveCursorToRecno() as its move function. 1013 btCursorFunc = new BTCursorMoveFuncDelegate( 1014 ReturnRecno); 1015 1016 // Move to a specified key and a key/data pair. 1017 MoveWithRMW(testHome, testName); 1018 } 1019 1020 /* 1021 * Move the cursor according to recno. The recno 1022 * starts from 1 and is increased by 1. 1023 */ 1024 public void MoveCursorToRecno(BTreeCursor cursor, 1025 LockingInfo lck) 1026 { 1027 for (uint i = 1; i <= 5; i++) 1028 if (lck == null) 1029 Assert.IsTrue(cursor.Move(i)); 1030 else 1031 Assert.IsTrue(cursor.Move(i, lck)); 1032 } 1033 1034 /*l 1035 * Move the cursor according to a given recno and 1036 * return the current record's recno. The given recno 1037 * and the one got from the cursor should be the same. 1038 */ 1039 public void ReturnRecno(BTreeCursor cursor, 1040 LockingInfo lck) 1041 { 1042 for (uint i = 1; i <= 5; i++) 1043 if (lck == null) 1044 { 1045 if (cursor.Move(i) == true) 1046 Assert.AreEqual(i, cursor.Recno()); 1047 } 1048 else 1049 { 1050 if (cursor.Move(i, lck) == true) 1051 Assert.AreEqual(i, cursor.Recno(lck)); 1052 } 1053 } 1054 1055 public void GetCursorInBtreeDBUsingRecno(string home, 1056 string name, out BTreeDatabase db, 1057 out BTreeCursor cursor) 1058 { 1059 string dbFileName = home + "/" + name + ".db"; 1060 BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); 1061 dbConfig.UseRecordNumbers = true; 1062 dbConfig.Creation = CreatePolicy.IF_NEEDED; 1063 db = BTreeDatabase.Open(dbFileName, dbConfig); 1064 cursor = db.Cursor(); 1065 } 1066 1067 public void RdMfWt() 1068 { 1069 Transaction txn = paramEnv.BeginTransaction(); 1070 BTreeCursor dbc = paramDB.Cursor(txn); 1071 1072 try 1073 { 1074 LockingInfo lck = new LockingInfo(); 1075 lck.ReadModifyWrite = true; 1076 1077 // Read record. 1078 btCursorFunc(dbc, lck); 1079 1080 // Block the current thread until event is set. 1081 signal.WaitOne(); 1082 1083 // Write new records into database. 1084 DatabaseEntry key = new DatabaseEntry(BitConverter.GetBytes(55)); 1085 DatabaseEntry data = new DatabaseEntry(BitConverter.GetBytes(55)); 1086 dbc.Add(new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data)); 1087 1088 dbc.Close(); 1089 txn.Commit(); 1090 } 1091 catch (DeadlockException) 1092 { 1093 dbc.Close(); 1094 txn.Abort(); 1095 } 1096 } 1097 1098 1099 public void MoveWithRMW(string home, string name) 1100 { 1101 paramEnv = null; 1102 paramDB = null; 1103 1104 // Open the environment. 1105 DatabaseEnvironmentConfig envCfg = 1106 new DatabaseEnvironmentConfig(); 1107 envCfg.Create = true; 1108 envCfg.FreeThreaded = true; 1109 envCfg.UseLocking = true; 1110 envCfg.UseLogging = true; 1111 envCfg.UseMPool = true; 1112 envCfg.UseTxns = true; 1113 paramEnv = DatabaseEnvironment.Open(home, envCfg); 1114 1115 // Open database in transaction. 1116 Transaction openTxn = paramEnv.BeginTransaction(); 1117 BTreeDatabaseConfig cfg = new BTreeDatabaseConfig(); 1118 cfg.Creation = CreatePolicy.ALWAYS; 1119 cfg.Env = paramEnv; 1120 cfg.FreeThreaded = true; 1121 cfg.PageSize = 4096; 1122 // Use record number. 1123 cfg.UseRecordNumbers = true; 1124 paramDB = BTreeDatabase.Open(name + ".db", cfg, openTxn); 1125 openTxn.Commit(); 1126 1127 /* 1128 * Put 10 different, 2 duplicate and another different 1129 * records into database. 1130 */ 1131 Transaction txn = paramEnv.BeginTransaction(); 1132 for (int i = 0; i < 13; i++) 1133 { 1134 DatabaseEntry key, data; 1135 if (i == 10 || i == 11) 1136 { 1137 key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); 1138 data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); 1139 } 1140 else 1141 { 1142 key = new DatabaseEntry(BitConverter.GetBytes(i)); 1143 data = new DatabaseEntry(BitConverter.GetBytes(i)); 1144 } 1145 paramDB.Put(key, data, txn); 1146 } 1147 1148 txn.Commit(); 1149 1150 // Get a event wait handle. 1151 signal = new EventWaitHandle(false, 1152 EventResetMode.ManualReset); 1153 1154 /* 1155 * Start RdMfWt() in two threads. RdMfWt() reads 1156 * and writes data into database. 1157 */ 1158 Thread t1 = new Thread(new ThreadStart(RdMfWt)); 1159 Thread t2 = new Thread(new ThreadStart(RdMfWt)); 1160 t1.Start(); 1161 t2.Start(); 1162 1163 // Give both threads time to read before signalling them to write. 1164 Thread.Sleep(1000); 1165 1166 // Invoke the write operation in both threads. 1167 signal.Set(); 1168 1169 // Return the number of deadlocks. 1170 while (t1.IsAlive || t2.IsAlive) 1171 { 1172 /* 1173 * Give both threads time to write before 1174 * counting the number of deadlocks. 1175 */ 1176 Thread.Sleep(1000); 1177 uint deadlocks = paramEnv.DetectDeadlocks(DeadlockPolicy.DEFAULT); 1178 1179 // Confirm that there won't be any deadlock. 1180 Assert.AreEqual(0, deadlocks); 1181 } 1182 1183 t1.Join(); 1184 t2.Join(); 1185 paramDB.Close(); 1186 paramEnv.Close(); 1187 } 1188 1189 } 1190} 1191 1192 1193