/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2009 Oracle. All rights reserved.
*
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using BerkeleyDB.Internal;
namespace BerkeleyDB {
///
/// A class representing a BTreeDatabase. The Btree format is a
/// representation of a sorted, balanced tree structure.
///
public class BTreeDatabase : Database {
private BTreeCompressDelegate compressHandler;
private BTreeDecompressDelegate decompressHandler;
private EntryComparisonDelegate compareHandler, prefixCompareHandler;
private EntryComparisonDelegate dupCompareHandler;
private BDB_CompareDelegate doCompareRef;
private BDB_CompareDelegate doPrefixCompareRef;
private BDB_CompareDelegate doDupCompareRef;
private BDB_CompressDelegate doCompressRef;
private BDB_DecompressDelegate doDecompressRef;
#region Constructors
private BTreeDatabase(DatabaseEnvironment env, uint flags)
: base(env, flags) { }
internal BTreeDatabase(BaseDatabase clone) : base(clone) { }
private void Config(BTreeDatabaseConfig cfg) {
base.Config(cfg);
/*
* Database.Config calls set_flags, but that doesn't get the BTree
* specific flags. No harm in calling it again.
*/
db.set_flags(cfg.flags);
if (cfg.BTreeCompare != null)
Compare = cfg.BTreeCompare;
if (cfg.BTreePrefixCompare != null)
PrefixCompare = cfg.BTreePrefixCompare;
// The duplicate comparison function cannot change.
if (cfg.DuplicateCompare != null)
DupCompare = cfg.DuplicateCompare;
if (cfg.minkeysIsSet)
db.set_bt_minkey(cfg.MinKeysPerPage);
if (cfg.compressionIsSet) {
Compress = cfg.Compress;
Decompress = cfg.Decompress;
if (Compress == null)
doCompressRef = null;
else
doCompressRef = new BDB_CompressDelegate(doCompress);
if (Decompress == null)
doDecompressRef = null;
else
doDecompressRef = new BDB_DecompressDelegate(doDecompress);
db.set_bt_compress(doCompressRef, doDecompressRef);
}
}
///
/// Instantiate a new BTreeDatabase object and open the database
/// represented by .
///
///
///
/// If is null, the database is strictly
/// temporary and cannot be opened by any other thread of control, thus
/// the database can only be accessed by sharing the single database
/// object that created it, in circumstances where doing so is safe.
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database. In-memory databases never intended to be preserved on disk
/// may be created by setting this parameter to null.
///
/// The database's configuration
/// A new, open database object
public static BTreeDatabase Open(
string Filename, BTreeDatabaseConfig cfg) {
return Open(Filename, null, cfg, null);
}
///
/// Instantiate a new BTreeDatabase object and open the database
/// represented by and
/// .
///
///
///
/// If both and
/// are null, the database is strictly
/// temporary and cannot be opened by any other thread of control, thus
/// the database can only be accessed by sharing the single database
/// object that created it, in circumstances where doing so is safe. If
/// is null and
/// is non-null, the database can be
/// opened by other threads of control and will be replicated to client
/// sites in any replication group.
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database. In-memory databases never intended to be preserved on disk
/// may be created by setting this parameter to null.
///
///
/// This parameter allows applications to have multiple databases in a
/// single file. Although no DatabaseName needs to be specified, it is
/// an error to attempt to open a second database in a file that was not
/// initially created using a database name.
///
/// The database's configuration
/// A new, open database object
public static BTreeDatabase Open(
string Filename, string DatabaseName, BTreeDatabaseConfig cfg) {
return Open(Filename, DatabaseName, cfg, null);
}
///
/// Instantiate a new BTreeDatabase object and open the database
/// represented by .
///
///
///
/// If is null, the database is strictly
/// temporary and cannot be opened by any other thread of control, thus
/// the database can only be accessed by sharing the single database
/// object that created it, in circumstances where doing so is safe.
///
///
/// If is null, but
/// is set, the operation will
/// be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open. Also note that the
/// transaction must be committed before the object is closed.
///
///
///
/// The name of an underlying file that will be used to back the
/// database. In-memory databases never intended to be preserved on disk
/// may be created by setting this parameter to null.
///
/// The database's configuration
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// A new, open database object
public static BTreeDatabase Open(
string Filename, BTreeDatabaseConfig cfg, Transaction txn) {
return Open(Filename, null, cfg, txn);
}
///
/// Instantiate a new BTreeDatabase object and open the database
/// represented by and
/// .
///
///
///
/// If both and
/// are null, the database is strictly
/// temporary and cannot be opened by any other thread of control, thus
/// the database can only be accessed by sharing the single database
/// object that created it, in circumstances where doing so is safe. If
/// is null and
/// is non-null, the database can be
/// opened by other threads of control and will be replicated to client
/// sites in any replication group.
///
///
/// If is null, but
/// is set, the operation will
/// be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open. Also note that the
/// transaction must be committed before the object is closed.
///
///
///
/// The name of an underlying file that will be used to back the
/// database. In-memory databases never intended to be preserved on disk
/// may be created by setting this parameter to null.
///
///
/// This parameter allows applications to have multiple databases in a
/// single file. Although no DatabaseName needs to be specified, it is
/// an error to attempt to open a second database in a file that was not
/// initially created using a database name.
///
/// The database's configuration
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// A new, open database object
public static BTreeDatabase Open(string Filename,
string DatabaseName, BTreeDatabaseConfig cfg, Transaction txn) {
BTreeDatabase ret = new BTreeDatabase(cfg.Env, 0);
ret.Config(cfg);
ret.db.open(Transaction.getDB_TXN(txn),
Filename, DatabaseName, DBTYPE.DB_BTREE, cfg.openFlags, 0);
ret.isOpen = true;
return ret;
}
#endregion Constructors
#region Callbacks
private static int doCompare(IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2) {
DB db = new DB(dbp, false);
DBT dbt1 = new DBT(dbtp1, false);
DBT dbt2 = new DBT(dbtp2, false);
BTreeDatabase btdb = (BTreeDatabase)(db.api_internal);
return btdb.Compare(
DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2));
}
private static int doCompress(IntPtr dbp, IntPtr prevKeyp,
IntPtr prevDatap, IntPtr keyp, IntPtr datap, IntPtr destp) {
DB db = new DB(dbp, false);
DatabaseEntry prevKey =
DatabaseEntry.fromDBT(new DBT(prevKeyp, false));
DatabaseEntry prevData =
DatabaseEntry.fromDBT(new DBT(prevDatap, false));
DatabaseEntry key = DatabaseEntry.fromDBT(new DBT(keyp, false));
DatabaseEntry data = DatabaseEntry.fromDBT(new DBT(datap, false));
DBT dest = new DBT(destp, false);
BTreeDatabase btdb = (BTreeDatabase)(db.api_internal);
byte[] arr = new byte[(int)dest.ulen];
int len;
try {
if (btdb.Compress(prevKey, prevData, key, data, ref arr, out len)) {
Marshal.Copy(arr, 0, dest.dataPtr, len);
dest.size = (uint)len;
return 0;
} else {
return DbConstants.DB_BUFFER_SMALL;
}
} catch (Exception) {
return -1;
}
}
private static int doDecompress(IntPtr dbp, IntPtr prevKeyp,
IntPtr prevDatap, IntPtr cmpp, IntPtr destKeyp, IntPtr destDatap) {
DB db = new DB(dbp, false);
DatabaseEntry prevKey =
DatabaseEntry.fromDBT(new DBT(prevKeyp, false));
DatabaseEntry prevData =
DatabaseEntry.fromDBT(new DBT(prevDatap, false));
DBT compressed = new DBT(cmpp, false);
DBT destKey = new DBT(destKeyp, false);
DBT destData = new DBT(destDatap, false);
BTreeDatabase btdb = (BTreeDatabase)(db.api_internal);
uint size;
try {
KeyValuePair kvp = btdb.Decompress(prevKey, prevData, compressed.data, out size);
int keylen = kvp.Key.Data.Length;
int datalen = kvp.Value.Data.Length;
destKey.size = (uint)keylen;
destData.size = (uint)datalen;
if (keylen > destKey.ulen ||
datalen > destData.ulen)
return DbConstants.DB_BUFFER_SMALL;
Marshal.Copy(kvp.Key.Data, 0, destKey.dataPtr, keylen);
Marshal.Copy(kvp.Value.Data, 0, destData.dataPtr, datalen);
compressed.size = size;
return 0;
} catch (Exception) {
return -1;
}
}
private static int doDupCompare(
IntPtr dbp, IntPtr dbt1p, IntPtr dbt2p) {
DB db = new DB(dbp, false);
DBT dbt1 = new DBT(dbt1p, false);
DBT dbt2 = new DBT(dbt2p, false);
BTreeDatabase btdb = (BTreeDatabase)(db.api_internal);
return btdb.DupCompare(
DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2));
}
private static int doPrefixCompare(
IntPtr dbp, IntPtr dbtp1, IntPtr dbtp2) {
DB db = new DB(dbp, false);
DBT dbt1 = new DBT(dbtp1, false);
DBT dbt2 = new DBT(dbtp2, false);
BTreeDatabase btdb = (BTreeDatabase)(db.api_internal);
return btdb.PrefixCompare(
DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2));
}
#endregion Callbacks
#region Properties
// Sorted alpha by property name
///
/// The Btree key comparison function. The comparison function is called
/// whenever it is necessary to compare a key specified by the
/// application with a key currently stored in the tree.
///
public EntryComparisonDelegate Compare {
get { return compareHandler; }
private set {
if (value == null)
db.set_bt_compare(null);
else if (compareHandler == null) {
if (doCompareRef == null)
doCompareRef = new BDB_CompareDelegate(doCompare);
db.set_bt_compare(doCompareRef);
}
compareHandler = value;
}
}
///
/// The compression function used to store key/data pairs in the
/// database.
///
public BTreeCompressDelegate Compress {
get { return compressHandler; }
private set { compressHandler = value; }
}
///
/// The decompression function used to retrieve key/data pairs from the
/// database.
///
public BTreeDecompressDelegate Decompress {
get { return decompressHandler; }
private set { decompressHandler = value; }
}
///
/// The duplicate data item comparison function.
///
public EntryComparisonDelegate DupCompare {
get { return dupCompareHandler; }
private set {
/* Cannot be called after open. */
if (value == null)
db.set_dup_compare(null);
else if (dupCompareHandler == null) {
if (doDupCompareRef == null)
doDupCompareRef = new BDB_CompareDelegate(doDupCompare);
db.set_dup_compare(doDupCompareRef);
}
dupCompareHandler = value;
}
}
///
/// Whether the insertion of duplicate data items in the database is
/// permitted, and whether duplicates items are sorted.
///
public DuplicatesPolicy Duplicates {
get {
uint flags = 0;
db.get_flags(ref flags);
if ((flags & DbConstants.DB_DUPSORT) != 0)
return DuplicatesPolicy.SORTED;
else if ((flags & DbConstants.DB_DUP) != 0)
return DuplicatesPolicy.UNSORTED;
else
return DuplicatesPolicy.NONE;
}
}
///
/// The minimum number of key/data pairs intended to be stored on any
/// single Btree leaf page.
///
public uint MinKeysPerPage {
get {
uint ret = 0;
db.get_bt_minkey(ref ret);
return ret;
}
}
///
/// The Btree prefix function. The prefix function is used to determine
/// the amount by which keys stored on the Btree internal pages can be
/// safely truncated without losing their uniqueness.
///
public EntryComparisonDelegate PrefixCompare {
get { return prefixCompareHandler; }
private set {
if (value == null)
db.set_bt_prefix(null);
else if (prefixCompareHandler == null) {
if (doPrefixCompareRef == null)
doPrefixCompareRef =
new BDB_CompareDelegate(doPrefixCompare);
db.set_bt_prefix(doPrefixCompareRef);
}
prefixCompareHandler = value;
}
}
///
/// If true, this object supports retrieval from the Btree using record
/// numbers.
///
public bool RecordNumbers {
get {
uint flags = 0;
db.get_flags(ref flags);
return (flags & DbConstants.DB_RECNUM) != 0;
}
}
///
/// If false, empty pages will not be coalesced into higher-level pages.
///
public bool ReverseSplit {
get {
uint flags = 0;
db.get_flags(ref flags);
return (flags & DbConstants.DB_REVSPLITOFF) == 0;
}
}
#endregion Properties
#region Methods
// Sorted alpha by method name
///
/// Compact the database, and optionally return unused database pages to
/// the underlying filesystem.
///
///
/// If the operation occurs in a transactional database, the operation
/// will be implicitly transaction protected using multiple
/// transactions. These transactions will be periodically committed to
/// avoid locking large sections of the tree. Any deadlocks encountered
/// cause the compaction operation to be retried from the point of the
/// last transaction commit.
///
/// Compact configuration parameters
/// Compact operation statistics
public CompactData Compact(CompactConfig cdata) {
return Compact(cdata, null);
}
///
/// Compact the database, and optionally return unused database pages to
/// the underlying filesystem.
///
///
///
/// If is non-null, then the operation is
/// performed using that transaction. In this event, large sections of
/// the tree may be locked during the course of the transaction.
///
///
/// If is null, but the operation occurs in a
/// transactional database, the operation will be implicitly transaction
/// protected using multiple transactions. These transactions will be
/// periodically committed to avoid locking large sections of the tree.
/// Any deadlocks encountered cause the compaction operation to be
/// retried from the point of the last transaction commit.
///
///
/// Compact configuration parameters
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// Compact operation statistics
public CompactData Compact(CompactConfig cdata, Transaction txn) {
DatabaseEntry end = null;
if (cdata.returnEnd)
end = new DatabaseEntry();
db.compact(Transaction.getDB_TXN(txn), cdata.start, cdata.stop,
CompactConfig.getDB_COMPACT(cdata), cdata.flags, end);
return new CompactData(CompactConfig.getDB_COMPACT(cdata), end);
}
///
/// Create a database cursor.
///
/// A newly created cursor
public new BTreeCursor Cursor() {
return Cursor(new CursorConfig(), null);
}
///
/// Create a database cursor with the given configuration.
///
///
/// The configuration properties for the cursor.
///
/// A newly created cursor
public new BTreeCursor Cursor(CursorConfig cfg) {
return Cursor(cfg, null);
}
///
/// Create a transactionally protected database cursor.
///
///
/// The transaction context in which the cursor may be used.
///
/// A newly created cursor
public new BTreeCursor Cursor(Transaction txn) {
return Cursor(new CursorConfig(), txn);
}
///
/// Create a transactionally protected database cursor with the given
/// configuration.
///
///
/// The configuration properties for the cursor.
///
///
/// The transaction context in which the cursor may be used.
///
/// A newly created cursor
public new BTreeCursor Cursor(CursorConfig cfg, Transaction txn) {
return new BTreeCursor(
db.cursor(Transaction.getDB_TXN(txn), cfg.flags), Pagesize);
}
///
/// Return the database statistical information which does not require
/// traversal of the database.
///
///
/// The database statistical information which does not require
/// traversal of the database.
///
public BTreeStats FastStats() {
return Stats(null, true, Isolation.DEGREE_THREE);
}
///
/// Return the database statistical information which does not require
/// traversal of the database.
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// The database statistical information which does not require
/// traversal of the database.
///
public BTreeStats FastStats(Transaction txn) {
return Stats(txn, true, Isolation.DEGREE_THREE);
}
///
/// Return the database statistical information which does not require
/// traversal of the database.
///
///
///
/// Among other things, this method makes it possible for applications
/// to request key and record counts without incurring the performance
/// penalty of traversing the entire database.
///
///
/// The statistical information is described by the
/// , ,
/// , and classes.
///
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// The level of isolation for database reads.
/// will be silently ignored for
/// databases which did not specify
/// .
///
///
/// The database statistical information which does not require
/// traversal of the database.
///
public BTreeStats FastStats(Transaction txn, Isolation isoDegree) {
return Stats(txn, true, isoDegree);
}
///
/// Retrieve a specific numbered key/data pair from the database.
///
///
/// The record number of the record to be retrieved.
///
///
/// A whose Key
/// parameter is and whose Value parameter is the
/// retrieved data.
///
public KeyValuePair Get(uint recno) {
return Get(recno, null, null);
}
///
/// Retrieve a specific numbered key/data pair from the database.
///
///
/// The record number of the record to be retrieved.
///
///
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// A whose Key
/// parameter is and whose Value parameter is the
/// retrieved data.
///
public KeyValuePair Get(
uint recno, Transaction txn) {
return Get(recno, txn, null);
}
///
/// Retrieve a specific numbered key/data pair from the database.
///
///
/// The record number of the record to be retrieved.
///
///
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// The locking behavior to use.
///
/// A whose Key
/// parameter is and whose Value parameter is the
/// retrieved data.
///
public KeyValuePair Get(
uint recno, Transaction txn, LockingInfo info) {
DatabaseEntry key = new DatabaseEntry();
key.Data = BitConverter.GetBytes(recno);
return Get(key, null, txn, info, DbConstants.DB_SET_RECNO);
}
public KeyValuePair GetMultiple(
uint recno) {
return GetMultiple(recno, (int)Pagesize, null, null);
}
public KeyValuePair GetMultiple(
uint recno, int BufferSize) {
return GetMultiple(recno, BufferSize, null, null);
}
public KeyValuePair GetMultiple(
uint recno, int BufferSize, Transaction txn) {
return GetMultiple(recno, BufferSize, txn, null);
}
public KeyValuePair GetMultiple(
uint recno, int BufferSize, Transaction txn, LockingInfo info) {
KeyValuePair kvp;
DatabaseEntry key = new DatabaseEntry();
key.Data = BitConverter.GetBytes(recno);
DatabaseEntry data = new DatabaseEntry();
for (; ; ) {
data.UserData = new byte[BufferSize];
try {
kvp = Get(key, data, txn, info,
DbConstants.DB_MULTIPLE | DbConstants.DB_SET_RECNO);
break;
} catch (MemoryException) {
int sz = (int)data.size;
if (sz > BufferSize)
BufferSize = sz;
else
BufferSize *= 2;
}
}
MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value);
return new KeyValuePair(
kvp.Key, dbe);
}
///
/// Return an estimate of the proportion of keys that are less than,
/// equal to, and greater than the specified key.
///
/// The key to search for
///
/// An estimate of the proportion of keys that are less than, equal to,
/// and greater than the specified key.
///
public KeyRange KeyRange(DatabaseEntry key) {
return KeyRange(key, null);
}
///
/// Return an estimate of the proportion of keys that are less than,
/// equal to, and greater than the specified key.
///
/// The key to search for
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// An estimate of the proportion of keys that are less than, equal to,
/// and greater than the specified key.
///
public KeyRange KeyRange(DatabaseEntry key, Transaction txn) {
DB_KEY_RANGE range = new DB_KEY_RANGE();
db.key_range(Transaction.getDB_TXN(txn), key, range, 0);
return new KeyRange(range);
}
///
/// Store the key/data pair in the database only if it does not already
/// appear in the database.
///
/// The key to store in the database
/// The data item to store in the database
public void PutNoDuplicate(DatabaseEntry key, DatabaseEntry data) {
PutNoDuplicate(key, data, null);
}
///
/// Store the key/data pair in the database only if it does not already
/// appear in the database.
///
/// The key to store in the database
/// The data item to store in the database
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
public void PutNoDuplicate(
DatabaseEntry key, DatabaseEntry data, Transaction txn) {
Put(key, data, txn, DbConstants.DB_NODUPDATA);
}
///
/// Return the database statistical information for this database.
///
/// Database statistical information.
public BTreeStats Stats() {
return Stats(null, false, Isolation.DEGREE_THREE);
}
///
/// Return the database statistical information for this database.
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// Database statistical information.
public BTreeStats Stats(Transaction txn) {
return Stats(txn, false, Isolation.DEGREE_THREE);
}
///
/// Return the database statistical information for this database.
///
///
/// The statistical information is described by
/// .
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// The level of isolation for database reads.
/// will be silently ignored for
/// databases which did not specify
/// .
///
/// Database statistical information.
public BTreeStats Stats(Transaction txn, Isolation isoDegree) {
return Stats(txn, false, isoDegree);
}
private BTreeStats Stats(
Transaction txn, bool fast, Isolation isoDegree) {
uint flags = 0;
flags |= fast ? DbConstants.DB_FAST_STAT : 0;
switch (isoDegree) {
case Isolation.DEGREE_ONE:
flags |= DbConstants.DB_READ_UNCOMMITTED;
break;
case Isolation.DEGREE_TWO:
flags |= DbConstants.DB_READ_COMMITTED;
break;
}
BTreeStatStruct st = db.stat_bt(Transaction.getDB_TXN(txn), flags);
return new BTreeStats(st);
}
///
/// Return pages to the filesystem that are already free and at the end
/// of the file.
///
///
/// The number of database pages returned to the filesystem
///
public uint TruncateUnusedPages() {
return TruncateUnusedPages(null);
}
///
/// Return pages to the filesystem that are already free and at the end
/// of the file.
///
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
///
/// The number of database pages returned to the filesystem
///
public uint TruncateUnusedPages(Transaction txn) {
DB_COMPACT cdata = new DB_COMPACT();
db.compact(Transaction.getDB_TXN(txn),
null, null, cdata, DbConstants.DB_FREELIST_ONLY, null);
return cdata.compact_pages_truncated;
}
#endregion Methods
}
}