context: /*-
   * See the file LICENSE for redistribution information.
   *
   * Copyright (c) 2009, 2015 Oracle and/or its affiliates.  All rights reserved.
   *
   */
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Text;
  using System.Threading;
  using System.Xml;
  using NUnit.Framework;
  using BerkeleyDB;
  
  namespace CsharpAPITest
  {
      class BackupWriter : IBackup {
          FileStream f;
          public int Close(string dbname) {
              f.Close();
              return 0;
          }
          public int Open(string dbname, string target) {
              string path = Path.Combine(target, dbname);
              f = new FileStream(path, FileMode.Create);
              return 0;
          }
          public int Write(byte[] data, long offset, int count) {
              f.Seek(offset, SeekOrigin.Begin);
              f.Write(data, 0, count);
              return 0;
          }
      }
  	[TestFixture]
  	public class DatabaseEnvironmentTest : CSharpTestFixture
  	{
  
  		private DatabaseEnvironment testBeginTransactionEnv;
  		private BTreeDatabase testBeginTransactionDB;
  
  		private DatabaseEnvironment testCheckpointEnv;
  		private BTreeDatabase testCheckpointDB;
  
  		private DatabaseEnvironment testDetectDeadlocksEnv;
  		private BTreeDatabase testDetectDeadlocksDB;
  
  		private DatabaseEnvironment testFailCheckEnv;
  
  		private EventWaitHandle signal;
  
  		[TestFixtureSetUp]
  		public void SetUp()
  		{
  			testFixtureName = "DatabaseEnvironmentTest";
  			base.SetUpTestfixture();
  		}
  
  		[Test]
  		public void TestArchivableDatabaseFiles()
  		{
  			testName = "TestArchivableDatabaseFiles";
  			SetUpTest(true);
  			string dbFileName1 = testName + "1.db";
  			string dbFileName2 = testName + "2.db";
  
  			// Open an environment.
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.AutoCommit = true;
  			envConfig.Create = true;
  			envConfig.UseMPool = true;
  			envConfig.UseLogging = true;
  			envConfig.UseTxns = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    testHome, envConfig);
  
  			// Open two databases.
  			BTreeDatabaseConfig dbConfig =
  			    new BTreeDatabaseConfig();
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = env;
  			BTreeDatabase db1 = BTreeDatabase.Open(dbFileName1, dbConfig);
  			db1.Close();
  			BTreeDatabase db2 = BTreeDatabase.Open(dbFileName2, dbConfig);
  			db2.Close();
  
  			/*
  			 * Get all database files name in the environment.
  			 * Two database file name should be returned and
  			 * the same as the ones when opening the databases.
  			 */
  			List<string> dbFiles = env.ArchivableDatabaseFiles(false);
  			Assert.AreEqual(2, dbFiles.Count);
  			Assert.IsTrue(dbFiles.Contains(dbFileName1));
  			Assert.IsTrue(dbFiles.Contains(dbFileName2));
  
  			/*
  			 * Get all database file's abosolute path in the
  			 * environment. Confirm those files exist.
  			 */
  			List<string> dbFilesPath = env.ArchivableDatabaseFiles(true);
  			Assert.IsTrue(File.Exists(dbFilesPath[0]));
  			Assert.IsTrue(File.Exists(dbFilesPath[1]));
  
  			env.Close();
  		}
  
  		[Test]
  		public void TestArchivableLogFiles()
  		{
  			testName = "TestArchivableLogFiles";
  			SetUpTest(true);
  			string dbFileName = testName + ".db";
  
  			// Open an environment.
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.AutoCommit = true;
  			envConfig.Create = true;
  			envConfig.UseMPool = true;
  			envConfig.UseLogging = true;
  			envConfig.UseTxns = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    testHome, envConfig);
  
  			// Open a databases.
  			BTreeDatabaseConfig dbConfig =
  			    new BTreeDatabaseConfig();
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = env;
  			BTreeDatabase db = BTreeDatabase.Open(
  			    dbFileName, dbConfig);
  
  			/*
  			 * Put 1000 records into the database to generate
  			 * more than one log files.
  			 */
  			byte[] byteArr = new byte[1024];
  			for (int i = 0; i < 1000; i++)
  				db.Put(new DatabaseEntry(
  				    BitConverter.GetBytes(i)),
  				    new DatabaseEntry(byteArr));
  
  			db.Close();
  
  			List<string> logFiles = env.ArchivableLogFiles(false);
  
  			List<string> logFilesPath =
  			    env.ArchivableLogFiles(true);
  			for (int i = 0; i < logFilesPath.Count; i++)
  				Assert.IsTrue(File.Exists(logFilesPath[i]));
  
  			env.Close();
  		}
  
          [Test]
          public void TestBackup() {
              testName = "TestBackup";
              SetUpTest(true);
              string dbFileName = testName + ".db";
  
              // Open an environment.
              DatabaseEnvironmentConfig envConfig =
                  new DatabaseEnvironmentConfig();
              envConfig.AutoCommit = true;
              envConfig.Create = true;
              envConfig.UseMPool = true;
              envConfig.UseLogging = true;
              envConfig.UseTxns = true;
              DatabaseEnvironment env = DatabaseEnvironment.Open(
                  testHome, envConfig);
  
              // Open a databases.
              BTreeDatabaseConfig dbConfig =
                  new BTreeDatabaseConfig();
              dbConfig.Creation = CreatePolicy.IF_NEEDED;
              dbConfig.Env = env;
              BTreeDatabase db = BTreeDatabase.Open(
                  dbFileName, dbConfig);
  
              /*
               * Put 1000 records into the database to generate
               * more than one log file.
               */
              byte[] byteArr = new byte[1024];
              for (int i = 0; i < 1000; i++)
                  db.Put(new DatabaseEntry(
                      BitConverter.GetBytes(i)),
                      new DatabaseEntry(byteArr));
  
              db.Close();
  
              /* Set up the target directory for the backup. */
              string target = testFixtureHome + "/" + testName + "_backup";
              Configuration.ClearDir(target);
              
              BackupOptions opt = new BackupOptions();
              opt.Creation = CreatePolicy.ALWAYS;
              env.Backup(target, opt);
              Assert.Greater(Directory.GetFiles(target).Length, 0);
              Directory.Delete(target, true);
              env.Close();
          }
  
          [Test]
          public void TestBackupCallbacks() {
              testName = "TestBackupCallbacks";
              SetUpTest(true);
              string dbFileName = testName + ".db";
  
              // Open an environment.
              DatabaseEnvironmentConfig envConfig =
                  new DatabaseEnvironmentConfig();
              envConfig.AutoCommit = true;
              envConfig.Create = true;
              envConfig.UseMPool = true;
              envConfig.UseLogging = true;
              envConfig.UseTxns = true;
              DatabaseEnvironment env = DatabaseEnvironment.Open(
                  testHome, envConfig);
  
              // Open a databases.
              BTreeDatabaseConfig dbConfig =
                  new BTreeDatabaseConfig();
              dbConfig.Creation = CreatePolicy.IF_NEEDED;
              dbConfig.Env = env;
              BTreeDatabase db = BTreeDatabase.Open(
                  dbFileName, dbConfig);
  
              /*
               * Populate the database but keep it small, we're going to do a 
               * byte-by-byte comparison at the end.
               */
              byte[] byteArr = new byte[1024];
              for (int i = 0; i < 10; i++)
                  db.Put(new DatabaseEntry(
                      BitConverter.GetBytes(i)),
                      new DatabaseEntry(byteArr));
  
              db.Close();
  
              /* Set up the target directory for the backup. */
              string target = testFixtureHome + "/" + testName + "_backup";
              Configuration.ClearDir(target);
              
              BackupWriter backup = new BackupWriter();
              env.BackupHandler = backup;
  
              BackupOptions opt = new BackupOptions();
              opt.Creation = CreatePolicy.ALWAYS;
              env.Backup(target, opt);
              Assert.Greater(Directory.GetFiles(target).Length, 0);
              
              /* Check that our callbacks wrote the file correctly. */
              FileStream orig = new FileStream(Path.Combine(testHome, dbFileName), FileMode.Open, FileAccess.Read);
              FileStream bak = new FileStream(Path.Combine(target, dbFileName), FileMode.Open, FileAccess.Read);
              int orig_byte, bak_byte;
              do {
                  orig_byte = orig.ReadByte();
                  bak_byte = bak.ReadByte();
                  Assert.AreEqual(orig_byte, bak_byte);
              } while (orig_byte != -1 && bak_byte != -1);
              orig.Close();
              bak.Close();
              Directory.Delete(target, true);
              env.Close();
          }
  
          [Test]
          public void TestBackupDatabase() {
              testName = "TestBackupDatabase";
              SetUpTest(true);
              string dbFileName = testName + ".db";
  
              // Open an environment.
              DatabaseEnvironmentConfig envConfig =
                  new DatabaseEnvironmentConfig();
              envConfig.AutoCommit = true;
              envConfig.Create = true;
              envConfig.UseMPool = true;
              envConfig.UseLogging = true;
              envConfig.UseTxns = true;
              DatabaseEnvironment env = DatabaseEnvironment.Open(
                  testHome, envConfig);
  
              // Open a databases.
              BTreeDatabaseConfig dbConfig =
                  new BTreeDatabaseConfig();
              dbConfig.Creation = CreatePolicy.IF_NEEDED;
              dbConfig.Env = env;
              BTreeDatabase db = BTreeDatabase.Open(
                  dbFileName, dbConfig);
              
              /*
               * Put 1000 records into the database to generate
               * more than one log file.
               */
              byte[] byteArr = new byte[1024];
              for (int i = 0; i < 1000; i++)
                  db.Put(new DatabaseEntry(
                      BitConverter.GetBytes(i)),
                      new DatabaseEntry(byteArr));
              
              db.Close();
  
              /* Set up the target directory for the backup. */
              string target = testFixtureHome + "/" + testName + "_backup";
              Configuration.ClearDir(target);
              
              /* We should only copy one file, the database. */
              env.BackupDatabase(target, dbFileName, true);
              Assert.AreEqual(1, Directory.GetFiles(target).Length);
              
              Directory.Delete(target, true);
              env.Close();
          }
  
          [Test]
          public void TestBackupOptions() {
              testName = "TestBackupOptions";
              SetUpTest(true);
              
              // Open an environment.
              DatabaseEnvironmentConfig envConfig =
                  new DatabaseEnvironmentConfig();
              envConfig.AutoCommit = true;
              envConfig.Create = true;
              envConfig.UseMPool = true;
              envConfig.UseLogging = true;
              envConfig.UseTxns = true;
              DatabaseEnvironment env = DatabaseEnvironment.Open(
                  testHome, envConfig);
  
              /* 
               * Check that we can get and set backup options successfully.  There
               * are other tests to check that the backup options are obeyed.
               */
              env.BackupBufferSize = (uint)1024;
              Assert.AreEqual((uint)1024, env.BackupBufferSize);
              
              env.BackupReadCount = (uint)4096;
              Assert.AreEqual((uint)4096, env.BackupReadCount);
              
              env.BackupReadSleepDuration = (uint)1000;
              Assert.AreEqual((uint)1000, env.BackupReadSleepDuration);
              
              env.BackupWriteDirect = true;
              Assert.IsTrue(env.BackupWriteDirect);
          }
  
  		[Test]
  		public void TestBeginCDSGroup()
  		{
  			testName = "TestBeginCDSGroup";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseCDB = true;
  			cfg.UseMPool = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(testHome, cfg);
  			Transaction txn = env.BeginCDSGroup();
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = env;
  			BTreeDatabase db = BTreeDatabase.Open(
  			    testName + ".db", dbConfig, txn);
  			db.Put(new DatabaseEntry(
  			    ASCIIEncoding.ASCII.GetBytes("key")),
  			    new DatabaseEntry(
  			    ASCIIEncoding.ASCII.GetBytes("data")), txn);
  			db.Close();
  			txn.Commit();
  			env.Close();
  		}
  
  		[Test]
  		public void TestBeginTransaction()
  		{
  			testName = "TestBeginTransaction";
  			SetUpTest(true);
  
  			// Open an environment.
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseTxns = true;
  			cfg.UseMPool = true;
  			cfg.UseLogging = true;
  			cfg.UseLocking = true;
  			cfg.NoLocking = false;
  			cfg.FreeThreaded = true;
  			testBeginTransactionEnv = DatabaseEnvironment.Open(testHome, cfg);
  			testBeginTransactionEnv.DeadlockResolution = DeadlockPolicy.OLDEST;
  
  			// Open btree database.
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.AutoCommit = true;
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = testBeginTransactionEnv;
  			dbConfig.Duplicates = DuplicatesPolicy.NONE;
  			dbConfig.FreeThreaded = true;
  			testBeginTransactionDB = BTreeDatabase.Open(
  			    testName + ".db", dbConfig);
  
  			testBeginTransactionDB.Put(
  			    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
  			    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")));
  
  			// Begin two threads to run dead lock detection.
  			Thread thread1 = new Thread(new ThreadStart(
  			    DeadLockThreadWithLockTimeOut));
  			Thread thread2 = new Thread(new ThreadStart(
  			    DeadLockThreadWithTxnTimeout));
  			signal = new EventWaitHandle(false, EventResetMode.ManualReset);
  			thread1.Start();
  			thread2.Start();
  			Thread.Sleep(1000);
  			signal.Set();
  			thread1.Join();
  			thread2.Join();
  
  			// Close all.
  			testBeginTransactionDB.Close();
  			testBeginTransactionEnv.Close();
  		}
  
  		public void DeadLockThreadWithLockTimeOut()
  		{
  			// Configure and begin a transaction.
  			TransactionConfig txnConfig = new TransactionConfig();
  			txnConfig.LockTimeout = 5000;
  			txnConfig.Name = "DeadLockThreadWithLockTimeOut";
  			Transaction txn = 
  			    testBeginTransactionEnv.BeginTransaction(txnConfig, null);
  			try
  			{
  				testBeginTransactionDB.Put(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")));
  				signal.WaitOne();
  				testBeginTransactionDB.Put(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newkey")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newdata")),
  				    txn);
  				txn.Commit();
  			}
  			catch (DeadlockException)
  			{
  				try
  				{
  					txn.Abort();
  				}
  				catch (DatabaseException)
  				{
  					throw new TestException();
  				}
  			}
  			catch (DatabaseException)
  			{
  				try
  				{
  					txn.Abort();
  				}
  				catch (DatabaseException)
  				{
  					throw new TestException();
  				}
  			}
  		}
  
  		public void DeadLockThreadWithTxnTimeout()
  		{
  			// Configure and begin a transaction.
  			TransactionConfig txnConfig = new TransactionConfig();
  			txnConfig.TxnTimeout = 5000;
  			txnConfig.Name = "DeadLockThreadWithTxnTimeout";
  			Transaction txn =
  			    testBeginTransactionEnv.BeginTransaction(txnConfig, null);
  			try
  			{
  				testBeginTransactionDB.Put(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")));
  				signal.WaitOne();
  				testBeginTransactionDB.Put(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newkey")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newdata")),
  				    txn);
  				txn.Commit();
  			}
  			catch (DeadlockException)
  			{
  				try
  				{
  					txn.Abort();
  				}
  				catch (DatabaseException)
  				{
  					throw new TestException();
  				}
  			}
  			catch (DatabaseException)
  			{
  				try
  				{
  					txn.Abort();
  				}
  				catch (DatabaseException)
  				{
  					throw new TestException();
  				}
  			}
  		}
  
  		[Test]
  		public void TestBlob()
  		{
  			testName = "TestBlob";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.AutoCommit = true;
  			envConfig.Create = true;
  			envConfig.UseMPool = true;
  			envConfig.UseLogging = true;
  			envConfig.UseTxns = true;
  
  			// Not set the blob file directory when enabling blob.
  			envConfig.BlobThreshold = 10485760;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    testHome, envConfig);
  			Assert.AreEqual(null, env.BlobDir);
  			Assert.AreEqual(10485760, env.BlobThreshold);
  			env.Close();
  
  			Configuration.ClearDir(testHome);
  
  			// Set the blob file directory with an empty string.
  			envConfig.BlobDir = "";
  			env = DatabaseEnvironment.Open(testHome, envConfig);
  			Assert.AreEqual("", env.BlobDir);
  			Assert.AreEqual(10485760, env.BlobThreshold);
  			env.Close();
  
  			Configuration.ClearDir(testHome);
  
  			// Set the blob file directory with a non-emptry
  			// string.
  			envConfig.BlobDir = "BLOBDIR";
  			env = DatabaseEnvironment.Open(testHome, envConfig);
  			Assert.AreEqual("BLOBDIR", env.BlobDir);
  			Assert.AreEqual(10485760, env.BlobThreshold);
  			env.Close();
  		}
  
  		[Test]
  		public void TestCheckpoint()
  		{
  			testName = "TestCheckpoint";
  			SetUpTest(true);
  
  			// Open an environment.
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseTxns = true;
  			cfg.UseMPool = true;
  			cfg.UseLogging = true;
  			cfg.UseLocking = true;
  			cfg.NoLocking = false;
  			cfg.FreeThreaded = true;
  			testCheckpointEnv = DatabaseEnvironment.Open(testHome, cfg);
  
  			// Open btree database.
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.AutoCommit = true;
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = testCheckpointEnv;
  			dbConfig.FreeThreaded = true;
  			testCheckpointDB = BTreeDatabase.Open(testName + ".db", dbConfig);
  
  			// Run a thread to put records into database.
  			Thread thread1 = new Thread(new ThreadStart(PutRecordsThread));
  
  			/*
  			 * Run a thread to do checkpoint periodically and
  			 * finally do a checkpoint to flush all in memory pool
  			 * to log files.
  			 */
  			Thread thread2 = new Thread(new ThreadStart(CheckpointThread));
  
  			thread1.Start();
  			thread2.Start();
  			thread1.Join();
  			thread2.Join();
  
  			// Close all.
  			testCheckpointDB.Close();
  			testCheckpointEnv.Close();
  		}
  
  		public void PutRecordsThread()
  		{
  			Transaction txn = testCheckpointEnv.BeginTransaction();
  			byte[] byteArr = new byte[1024];
  			for (int i = 0; i < 1000; i++)
  				testCheckpointDB.Put(
  				    new DatabaseEntry(BitConverter.GetBytes(i)),
  				    new DatabaseEntry(byteArr), txn);
  			txn.Commit();
  		}
  
  		public void CheckpointThread()
  		{
  			uint bytes = 64;
  			uint minutes = 1;
  			uint count = 1;
  			while (count < 3)
  			{
  				testCheckpointEnv.Checkpoint(bytes, minutes);
  				count++;
  			}
  			Thread.Sleep(500);
  			testCheckpointEnv.Checkpoint();
  		}
  
  		[Test]
  		public void TestClose()
  		{
  			testName = "TestClose";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    testHome, cfg);
  			env.Close();
  		}
  
  		[Test]
  		public void TestConfigAll()
  		{
  			testName = "TestConfigAll";
  			SetUpTest(true);
  
  			XmlElement xmlElem = Configuration.TestSetUp(
  			    testFixtureName, testName);
  
  			/*
  			 * Open a new environment with all properties,
  			 * fields and subsystems configured.
  			 */
  			DatabaseEnvironmentConfig envConig =
  			    new DatabaseEnvironmentConfig();
  			Config(xmlElem, ref envConig, true, true, true,
  			    true, true, true);
  
  			// Configure with methods.
  			ReplicationHostAddress address =
  			    new ReplicationHostAddress("127.0.0.0", 11111);
  			envConig.RepSystemCfg.Clockskew(102, 100);
  			envConig.RepSystemCfg.RetransmissionRequest(10, 100);
  			envConig.RepSystemCfg.TransmitLimit(1, 1024);
  
  			// Open the environment.
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    testHome, envConig);
  
  			// Confirm environment status with its configuration.
  			Confirm(xmlElem, env, true, true, true, true, true, true);
  
  			// Print statistics of the current environment.
  			env.Msgfile = testHome + "/" + testName+ ".log";
  			env.PrintStats(true, true);
  
  			// Print statistics of all subsytems.
  			env.PrintSubsystemStats(true, true);
  
  			env.Close();
  		}
  
  		[Test]
  		public void TestDeadlockPolicy()
  		{
  			testName = "TestDeadlockPolicy";
  			SetUpTest(true);
  
  			DetectDeadlockPolicy(testHome + "_DEFAULT",
  			    DeadlockPolicy.DEFAULT);
  
  			DetectDeadlockPolicy(testHome + "_EXPIRE",
  			    DeadlockPolicy.EXPIRE);
  			DetectDeadlockPolicy(testHome + "_MAX_LOCKS",
  			    DeadlockPolicy.MAX_LOCKS);
  			DetectDeadlockPolicy(testHome + "_MAX_WRITE",
  			    DeadlockPolicy.MAX_WRITE);
  			DetectDeadlockPolicy(testHome + "_MIN_LOCKS",
  			    DeadlockPolicy.MIN_LOCKS);
  			DetectDeadlockPolicy(testHome + "_MIN_WRITE",
  			    DeadlockPolicy.MIN_WRITE);
  			DetectDeadlockPolicy(testHome + "_OLDEST",
  			    DeadlockPolicy.OLDEST);
  			DetectDeadlockPolicy(testHome + "_RANDOM",
  			    DeadlockPolicy.RANDOM);
  			DetectDeadlockPolicy(testHome + "_YOUNGEST",
  			    DeadlockPolicy.YOUNGEST);
  		}
  
  		public void DetectDeadlockPolicy(
  		    string home, DeadlockPolicy deadlock)
  		{
  			Configuration.ClearDir(home);
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.Create = true;
  			envConfig.UseLocking = true;
  			envConfig.UseLogging = true;
  			envConfig.UseMPool = true;
  			envConfig.UseTxns = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(
  			    home, envConfig);
  			env.DeadlockResolution = deadlock;
  			Assert.AreEqual(deadlock, env.DeadlockResolution);
  			env.DetectDeadlocks(deadlock);
  			env.Close();
  		}
  
  		[Test]
  		public void TestDetectDeadlocks()
  		{
  			testName = "TestDetectDeadlocks";
  			SetUpTest(true);
  
  			// Open an environment.
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseTxns = true;
  			cfg.UseMPool = true;
  			cfg.UseLogging = true;
  			cfg.UseLocking = true;
  			cfg.FreeThreaded = true;
  			testDetectDeadlocksEnv = DatabaseEnvironment.Open(
  			    testHome, cfg);
  
  			// Open btree database.
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.AutoCommit = true;
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = testDetectDeadlocksEnv;
  			dbConfig.Duplicates = DuplicatesPolicy.NONE;
  			dbConfig.FreeThreaded = true;
  			testDetectDeadlocksDB = BTreeDatabase.Open(
  			    testName + ".db", dbConfig);
  
  			// Put one record("key", "data") into database.
  			testDetectDeadlocksDB.Put(
  			    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
  			    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")));
  
  			// Begin two threads to read and write record.
  			Thread thread1 = new Thread(new ThreadStart(ReadAndPutRecordThread));
  			Thread thread2 = new Thread(new ThreadStart(ReadAndPutRecordThread));
  			signal = new EventWaitHandle(false, EventResetMode.ManualReset);
  			thread1.Start();
  			thread2.Start();
  
  			// Give enough time for threads to read record.
  			Thread.Sleep(1000);
  
  			/*
  			 * Let the two threads apply for write lock
  			 * synchronously.
  			 */
  			signal.Set();
  
  			// Confirm that there is deadlock in the environment.
  			Thread.Sleep(1000);
  			uint deadlockNum = testDetectDeadlocksEnv.DetectDeadlocks(
  			    DeadlockPolicy.DEFAULT);
  			Assert.Less(0, deadlockNum);
  
  			thread1.Join();
  			thread2.Join();
  
  			// Close all.
  			testDetectDeadlocksDB.Close(false);
  			testDetectDeadlocksEnv.Close();
  		}
  
  		public void ReadAndPutRecordThread()
  		{
  			Transaction txn =
  			    testDetectDeadlocksEnv.BeginTransaction();
  			try
  			{
  				testDetectDeadlocksDB.GetBoth(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("data")), txn);
  				signal.WaitOne();
  				testDetectDeadlocksDB.Put(
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newKey")),
  				    new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("newData")),
  				    txn);
  				txn.Commit();
  			}
  			catch (DeadlockException)
  			{
  				txn.Abort();
  			}
  		}
  
  		[Test]
  		public void TestEncryption() 
  		{
  			testName = "TestEncryption";
  			SetUpTest(true);
  
  			// Open an encrypted environment.
  			DatabaseEnvironmentConfig envCfg =
  			    new DatabaseEnvironmentConfig();
  			envCfg.Create = true;
  			envCfg.UseMPool = true;
  			envCfg.UseLogging = true;
  			envCfg.UseTxns = true;
  			envCfg.SetEncryption("bdb", EncryptionAlgorithm.AES);
  			DatabaseEnvironment env =
  			DatabaseEnvironment.Open(testHome, envCfg);
  			Transaction txn = env.BeginTransaction();
  
  			// Open a non-encrypted database in the environment.
  			BTreeDatabaseConfig dbCfg =
  			    new BTreeDatabaseConfig();
  			dbCfg.Creation = CreatePolicy.IF_NEEDED;
  			dbCfg.Env = env;
  			BTreeDatabase db1 = BTreeDatabase.Open(
  			    testName + "1.db", dbCfg, txn);
  			Assert.IsFalse(db1.Encrypted);
  			for (int i = 0; i < 10; i++)
  				db1.Put(new DatabaseEntry(
  				    BitConverter.GetBytes(i)),
  				    new DatabaseEntry(
  				    BitConverter.GetBytes(i)), txn);
  
  			// Open an encrypted database in the environment.
  			dbCfg.Encrypted = true;
  			BTreeDatabase db2 = BTreeDatabase.Open(
  			    testName + "2.db", dbCfg, txn);
  			Assert.IsTrue(db2.Encrypted);
  			for (int i = 0; i < 10; i++)
  			db2.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
  			    new DatabaseEntry(BitConverter.GetBytes(i)), txn);
  
  			// Close all.
  			txn.Commit();
  			db1.Close();
  			db2.Close();
  			env.Close();
  
  			// Verify the environment is encrypted.
  			DatabaseEnvironmentConfig verifyEnvCfg =
  			    new DatabaseEnvironmentConfig();
  			verifyEnvCfg.Create = true;
  			verifyEnvCfg.UseMPool = true;
  			verifyEnvCfg.UseLogging = true;
  			verifyEnvCfg.UseTxns = true;
  			try {
  				env = DatabaseEnvironment.Open(
  				    testHome, verifyEnvCfg);
  				// Do nothing
  				env.Close();
  				throw new TestException();
  			} catch (DatabaseException) {
  			}
  
  			// Verify the non-encrypted database is not encrypted.
  			BTreeDatabaseConfig verifyDbCfg =
  			    new BTreeDatabaseConfig();
  			verifyDbCfg.Creation = CreatePolicy.IF_NEEDED;
  
  			using (db1 = BTreeDatabase.Open(
  			    testHome + "/" + testName + "1.db", verifyDbCfg)) {
  				for (int i = 0; i < 10; i++)
  					db1.Get(new DatabaseEntry(
  					    BitConverter.GetBytes(i)));
  			};
  
  			/// Verify the encrypted database is encrypted.
  			verifyDbCfg.SetEncryption(envCfg.EncryptionPassword,
  			    envCfg.EncryptAlgorithm);
  			verifyDbCfg.Encrypted = true;
  			using (db1 = BTreeDatabase.Open(
  			    testHome + "/" + testName + "2.db",
  			    verifyDbCfg)) {
  				for (int i = 0; i < 10; i++)
  					db1.Get(new DatabaseEntry(
  					    BitConverter.GetBytes(i)));
  			};
  		}
  
  		[Test]
  		public void TestFailCheck()
  		{
  			testName = "TestFailCheck";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseTxns = true;
  			cfg.UseMPool = true;
  			cfg.UseLogging = true;
  			cfg.UseLocking = true;
  			cfg.FreeThreaded = true;
  			cfg.ThreadIsAlive = new ThreadIsAliveDelegate(ThrdAlive);
  			cfg.SetThreadID = new SetThreadIDDelegate(SetThrdID);
  			cfg.ThreadCount = 10;
  			testFailCheckEnv = DatabaseEnvironment.Open(testHome, cfg);
  
  			Thread thread = new Thread(new ThreadStart(WriteThreadWithoutTxnCommit));
  			thread.Start();
  			thread.Join();
  			testFailCheckEnv.FailCheck();
  			testFailCheckEnv.Close();
  		}
  
  		public void WriteThreadWithoutTxnCommit()
  		{
  			Transaction txn = testFailCheckEnv.BeginTransaction();
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = testFailCheckEnv;
  			BTreeDatabase db = BTreeDatabase.Open("TestFailCheck.db", dbConfig, txn);
  			db.Close();
  			txn.Commit();
  		}
  
  		public bool ThrdAlive(DbThreadID info, bool procOnly)
  		{
  			Process pcs = Process.GetProcessById(info.processID);
  			if (pcs.HasExited == true)
  				return false;
  			else if (procOnly)
  				return true;
  			ProcessThreadCollection thrds = pcs.Threads;
  			foreach (ProcessThread pcsThrd in thrds)
  			{
  				if (pcsThrd.Id == info.threadID)
  				{
  					/*
  					 * We have to use the fully qualified name, ThreadState
  					 * defaults to System.Threading.ThreadState.
  					 */
  					return (pcsThrd.ThreadState !=
  						System.Diagnostics.ThreadState.Terminated);
  				}
  			}
  			// If we can't find the thread, we say it's not alive
  			return false;
  		}
  
  		public DbThreadID SetThrdID()
  		{
  			DbThreadID threadID;
  
  			int pid = Process.GetCurrentProcess().Id;
  			uint tid = (uint)AppDomain.GetCurrentThreadId();
  			threadID = new DbThreadID(pid, tid);
  			return threadID;
  		}
  
  		[Test]
  		public void TestFeedback()
  		{
  			testName = "TestFeedback";
  			SetUpTest(true);
  
  			// Open the environment.
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.AutoCommit = true;
  			cfg.UseLocking = true;
  			cfg.UseLogging = true;
  			cfg.UseMPool = true;
  			cfg.UseTxns = true;
  			cfg.Create = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(testHome, cfg);
  
  			env.Feedback = new EnvironmentFeedbackDelegate(
  			    EnvRecovery10PercentFeedback);
  			env.Feedback(EnvironmentFeedbackEvent.RECOVERY, 10);
  
  			env.Close();
  		}
  
  		public void EnvRecovery10PercentFeedback(
  		    EnvironmentFeedbackEvent opcode, int percent)
  		{
  			Assert.AreEqual(opcode, EnvironmentFeedbackEvent.RECOVERY);
  			Assert.AreEqual(10, percent);
  		}
  
  		[Test]
  		public void TestMessageCall()
  		{
  			testName = "TestMessageCall";
  			SetUpTest(true);
  
  			// Configure and open an environment.
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.Create = true;
  			envConfig.UseMPool = true;
  			DatabaseEnvironment env =
  			    DatabaseEnvironment.Open(testHome, envConfig);
  
  			// Confirm message file does not exist.
  			string messageCallFile = testHome + "/" + "MessageCallFile";
  			Assert.AreEqual(false, File.Exists(messageCallFile));
  
  			string messageInfo = "Message come from db.set_msgcall!";
  
  			// Call set_msgcall() of env.
  			env.messageFeedback = new MessageFeedbackDelegate(Msgcall_fcn);
  			env.messageFeedback(messageInfo);
  
  			// Unconfigures the callback interface.
  			env.messageFeedback = null;
  
  			// Confirm message file exists now.
  			Assert.AreEqual(true, File.Exists(messageCallFile));
  
  			// Read the first line of message file.
  			string line = null;
  			System.IO.StreamReader file = new System.IO.StreamReader(@"" + messageCallFile);
  			line = file.ReadLine();
  
  			// Confirm the message file is not empty.
  			Assert.AreEqual(line, messageInfo);
  
  			file.Close();
  			env.Close();
  		}
  
  		public void Msgcall_fcn(string message)
  		{
  			string msgfile = testHome + "/" + "MessageCallFile";
  			FileStream fs = new FileStream(msgfile, FileMode.OpenOrCreate);
  			StreamWriter sw = new StreamWriter(fs);
  			sw.Write(message);
  			sw.Flush();
  			sw.Close();
  			fs.Close();
  		}
  
  		[Test]
  		public void TestMessageFile()
  		{
  			testName = "TestMessageFile";
  			SetUpTest(true);
  
  			// Configure and open an environment.
  			DatabaseEnvironmentConfig envConfig =
  			    new DatabaseEnvironmentConfig();
  			envConfig.Create = true;
  			envConfig.UseMPool = true;
  			DatabaseEnvironment env =
  			    DatabaseEnvironment.Open(testHome, envConfig);
  
  			// Confirm message file does not exist.
  			string messageFile = testHome + "/" + "msgfile";
  			Assert.AreEqual(false, File.Exists(messageFile));
  
  			// Call set_msgfile() of db.
  			env.Msgfile = messageFile;
  
  			// Print db statistic to message file.
  			env.PrintStats(true, true);
  
  			// Confirm message file exists now.
  			Assert.AreEqual(true, File.Exists(messageFile));
  
  			env.Msgfile = "";
  			string line = null;
  
  			// Read the third line of message file.
  			System.IO.StreamReader file = new System.IO.StreamReader(@"" + messageFile);
  			line = file.ReadLine();
  			line = file.ReadLine();
  			line = file.ReadLine();
  
  			// Confirm the message file is not empty.
  			Assert.AreEqual(line, "Default database environment information:");
  
  			file.Close();
  			env.Close();
  		}
  
  		[Test]
  		public void TestMetadataDir()
  		{
  			testName = "TestMetadataDir";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseLocking = true;
  			cfg.UseLogging = true;
  			cfg.UseMPool = true;
  			cfg.UseReplication = true;
  			cfg.UseTxns = true;
  
  			// Metadata Directory defaults to NULL
  			DatabaseEnvironment env =
  			    DatabaseEnvironment.Open(testHome, cfg);
  			Assert.Null(env.MetadataDir);
  			env.Close();
  			int cnt = Directory.GetFiles(
  			    testHome, "__db.rep.system*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.gen*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.egen*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.init*").Length;
  			Assert.Less(0, cnt);
  
  			// Set Metadata Directory
  			Configuration.ClearDir(testHome);
  			string md = testHome + "/" + "Meta";
  			Directory.CreateDirectory(md);
  			cfg.MetadataDir = "Meta";
  			env = DatabaseEnvironment.Open(testHome, cfg);
  			Assert.AreEqual("Meta", env.MetadataDir);
  			env.Close();
  			cnt = Directory.GetFiles(
  			    testHome, "__db.rep.system*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.gen*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.egen*").Length +
  			    Directory.GetFiles(
  			    testHome, "__db.rep.init*").Length;
  			Assert.AreEqual(0, cnt);
  			cnt =
  			    Directory.GetFiles(md, "__db.rep.system*").Length +
  			    Directory.GetFiles(md, "__db.rep.gen*").Length +
  			    Directory.GetFiles(md, "__db.rep.egen*").Length +
  			    Directory.GetFiles(md, "__db.rep.init*").Length;
  			Assert.Less(0, cnt);
  		}
  
  		[Test]
  		public void TestMutexSystemStats()
  		{
  			testName = "TestMutexSystemStats";
  			SetUpTest(true);
  
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseLogging = true;
  			cfg.UseLocking = true;
  			cfg.UseMPool = true;
  			cfg.UseTxns = true;
  			cfg.MutexSystemCfg = new MutexConfig();
  			cfg.MutexSystemCfg.Alignment = 512;
  			cfg.MutexSystemCfg.Increment = 128;
  			cfg.MutexSystemCfg.MaxMutexes = 150;
  			cfg.MutexSystemCfg.NumTestAndSetSpins = 10;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(testHome, cfg);
  
  			MutexStats stats = env.MutexSystemStats();
  			env.Msgfile = testHome + "/" + testName+ ".log";
  			env.PrintMutexSystemStats(true, true);
  			Assert.AreEqual(512, stats.Alignment);
  			Assert.AreEqual(stats.Count, stats.Available + stats.InUse);
  			Assert.LessOrEqual(stats.InUse, stats.MaxInUse);
  			Assert.AreNotEqual(0, stats.InitCount);
  			Assert.AreNotEqual(0, stats.Max);
  			Assert.AreNotEqual(0, stats.RegionMax);
  			Assert.AreNotEqual(0, stats.RegionSize);
  			Assert.AreEqual(0, stats.RegionWait);
  			Assert.AreEqual(10, stats.TASSpins);
  			ulong regionNoWait = stats.RegionNoWait;
  
  			BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
  			dbCfg.Creation = CreatePolicy.IF_NEEDED;
  			dbCfg.Env = env;
  			BTreeDatabase db = BTreeDatabase.Open(testName + ".db", dbCfg);
  			for (int i = 0; i < 1000; i++)
  			{
  				db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
  				    new DatabaseEntry(BitConverter.GetBytes(i)));
  				stats = env.MutexSystemStats();
  			}
  			Assert.LessOrEqual(regionNoWait, stats.RegionNoWait);
  			regionNoWait = stats.RegionNoWait;
  
  			stats = env.MutexSystemStats(true);
  			env.PrintMutexSystemStats();
  			stats = env.MutexSystemStats();
  			Assert.GreaterOrEqual(regionNoWait, stats.RegionNoWait);
  
  			db.Close();
  			env.Close();
  		}
  
  		[Test]
  		public void TestMutexStatPrint()
  		{
  			testName = "TestMutexStatPrint";
  			SetUpTest(true);
  
  			string[] messageInfo = new string[]
  			{ 
  			  "Mutex region size",
  			  "Mutex region max size",
  			  "The number of region locks that required waiting (0%)",
  			  "Mutex alignment",
  			  "Mutex test-and-set spins",
  			  "Mutex initial count",
  			  "Mutex total count",
  			  "Mutex max count",
  			  "Mutex free count",
  			  "Mutex in-use count",
  			  "Mutex maximum in-use count",
  			  "",
  			  "Unallocated",
  			  "env region",
  			  "mutex region",
  			};
  
  			// Configure and open an environment.
  			DatabaseEnvironmentConfig envConfig =
  			new DatabaseEnvironmentConfig();
  			envConfig.Create = true;
  			envConfig.MutexSystemCfg = new MutexConfig();
  			envConfig.MutexSystemCfg.Alignment = 512;
  			envConfig.MutexSystemCfg.Increment = 128;
  			envConfig.MutexSystemCfg.MaxMutexes = 150;
  			envConfig.MutexSystemCfg.NumTestAndSetSpins = 10;
  
  			DatabaseEnvironment env =
  			    DatabaseEnvironment.Open(testHome, envConfig);
  
  			// Confirm message file does not exist.
  			string messageFile = testHome + "/" + "msgfile";
  			Assert.AreEqual(false, File.Exists(messageFile));
  
  			// Call set_msgfile() of env.
  			env.Msgfile = messageFile;
  
  			// Print env statistic to message file.
  			env.PrintMutexSystemStats();
  
  			// Confirm message file exists now.
  			Assert.AreEqual(true, File.Exists(messageFile));
  
  			env.Msgfile = "";
  			int counter = 0;
  			string line;
  			line = null;
  
  			// Read the message file line by line.
  			System.IO.StreamReader file = new System.IO.StreamReader(@"" + messageFile);
  			while ((line = file.ReadLine()) != null)
  			{
  				string[] tempStr = line.Split('\t');
  				// Confirm the content of the message file.
  				if (tempStr[0] != "Mutex counts")
  				{
  					Assert.AreEqual(tempStr[1], messageInfo[counter]);
  				}
  				counter++;
  			}
  			Assert.AreNotEqual(0, counter);
  
  			file.Close();
  			env.Close();
  		}
  
  		[Test]
  		public void TestLogFile()
  		{
  			testName = "TestLogFile";
  			SetUpTest(true);
  
  			// Open environment and configure logging subsystem.
  			DatabaseEnvironmentConfig cfg =
  			    new DatabaseEnvironmentConfig();
  			cfg.Create = true;
  			cfg.UseTxns = true;
  			cfg.AutoCommit = true;
  			cfg.UseLocking = true;
  			cfg.UseMPool = true;
  			cfg.UseLogging = true;
  			cfg.MPoolSystemCfg = new MPoolConfig();
  			cfg.MPoolSystemCfg.CacheSize = 
  			    new CacheInfo(0, 1048576, 1);
  			cfg.LogSystemCfg = new LogConfig();
  			cfg.LogSystemCfg.AutoRemove = false;
  			cfg.LogSystemCfg.BufferSize = 10240;
  			cfg.LogSystemCfg.Dir = "./";
  			cfg.LogSystemCfg.FileMode = 755;
  			cfg.LogSystemCfg.ForceSync = true;
  			cfg.LogSystemCfg.InMemory = false;
  			cfg.LogSystemCfg.LogBlobContent = false;
  			cfg.LogSystemCfg.MaxFileSize = 1048576;
  			cfg.LogSystemCfg.NoBuffer = false;
  			cfg.LogSystemCfg.NoSync = true;
  			cfg.LogSystemCfg.RegionSize = 204800;
  			cfg.LogSystemCfg.ZeroOnCreate = true;
  			DatabaseEnvironment env = DatabaseEnvironment.Open(testHome, cfg);
  
  			// Open database.
  			Transaction allTxn = env.BeginTransaction();
  			TransactionConfig txnConfig = new TransactionConfig();
  			txnConfig.Name = "OpenTransaction";
  			Transaction openTxn = env.BeginTransaction(txnConfig, allTxn);
  			BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();
  			dbConfig.Creation = CreatePolicy.IF_NEEDED;
  			dbConfig.Env = env;
  			BTreeDatabase db = BTreeDatabase.Open(
  			    testName + ".db", dbConfig, openTxn);
  
  			List<ActiveTransaction> activeTxns =
  			    env.TransactionSystemStats().Transactions;
  			for (int i = 0; i < activeTxns.Count; i++)
  				if (activeTxns[i].Name == "OpenTransaction")
  				{
  					LSN lsn = new LSN(
  					    activeTxns[i].Begun.LogFileNumber,
  					    activeTxns[i].Begun.Offset);
  					env.LogFlush(lsn);
  					string fileName = env.LogFile(lsn);
  				}
  
  			openTxn.Commit();
  
  			// Write "##" to log before putting data into database.
  			env.WriteToLog("##");
  
  			// Write 1000 records into database.
  			TransactionConfig writeTxnConfig = new TransactionConfig();
  			writeTxnConfig.Name = "WriteTxn";
  			Transaction writeTxn = env.BeginTransaction(writeTxnConfig, allTxn);
  			byte[] byteArr = new byte[1024];
  			for (int i = 0; i < 1000; i++)
  			{
  				db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
  
gt: 				    new DatabaseEntry(byteArr), writeTxn);