[sgen] Exclusive write on binary protocol file
[mono.git] / mcs / class / System.Transactions / System.Transactions / TransactionScope.cs
1 //
2 // TransactionScope.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //      Ankit Jain       <JAnkit@novell.com>
7 //
8 // (C)2005 Novell Inc,
9 // (C)2006 Novell Inc,
10 //
11
12
13 using DTCOption = System.Transactions.EnterpriseServicesInteropOption;
14
15 namespace System.Transactions
16 {
17         public sealed class TransactionScope : IDisposable
18         {
19                 static TransactionOptions defaultOptions =
20                         new TransactionOptions (0, TransactionManager.DefaultTimeout);
21
22                 Transaction transaction;
23                 Transaction oldTransaction;
24                 TransactionScope parentScope;
25                 TimeSpan timeout;
26
27                 /* Num of non-disposed nested scopes */
28                 int nested;
29
30                 bool disposed;
31                 bool completed;
32                 bool isRoot;
33
34                 public TransactionScope ()
35                         : this (TransactionScopeOption.Required,
36                                 TransactionManager.DefaultTimeout)
37                 {
38                 }
39
40                 public TransactionScope (Transaction transaction)
41                         : this (transaction, TransactionManager.DefaultTimeout)
42                 {
43                 }
44
45                 public TransactionScope (Transaction transaction,
46                         TimeSpan timeout)
47                         : this (transaction, timeout, DTCOption.None)
48                 {
49                 }
50
51                 [MonoTODO ("EnterpriseServicesInteropOption not supported.")]
52                 public TransactionScope (Transaction transaction,
53                         TimeSpan timeout, DTCOption opt)
54                 {
55                         Initialize (TransactionScopeOption.Required,
56                                 transaction, defaultOptions, opt, timeout);
57                 }
58
59                 public TransactionScope (TransactionScopeOption option)
60                         : this (option, TransactionManager.DefaultTimeout)
61                 {
62                 }
63
64                 public TransactionScope (TransactionScopeOption option,
65                         TimeSpan timeout)
66                 {
67                         Initialize (option, null, defaultOptions,
68                                 DTCOption.None, timeout);
69                 }
70
71                 public TransactionScope (TransactionScopeOption scopeOption,
72                         TransactionOptions options)
73                         : this (scopeOption, options, DTCOption.None)
74                 {
75                 }
76
77                 [MonoTODO ("EnterpriseServicesInteropOption not supported")]
78                 public TransactionScope (TransactionScopeOption scopeOption,
79                         TransactionOptions options,
80                         DTCOption opt)
81                 {
82                         Initialize (scopeOption, null, options, opt,
83                                 TransactionManager.DefaultTimeout);
84                 }
85
86                 void Initialize (TransactionScopeOption scopeOption,
87                         Transaction tx, TransactionOptions options,
88                         DTCOption interop, TimeSpan timeout)
89                 {
90                         completed = false;
91                         isRoot = false;
92                         nested = 0;
93
94                         if (timeout < TimeSpan.Zero)
95                                 throw new ArgumentOutOfRangeException ("timeout");
96
97                         this.timeout = timeout;
98
99                         oldTransaction = Transaction.CurrentInternal;
100
101                         Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
102                         if (transaction != null)
103                                 transaction.InitScope (this);
104                         if (parentScope != null)
105                                 parentScope.nested ++;
106                 }
107
108                 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
109                 {
110                         if (tx != null)
111                                 return tx;
112                                 
113                         if (scopeOption == TransactionScopeOption.Suppress) {
114                                 if (Transaction.CurrentInternal != null)
115                                         parentScope = Transaction.CurrentInternal.Scope;
116                                 return null;
117                         }
118
119                         if (scopeOption == TransactionScopeOption.Required) {
120                                 if (Transaction.CurrentInternal == null) {
121                                         isRoot = true;
122                                         return new Transaction ();
123                                 }
124
125                                 parentScope = Transaction.CurrentInternal.Scope;
126                                 return Transaction.CurrentInternal;
127                         }
128
129                         /* RequiresNew */
130                         if (Transaction.CurrentInternal != null)
131                                 parentScope = Transaction.CurrentInternal.Scope;
132                         isRoot = true;
133                         return new Transaction ();
134                 }
135
136                 public void Complete ()
137                 {
138                         if (completed)
139                                 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
140
141                         completed = true;
142                 }
143
144                 internal bool IsComplete {
145                         get { return completed; }
146                 }
147
148                 internal TimeSpan Timeout
149                 {
150                         get { return timeout; }
151                 }
152
153                 public void Dispose ()
154                 {
155                         if (disposed)
156                                 return;
157
158                         disposed = true;
159
160                         if (parentScope != null)
161                                 parentScope.nested --;
162
163                         if (nested > 0) {
164                                 transaction.Rollback ();
165                                 throw new InvalidOperationException ("TransactionScope nested incorrectly");
166                         }
167
168                         if (Transaction.CurrentInternal != transaction) {
169                                 if (transaction != null)
170                                         transaction.Rollback ();
171                                 if (Transaction.CurrentInternal != null)
172                                         Transaction.CurrentInternal.Rollback ();
173
174                                 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
175                         }
176
177                         if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
178                                 oldTransaction.Scope = parentScope;
179
180                         Transaction.CurrentInternal = oldTransaction;
181
182                         if (transaction == null)
183                                 /* scope was not in a transaction, (Suppress) */
184                                 return;
185
186                         transaction.Scope = null;
187
188                         if (!IsComplete) {
189                                 transaction.Rollback ();
190                                 return;
191                         }
192
193                         if (!isRoot)
194                                 /* Non-root scope has completed+ended */
195                                 return;
196
197                         transaction.CommitInternal ();
198                 }
199
200
201         }
202 }
203