1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2009 Oracle. All rights reserved. 5 * 6 */ 7using System; 8using System.Collections.Generic; 9using System.Text; 10using BerkeleyDB.Internal; 11 12namespace BerkeleyDB { 13 /// <summary> 14 /// A class representing Berkeley DB transactions 15 /// </summary> 16 /// <remarks> 17 /// <para> 18 /// Calling <see cref="Transaction.Abort"/>, 19 /// <see cref="Transaction.Commit"/> or 20 /// <see cref="Transaction.Discard"/> will release the resources held by 21 /// the created object. 22 /// </para> 23 /// <para> 24 /// Transactions may only span threads if they do so serially; that is, 25 /// each transaction must be active in only a single thread of control 26 /// at a time. This restriction holds for parents of nested transactions 27 /// as well; no two children may be concurrently active in more than one 28 /// thread of control at any one time. 29 /// </para> 30 /// <para> 31 /// Cursors may not span transactions; that is, each cursor must be 32 /// opened and closed within a single transaction. 33 /// </para> 34 /// <para> 35 /// A parent transaction may not issue any Berkeley DB operations � 36 /// except for <see cref="DatabaseEnvironment.BeginTransaction"/>, 37 /// <see cref="Transaction.Abort"/>and <see cref="Transaction.Commit"/> 38 /// � while it has active child transactions (child transactions that 39 /// have not yet been committed or aborted). 40 /// </para> 41 /// </remarks> 42 public class Transaction { 43 /// <summary> 44 /// The size of the global transaction ID 45 /// </summary> 46 public static uint GlobalIdLength = DbConstants.DB_GID_SIZE; 47 48 internal DB_TXN dbtxn; 49 50 internal Transaction(DB_TXN txn) { 51 dbtxn = txn; 52 } 53 54 private bool idCached = false; 55 private uint _id; 56 /// <summary> 57 /// The unique transaction id associated with this transaction. 58 /// </summary> 59 public uint Id { 60 get { 61 if (!idCached) { 62 _id = dbtxn.id(); 63 idCached = true; 64 } 65 return _id; 66 } 67 } 68 69 /// <summary> 70 /// Cause an abnormal termination of the transaction. 71 /// </summary> 72 /// <remarks> 73 /// <para> 74 /// Before Abort returns, any locks held by the transaction will have 75 /// been released. 76 /// </para> 77 /// <para> 78 /// In the case of nested transactions, aborting a parent transaction 79 /// causes all children (unresolved or not) of the parent transaction to 80 /// be aborted. 81 /// </para> 82 /// <para> 83 /// All cursors opened within the transaction must be closed before the 84 /// transaction is aborted. 85 /// </para> 86 /// </remarks> 87 public void Abort() { 88 dbtxn.abort(); 89 } 90 91 /// <summary> 92 /// End the transaction. 93 /// </summary> 94 /// <overloads> 95 /// <para> 96 /// In the case of nested transactions, if the transaction is a parent 97 /// transaction, committing the parent transaction causes all unresolved 98 /// children of the parent to be committed. In the case of nested 99 /// transactions, if the transaction is a child transaction, its locks 100 /// are not released, but are acquired by its parent. Although the 101 /// commit of the child transaction will succeed, the actual resolution 102 /// of the child transaction is postponed until the parent transaction 103 /// is committed or aborted; that is, if its parent transaction commits, 104 /// it will be committed; and if its parent transaction aborts, it will 105 /// be aborted. 106 /// </para> 107 /// <para> 108 /// All cursors opened within the transaction must be closed before the 109 /// transaction is committed. 110 /// </para> 111 /// </overloads> 112 public void Commit() { 113 dbtxn.commit(0); 114 } 115 /// <summary> 116 /// End the transaction. 117 /// </summary> 118 /// <remarks> 119 /// Synchronously flushing the log is the default for Berkeley DB 120 /// environments unless 121 /// <see cref="DatabaseEnvironmentConfig.TxnNoSync"/> was specified. 122 /// Synchronous log flushing may also be set or unset for a single 123 /// transaction using 124 /// <see cref="DatabaseEnvironment.BeginTransaction"/>. The 125 /// value of <paramref name="syncLog"/> overrides both of those 126 /// settings. 127 /// </remarks> 128 /// <param name="syncLog">If true, synchronously flush the log.</param> 129 public void Commit(bool syncLog) { 130 dbtxn.commit( 131 syncLog ? DbConstants.DB_TXN_SYNC : DbConstants.DB_TXN_NOSYNC); 132 } 133 134 /// <summary> 135 /// Free up all the per-process resources associated with the specified 136 /// Transaction instance, neither committing nor aborting the 137 /// transaction. 138 /// </summary> 139 /// <remarks> 140 /// This call may be used only after calls to 141 /// <see cref="DatabaseEnvironment.Recover"/> when there are multiple 142 /// global transaction managers recovering transactions in a single 143 /// Berkeley DB environment. Any transactions returned by 144 /// <see cref="DatabaseEnvironment.Recover"/> that are not handled by 145 /// the current global transaction manager should be discarded using 146 /// Discard. 147 /// </remarks> 148 public void Discard() { 149 dbtxn.discard(0); 150 } 151 152 /// <summary> 153 /// The transaction's name. The name is returned by 154 /// <see cref="DatabaseEnvironment.TransactionSystemStats"/> 155 /// and displayed by 156 /// <see cref="DatabaseEnvironment.PrintTransactionSystemStats"/>. 157 /// </summary> 158 /// <remarks> 159 /// If the database environment has been configured for logging and the 160 /// Berkeley DB library was built in Debug mode (or with DIAGNOSTIC 161 /// defined), a debugging log record is written including the 162 /// transaction ID and the name. 163 /// </remarks> 164 public string Name { 165 get { 166 string ret = ""; 167 dbtxn.get_name(ref ret); 168 return ret; 169 } 170 set { dbtxn.set_name(value); } 171 } 172 173 /// <summary> 174 /// Initiate the beginning of a two-phase commit. 175 /// </summary> 176 /// <remarks> 177 /// <para> 178 /// In a distributed transaction environment, Berkeley DB can be used as 179 /// a local transaction manager. In this case, the distributed 180 /// transaction manager must send prepare messages to each local 181 /// manager. The local manager must then call Prepare and await its 182 /// successful return before responding to the distributed transaction 183 /// manager. Only after the distributed transaction manager receives 184 /// successful responses from all of its prepare messages should it 185 /// issue any commit messages. 186 /// </para> 187 /// <para> 188 /// In the case of nested transactions, preparing the parent causes all 189 /// unresolved children of the parent transaction to be committed. Child 190 /// transactions should never be explicitly prepared. Their fate will be 191 /// resolved along with their parent's during global recovery. 192 /// </para> 193 /// </remarks> 194 /// <param name="globalId"> 195 /// The global transaction ID by which this transaction will be known. 196 /// This global transaction ID will be returned in calls to 197 /// <see cref="DatabaseEnvironment.Recover"/> telling the 198 /// application which global transactions must be resolved. 199 /// </param> 200 public void Prepare(byte[] globalId) { 201 if (globalId.Length != Transaction.GlobalIdLength) 202 throw new ArgumentException( 203 "Global ID length must be " + Transaction.GlobalIdLength); 204 dbtxn.prepare(globalId); 205 } 206 207 /// <summary> 208 /// Set the timeout value for locks for this transaction. 209 /// </summary> 210 /// <remarks> 211 /// <para> 212 /// Timeouts are checked whenever a thread of control blocks on a lock 213 /// or when deadlock detection is performed. This timeout is for any 214 /// single lock request. As timeouts are only checked when the lock 215 /// request first blocks or when deadlock detection is performed, the 216 /// accuracy of the timeout depends on how often deadlock detection is 217 /// performed. 218 /// </para> 219 /// <para> 220 /// Timeout values may be specified for the database environment as a 221 /// whole. See <see cref="DatabaseEnvironment.LockTimeout"/> for more 222 /// information. 223 /// </para> 224 /// </remarks> 225 /// <param name="timeout"> 226 /// An unsigned 32-bit number of microseconds, limiting the maximum 227 /// timeout to roughly 71 minutes. A value of 0 disables timeouts for 228 /// the transaction. 229 /// </param> 230 public void SetLockTimeout(uint timeout) { 231 dbtxn.set_timeout(timeout, DbConstants.DB_SET_LOCK_TIMEOUT); 232 } 233 234 /// <summary> 235 /// Set the timeout value for transactions for this transaction. 236 /// </summary> 237 /// <remarks> 238 /// <para> 239 /// Timeouts are checked whenever a thread of control blocks on a lock 240 /// or when deadlock detection is performed. This timeout is for the 241 /// life of the transaction. As timeouts are only checked when the lock 242 /// request first blocks or when deadlock detection is performed, the 243 /// accuracy of the timeout depends on how often deadlock detection is 244 /// performed. 245 /// </para> 246 /// <para> 247 /// Timeout values may be specified for the database environment as a 248 /// whole. See <see cref="DatabaseEnvironment.TxnTimeout"/> for more 249 /// information. 250 /// </para> 251 /// </remarks> 252 /// <param name="timeout"> 253 /// An unsigned 32-bit number of microseconds, limiting the maximum 254 /// timeout to roughly 71 minutes. A value of 0 disables timeouts for 255 /// the transaction. 256 /// </param> 257 public void SetTxnTimeout(uint timeout) { 258 dbtxn.set_timeout(timeout, DbConstants.DB_SET_TXN_TIMEOUT); 259 } 260 261 static internal DB_TXN getDB_TXN(Transaction txn) { 262 return txn == null ? null : txn.dbtxn; 263 } 264 } 265} 266