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