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.Generic; 9using System.IO; 10using System.Text; 11using System.Xml; 12using NUnit.Framework; 13using BerkeleyDB; 14 15namespace CsharpAPITest 16{ 17 [TestFixture] 18 public class QueueDatabaseTest : DatabaseTest 19 { 20 private string testFixtureHome; 21 private string testFixtureName; 22 private string testName; 23 private string testHome; 24 25 [TestFixtureSetUp] 26 public void RunBeforeTests() 27 { 28 testFixtureName = "QueueDatabaseTest"; 29 testFixtureHome = "./TestOut/" + testFixtureName; 30 31 Configuration.ClearDir(testFixtureHome); 32 } 33 34 [Test] 35 public void TestAppendWithoutTxn() 36 { 37 testName = "TestAppendWithoutTxn"; 38 testHome = testFixtureHome + "/" + testName; 39 string queueDBFileName = testHome + "/" + testName + ".db"; 40 41 Configuration.ClearDir(testHome); 42 43 QueueDatabaseConfig queueConfig = new QueueDatabaseConfig(); 44 queueConfig.Creation = CreatePolicy.ALWAYS; 45 queueConfig.Length = 1000; 46 QueueDatabase queueDB = QueueDatabase.Open( 47 queueDBFileName, queueConfig); 48 49 byte[] byteArr = new byte[4]; 50 byteArr = BitConverter.GetBytes((int)1); 51 DatabaseEntry data = new DatabaseEntry(byteArr); 52 uint recno = queueDB.Append(data); 53 54 // Confirm that the recno is larger than 0. 55 Assert.AreNotEqual(0, recno); 56 57 // Confirm that the record exists in the database. 58 byteArr = BitConverter.GetBytes(recno); 59 DatabaseEntry key = new DatabaseEntry(); 60 key.Data = byteArr; 61 Assert.IsTrue(queueDB.Exists(key)); 62 queueDB.Close(); 63 } 64 65 [Test] 66 public void TestAppendWithTxn() 67 { 68 testName = "TestAppendWithTxn"; 69 testHome = testFixtureHome + "/" + testName; 70 string queueDBFileName = testHome + "/" + testName + ".db"; 71 string queueDBName = 72 Path.GetFileNameWithoutExtension(queueDBFileName); 73 74 Configuration.ClearDir(testHome); 75 76 DatabaseEnvironmentConfig envConfig = 77 new DatabaseEnvironmentConfig(); 78 envConfig.Create = true; 79 envConfig.UseTxns = true; 80 envConfig.UseMPool = true; 81 82 DatabaseEnvironment env = DatabaseEnvironment.Open( 83 testHome, envConfig); 84 Transaction txn = env.BeginTransaction(); 85 86 QueueDatabaseConfig queueConfig = new QueueDatabaseConfig(); 87 queueConfig.Creation = CreatePolicy.ALWAYS; 88 queueConfig.Env = env; 89 queueConfig.Length = 1000; 90 91 /* If environmnet home is set, the file name in 92 * Open() is the relative path. 93 */ 94 QueueDatabase queueDB = QueueDatabase.Open( 95 queueDBName, queueConfig, txn); 96 DatabaseEntry data; 97 int i = 1000; 98 try 99 { 100 while (i > 0) 101 { 102 data = new DatabaseEntry( 103 BitConverter.GetBytes(i)); 104 queueDB.Append(data, txn); 105 i--; 106 } 107 txn.Commit(); 108 } 109 catch 110 { 111 txn.Abort(); 112 } 113 finally 114 { 115 queueDB.Close(); 116 env.Close(); 117 } 118 119 } 120 121 [Test, ExpectedException(typeof(ExpectedTestException))] 122 public void TestConsumeWithTxn() 123 { 124 testName = "TestConsumeWithTxn"; 125 testHome = testFixtureHome + "/" + testName; 126 string queueDBFileName = testHome + "/" + testName + ".db"; 127 string queueDBName = Path.GetFileName(queueDBFileName); 128 129 Configuration.ClearDir(testHome); 130 131 DatabaseEnvironmentConfig envConfig = 132 new DatabaseEnvironmentConfig(); 133 envConfig.Create = true; 134 envConfig.UseTxns = true; 135 envConfig.UseMPool = true; 136 137 DatabaseEnvironment env = DatabaseEnvironment.Open( 138 testHome, envConfig); 139 Transaction txn = env.BeginTransaction(); 140 141 QueueDatabaseConfig queueConfig = 142 new QueueDatabaseConfig(); 143 queueConfig.Creation = CreatePolicy.ALWAYS; 144 queueConfig.Env = env; 145 queueConfig.Length = 1000; 146 QueueDatabase queueDB = QueueDatabase.Open( 147 queueDBName, queueConfig, txn); 148 149 int i = 1; 150 DatabaseEntry data; 151 DatabaseEntry getData = new DatabaseEntry(); 152 while (i <= 10) 153 { 154 data = new DatabaseEntry( 155 ASCIIEncoding.ASCII.GetBytes(i.ToString())); 156 queueDB.Append(data, txn); 157 if (i == 5) 158 { 159 getData = data; 160 } 161 i++; 162 } 163 164 KeyValuePair<uint, DatabaseEntry> pair = queueDB.Consume(false, txn); 165 166 queueDB.Close(); 167 txn.Commit(); 168 env.Close(); 169 170 Database db = Database.Open(queueDBFileName, 171 new QueueDatabaseConfig()); 172 try 173 { 174 DatabaseEntry key = 175 new DatabaseEntry(BitConverter.GetBytes(pair.Key)); 176 db.Get(key); 177 } 178 catch (NotFoundException) 179 { 180 throw new ExpectedTestException(); 181 } 182 finally 183 { 184 db.Close(); 185 } 186 } 187 188 [Test, ExpectedException(typeof(ExpectedTestException))] 189 public void TestConsumeWithoutTxn() 190 { 191 testName = "TestConsumeWithoutTxn"; 192 testHome = testFixtureHome + "/" + testName; 193 string queueDBFileName = testHome + "/" + 194 testName + ".db"; 195 196 Configuration.ClearDir(testHome); 197 198 QueueDatabaseConfig queueConfig = 199 new QueueDatabaseConfig(); 200 queueConfig.Creation = CreatePolicy.ALWAYS; 201 queueConfig.ErrorPrefix = testName; 202 queueConfig.Length = 1000; 203 204 QueueDatabase queueDB = QueueDatabase.Open( 205 queueDBFileName, queueConfig); 206 DatabaseEntry data = new DatabaseEntry( 207 ASCIIEncoding.ASCII.GetBytes("data")); 208 queueDB.Append(data); 209 210 DatabaseEntry consumeData = new DatabaseEntry(); 211 KeyValuePair<uint, DatabaseEntry> pair = queueDB.Consume(false); 212 try 213 { 214 DatabaseEntry key = 215 new DatabaseEntry(BitConverter.GetBytes(pair.Key)); 216 queueDB.Get(key); 217 } 218 catch (NotFoundException) 219 { 220 throw new ExpectedTestException(); 221 } 222 finally 223 { 224 queueDB.Close(); 225 } 226 } 227 228 public void TestCursor() 229 { 230 testName = "TestCursor"; 231 testHome = testFixtureHome + "/" + testName; 232 233 Configuration.ClearDir(testHome); 234 235 GetCursur(testHome + "/" + testName + ".db", false); 236 } 237 238 public void TestCursorWithConfig() 239 { 240 testName = "TestCursorWithConfig"; 241 testHome = testFixtureHome + "/" + testName; 242 243 Configuration.ClearDir(testHome); 244 245 GetCursur(testHome + "/" + testName + ".db", true); 246 } 247 248 public void GetCursur(string dbFileName, bool ifConfig) 249 { 250 QueueDatabaseConfig dbConfig = new QueueDatabaseConfig(); 251 dbConfig.Creation = CreatePolicy.IF_NEEDED; 252 dbConfig.Length = 100; 253 QueueDatabase db = QueueDatabase.Open(dbFileName, dbConfig); 254 Cursor cursor; 255 if (ifConfig == false) 256 cursor = db.Cursor(); 257 else 258 cursor = db.Cursor(new CursorConfig()); 259 cursor.Close(); 260 db.Close(); 261 } 262 263 //[Test] 264 //public void TestDupCompare() 265 //{ 266 // testName = "TestDupCompare"; 267 // testHome = testFixtureHome + "/" + testName; 268 // string dbFileName = testHome + "/" + testName + ".db"; 269 270 // Configuration.ClearDir(testHome); 271 272 // QueueDatabaseConfig dbConfig = new QueueDatabaseConfig(); 273 // dbConfig.Creation = CreatePolicy.IF_NEEDED; 274 // dbConfig.DuplicateCompare = new EntryComparisonDelegate(dbIntCompare); 275 // dbConfig.Length = 10; 276 // dbConfig.PageSize = 40860; 277 // try 278 // { 279 // QueueDatabase db = QueueDatabase.Open(dbFileName, dbConfig); 280 // int ret = db.DupCompare(new DatabaseEntry(BitConverter.GetBytes(255)), 281 // new DatabaseEntry(BitConverter.GetBytes(257))); 282 // Assert.Greater(0, ret); 283 // db.Close(); 284 // } 285 // catch (DatabaseException e) 286 // { 287 // Console.WriteLine(e.Message); 288 // } 289 //} 290 291 private int dbIntCompare(DatabaseEntry dbt1, 292 DatabaseEntry dbt2) 293 { 294 int a, b; 295 a = BitConverter.ToInt16(dbt1.Data, 0); 296 b = BitConverter.ToInt16(dbt2.Data, 0); 297 return a - b; 298 } 299 300 [Test, ExpectedException(typeof(ExpectedTestException))] 301 public void TestKeyEmptyException() 302 { 303 testName = "TestKeyEmptyException"; 304 testHome = testFixtureHome + "/" + testName; 305 306 Configuration.ClearDir(testHome); 307 308 DatabaseEnvironmentConfig envConfig = 309 new DatabaseEnvironmentConfig(); 310 envConfig.Create = true; 311 envConfig.UseLocking = true; 312 envConfig.UseLogging = true; 313 envConfig.UseMPool = true; 314 envConfig.UseTxns = true; 315 DatabaseEnvironment env = DatabaseEnvironment.Open( 316 testHome, envConfig); 317 318 QueueDatabase db; 319 try 320 { 321 Transaction openTxn = env.BeginTransaction(); 322 try 323 { 324 QueueDatabaseConfig queueConfig = 325 new QueueDatabaseConfig(); 326 queueConfig.Creation = CreatePolicy.IF_NEEDED; 327 queueConfig.Length = 10; 328 queueConfig.Env = env; 329 db = QueueDatabase.Open(testName + ".db", 330 queueConfig, openTxn); 331 openTxn.Commit(); 332 } 333 catch (DatabaseException e) 334 { 335 openTxn.Abort(); 336 throw e; 337 } 338 339 Transaction cursorTxn = env.BeginTransaction(); 340 Cursor cursor; 341 try 342 { 343 /* 344 * Put a record into queue database with 345 * cursor and abort the operation. 346 */ 347 cursor = db.Cursor(cursorTxn); 348 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 349 pair = new KeyValuePair<DatabaseEntry, DatabaseEntry>( 350 new DatabaseEntry(BitConverter.GetBytes((int)10)), 351 new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); 352 cursor.Add(pair); 353 cursor.Close(); 354 cursorTxn.Abort(); 355 } 356 catch (DatabaseException e) 357 { 358 cursorTxn.Abort(); 359 db.Close(); 360 throw e; 361 } 362 363 Transaction delTxn = env.BeginTransaction(); 364 try 365 { 366 /* 367 * The put operation is aborted in the queue 368 * database so querying if the record still exists 369 * throws KeyEmptyException. 370 */ 371 db.Exists(new DatabaseEntry( 372 BitConverter.GetBytes((int)10)), delTxn); 373 delTxn.Commit(); 374 } 375 catch (DatabaseException e) 376 { 377 delTxn.Abort(); 378 throw e; 379 } 380 finally 381 { 382 db.Close(); 383 } 384 } 385 catch (KeyEmptyException) 386 { 387 throw new ExpectedTestException(); 388 } 389 finally 390 { 391 env.Close(); 392 } 393 } 394 395 [Test] 396 public void TestOpenExistingQueueDB() 397 { 398 testName = "TestOpenExistingQueueDB"; 399 testHome = testFixtureHome + "/" + testName; 400 string queueDBFileName = testHome + "/" + testName + ".db"; 401 402 Configuration.ClearDir(testHome); 403 404 QueueDatabaseConfig queueConfig = new QueueDatabaseConfig(); 405 queueConfig.Creation = CreatePolicy.ALWAYS; 406 QueueDatabase queueDB = QueueDatabase.Open( 407 queueDBFileName, queueConfig); 408 queueDB.Close(); 409 410 DatabaseConfig dbConfig = new DatabaseConfig(); 411 Database db = Database.Open(queueDBFileName, dbConfig); 412 Assert.AreEqual(db.Type, DatabaseType.QUEUE); 413 db.Close(); 414 } 415 416 [Test] 417 public void TestOpenNewQueueDB() 418 { 419 testName = "TestOpenNewQueueDB"; 420 testHome = testFixtureHome + "/" + testName; 421 string queueDBFileName = testHome + "/" + testName + ".db"; 422 423 Configuration.ClearDir(testHome); 424 425 // Configure all fields/properties in queue database. 426 XmlElement xmlElem = Configuration.TestSetUp( 427 testFixtureName, testName); 428 QueueDatabaseConfig queueConfig = new QueueDatabaseConfig(); 429 QueueDatabaseConfigTest.Config(xmlElem, ref queueConfig, true); 430 queueConfig.Feedback = new DatabaseFeedbackDelegate(DbFeedback); 431 432 // Open the queue database with above configuration. 433 QueueDatabase queueDB = QueueDatabase.Open( 434 queueDBFileName, queueConfig); 435 436 // Check the fields/properties in opened queue database. 437 Confirm(xmlElem, queueDB, true); 438 439 queueDB.Close(); 440 } 441 442 private void DbFeedback(DatabaseFeedbackEvent opcode, int percent) 443 { 444 if (opcode == DatabaseFeedbackEvent.UPGRADE) 445 Console.WriteLine("Update for %d%", percent); 446 447 if (opcode == DatabaseFeedbackEvent.VERIFY) 448 Console.WriteLine("Vertify for %d", percent); 449 } 450 451 [Test, ExpectedException(typeof(NotFoundException))] 452 public void TestPutToQueue() 453 { 454 KeyValuePair<DatabaseEntry, DatabaseEntry> pair; 455 456 testName = "TestPutQueue"; 457 testHome = testFixtureHome + "/" + testName; 458 string queueDBFileName = testHome + "/" + 459 testName + ".db"; 460 461 Configuration.ClearDir(testHome); 462 463 QueueDatabaseConfig queueConfig = 464 new QueueDatabaseConfig(); 465 queueConfig.Length = 512; 466 queueConfig.Creation = CreatePolicy.ALWAYS; 467 using (QueueDatabase queueDB = QueueDatabase.Open( 468 queueDBFileName, queueConfig)) 469 { 470 DatabaseEntry key = new DatabaseEntry(); 471 key.Data = BitConverter.GetBytes((int)100); 472 DatabaseEntry data = new DatabaseEntry( 473 BitConverter.GetBytes((int)1)); 474 queueDB.Put(key, data); 475 pair = queueDB.GetBoth(key, data); 476 } 477 } 478 479 [Test] 480 public void TestStats() 481 { 482 testName = "TestStats"; 483 testHome = testFixtureHome + "/" + testName; 484 string dbFileName = testHome + "/" + 485 testName + ".db"; 486 Configuration.ClearDir(testHome); 487 488 QueueDatabaseConfig dbConfig = 489 new QueueDatabaseConfig(); 490 ConfigCase1(dbConfig); 491 QueueDatabase db = QueueDatabase.Open(dbFileName, dbConfig); 492 493 QueueStats stats = db.Stats(); 494 ConfirmStatsPart1Case1(stats); 495 db.PrintFastStats(true); 496 497 // Put 500 records into the database. 498 PutRecordCase1(db, null); 499 500 stats = db.Stats(); 501 ConfirmStatsPart2Case1(stats); 502 db.PrintFastStats(); 503 504 db.Close(); 505 } 506 507 [Test] 508 public void TestStatsInTxn() 509 { 510 testName = "TestStatsInTxn"; 511 testHome = testFixtureHome + "/" + testName; 512 Configuration.ClearDir(testHome); 513 514 StatsInTxn(testHome, testName, false); 515 } 516 517 [Test] 518 public void TestStatsWithIsolation() 519 { 520 testName = "TestStatsWithIsolation"; 521 testHome = testFixtureHome + "/" + testName; 522 Configuration.ClearDir(testHome); 523 524 StatsInTxn(testHome, testName, true); 525 } 526 527 public void StatsInTxn(string home, string name, bool ifIsolation) 528 { 529 DatabaseEnvironmentConfig envConfig = 530 new DatabaseEnvironmentConfig(); 531 EnvConfigCase1(envConfig); 532 DatabaseEnvironment env = DatabaseEnvironment.Open( 533 home, envConfig); 534 535 Transaction openTxn = env.BeginTransaction(); 536 QueueDatabaseConfig dbConfig = 537 new QueueDatabaseConfig(); 538 ConfigCase1(dbConfig); 539 dbConfig.Env = env; 540 QueueDatabase db = QueueDatabase.Open(name + ".db", 541 dbConfig, openTxn); 542 openTxn.Commit(); 543 544 Transaction statsTxn = env.BeginTransaction(); 545 QueueStats stats; 546 if (ifIsolation == false) 547 stats = db.Stats(statsTxn); 548 else 549 stats = db.Stats(statsTxn, Isolation.DEGREE_ONE); 550 551 ConfirmStatsPart1Case1(stats); 552 db.PrintStats(true); 553 554 // Put 500 records into the database. 555 PutRecordCase1(db, statsTxn); 556 557 if (ifIsolation == false) 558 stats = db.Stats(statsTxn); 559 else 560 stats = db.Stats(statsTxn, Isolation.DEGREE_TWO); 561 ConfirmStatsPart2Case1(stats); 562 db.PrintStats(); 563 564 statsTxn.Commit(); 565 db.Close(); 566 env.Close(); 567 } 568 569 public void EnvConfigCase1(DatabaseEnvironmentConfig cfg) 570 { 571 cfg.Create = true; 572 cfg.UseTxns = true; 573 cfg.UseMPool = true; 574 cfg.UseLogging = true; 575 } 576 577 public void ConfigCase1(QueueDatabaseConfig dbConfig) 578 { 579 dbConfig.Creation = CreatePolicy.IF_NEEDED; 580 dbConfig.PageSize = 4096; 581 dbConfig.ExtentSize = 1024; 582 dbConfig.Length = 4000; 583 dbConfig.PadByte = 32; 584 } 585 586 public void PutRecordCase1(QueueDatabase db, Transaction txn) 587 { 588 byte[] bigArray = new byte[4000]; 589 for (int i = 1; i <= 100; i++) 590 { 591 if (txn == null) 592 db.Put(new DatabaseEntry(BitConverter.GetBytes(i)), 593 new DatabaseEntry(BitConverter.GetBytes(i))); 594 else 595 db.Put(new DatabaseEntry(BitConverter.GetBytes(i)), 596 new DatabaseEntry(BitConverter.GetBytes(i)), txn); 597 } 598 DatabaseEntry key = new DatabaseEntry(BitConverter.GetBytes((int)100)); 599 for (int i = 100; i <= 500; i++) 600 { 601 if (txn == null) 602 db.Put(key, new DatabaseEntry(bigArray)); 603 else 604 db.Put(key, new DatabaseEntry(bigArray), txn); 605 } 606 } 607 608 public void ConfirmStatsPart1Case1(QueueStats stats) 609 { 610 Assert.AreEqual(1, stats.FirstRecordNumber); 611 Assert.AreNotEqual(0, stats.MagicNumber); 612 Assert.AreEqual(1, stats.NextRecordNumber); 613 Assert.AreEqual(4096, stats.PageSize); 614 Assert.AreEqual(1024, stats.PagesPerExtent); 615 Assert.AreEqual(4000, stats.RecordLength); 616 Assert.AreEqual(32, stats.RecordPadByte); 617 Assert.AreEqual(4, stats.Version); 618 } 619 620 public void ConfirmStatsPart2Case1(QueueStats stats) 621 { 622 Assert.AreNotEqual(0, stats.DataPages); 623 Assert.AreEqual(0, stats.DataPagesBytesFree); 624 Assert.AreEqual(0, stats.MetadataFlags); 625 Assert.AreEqual(100, stats.nData); 626 Assert.AreEqual(100, stats.nKeys); 627 } 628 629 public static void Confirm(XmlElement xmlElem, 630 QueueDatabase queueDB, bool compulsory) 631 { 632 DatabaseTest.Confirm(xmlElem, queueDB, compulsory); 633 634 // Confirm queue database specific field/property 635 Configuration.ConfirmUint(xmlElem, "ExtentSize", 636 queueDB.ExtentSize, compulsory); 637 Configuration.ConfirmBool(xmlElem, "ConsumeInOrder", 638 queueDB.InOrder, compulsory); 639 Configuration.ConfirmInt(xmlElem, "PadByte", 640 queueDB.PadByte, compulsory); 641 Assert.AreEqual(DatabaseType.QUEUE, queueDB.Type); 642 string type = queueDB.Type.ToString(); 643 Assert.IsNotNull(type); 644 } 645 } 646} 647