/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2009, 2012 Oracle and/or its affiliates. All rights reserved. * */ using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; using NUnit.Framework; using BerkeleyDB; namespace CsharpAPITest { [TestFixture] public class BTreeCursorTest : CSharpTestFixture { private DatabaseEnvironment paramEnv; private BTreeDatabase paramDB; private EventWaitHandle signal; private delegate void BTCursorMoveFuncDelegate( BTreeCursor cursor, LockingInfo lockingInfo); private BTCursorMoveFuncDelegate btCursorFunc; [TestFixtureSetUp] public void SetUpTestFixture() { testFixtureName = "BTreeCursorTest"; base.SetUpTestfixture(); } [Test] public void TestAddKeyFirst() { BTreeDatabase db; BTreeCursor cursor; KeyValuePair pair; testName = "TestAddKeyFirst"; SetUpTest(true); // Add record("key", "data") into database. CursorTest.GetCursorInBtreeDBWithoutEnv( testHome, testName, out db, out cursor); CursorTest.AddOneByCursor(db, cursor); // Add record("key","data1") as the first of the data item of "key". pair = new KeyValuePair( new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1"))); cursor.Add(pair, Cursor.InsertLocation.FIRST); // Confirm the record is added as the first of the data item of "key". cursor.Move(new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), true); Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); cursor.Close(); db.Close(); } [Test] public void TestAddKeyLast() { BTreeDatabase db; BTreeCursor cursor; KeyValuePair pair; testName = "TestAddKeyLast"; SetUpTest(true); // Add record("key", "data") into database. CursorTest.GetCursorInBtreeDBWithoutEnv(testHome, testName, out db, out cursor); CursorTest.AddOneByCursor(db, cursor); // Add new record("key","data1") as the last of the data item of "key". pair = new KeyValuePair( new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1"))); cursor.Add(pair, Cursor.InsertLocation.LAST); // Confirm the record is added as the first of the data item of "key". cursor.Move(new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), true); Assert.AreNotEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); cursor.Close(); db.Close(); } [Test] public void TestAddUnique() { BTreeDatabase db; BTreeCursor cursor; KeyValuePair pair; testName = "TestAddUnique"; SetUpTest(true); // Open a database and cursor. BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.IF_NEEDED; // To put no duplicate data, the database should be set to be sorted. dbConfig.Duplicates = DuplicatesPolicy.SORTED; db = BTreeDatabase.Open(testHome + "/" + testName + ".db", dbConfig); cursor = db.Cursor(); // Add record("key", "data") into database. CursorTest.AddOneByCursor(db, cursor); // Fail to add duplicate record("key","data"). pair = new KeyValuePair( new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); try { cursor.AddUnique(pair); } catch (KeyExistException) { } finally { cursor.Close(); db.Close(); } } [Test] public void TestDuplicateWithSamePos() { BTreeDatabase db; BTreeDatabaseConfig dbConfig; BTreeCursor cursor, dupCursor; DatabaseEnvironment env; DatabaseEnvironmentConfig envConfig; DatabaseEntry key, data; KeyValuePair pair; Transaction txn; testName = "TestDuplicateWithSamePos"; SetUpTest(true); envConfig = new DatabaseEnvironmentConfig(); envConfig.Create = true; envConfig.UseMPool = true; envConfig.UseTxns = true; envConfig.NoMMap = false; env = DatabaseEnvironment.Open(testHome, envConfig); txn = env.BeginTransaction(); dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.IF_NEEDED; dbConfig.Env = env; db = BTreeDatabase.Open(testName + ".db", dbConfig, txn); key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); pair = new KeyValuePair(key, data); db.Put(key, data, txn); txn.Commit(); txn = env.BeginTransaction(); cursor = db.Cursor(txn); cursor.Move(key, true); //Duplicate a new cursor to the same position. dupCursor = cursor.Duplicate(true); // Overwrite the record. dupCursor.Overwrite(new DatabaseEntry( ASCIIEncoding.ASCII.GetBytes("newdata"))); // Confirm that the original data doesn't exist. Assert.IsFalse(dupCursor.Move(pair, true)); dupCursor.Close(); cursor.Close(); txn.Commit(); db.Close(); env.Close(); } [Test, ExpectedException(typeof(ExpectedTestException))] public void TestDuplicateToDifferentPos() { BTreeDatabase db; BTreeDatabaseConfig dbConfig; BTreeCursor cursor, dupCursor; DatabaseEnvironment env; DatabaseEnvironmentConfig envConfig; DatabaseEntry key, data; KeyValuePair pair; Transaction txn; testName = "TestDuplicateToDifferentPos"; SetUpTest(true); envConfig = new DatabaseEnvironmentConfig(); envConfig.Create = true; envConfig.UseMPool = true; envConfig.UseTxns = true; envConfig.NoMMap = false; env = DatabaseEnvironment.Open(testHome, envConfig); txn = env.BeginTransaction(); dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.IF_NEEDED; dbConfig.Env = env; db = BTreeDatabase.Open(testName + ".db", dbConfig, txn); key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); pair = new KeyValuePair(key, data); db.Put(key, data, txn); txn.Commit(); txn = env.BeginTransaction(); cursor = db.Cursor(txn); cursor.Move(key, true); //Duplicate a new cursor to the same position. dupCursor = cursor.Duplicate(false); /* * The duplicate cursor points to nothing so overwriting the * record is not allowed. */ try { dupCursor.Overwrite(new DatabaseEntry( ASCIIEncoding.ASCII.GetBytes("newdata"))); } catch (DatabaseException) { throw new ExpectedTestException(); } finally { dupCursor.Close(); cursor.Close(); txn.Commit(); db.Close(); env.Close(); } } [Test] public void TestInsertAfter() { BTreeDatabase db; BTreeCursor cursor; DatabaseEntry data; KeyValuePair pair; testName = "TestInsertAfter"; SetUpTest(true); // Add record("key", "data") into database. CursorTest.GetCursorInBtreeDBWithoutEnv(testHome, testName, out db, out cursor); CursorTest.AddOneByCursor(db, cursor); // Insert the new record("key","data1") after the record("key", "data"). data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1")); cursor.Insert(data, Cursor.InsertLocation.AFTER); /* * Move the cursor to the record("key", "data") and confirm that * the next record is the one just inserted. */ pair = new KeyValuePair( new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); Assert.IsTrue(cursor.Move(pair, true)); Assert.IsTrue(cursor.MoveNext()); Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("key"), cursor.Current.Key.Data); Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); cursor.Close(); db.Close(); } [Test] public void TestMoveFirstMultipleAndMultipleKey() { testName = "TestMoveFirstMultipleAndMultipleKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; KeyValuePair pair; MultipleKeyDatabaseEntry multiPair; int cnt; int[] size = new int[2]; size[0] = 0; size[1] = 1024; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); for (int i = 0; i < 2; i++) { cnt = 0; if (size[i] == 0) cursor.MoveFirstMultiple(); else cursor.MoveFirstMultiple(size[i]); pair = cursor.CurrentMultiple; foreach (DatabaseEntry dbt in pair.Value) cnt++; Assert.AreEqual(1, cnt); } for (int i = 0; i < 2; i++) { cnt = 0; if (size[i] == 0) cursor.MoveFirstMultipleKey(); else cursor.MoveFirstMultipleKey(size[i]); multiPair = cursor.CurrentMultipleKey; foreach (KeyValuePair dbt in multiPair) cnt++; Assert.Less(1, cnt); } cursor.Close(); db.Close(); } [Test] public void TestMoveMultiple() { testName = "TestMoveMultiple"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key; KeyValuePair pair; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); // Move cursor to pairs with exact 99 as its key. cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); cursor.MoveMultiple(key, true); pair = cursor.CurrentMultiple; Assert.AreEqual(99, BitConverter.ToInt32(pair.Key.Data, 0)); foreach (DatabaseEntry dbt in pair.Value) cnt++; Assert.AreEqual(2, cnt); // Move cursor to pairs with the smallest key larger than 100. cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)100)); cursor.MoveMultiple(key, false); pair = cursor.CurrentMultiple; Assert.AreEqual(101, BitConverter.ToInt32(pair.Key.Data, 0)); foreach (DatabaseEntry dbt in pair.Value) cnt++; Assert.AreEqual(1, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveMultipleKey() { testName = "TestMoveMultipleKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key; MultipleKeyDatabaseEntry mulPair; ; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); /* * Bulk retrieve key/value pair from the pair whose key * is exact 99. */ cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); cursor.MoveMultipleKey(key, true); mulPair = cursor.CurrentMultipleKey; foreach (KeyValuePair pair in mulPair) { Assert.GreaterOrEqual(3, BitConverter.ToInt32(pair.Key.Data, 0) - 98); cnt++; } Assert.AreEqual(3, cnt); /* * Bulk retrieve key/value pair from the pair whose key * is the smallest one larger than 100. */ cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)100)); cursor.MoveMultipleKey(key, false); mulPair = cursor.CurrentMultipleKey; foreach (KeyValuePair pair in mulPair) { Assert.AreEqual(101, BitConverter.ToInt32(pair.Key.Data, 0)); cnt++; } Assert.LessOrEqual(1, cnt); cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)100)); cursor.MoveMultipleKey(key, false, 1024); mulPair = cursor.CurrentMultipleKey; foreach (KeyValuePair pair in mulPair) { Assert.AreEqual(101, BitConverter.ToInt32(pair.Key.Data, 0)); Assert.AreEqual(101, BitConverter.ToInt32(pair.Value.Data, 0)); cnt++; } Assert.LessOrEqual(1, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveMultipleKeyWithRecno() { testName = "TestMoveMultipleKeyWithRecno"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; MultipleKeyDatabaseEntry multiDBT; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.UseRecordNumbers = true; dbConfig.Creation = CreatePolicy.IF_NEEDED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); cnt = 0; cursor.MoveMultipleKey(98); multiDBT = cursor.CurrentMultipleKey; foreach (KeyValuePair pair in multiDBT) cnt++; Assert.AreEqual(3, cnt); cnt = 0; cursor.MoveMultipleKey(98, 1024); multiDBT = cursor.CurrentMultipleKey; foreach (KeyValuePair pair in multiDBT) cnt++; Assert.AreEqual(3, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveMultiplePairs() { testName = "TestMoveMultiplePairs"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key, data; KeyValuePair pair; MultipleKeyDatabaseEntry multiKeyDBTs1, multiKeyDBTs2; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.SORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); /* * Bulk retrieve pairs from the pair whose key/data * is exact 99/99. */ cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); data = new DatabaseEntry(BitConverter.GetBytes((int)99)); pair = new KeyValuePair(key, data); cursor.MoveMultipleKey(pair, true); multiKeyDBTs1 = cursor.CurrentMultipleKey; foreach (KeyValuePair p in multiKeyDBTs1) cnt++; Assert.AreEqual(3, cnt); // Bulk retrieve pairs from the pair whose key is exact 99. cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); data = new DatabaseEntry(BitConverter.GetBytes((int)98)); cursor.MoveMultipleKey(pair, true); multiKeyDBTs2 = cursor.CurrentMultipleKey; foreach (KeyValuePair dbts in multiKeyDBTs2) cnt++; Assert.AreEqual(3, cnt); /* * Bulk retrieve pairs from the pair whose key is * exact 99 in buffer size of 1024k. */ cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); data = new DatabaseEntry(BitConverter.GetBytes((int)102)); cursor.MoveMultipleKey(pair, true, 1024); multiKeyDBTs2 = cursor.CurrentMultipleKey; foreach (KeyValuePair dbts in multiKeyDBTs2) cnt++; Assert.AreEqual(3, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveMultiplePairWithKey() { testName = "TestMoveMultiplePairWithKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key, data; KeyValuePair pair; KeyValuePair mulPair; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); /* * Move the cursor to pairs with exact 99 as its key * and 99 as its data. */ cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)99)); data = new DatabaseEntry(BitConverter.GetBytes((int)99)); pair = new KeyValuePair(key, data); cursor.MoveMultiple(pair, true); mulPair = cursor.CurrentMultiple; Assert.AreEqual(99, BitConverter.ToInt32(mulPair.Key.Data, 0)); foreach (DatabaseEntry dbt in mulPair.Value) { Assert.AreEqual(99, BitConverter.ToInt32(dbt.Data, 0)); cnt++; } Assert.AreEqual(1, cnt); // Move cursor to pairs with the smallest key larger than 100. cnt = 0; key = new DatabaseEntry(BitConverter.GetBytes((int)100)); data = new DatabaseEntry(BitConverter.GetBytes((int)100)); cursor.MoveMultiple(pair, false); mulPair = cursor.CurrentMultiple; Assert.AreEqual(99, BitConverter.ToInt32(mulPair.Key.Data, 0)); foreach (DatabaseEntry dbt in mulPair.Value) { Assert.GreaterOrEqual(1, BitConverter.ToInt32(dbt.Data, 0) - 99); cnt++; } Assert.AreEqual(1, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveNextMultipleKey() { testName = "TestMoveNextMultipleKey"; SetUpTest(true); BTreeDatabase db; BTreeCursor cursor; DatabaseEnvironment env; Transaction txn; int cnt = 0; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; GetMultipleDB(testHome, testName + ".db", dbConfig, out env, out txn, out db, out cursor); /* * Position the cursor to the first record, and bulk get * all other records. */ Assert.True(cursor.MoveFirst()); Assert.True(cursor.MoveNextMultipleKey()); MultipleKeyDatabaseEntry pairs = cursor.CurrentMultipleKey; foreach (KeyValuePair p in pairs) cnt++; Assert.AreEqual(cnt, 100); // Bulk read uncommitted records. cnt = 0; LockingInfo lockingInfo = new LockingInfo(); Assert.True(cursor.MoveFirst(lockingInfo)); lockingInfo.IsolationDegree = Isolation.DEGREE_ONE; Assert.True(cursor.MoveNextMultipleKey(lockingInfo)); pairs = cursor.CurrentMultipleKey; foreach (KeyValuePair p in pairs) cnt++; Assert.AreEqual(cnt, 100); cursor.Dispose(); txn.Commit(); /* * Insert duplicate records of the key in the last * record. */ txn = env.BeginTransaction(); cursor = db.Cursor(txn); Assert.IsTrue(cursor.MoveLast()); DatabaseEntry key = cursor.Current.Key; for (int i = 200; i < 800; i++) cursor.Insert(new DatabaseEntry( BitConverter.GetBytes(i)), Cursor.InsertLocation.AFTER); /* * Move to the first duplicate records, and bulk read * all duplicate ones. */ cnt = 0; Assert.True(cursor.Move(key, true)); while (cursor.MoveNextDuplicateMultipleKey( (int)db.Pagesize)) { pairs = cursor.CurrentMultipleKey; foreach (KeyValuePair< DatabaseEntry, DatabaseEntry> p in pairs) { Assert.AreEqual(key.Data, p.Key.Data); cnt++; } } Assert.AreEqual(cnt, 600); cursor.Close(); db.Close(); txn.Commit(); env.Close(); } [Test] public void TestMoveMultipleWithRecno() { testName = "TestMoveMultipleWithRecno"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; KeyValuePair pair; int cnt; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.PageSize = 1024; dbConfig.UseRecordNumbers = true; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); // Move cursor to the No.100 record. cnt = 0; cursor.MoveMultiple(100); pair = cursor.CurrentMultiple; Assert.AreEqual(100, BitConverter.ToInt32(pair.Key.Data, 0)); foreach (DatabaseEntry dbt in pair.Value) cnt++; Assert.AreEqual(1, cnt); // Move cursor to the No.100 record with buffer size of 1024k. cnt = 0; cursor.MoveMultiple(100, 1024); pair = cursor.CurrentMultiple; Assert.AreEqual(100, BitConverter.ToInt32(pair.Key.Data, 0)); foreach (DatabaseEntry dbt in pair.Value) cnt++; Assert.AreEqual(1, cnt); cursor.Close(); db.Close(); } [Test] public void TestMoveNextDuplicateMultipleAndMultipleKey() { testName = "TestMoveNextDuplicateMultipleAndMultipleKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key, data; KeyValuePair pair; KeyValuePair pairs; MultipleKeyDatabaseEntry multiPair; int cnt; int[] size = new int[2]; size[0] = 0; size[1] = 1024; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.SORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); key = new DatabaseEntry(BitConverter.GetBytes(99)); data = new DatabaseEntry(BitConverter.GetBytes(99)); pair = new KeyValuePair(key, data); for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { cnt = 0; cursor.Move(pair, true); if (j == 0) { if (size[i] == 0) Assert.IsTrue(cursor.MoveNextDuplicateMultiple()); else Assert.IsTrue(cursor.MoveNextDuplicateMultiple(size[i])); pairs = cursor.CurrentMultiple; foreach (DatabaseEntry dbt in pairs.Value) { Assert.AreEqual(100, BitConverter.ToInt32(dbt.Data, 0)); cnt++; } Assert.AreEqual(1, cnt); } else { if (size[i] == 0) Assert.IsTrue(cursor.MoveNextDuplicateMultipleKey()); else Assert.IsTrue(cursor.MoveNextDuplicateMultipleKey(size[i])); multiPair = cursor.CurrentMultipleKey; foreach (KeyValuePair p in multiPair) { Assert.AreEqual(100, BitConverter.ToInt32(p.Value.Data, 0)); cnt++; } Assert.AreEqual(1, cnt); } } } cursor.Close(); db.Close(); } [Test] public void TestMoveNextUniqueMultipleAndMultipleKey() { testName = "TestMoveNextUniqueMultipleAndMultipleKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key, data; KeyValuePair pair; KeyValuePair pairs; MultipleKeyDatabaseEntry multiPair; int cnt; int[] size = new int[2]; size[0] = 0; size[1] = 1024; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.UNSORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); key = new DatabaseEntry(BitConverter.GetBytes(99)); data = new DatabaseEntry(BitConverter.GetBytes(99)); pair = new KeyValuePair(key, data); for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { cnt = 0; cursor.Move(pair, true); if (j == 0) { if (size[i] == 0) Assert.IsTrue(cursor.MoveNextUniqueMultiple()); else Assert.IsTrue(cursor.MoveNextUniqueMultiple(size[i])); pairs = cursor.CurrentMultiple; foreach (DatabaseEntry dbt in pairs.Value) { Assert.AreEqual(101, BitConverter.ToInt32(dbt.Data, 0)); cnt++; } Assert.AreEqual(1, cnt); } else { if (size[i] == 0) Assert.IsTrue(cursor.MoveNextUniqueMultipleKey()); else Assert.IsTrue(cursor.MoveNextUniqueMultipleKey(size[i])); multiPair = cursor.CurrentMultipleKey; foreach (KeyValuePair p in multiPair) { Assert.AreEqual(101, BitConverter.ToInt32(p.Value.Data, 0)); cnt++; } Assert.AreEqual(1, cnt); } } } cursor.Close(); db.Close(); } [Test] public void TestRefreshMultipleAndMultipleKey() { testName = "TestRefreshMultipleAndMultipleKey"; SetUpTest(true); string btreeDBFileName = testHome + "/" + testName + ".db"; BTreeDatabase db; BTreeCursor cursor; DatabaseEntry key, data; KeyValuePair pair; KeyValuePair pairs; MultipleKeyDatabaseEntry multiPair; int cnt; int[] size = new int[2]; size[0] = 0; size[1] = 1024; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.Creation = CreatePolicy.ALWAYS; dbConfig.Duplicates = DuplicatesPolicy.SORTED; dbConfig.PageSize = 1024; GetMultipleDB(btreeDBFileName, dbConfig, null, out db, out cursor); key = new DatabaseEntry(BitConverter.GetBytes(99)); data = new DatabaseEntry(BitConverter.GetBytes(99)); pair = new KeyValuePair(key, data); for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { cnt = 0; cursor.Move(pair, true); if (j == 0) { if (size[i] == 0) Assert.IsTrue(cursor.RefreshMultiple()); else Assert.IsTrue(cursor.RefreshMultiple(size[i])); pairs = cursor.CurrentMultiple; foreach (DatabaseEntry dbt in pairs.Value) cnt++; Assert.AreEqual(2, cnt); } else { if (size[i] == 0) Assert.IsTrue(cursor.RefreshMultipleKey()); else Assert.IsTrue(cursor.RefreshMultipleKey(size[i])); multiPair = cursor.CurrentMultipleKey; foreach (KeyValuePair p in multiPair) cnt++; Assert.AreEqual(3, cnt); } } } cursor.Close(); db.Close(); } private void GetMultipleDB(string dbFileName, BTreeDatabaseConfig dbConfig, Transaction txn, out BTreeDatabase db, out BTreeCursor cursor) { if (txn == null) { db = BTreeDatabase.Open(dbFileName, dbConfig); cursor = db.Cursor(); } else { db = BTreeDatabase.Open( dbFileName, dbConfig, txn); CursorConfig cursorConfig = new CursorConfig(); cursor = db.Cursor(cursorConfig, txn); } KeyValuePair pair; DatabaseEntry key, data; for (int i = 1; i < 100; i++) { key = new DatabaseEntry(BitConverter.GetBytes(i)); data = new DatabaseEntry(BitConverter.GetBytes(i)); pair = new KeyValuePair(key, data); cursor.Add(pair); } if (dbConfig.UseRecordNumbers == true) { byte[] bytes = new byte[512]; for (int i = 0; i < 512; i++) bytes[i] = (byte)i; key = new DatabaseEntry(BitConverter.GetBytes(100)); data = new DatabaseEntry(bytes); pair = new KeyValuePair(key, data); cursor.Add(pair); } else { if (dbConfig.Duplicates == DuplicatesPolicy.UNSORTED || dbConfig.Duplicates == DuplicatesPolicy.SORTED) { key = new DatabaseEntry(BitConverter.GetBytes(99)); data = new DatabaseEntry(BitConverter.GetBytes(100)); pair = new KeyValuePair(key, data); cursor.Add(pair); } key = new DatabaseEntry(BitConverter.GetBytes(101)); data = new DatabaseEntry(BitConverter.GetBytes(101)); pair = new KeyValuePair(key, data); cursor.Add(pair); } } private void GetMultipleDB(string home, string dbFileName, BTreeDatabaseConfig dbConfig, out DatabaseEnvironment env, out Transaction txn, out BTreeDatabase db, out BTreeCursor cursor) { DatabaseEnvironmentConfig envConfig = new DatabaseEnvironmentConfig(); envConfig.Create = true; envConfig.UseTxns = true; envConfig.UseLocking = true; envConfig.UseLogging = true; envConfig.UseMPool = true; env = DatabaseEnvironment.Open(home, envConfig); txn = env.BeginTransaction(); if (dbConfig == null) dbConfig = new BTreeDatabaseConfig(); dbConfig.Env = env; GetMultipleDB(dbFileName, dbConfig, txn, out db, out cursor); } [Test] public void TestInsertBefore() { BTreeDatabase db; BTreeCursor cursor; DatabaseEntry data; KeyValuePair pair; testName = "TestInsertBefore"; SetUpTest(true); // Add record("key", "data") into database. CursorTest.GetCursorInBtreeDBWithoutEnv( testHome, testName, out db, out cursor); CursorTest.AddOneByCursor(db, cursor); // Insert the new record("key","data1") before the record("key", "data"). data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data1")); cursor.Insert(data, Cursor.InsertLocation.BEFORE); /* * Move the cursor to the record("key", "data") and confirm * that the previous record is the one just inserted. */ pair = new KeyValuePair( new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")), new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data"))); Assert.IsTrue(cursor.Move(pair, true)); Assert.IsTrue(cursor.MovePrev()); Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("key"),cursor.Current.Key.Data); Assert.AreEqual(ASCIIEncoding.ASCII.GetBytes("data1"), cursor.Current.Value.Data); cursor.Close(); db.Close(); } [Test] public void TestMoveToRecno() { BTreeDatabase db; BTreeCursor cursor; testName = "TestMoveToRecno"; SetUpTest(true); GetCursorInBtreeDBUsingRecno(testHome, testName, out db, out cursor); for (int i = 0; i < 10; i++) db.Put( new DatabaseEntry(BitConverter.GetBytes(i)), new DatabaseEntry(BitConverter.GetBytes(i))); MoveCursorToRecno(cursor, null); cursor.Close(); db.Close(); } [Test] public void TestMoveToRecnoWithRMW() { testName = "TestMoveToRecnoWithRMW"; SetUpTest(true); btCursorFunc = new BTCursorMoveFuncDelegate( MoveCursorToRecno); // Move to a specified key and a key/data pair. MoveWithRMW(testHome, testName); } [Test] public void TestRecno() { BTreeDatabase db; BTreeCursor cursor; testName = "TestRecno"; SetUpTest(true); GetCursorInBtreeDBUsingRecno(testHome, testName, out db, out cursor); for (int i = 0; i < 10; i++) db.Put( new DatabaseEntry(BitConverter.GetBytes(i)), new DatabaseEntry(BitConverter.GetBytes(i))); ReturnRecno(cursor, null); cursor.Close(); db.Close(); } [Test] public void TestRecnoWithRMW() { testName = "TestRecnoWithRMW"; SetUpTest(true); // Use MoveCursorToRecno() as its move function. btCursorFunc = new BTCursorMoveFuncDelegate( ReturnRecno); // Move to a specified key and a key/data pair. MoveWithRMW(testHome, testName); } /* * Move the cursor according to recno. The recno * starts from 1 and is increased by 1. */ public void MoveCursorToRecno(BTreeCursor cursor, LockingInfo lck) { for (uint i = 1; i <= 5; i++) if (lck == null) Assert.IsTrue(cursor.Move(i)); else Assert.IsTrue(cursor.Move(i, lck)); } /*l * Move the cursor according to a given recno and * return the current record's recno. The given recno * and the one got from the cursor should be the same. */ public void ReturnRecno(BTreeCursor cursor, LockingInfo lck) { for (uint i = 1; i <= 5; i++) if (lck == null) { if (cursor.Move(i) == true) Assert.AreEqual(i, cursor.Recno()); } else { if (cursor.Move(i, lck) == true) Assert.AreEqual(i, cursor.Recno(lck)); } } public void GetCursorInBtreeDBUsingRecno(string home, string name, out BTreeDatabase db, out BTreeCursor cursor) { string dbFileName = home + "/" + name + ".db"; BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig(); dbConfig.UseRecordNumbers = true; dbConfig.Creation = CreatePolicy.IF_NEEDED; db = BTreeDatabase.Open(dbFileName, dbConfig); cursor = db.Cursor(); } public void RdMfWt() { Transaction txn = paramEnv.BeginTransaction(); BTreeCursor dbc = paramDB.Cursor(txn); try { LockingInfo lck = new LockingInfo(); lck.ReadModifyWrite = true; // Read record. btCursorFunc(dbc, lck); // Block the current thread until event is set. signal.WaitOne(); // Write new records into database. DatabaseEntry key = new DatabaseEntry(BitConverter.GetBytes(55)); DatabaseEntry data = new DatabaseEntry(BitConverter.GetBytes(55)); dbc.Add(new KeyValuePair(key, data)); dbc.Close(); txn.Commit(); } catch (DeadlockException) { dbc.Close(); txn.Abort(); } } public void MoveWithRMW(string home, string name) { paramEnv = null; paramDB = null; // Open the environment. DatabaseEnvironmentConfig envCfg = new DatabaseEnvironmentConfig(); envCfg.Create = true; envCfg.FreeThreaded = true; envCfg.UseLocking = true; envCfg.UseLogging = true; envCfg.UseMPool = true; envCfg.UseTxns = true; paramEnv = DatabaseEnvironment.Open(home, envCfg); // Open database in transaction. Transaction openTxn = paramEnv.BeginTransaction(); BTreeDatabaseConfig cfg = new BTreeDatabaseConfig(); cfg.Creation = CreatePolicy.ALWAYS; cfg.Env = paramEnv; cfg.FreeThreaded = true; cfg.PageSize = 4096; // Use record number. cfg.UseRecordNumbers = true; paramDB = BTreeDatabase.Open(name + ".db", cfg, openTxn); openTxn.Commit(); /* * Put 10 different, 2 duplicate and another different * records into database. */ Transaction txn = paramEnv.BeginTransaction(); for (int i = 0; i < 13; i++) { DatabaseEntry key, data; if (i == 10 || i == 11) { key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")); data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")); } else { key = new DatabaseEntry(BitConverter.GetBytes(i)); data = new DatabaseEntry(BitConverter.GetBytes(i)); } paramDB.Put(key, data, txn); } txn.Commit(); // Get a event wait handle. signal = new EventWaitHandle(false, EventResetMode.ManualReset); /* * Start RdMfWt() in two threads. RdMfWt() reads * and writes data into database. */ Thread t1 = new Thread(new ThreadStart(RdMfWt)); Thread t2 = new Thread(new ThreadStart(RdMfWt)); t1.Start(); t2.Start(); // Give both threads time to read before signalling them to write. Thread.Sleep(1000); // Invoke the write operation in both threads. signal.Set(); // Return the number of deadlocks. while (t1.IsAlive || t2.IsAlive) { /* * Give both threads time to write before * counting the number of deadlocks. */ Thread.Sleep(1000); uint deadlocks = paramEnv.DetectDeadlocks(DeadlockPolicy.DEFAULT); // Confirm that there won't be any deadlock. Assert.AreEqual(0, deadlocks); } t1.Join(); t2.Join(); paramDB.Close(); paramEnv.Close(); } } }