libdb/test/csharp/TransactionTest.cs
2011-09-13 13:44:24 -04:00

429 lines
9.9 KiB
C#

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2009, 2011 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 System.Xml;
using NUnit.Framework;
using BerkeleyDB;
namespace CsharpAPITest
{
[TestFixture]
public class TransactionTest : CSharpTestFixture
{
private DatabaseEnvironment deadLockEnv;
[TestFixtureSetUp]
public void SetUpTestFixture()
{
testFixtureName = "TransactionTest";
base.SetUpTestfixture();
DatabaseEnvironment.Remove(testFixtureHome);
}
[Test, ExpectedException(typeof(ExpectedTestException))]
public void TestAbort()
{
testName = "TestAbort";
SetUpTest(true);
DatabaseEnvironment env;
Transaction txn;
BTreeDatabase db;
/*
* Open an environment and begin a transaction. Open
* a db and write a record the db within this transaction.
*/
PutRecordWithTxn(out env, testHome, testName, out txn);
// Abort the transaction.
txn.Abort();
/*
* Undo all operations in the transaction so the
* database couldn't be reopened.
*/
try
{
OpenBtreeDBInEnv(testName + ".db", env,
out db, false, null);
}
catch (DatabaseException)
{
throw new ExpectedTestException();
}
finally
{
env.Close();
}
}
[Test]
public void TestCommit()
{
testName = "TestCommit";
SetUpTest(true);
DatabaseEnvironment env;
Transaction txn;
BTreeDatabase db;
/*
* Open an environment and begin a transaction. Open
* a db and write a record the db within this transaction.
*/
PutRecordWithTxn(out env, testHome, testName, out txn);
// Commit the transaction.
txn.Commit();
// Reopen the database.
OpenBtreeDBInEnv(testName + ".db", env,
out db, false, null);
/*
* Confirm that the record("key", "data") exists in the
* database.
*/
try
{
db.GetBoth(new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("key")),
new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("data")));
}
catch (DatabaseException)
{
throw new TestException();
}
finally
{
db.Close();
env.Close();
}
}
[Test]
public void TestDiscard()
{
DatabaseEnvironment env;
byte[] gid;
testName = "TestDiscard";
SetUpTest(true);
/*
* Open an environment and begin a transaction
* called "transaction". Within the transacion, open a
* database, write a record and close it. Then prepare
* the transaction and panic the environment.
*/
PanicPreparedTxn(testHome, testName, out env, out gid);
/*
* Recover the environment. Log and db files are not
* destoyed so run normal recovery. Recovery should
* use DB_CREATE and DB_INIT_TXN flags when
* opening the environment.
*/
DatabaseEnvironmentConfig envConfig
= new DatabaseEnvironmentConfig();
envConfig.RunRecovery = true;
envConfig.Create = true;
envConfig.UseTxns = true;
envConfig.UseMPool = true;
env = DatabaseEnvironment.Open(testHome, envConfig);
PreparedTransaction[] preparedTxns
= new PreparedTransaction[10];
preparedTxns = env.Recover(10, true);
Assert.AreEqual(gid, preparedTxns[0].GlobalID);
preparedTxns[0].Txn.Discard();
try {
preparedTxns[0].Txn.Commit();
throw new TestException();
} catch (AccessViolationException) {
} finally {
env.Close();
}
}
[Test]
public void TestPrepare()
{
testName = "TestPrepare";
SetUpTest(true);
DatabaseEnvironment env;
byte[] gid;
/*
* Open an environment and begin a transaction
* called "transaction". Within the transacion, open a
* database, write a record and close it. Then prepare
* the transaction and panic the environment.
*/
PanicPreparedTxn(testHome, testName, out env, out gid);
/*
* Recover the environment. Log and db files are not
* destoyed so run normal recovery. Recovery should
* use DB_CREATE and DB_INIT_TXN flags when
* opening the environment.
*/
DatabaseEnvironmentConfig envConfig
= new DatabaseEnvironmentConfig();
envConfig.RunRecovery = true;
envConfig.Create = true;
envConfig.UseTxns = true;
envConfig.UseMPool = true;
env = DatabaseEnvironment.Open(testHome, envConfig);
// Reopen the database.
BTreeDatabase db;
OpenBtreeDBInEnv(testName + ".db", env, out db,
false, null);
/*
* Confirm that record("key", "data") exists in the
* database.
*/
DatabaseEntry key, data;
key = new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("key"));
data = new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("data"));
try
{
db.GetBoth(key, data);
}
catch (DatabaseException)
{
throw new TestException();
}
finally
{
db.Close();
env.Close();
}
}
public void PanicPreparedTxn(string home, string dbName,
out DatabaseEnvironment env, out byte[] globalID)
{
Transaction txn;
// Put record into database within transaction.
PutRecordWithTxn(out env, home, dbName, out txn);
/*
* Generate global ID for the transaction. Copy
* transaction ID to the first 4 tyes in global ID.
*/
globalID = new byte[Transaction.GlobalIdLength];
byte[] txnID = new byte[4];
txnID = BitConverter.GetBytes(txn.Id);
for (int i = 0; i < txnID.Length; i++)
globalID[i] = txnID[i];
// Prepare the transaction.
txn.Prepare(globalID);
// Panic the environment.
env.Panic();
}
[Test]
public void TestTxnName()
{
DatabaseEnvironment env;
Transaction txn;
testName = "TestTxnName";
SetUpTest(true);
SetUpTransactionalEnv(testHome, out env);
txn = env.BeginTransaction();
txn.Name = testName;
Assert.AreEqual(testName, txn.Name);
txn.Commit();
env.Close();
}
[Test]
public void TestTxnPriority() {
DatabaseEnvironment env;
Transaction txn;
testName = "TestTxnPriority";
SetUpTest(true);
SetUpTransactionalEnv(testHome, out env);
txn = env.BeginTransaction();
txn.Priority = 555;
Assert.AreEqual(555, txn.Priority);
txn.Commit();
env.Close();
}
[Test]
public void TestSetLockTimeout()
{
testName = "TestSetLockTimeout";
SetUpTest(true);
// Set lock timeout.
TestTimeOut(true);
}
[Test]
public void TestSetTxnTimeout()
{
testName = "TestSetTxnTimeout";
SetUpTest(true);
// Set transaction time out.
TestTimeOut(false);
}
/*
* ifSetLock is used to indicate which timeout function
* is used, SetLockTimeout or SetTxnTimeout.
*/
public void TestTimeOut(bool ifSetLock)
{
// Open environment and begin transaction.
Transaction txn;
deadLockEnv = null;
SetUpEnvWithTxnAndLocking(testHome,
out deadLockEnv, out txn, 0, 0, 0, 0);
// Define deadlock detection and resolve policy.
deadLockEnv.DeadlockResolution =
DeadlockPolicy.YOUNGEST;
if (ifSetLock == true)
txn.SetLockTimeout(10);
else
txn.SetTxnTimeout(10);
txn.Commit();
deadLockEnv.Close();
}
public static void SetUpEnvWithTxnAndLocking(string envHome,
out DatabaseEnvironment env, out Transaction txn,
uint maxLock, uint maxLocker, uint maxObject, uint partition)
{
// Configure env and locking subsystem.
LockingConfig lkConfig = new LockingConfig();
/*
* If the maximum number of locks/lockers/objects
* is given, then the LockingConfig is set. Unless,
* it is not set to any value.
*/
if (maxLock != 0)
lkConfig.MaxLocks = maxLock;
if (maxLocker != 0)
lkConfig.MaxLockers = maxLocker;
if (maxObject != 0)
lkConfig.MaxObjects = maxObject;
if (partition != 0)
lkConfig.Partitions = partition;
DatabaseEnvironmentConfig envConfig =
new DatabaseEnvironmentConfig();
envConfig.Create = true;
envConfig.UseTxns = true;
envConfig.UseMPool = true;
envConfig.LockSystemCfg = lkConfig;
envConfig.UseLocking = true;
envConfig.NoLocking = false;
env = DatabaseEnvironment.Open(envHome, envConfig);
txn = env.BeginTransaction();
}
public void PutRecordWithTxn(out DatabaseEnvironment env,
string home, string dbName, out Transaction txn)
{
BTreeDatabase db;
// Open a new environment and begin a transaction.
SetUpTransactionalEnv(home, out env);
TransactionConfig txnConfig = new TransactionConfig();
txnConfig.Name = "Transaction";
txn = env.BeginTransaction(txnConfig);
Assert.AreEqual("Transaction", txn.Name);
// Open a new database within the transaction.
OpenBtreeDBInEnv(dbName + ".db", env, out db, true, txn);
// Write to the database within the transaction.
WriteOneIntoBtreeDBWithTxn(db, txn);
// Close the database.
db.Close();
}
public void SetUpTransactionalEnv(string home,
out DatabaseEnvironment env)
{
DatabaseEnvironmentConfig envConfig =
new DatabaseEnvironmentConfig();
envConfig.Create = true;
envConfig.UseLogging = true;
envConfig.UseLocking = true;
envConfig.UseMPool = true;
envConfig.UseTxns = true;
env = DatabaseEnvironment.Open(
home, envConfig);
}
public void OpenBtreeDBInEnv(string dbName,
DatabaseEnvironment env, out BTreeDatabase db,
bool create, Transaction txn)
{
BTreeDatabaseConfig btreeDBConfig =
new BTreeDatabaseConfig();
btreeDBConfig.Env = env;
if (create == true)
btreeDBConfig.Creation = CreatePolicy.IF_NEEDED;
else
btreeDBConfig.Creation = CreatePolicy.NEVER;
if (txn == null)
db = BTreeDatabase.Open(dbName,
btreeDBConfig);
else
db = BTreeDatabase.Open(dbName,
btreeDBConfig, txn);
}
public void WriteOneIntoBtreeDBWithTxn(BTreeDatabase db,
Transaction txn)
{
DatabaseEntry key, data;
key = new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("key"));
data = new DatabaseEntry(
ASCIIEncoding.ASCII.GetBytes("data"));
db.Put(key, data, txn);
}
}
}