File: LocalTransaction.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (156 lines) | stat: -rw-r--r-- 4,791 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//------------------------------------------------------------------------------
// <copyright file="LocalTransaction.cs" company="Microsoft">
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#region Using directives

using System;
using System.Diagnostics;
using System.Transactions;
using System.Data;
using System.Data.Common;
using System.Threading;

#endregion

namespace System.Workflow.Runtime.Hosting
{
    /// <summary>
    /// This class wraps a local transaction (DbTransaction) by implementing IPromotableSinglePhaseNotification:
    /// It instantiate a DbTransaction and never allows promotion to a DTC transaction.
    /// </summary>
    internal sealed class LocalTransaction : IPromotableSinglePhaseNotification
    {
        readonly DbTransaction transaction;
        System.Data.Common.DbConnection connection;
        ManualResetEvent handle;
        object syncRoot = new Object();

        #region Constructor

        /// <summary>
        /// Wraps a local transaction inside
        /// </summary>
        /// <param name="dbHelper"></param>
        internal LocalTransaction(DbResourceAllocator dbHelper, ManualResetEvent handle)
        {
            if (null == handle)
                throw new ArgumentNullException("handle");

            // Open a connection that specifically does not auto-enlist ("Enlist=false" in connection string)
            // to prevent auto-promotion of the transaction
            this.connection = dbHelper.OpenNewConnectionNoEnlist();
            this.transaction = this.connection.BeginTransaction();
            this.handle = handle;
        }

        #endregion Constructor


        #region Accessors

        public System.Data.Common.DbConnection Connection
        {
            get { return this.connection; }
        }

        public DbTransaction Transaction
        {
            get { return this.transaction; }
        }

        #endregion Accessors


        #region IPromotableSinglePhaseNotification Members

        public void Initialize()
        {
        }

        public void SinglePhaseCommit(SinglePhaseEnlistment en)
        {
            if (en == null)
                throw new ArgumentNullException("en");

            //
            // Wait until IPendingWork members have completed (WinOE bugs 17580 and 13395)
            try
            {
                handle.WaitOne();
            }
            catch (ObjectDisposedException)
            {
                // If an ObjectDisposedException is thrown because
                // the WaitHandle has already closed, nothing to worry
                // about. Move on.
            }

            lock (syncRoot)
            {
                try
                {
                    this.transaction.Commit();
                    en.Committed();
                }
                catch (Exception e)
                {
                    en.Aborted(e);
                }
                finally
                {
                    if ((null != connection) && (ConnectionState.Closed != connection.State))
                    {
                        connection.Close();
                        connection = null;
                    }
                }
            }
        }

        public void Rollback(SinglePhaseEnlistment en)
        {
            if (en == null)
                throw new ArgumentNullException("en");

            //
            // Wait until IPendingWork members have completed (WinOE bugs 17580 and 13395)
            try
            {
                handle.WaitOne();
            }
            catch (ObjectDisposedException)
            {
                // If an ObjectDisposedException is thrown because
                // the WaitHandle has already closed, nothing to worry
                // about. Move on.
            }
            // DbTransaction.Dispose will call Rollback if the DbTransaction is not Zombied.
            // Not safe to call DbTransaction.Rollback here as the the underlining 
            // DbTransaction may have already been Rolled back
            lock (syncRoot)
            {
                if (null != transaction)
                    transaction.Dispose();

                if ((null != connection) && (ConnectionState.Closed != connection.State))
                {
                    connection.Close();
                    connection = null;
                }

                en.Aborted();
            }
        }

        public byte[] Promote()
        {
            throw new TransactionPromotionException(
                ExecutionStringManager.PromotionNotSupported);
        }

        #endregion IPromotableSinglePhaseNotification Members
    }
}