mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
509 lines
14 KiB
C#
509 lines
14 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.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using NUnit.Framework;
|
|
using BerkeleyDB;
|
|
|
|
namespace CsharpAPITest
|
|
{
|
|
[TestFixture]
|
|
public class HashDatabaseTest : CSharpTestFixture
|
|
{
|
|
|
|
[TestFixtureSetUp]
|
|
public void SetUpTestFixture()
|
|
{
|
|
testFixtureName = "HashDatabaseTest";
|
|
base.SetUpTestfixture();
|
|
}
|
|
|
|
[Test]
|
|
public void TestCompactWithoutTxn() {
|
|
int i, nRecs;
|
|
nRecs = 10000;
|
|
testName = "TestCompactWithoutTxn";
|
|
SetUpTest(true);
|
|
string hashDBFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig hashDBConfig = new HashDatabaseConfig();
|
|
hashDBConfig.Creation = CreatePolicy.ALWAYS;
|
|
// The minimum page size
|
|
hashDBConfig.PageSize = 512;
|
|
hashDBConfig.HashComparison =
|
|
new EntryComparisonDelegate(dbIntCompare);
|
|
using (HashDatabase hashDB = HashDatabase.Open(
|
|
hashDBFileName, hashDBConfig)) {
|
|
DatabaseEntry key;
|
|
DatabaseEntry data;
|
|
|
|
// Fill the database with entries from 0 to 9999
|
|
for (i = 0; i < nRecs; i++) {
|
|
key = new DatabaseEntry(BitConverter.GetBytes(i));
|
|
data = new DatabaseEntry(BitConverter.GetBytes(i));
|
|
hashDB.Put(key, data);
|
|
}
|
|
|
|
/*
|
|
* Delete entries below 500, between 3000 and
|
|
* 5000 and above 7000
|
|
*/
|
|
for (i = 0; i < nRecs; i++)
|
|
if (i < 500 || i > 7000 || (i < 5000 && i > 3000)) {
|
|
key = new DatabaseEntry(BitConverter.GetBytes(i));
|
|
hashDB.Delete(key);
|
|
}
|
|
|
|
hashDB.Sync();
|
|
long fileSize = new FileInfo(hashDBFileName).Length;
|
|
|
|
// Compact database
|
|
CompactConfig cCfg = new CompactConfig();
|
|
cCfg.FillPercentage = 30;
|
|
cCfg.Pages = 10;
|
|
cCfg.Timeout = 1000;
|
|
cCfg.TruncatePages = true;
|
|
cCfg.start = new DatabaseEntry(BitConverter.GetBytes(1));
|
|
cCfg.stop = new DatabaseEntry(BitConverter.GetBytes(7000));
|
|
CompactData compactData = hashDB.Compact(cCfg);
|
|
Assert.IsFalse((compactData.Deadlocks == 0) &&
|
|
(compactData.Levels == 0) &&
|
|
(compactData.PagesExamined == 0) &&
|
|
(compactData.PagesFreed == 0) &&
|
|
(compactData.PagesTruncated == 0));
|
|
|
|
hashDB.Sync();
|
|
long compactedFileSize = new FileInfo(hashDBFileName).Length;
|
|
Assert.Less(compactedFileSize, fileSize);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TestHashComparison()
|
|
{
|
|
testName = "TestHashComparison";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig dbConfig = new HashDatabaseConfig();
|
|
dbConfig.Creation = CreatePolicy.IF_NEEDED;
|
|
dbConfig.HashComparison = new EntryComparisonDelegate(EntryComparison);
|
|
HashDatabase db = HashDatabase.Open(dbFileName,dbConfig);
|
|
int ret;
|
|
|
|
/*
|
|
* Comparison gets the value that lowest byte of the
|
|
* former dbt minus that of the latter one.
|
|
*/
|
|
ret = db.Compare(new DatabaseEntry(BitConverter.GetBytes(2)),
|
|
new DatabaseEntry(BitConverter.GetBytes(2)));
|
|
Assert.AreEqual(0, ret);
|
|
|
|
ret = db.Compare(new DatabaseEntry(BitConverter.GetBytes(256)),
|
|
new DatabaseEntry(BitConverter.GetBytes(1)));
|
|
Assert.Greater(0, ret);
|
|
|
|
db.Close();
|
|
}
|
|
|
|
public int EntryComparison(DatabaseEntry dbt1,
|
|
DatabaseEntry dbt2)
|
|
{
|
|
return dbt1.Data[0] - dbt2.Data[0];
|
|
}
|
|
|
|
[Test]
|
|
public void TestHashFunction()
|
|
{
|
|
testName = "TestHashFunction";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig dbConfig = new HashDatabaseConfig();
|
|
dbConfig.Creation = CreatePolicy.IF_NEEDED;
|
|
dbConfig.HashFunction = new HashFunctionDelegate(HashFunction);
|
|
HashDatabase db = HashDatabase.Open(dbFileName, dbConfig);
|
|
|
|
// Hash function will change the lowest byte to 0;
|
|
uint data = db.HashFunction(BitConverter.GetBytes(1));
|
|
Assert.AreEqual(0, data);
|
|
db.Close();
|
|
}
|
|
|
|
public uint HashFunction(byte[] data)
|
|
{
|
|
data[0] = 0;
|
|
return BitConverter.ToUInt32(data, 0);
|
|
}
|
|
|
|
[Test]
|
|
public void TestOpenExistingHashDB()
|
|
{
|
|
testName = "TestOpenExistingHashDB";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig hashConfig =
|
|
new HashDatabaseConfig();
|
|
hashConfig.Creation = CreatePolicy.ALWAYS;
|
|
HashDatabase hashDB = HashDatabase.Open(dbFileName, hashConfig);
|
|
hashDB.Close();
|
|
|
|
DatabaseConfig dbConfig = new DatabaseConfig();
|
|
Database db = Database.Open(dbFileName, dbConfig);
|
|
Assert.AreEqual(db.Type, DatabaseType.HASH);
|
|
db.Close();
|
|
}
|
|
|
|
[Test]
|
|
public void TestOpenNewHashDB()
|
|
{
|
|
testName = "TestOpenNewHashDB";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
XmlElement xmlElem = Configuration.TestSetUp(testFixtureName, testName);
|
|
HashDatabaseConfig hashConfig = new HashDatabaseConfig();
|
|
HashDatabaseConfigTest.Config(xmlElem, ref hashConfig, true);
|
|
HashDatabase hashDB = HashDatabase.Open(dbFileName, hashConfig);
|
|
Confirm(xmlElem, hashDB, true);
|
|
hashDB.Close();
|
|
}
|
|
|
|
[Test, ExpectedException(typeof(ExpectedTestException))]
|
|
public void TestPutNoDuplicateWithUnsortedDuplicate()
|
|
{
|
|
testName = "TestPutNoDuplicateWithUnsortedDuplicate";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig hashConfig = new HashDatabaseConfig();
|
|
hashConfig.Creation = CreatePolicy.ALWAYS;
|
|
hashConfig.Duplicates = DuplicatesPolicy.UNSORTED;
|
|
hashConfig.ErrorPrefix = testName;
|
|
|
|
HashDatabase hashDB = HashDatabase.Open(dbFileName, hashConfig);
|
|
DatabaseEntry key, data;
|
|
key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("1"));
|
|
data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("1"));
|
|
|
|
try
|
|
{
|
|
hashDB.PutNoDuplicate(key, data);
|
|
}
|
|
catch (DatabaseException)
|
|
{
|
|
throw new ExpectedTestException();
|
|
}
|
|
finally
|
|
{
|
|
hashDB.Close();
|
|
}
|
|
}
|
|
|
|
[Test, ExpectedException(typeof(ExpectedTestException))]
|
|
public void TestKeyExistException()
|
|
{
|
|
testName = "TestKeyExistException";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig hashConfig = new HashDatabaseConfig();
|
|
hashConfig.Creation = CreatePolicy.ALWAYS;
|
|
hashConfig.Duplicates = DuplicatesPolicy.SORTED;
|
|
HashDatabase hashDB = HashDatabase.Open(dbFileName, hashConfig);
|
|
|
|
// Put the same record into db twice.
|
|
DatabaseEntry key, data;
|
|
key = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("1"));
|
|
data = new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("1"));
|
|
try
|
|
{
|
|
hashDB.PutNoDuplicate(key, data);
|
|
hashDB.PutNoDuplicate(key, data);
|
|
}
|
|
catch (KeyExistException)
|
|
{
|
|
throw new ExpectedTestException();
|
|
}
|
|
finally
|
|
{
|
|
hashDB.Close();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TestPutNoDuplicate()
|
|
{
|
|
testName = "TestPutNoDuplicate";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig hashConfig =
|
|
new HashDatabaseConfig();
|
|
hashConfig.Creation = CreatePolicy.ALWAYS;
|
|
hashConfig.Duplicates = DuplicatesPolicy.SORTED;
|
|
hashConfig.TableSize = 20;
|
|
HashDatabase hashDB = HashDatabase.Open(dbFileName, hashConfig);
|
|
|
|
DatabaseEntry key, data;
|
|
for (int i = 1; i <= 10; i++)
|
|
{
|
|
key = new DatabaseEntry(BitConverter.GetBytes(i));
|
|
data = new DatabaseEntry(BitConverter.GetBytes(i));
|
|
hashDB.PutNoDuplicate(key, data);
|
|
}
|
|
|
|
Assert.IsTrue(hashDB.Exists(
|
|
new DatabaseEntry(BitConverter.GetBytes((int)5))));
|
|
|
|
hashDB.Close();
|
|
}
|
|
|
|
[Test, ExpectedException(typeof(ExpectedTestException))]
|
|
public void TestPutNoDuplicateWithTxn()
|
|
{
|
|
testName = "TestPutNoDuplicateWithTxn";
|
|
SetUpTest(true);
|
|
|
|
// Open an environment.
|
|
DatabaseEnvironmentConfig envConfig =
|
|
new DatabaseEnvironmentConfig();
|
|
envConfig.Create = true;
|
|
envConfig.UseLogging = true;
|
|
envConfig.UseMPool = true;
|
|
envConfig.UseTxns = true;
|
|
DatabaseEnvironment env = DatabaseEnvironment.Open(
|
|
testHome, envConfig);
|
|
|
|
// Open a hash database within a transaction.
|
|
Transaction txn = env.BeginTransaction();
|
|
HashDatabaseConfig dbConfig = new HashDatabaseConfig();
|
|
dbConfig.Creation = CreatePolicy.IF_NEEDED;
|
|
dbConfig.Duplicates = DuplicatesPolicy.SORTED;
|
|
dbConfig.Env = env;
|
|
HashDatabase db = HashDatabase.Open(testName + ".db", dbConfig, txn);
|
|
|
|
DatabaseEntry dbt = new DatabaseEntry(BitConverter.GetBytes((int)100));
|
|
db.PutNoDuplicate(dbt, dbt, txn);
|
|
try
|
|
{
|
|
db.PutNoDuplicate(dbt, dbt, txn);
|
|
}
|
|
catch (KeyExistException)
|
|
{
|
|
throw new ExpectedTestException();
|
|
}
|
|
finally
|
|
{
|
|
// Close all.
|
|
db.Close();
|
|
txn.Commit();
|
|
env.Close();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void TestStats()
|
|
{
|
|
testName = "TestStats";
|
|
SetUpTest(true);
|
|
string dbFileName = testHome + "/" + testName + ".db";
|
|
|
|
HashDatabaseConfig dbConfig = new HashDatabaseConfig();
|
|
ConfigCase1(dbConfig);
|
|
HashDatabase db = HashDatabase.Open(dbFileName, dbConfig);
|
|
|
|
HashStats stats = db.Stats();
|
|
HashStats fastStats = db.FastStats();
|
|
ConfirmStatsPart1Case1(stats);
|
|
ConfirmStatsPart1Case1(fastStats);
|
|
|
|
// Put 100 records into the database.
|
|
PutRecordCase1(db, null);
|
|
|
|
stats = db.Stats();
|
|
ConfirmStatsPart2Case1(stats);
|
|
|
|
// Delete some data to get some free pages.
|
|
byte[] bigArray = new byte[262144];
|
|
db.Delete(new DatabaseEntry(bigArray));
|
|
stats = db.Stats();
|
|
ConfirmStatsPart3Case1(stats);
|
|
|
|
db.Close();
|
|
}
|
|
|
|
[Test]
|
|
public void TestStatsInTxn()
|
|
{
|
|
testName = "TestStatsInTxn";
|
|
SetUpTest(true);
|
|
|
|
StatsInTxn(testHome, testName, false);
|
|
}
|
|
|
|
[Test]
|
|
public void TestStatsWithIsolation()
|
|
{
|
|
testName = "TestStatsWithIsolation";
|
|
SetUpTest(true);
|
|
|
|
StatsInTxn(testHome, testName, true);
|
|
}
|
|
|
|
private int dbIntCompare(DatabaseEntry dbt1, DatabaseEntry dbt2) {
|
|
int a, b;
|
|
a = BitConverter.ToInt32(dbt1.Data, 0);
|
|
b = BitConverter.ToInt32(dbt2.Data, 0);
|
|
return a - b;
|
|
}
|
|
|
|
public void StatsInTxn(string home, string name, bool ifIsolation)
|
|
{
|
|
DatabaseEnvironmentConfig envConfig =
|
|
new DatabaseEnvironmentConfig();
|
|
EnvConfigCase1(envConfig);
|
|
DatabaseEnvironment env = DatabaseEnvironment.Open(home, envConfig);
|
|
|
|
Transaction openTxn = env.BeginTransaction();
|
|
HashDatabaseConfig dbConfig = new HashDatabaseConfig();
|
|
ConfigCase1(dbConfig);
|
|
dbConfig.Env = env;
|
|
HashDatabase db = HashDatabase.Open(name + ".db", dbConfig, openTxn);
|
|
openTxn.Commit();
|
|
|
|
Transaction statsTxn = env.BeginTransaction();
|
|
HashStats stats;
|
|
HashStats fastStats;
|
|
if (ifIsolation == false)
|
|
{
|
|
stats = db.Stats(statsTxn);
|
|
fastStats = db.Stats(statsTxn);
|
|
}
|
|
else
|
|
{
|
|
stats = db.Stats(statsTxn, Isolation.DEGREE_ONE);
|
|
fastStats = db.Stats(statsTxn, Isolation.DEGREE_ONE);
|
|
}
|
|
|
|
ConfirmStatsPart1Case1(stats);
|
|
|
|
// Put 100 records into the database.
|
|
PutRecordCase1(db, statsTxn);
|
|
|
|
if (ifIsolation == false)
|
|
stats = db.Stats(statsTxn);
|
|
else
|
|
stats = db.Stats(statsTxn, Isolation.DEGREE_TWO);
|
|
ConfirmStatsPart2Case1(stats);
|
|
|
|
// Delete some data to get some free pages.
|
|
byte[] bigArray = new byte[262144];
|
|
db.Delete(new DatabaseEntry(bigArray), statsTxn);
|
|
if (ifIsolation == false)
|
|
stats = db.Stats(statsTxn);
|
|
else
|
|
stats = db.Stats(statsTxn, Isolation.DEGREE_THREE);
|
|
ConfirmStatsPart3Case1(stats);
|
|
|
|
statsTxn.Commit();
|
|
db.Close();
|
|
env.Close();
|
|
}
|
|
|
|
public void EnvConfigCase1(DatabaseEnvironmentConfig cfg)
|
|
{
|
|
cfg.Create = true;
|
|
cfg.UseTxns = true;
|
|
cfg.UseMPool = true;
|
|
cfg.UseLogging = true;
|
|
}
|
|
|
|
public void ConfigCase1(HashDatabaseConfig dbConfig)
|
|
{
|
|
dbConfig.Creation = CreatePolicy.IF_NEEDED;
|
|
dbConfig.Duplicates = DuplicatesPolicy.UNSORTED;
|
|
dbConfig.FillFactor = 10;
|
|
dbConfig.TableSize = 20;
|
|
dbConfig.PageSize = 4096;
|
|
}
|
|
|
|
public void PutRecordCase1(HashDatabase db, Transaction txn)
|
|
{
|
|
byte[] bigArray = new byte[262144];
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
if (txn == null)
|
|
db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
|
|
new DatabaseEntry(BitConverter.GetBytes(i)));
|
|
else
|
|
db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
|
|
new DatabaseEntry(BitConverter.GetBytes(i)), txn);
|
|
}
|
|
for (int i = 50; i < 100; i++)
|
|
{
|
|
if (txn == null)
|
|
db.Put(new DatabaseEntry(bigArray),
|
|
new DatabaseEntry(bigArray));
|
|
else
|
|
db.Put(new DatabaseEntry(bigArray),
|
|
new DatabaseEntry(bigArray), txn);
|
|
}
|
|
}
|
|
|
|
public void ConfirmStatsPart1Case1(HashStats stats)
|
|
{
|
|
Assert.AreEqual(10, stats.FillFactor);
|
|
Assert.AreEqual(4096, stats.PageSize);
|
|
Assert.AreNotEqual(0, stats.Version);
|
|
}
|
|
|
|
public void ConfirmStatsPart2Case1(HashStats stats)
|
|
{
|
|
Assert.AreNotEqual(0, stats.BigPages);
|
|
Assert.AreNotEqual(0, stats.BigPagesFreeBytes);
|
|
Assert.AreNotEqual(0, stats.BucketPagesFreeBytes);
|
|
Assert.AreNotEqual(0, stats.DuplicatePages);
|
|
Assert.AreNotEqual(0, stats.DuplicatePagesFreeBytes);
|
|
Assert.AreNotEqual(0, stats.MagicNumber);
|
|
Assert.AreNotEqual(0, stats.MetadataFlags);
|
|
Assert.AreEqual(100, stats.nData);
|
|
Assert.AreNotEqual(0, stats.nHashBuckets);
|
|
Assert.AreEqual(51, stats.nKeys);
|
|
Assert.AreNotEqual(0, stats.nPages);
|
|
Assert.AreEqual(0, stats.OverflowPages);
|
|
Assert.AreEqual(0, stats.OverflowPagesFreeBytes);
|
|
}
|
|
|
|
public void ConfirmStatsPart3Case1(HashStats stats)
|
|
{
|
|
Assert.AreNotEqual(0, stats.FreePages);
|
|
}
|
|
|
|
public static void Confirm(XmlElement xmlElem,
|
|
HashDatabase hashDB, bool compulsory)
|
|
{
|
|
DatabaseTest.Confirm(xmlElem, hashDB, compulsory);
|
|
Configuration.ConfirmCreatePolicy(xmlElem,
|
|
"Creation", hashDB.Creation, compulsory);
|
|
Configuration.ConfirmDuplicatesPolicy(xmlElem,
|
|
"Duplicates", hashDB.Duplicates, compulsory);
|
|
Configuration.ConfirmUint(xmlElem,
|
|
"FillFactor", hashDB.FillFactor, compulsory);
|
|
Configuration.ConfirmUint(xmlElem,
|
|
"NumElements", hashDB.TableSize,
|
|
compulsory);
|
|
Assert.AreEqual(DatabaseType.HASH, hashDB.Type);
|
|
string type = hashDB.Type.ToString();
|
|
Assert.IsNotNull(type);
|
|
}
|
|
}
|
|
}
|