/*- * 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 { /// <summary> /// A class representing Berkeley DB transactions /// </summary> /// <remarks> /// <para> /// Calling <see cref="Transaction.Abort"/>, /// <see cref="Transaction.Commit"/> or /// <see cref="Transaction.Discard"/> will release the resources held by /// the created object. /// </para> /// <para> /// Transactions may only span threads if they do so serially; that is, /// each transaction must be active in only a single thread of control /// at a time. This restriction holds for parents of nested transactions /// as well; no two children may be concurrently active in more than one /// thread of control at any one time. /// </para> /// <para> /// Cursors may not span transactions; that is, each cursor must be /// opened and closed within a single transaction. /// </para> /// <para> /// A parent transaction may not issue any Berkeley DB operations � /// except for <see cref="DatabaseEnvironment.BeginTransaction"/>, /// <see cref="Transaction.Abort"/>and <see cref="Transaction.Commit"/> /// � while it has active child transactions (child transactions that /// have not yet been committed or aborted). /// </para> /// </remarks> public class Transaction { /// <summary> /// The size of the global transaction ID /// </summary> public static uint GlobalIdLength = DbConstants.DB_GID_SIZE; internal DB_TXN dbtxn; internal Transaction(DB_TXN txn) { dbtxn = txn; } private bool idCached = false; private uint _id; /// <summary> /// The unique transaction id associated with this transaction. /// </summary> public uint Id { get { if (!idCached) { _id = dbtxn.id(); idCached = true; } return _id; } } /// <summary> /// Cause an abnormal termination of the transaction. /// </summary> /// <remarks> /// <para> /// Before Abort returns, any locks held by the transaction will have /// been released. /// </para> /// <para> /// In the case of nested transactions, aborting a parent transaction /// causes all children (unresolved or not) of the parent transaction to /// be aborted. /// </para> /// <para> /// All cursors opened within the transaction must be closed before the /// transaction is aborted. /// </para> /// </remarks> public void Abort() { dbtxn.abort(); } /// <summary> /// End the transaction. /// </summary> /// <overloads> /// <para> /// In the case of nested transactions, if the transaction is a parent /// transaction, committing the parent transaction causes all unresolved /// children of the parent to be committed. In the case of nested /// transactions, if the transaction is a child transaction, its locks /// are not released, but are acquired by its parent. Although the /// commit of the child transaction will succeed, the actual resolution /// of the child transaction is postponed until the parent transaction /// is committed or aborted; that is, if its parent transaction commits, /// it will be committed; and if its parent transaction aborts, it will /// be aborted. /// </para> /// <para> /// All cursors opened within the transaction must be closed before the /// transaction is committed. /// </para> /// </overloads> public void Commit() { dbtxn.commit(0); } /// <summary> /// End the transaction. /// </summary> /// <remarks> /// Synchronously flushing the log is the default for Berkeley DB /// environments unless /// <see cref="DatabaseEnvironmentConfig.TxnNoSync"/> was specified. /// Synchronous log flushing may also be set or unset for a single /// transaction using /// <see cref="DatabaseEnvironment.BeginTransaction"/>. The /// value of <paramref name="syncLog"/> overrides both of those /// settings. /// </remarks> /// <param name="syncLog">If true, synchronously flush the log.</param> public void Commit(bool syncLog) { dbtxn.commit( syncLog ? DbConstants.DB_TXN_SYNC : DbConstants.DB_TXN_NOSYNC); } /// <summary> /// Free up all the per-process resources associated with the specified /// Transaction instance, neither committing nor aborting the /// transaction. /// </summary> /// <remarks> /// This call may be used only after calls to /// <see cref="DatabaseEnvironment.Recover"/> when there are multiple /// global transaction managers recovering transactions in a single /// Berkeley DB environment. Any transactions returned by /// <see cref="DatabaseEnvironment.Recover"/> that are not handled by /// the current global transaction manager should be discarded using /// Discard. /// </remarks> public void Discard() { dbtxn.discard(0); } /// <summary> /// The transaction's name. The name is returned by /// <see cref="DatabaseEnvironment.TransactionSystemStats"/> /// and displayed by /// <see cref="DatabaseEnvironment.PrintTransactionSystemStats"/>. /// </summary> /// <remarks> /// If the database environment has been configured for logging and the /// Berkeley DB library was built in Debug mode (or with DIAGNOSTIC /// defined), a debugging log record is written including the /// transaction ID and the name. /// </remarks> public string Name { get { string ret = ""; dbtxn.get_name(ref ret); return ret; } set { dbtxn.set_name(value); } } /// <summary> /// Initiate the beginning of a two-phase commit. /// </summary> /// <remarks> /// <para> /// In a distributed transaction environment, Berkeley DB can be used as /// a local transaction manager. In this case, the distributed /// transaction manager must send prepare messages to each local /// manager. The local manager must then call Prepare and await its /// successful return before responding to the distributed transaction /// manager. Only after the distributed transaction manager receives /// successful responses from all of its prepare messages should it /// issue any commit messages. /// </para> /// <para> /// In the case of nested transactions, preparing the parent causes all /// unresolved children of the parent transaction to be committed. Child /// transactions should never be explicitly prepared. Their fate will be /// resolved along with their parent's during global recovery. /// </para> /// </remarks> /// <param name="globalId"> /// The global transaction ID by which this transaction will be known. /// This global transaction ID will be returned in calls to /// <see cref="DatabaseEnvironment.Recover"/> telling the /// application which global transactions must be resolved. /// </param> public void Prepare(byte[] globalId) { if (globalId.Length != Transaction.GlobalIdLength) throw new ArgumentException( "Global ID length must be " + Transaction.GlobalIdLength); dbtxn.prepare(globalId); } /// <summary> /// Set the timeout value for locks for this transaction. /// </summary> /// <remarks> /// <para> /// Timeouts are checked whenever a thread of control blocks on a lock /// or when deadlock detection is performed. This timeout is for any /// single lock request. As timeouts are only checked when the lock /// request first blocks or when deadlock detection is performed, the /// accuracy of the timeout depends on how often deadlock detection is /// performed. /// </para> /// <para> /// Timeout values may be specified for the database environment as a /// whole. See <see cref="DatabaseEnvironment.LockTimeout"/> for more /// information. /// </para> /// </remarks> /// <param name="timeout"> /// An unsigned 32-bit number of microseconds, limiting the maximum /// timeout to roughly 71 minutes. A value of 0 disables timeouts for /// the transaction. /// </param> public void SetLockTimeout(uint timeout) { dbtxn.set_timeout(timeout, DbConstants.DB_SET_LOCK_TIMEOUT); } /// <summary> /// Set the timeout value for transactions for this transaction. /// </summary> /// <remarks> /// <para> /// Timeouts are checked whenever a thread of control blocks on a lock /// or when deadlock detection is performed. This timeout is for the /// life of the transaction. As timeouts are only checked when the lock /// request first blocks or when deadlock detection is performed, the /// accuracy of the timeout depends on how often deadlock detection is /// performed. /// </para> /// <para> /// Timeout values may be specified for the database environment as a /// whole. See <see cref="DatabaseEnvironment.TxnTimeout"/> for more /// information. /// </para> /// </remarks> /// <param name="timeout"> /// An unsigned 32-bit number of microseconds, limiting the maximum /// timeout to roughly 71 minutes. A value of 0 disables timeouts for /// the transaction. /// </param> public void SetTxnTimeout(uint timeout) { dbtxn.set_timeout(timeout, DbConstants.DB_SET_TXN_TIMEOUT); } static internal DB_TXN getDB_TXN(Transaction txn) { return txn == null ? null : txn.dbtxn; } } }