/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2009, 2015 Oracle and/or its affiliates. All rights reserved.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using BerkeleyDB.Internal;
namespace BerkeleyDB {
///
/// A class representing Berkeley DB transactions
///
///
///
/// Calling ,
/// or
/// releases the resources held by
/// the created object.
///
///
/// Transactions may only span threads if they do so serially;
/// 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.
///
///
/// Cursors may not span transactions; each cursor must be
/// opened and closed within a single transaction.
///
///
/// A parent transaction may not issue any Berkeley DB operations
/// except for ,
/// and
/// while it has active child transactions (child transactions that
/// have not yet been committed or aborted).
///
///
public class Transaction {
///
/// The size of the global transaction ID
///
public static uint GlobalIdLength = DbConstants.DB_GID_SIZE;
internal DB_TXN dbtxn;
internal DB_TXN_TOKEN dbtoken;
internal void SetCommitToken() {
if (dbtxn.is_commit_token_enabled()) {
dbtoken = new DB_TXN_TOKEN();
dbtxn.set_commit_token(dbtoken);
}
}
internal Transaction(DB_TXN txn) {
dbtxn = txn;
dbtoken = null;
}
private bool idCached = false;
private uint _id;
private bool isCommitted = false;
///
/// The unique transaction id associated with this transaction.
///
public uint Id {
get {
if (!idCached) {
_id = dbtxn.id();
idCached = true;
}
return _id;
}
}
///
/// The commit token generated at the commit time of this transaction.
/// This operation can only be performed after this transaction has committed.
///
public byte[] CommitToken {
/*
*If iscommitted is true, but dbtoken is null, then it is one
* of below cases:
* 1) either this transaction is a nested txn; or
* 2) this environment did not enable logging; or
* 3) the user calls this function on a rep client node.\
*/
get {
if (isCommitted)
if (dbtoken != null)
return dbtoken.buf;
else throw new ArgumentException("Cannot get token because of improper environment settings.");
else throw new InvalidOperationException("Cannot get token before transaction commit.");
}
}
///
/// The deadlock priority for this transaction. The deadlock detector
/// rejects lock requests from lower priority transactions before
/// those from higher priority transactions.
///
public uint Priority {
get {
uint ret = 0;
dbtxn.get_priority(ref ret);
return ret;
}
set {
dbtxn.set_priority(value);
}
}
///
/// Cause an abnormal termination of the transaction.
///
///
///
/// Before Abort returns, any locks held by the transaction are
/// released.
///
///
/// In the case of nested transactions, aborting a parent transaction
/// causes all children (unresolved or not) of the parent transaction to
/// be aborted.
///
///
/// All cursors opened within the transaction must be closed before the
/// transaction is aborted. This method closes all open cursor handles,
/// if any. And if a close operation fails, the rest of
/// the cursors are closed, and the database environment
/// is set to the panic state.
///
///
public void Abort() {
dbtxn.abort();
}
///
/// End the transaction.
///
///
///
/// 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 succeeds, the actual resolution
/// of the child transaction is postponed until the parent transaction
/// is committed or aborted; if its parent transaction commits,
/// it is committed; and if its parent transaction aborts, it
/// is aborted.
///
///
/// All cursors opened within the transaction must be closed before the
/// transaction is committed. If there are cursor handles
/// open when this method is called, they are all closed inside this
/// method. And if there are errors when closing the cursor handles,
/// the transaction is aborted and the first such error is returned.
///
///
public void Commit() {
SetCommitToken();
dbtxn.commit(0);
isCommitted = true;
}
///
/// End the transaction.
///
///
/// Synchronously flushing the log is the default for Berkeley DB
/// environments unless
/// was specified.
/// Synchronous log flushing may also be set or unset for a single
/// transaction using
/// . The
/// value of overrides both of those
/// settings.
///
/// If true, synchronously flush the log.
public void Commit(bool syncLog) {
SetCommitToken();
dbtxn.commit(
syncLog ? DbConstants.DB_TXN_SYNC : DbConstants.DB_TXN_NOSYNC);
isCommitted = true;
}
///
/// Free up all the per-process resources associated with the specified
/// Transaction instance, neither committing nor aborting the
/// transaction.
///
///
/// If there are cursor handles open when this method is called, they
/// are all closed inside this method. And if there are errors when
/// closing the cursor handles, the first such error is returned.
/// This call may be used only after calls to
/// when there are multiple
/// global transaction managers recovering transactions in a single
/// Berkeley DB environment. Any transactions returned by
/// that are not handled by
/// the current global transaction manager should be discarded using
/// Discard.
///
public void Discard() {
dbtxn.discard(0);
}
///
/// The transaction's name. The name is returned by
///
/// and displayed by
/// .
///
///
/// 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.
///
public string Name {
get {
string ret = "";
dbtxn.get_name(out ret);
return ret;
}
set { dbtxn.set_name(value); }
}
///
/// Initiate the beginning of a two-phase commit.
///
///
///
/// 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.
///
///
/// 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 is
/// resolved along with their parent's during global recovery.
///
///
/// If there are cursor handles open when this method is called, they
/// are all closed inside this method. And if there are errors when
/// closing the cursor handles, the first such error is returned.
///
///
///
/// The global transaction ID by which this transaction is known.
/// This global transaction ID is returned in calls to
/// telling the
/// application which global transactions must be resolved.
///
public void Prepare(byte[] globalId) {
if (globalId.Length != Transaction.GlobalIdLength)
throw new ArgumentException(
"Global ID length must be " + Transaction.GlobalIdLength);
dbtxn.prepare(globalId);
}
///
/// Set the timeout value for locks for this transaction.
///
///
///
/// 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.
///
///
/// Timeout values may be specified for the database environment as a
/// whole. See for more
/// information.
///
///
///
/// An unsigned 32-bit number of microseconds, limiting the maximum
/// timeout to roughly 71 minutes. A value of 0 disables timeouts for
/// the transaction.
///
public void SetLockTimeout(uint timeout) {
dbtxn.set_timeout(timeout, DbConstants.DB_SET_LOCK_TIMEOUT);
}
///
/// Set the timeout value for transactions for this transaction.
///
///
///
/// 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.
///
///
/// Timeout values may be specified for the database environment as a
/// whole. See for more
/// information.
///
///
///
/// An unsigned 32-bit number of microseconds, limiting the maximum
/// timeout to roughly 71 minutes. A value of 0 disables timeouts for
/// the transaction.
///
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;
}
}
}