What is the reason of "Transaction context in use by another session"
- by Shrike
Hi,
I'm looking for a description of the root of this error: "Transaction context in use by another session".
I get it sometimes in one of my unittests so I can't provider repro code. But I wonder what is "by design" reason for the error.
I've found this post:
http://blogs.msdn.com/asiatech/archive/2009/08/10/system-transaction-may-fail-in-multiple-thread-environment.aspx
and also that:
http://msdn.microsoft.com/en-us/library/ff649002.aspx
But I can't understand what "Multiple threads sharing the same transaction in a transaction scope will cause the following exception: 'Transaction context in use by another session.' " means. All words are understandable but not the point.
I actually can share a system transaction between threads. And there is even special mechanism for this - DependentTransaction class and Transaction.DependentClone method.
I'm trying to reproduce a usecase from the first post:
1. Main thread creates DTC transaction, receives DependentTransaction (created using Transaction.Current.DependentClone on the main thread
2. Child thread 1 enlists in this DTC transaction by creating a transaction scope based on the dependent transaction (passed via constructor)
3. Child thread 1 opens a connection
4. Child thread 2 enlists in DTC transaction by creating a transaction scope based on the dependent transaction (passed via constructor)
5. Child thread 2 opens a connection
with such code:
using System;
using System.Threading;
using System.Transactions;
using System.Data;
using System.Data.SqlClient;
public class Program
{
private static string ConnectionString = "Initial Catalog=DB;Data Source=.;User ID=user;PWD=pwd;";
public static void Main()
{
int MAX = 100;
for(int i =0; i< MAX;i++)
{
using(var ctx = new TransactionScope())
{
var tx = Transaction.Current;
// make the transaction distributed
using (SqlConnection con1 = new SqlConnection(ConnectionString))
using (SqlConnection con2 = new SqlConnection(ConnectionString))
{
con1.Open();
con2.Open();
}
showSysTranStatus();
DependentTransaction dtx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
Thread t1 = new Thread(o => workCallback(dtx));
Thread t2 = new Thread(o => workCallback(dtx));
t1.Start();
t2.Start();
t1.Join();
t2.Join();
ctx.Complete();
}
trace("root transaction completes");
}
}
private static void workCallback(DependentTransaction dtx)
{
using(var txScope1 = new TransactionScope(dtx))
{
using (SqlConnection con2 = new SqlConnection(ConnectionString))
{
con2.Open();
trace("connection opened");
showDbTranStatus(con2);
}
txScope1.Complete();
}
trace("dependant tran completes");
}
private static void trace(string msg)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " : " + msg);
}
private static void showSysTranStatus()
{
string msg;
if (Transaction.Current != null)
msg = Transaction.Current.TransactionInformation.DistributedIdentifier.ToString();
else
msg = "no sys tran";
trace( msg );
}
private static void showDbTranStatus(SqlConnection con)
{
var cmd = con.CreateCommand();
cmd.CommandText = "SELECT 1";
var c = cmd.ExecuteScalar();
trace("@@TRANCOUNT = " + c);
}
}
It fails on Complete's call of root TransactionScope. But error is different:
Unhandled Exception: System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---
pired. The timeout period elapsed prior to completion of the operation or the server is not responding.
To sum up: I want to understand what "Transaction context in use by another session" means and how to reproduce it.