/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2009 Oracle. All rights reserved. * */ using System; using System.Collections.Generic; using System.Text; using BerkeleyDB.Internal; namespace BerkeleyDB { /// /// A class representing a SecondaryBTreeDatabase. The Btree format is a /// representation of a sorted, balanced tree structure. /// public class SecondaryBTreeDatabase : SecondaryDatabase { private EntryComparisonDelegate compareHandler; private EntryComparisonDelegate prefixCompareHandler; private EntryComparisonDelegate dupCompareHandler; private BDB_CompareDelegate doCompareRef; private BDB_CompareDelegate doPrefixCompareRef; private BDB_CompareDelegate doDupCompareRef; #region Constructors internal SecondaryBTreeDatabase(DatabaseEnvironment env, uint flags) : base(env, flags) { } private void Config(SecondaryBTreeDatabaseConfig cfg) { base.Config((SecondaryDatabaseConfig)cfg); db.set_flags(cfg.flags); if (cfg.Compare != null) Compare = cfg.Compare; if (cfg.PrefixCompare != null) PrefixCompare = cfg.PrefixCompare; if (cfg.DuplicateCompare != null) DupCompare = cfg.DuplicateCompare; if (cfg.minkeysIsSet) db.set_bt_minkey(cfg.MinKeysPerPage); } /// /// Instantiate a new SecondaryBTreeDatabase object, open the /// database represented by and associate /// the database with the /// primary index. /// /// /// /// 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 SecondaryBTreeDatabase Open( string Filename, SecondaryBTreeDatabaseConfig cfg) { return Open(Filename, null, cfg, null); } /// /// Instantiate a new SecondaryBTreeDatabase object, open the /// database represented by and associate /// the database with the /// primary index. /// /// /// /// 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 SecondaryBTreeDatabase Open(string Filename, string DatabaseName, SecondaryBTreeDatabaseConfig cfg) { return Open(Filename, DatabaseName, cfg, null); } /// /// Instantiate a new SecondaryBTreeDatabase object, open the /// database represented by and associate /// the database with the /// primary index. /// /// /// /// 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 SecondaryBTreeDatabase Open(string Filename, SecondaryBTreeDatabaseConfig cfg, Transaction txn) { return Open(Filename, null, cfg, txn); } /// /// Instantiate a new SecondaryBTreeDatabase object, open the /// database represented by and associate /// the database with the /// primary index. /// /// /// /// 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 SecondaryBTreeDatabase Open( string Filename, string DatabaseName, SecondaryBTreeDatabaseConfig cfg, Transaction txn) { SecondaryBTreeDatabase ret = new SecondaryBTreeDatabase(cfg.Env, 0); ret.Config(cfg); ret.db.open(Transaction.getDB_TXN(txn), Filename, DatabaseName, cfg.DbType.getDBTYPE(), cfg.openFlags, 0); ret.isOpen = true; ret.doAssocRef = new BDB_AssociateDelegate( SecondaryDatabase.doAssociate); cfg.Primary.db.associate(Transaction.getDB_TXN(null), ret.db, ret.doAssocRef, cfg.assocFlags); if (cfg.ForeignKeyDatabase != null) { if (cfg.OnForeignKeyDelete == ForeignKeyDeleteAction.NULLIFY) ret.doNullifyRef = new BDB_AssociateForeignDelegate(doNullify); else ret.doNullifyRef = null; cfg.ForeignKeyDatabase.db.associate_foreign( ret.db, ret.doNullifyRef, cfg.foreignFlags); } return ret; } #endregion Constructors #region Callbacks 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); return ((SecondaryBTreeDatabase)(db.api_internal)).DupCompare( DatabaseEntry.fromDBT(dbt1), DatabaseEntry.fromDBT(dbt2)); } 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); SecondaryBTreeDatabase tmp = (SecondaryBTreeDatabase)db.api_internal; return tmp.compareHandler( 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); SecondaryBTreeDatabase tmp = (SecondaryBTreeDatabase)db.api_internal; return tmp.prefixCompareHandler( 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(doCompare); } compareHandler = 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; } } /// /// 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; } } /// /// 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; } } #endregion Properties } }