On 09/30/2011 02:21 PM, Scott Morgan wrote:
On 09/30/2011 12:59 PM, Mark Rotteveel wrote:
True, but making sure that you always lock resources in the same order,
is the only sure way to prevent deadlocks.
I think I see the problem:
In Version10/GdsTransaction.cs (copy/paste from the Sourceforge SVN
browser, so excuse the formatting)
...
The SyncObject lock is to protect the calls to this.database.Write etc.
(lines 194-200) but it also covers the transaction's state change (lines
202-207) which it shouldn't and is the point the deadlock occurs.
Something like this may be better:
...
Similar changes would need to be made to the other functions in this
class (Commit, RollbackRetaining, etc...)
Scott
See patch against the SVN trunk.
Scott
Index: GdsServiceManager.cs
===================================================================
--- GdsServiceManager.cs (revision 53626)
+++ GdsServiceManager.cs (working copy)
@@ -64,15 +64,18 @@
{
try
{
-
this.database.Write(IscCodes.op_service_attach);
- this.database.Write(0);
- this.database.Write(service);
-
this.database.WriteBuffer(spb.ToArray());
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_service_attach);
+ this.database.Write(0);
+ this.database.Write(service);
+
this.database.WriteBuffer(spb.ToArray());
+ this.database.Flush();
- response = this.database.ReadGenericResponse();
+ response =
this.database.ReadGenericResponse();
+ }
- this.handle = response.ObjectHandle;
+ this.handle = response.ObjectHandle;
}
catch (IOException)
{
@@ -89,12 +92,15 @@
{
try
{
-
this.database.Write(IscCodes.op_service_detach);
- this.database.Write(this.Handle);
-
this.database.Write(IscCodes.op_disconnect);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_service_detach);
+
this.database.Write(this.Handle);
+
this.database.Write(IscCodes.op_disconnect);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
+ }
this.handle = 0;
}
@@ -127,20 +133,23 @@
{
try
{
-
this.database.Write(IscCodes.op_service_start);
- this.database.Write(this.Handle);
- this.database.Write(0);
-
this.database.WriteBuffer(spb.ToArray(), spb.Length);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_service_start);
+
this.database.Write(this.Handle);
+ this.database.Write(0);
+
this.database.WriteBuffer(spb.ToArray(), spb.Length);
+ this.database.Flush();
- try
- {
- this.database.ReadResponse();
+ try
+ {
+
this.database.ReadResponse();
+ }
+ catch (IscException)
+ {
+ throw;
+ }
}
- catch (IscException)
- {
- throw;
- }
}
catch (IOException)
{
@@ -160,27 +169,30 @@
{
try
{
-
this.database.Write(IscCodes.op_service_info); // operation
- this.database.Write(this.Handle);
// db_handle
- this.database.Write(0);
// incarnation
- this.database.WriteTyped(
- IscCodes.isc_spb_version,
spb.ToArray()); // Service parameter buffer
- this.database.WriteBuffer(
- requestBuffer, requestLength);
// request buffer
- this.database.Write(bufferLength);
// result buffer length
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_service_info); // operation
+
this.database.Write(this.Handle); //
db_handle
+ this.database.Write(0);
// incarnation
+ this.database.WriteTyped(
+
IscCodes.isc_spb_version, spb.ToArray()); // Service parameter buffer
+ this.database.WriteBuffer(
+ requestBuffer,
requestLength); // request buffer
+
this.database.Write(bufferLength); // result
buffer length
- this.database.Flush();
+ this.database.Flush();
- GenericResponse response =
this.database.ReadGenericResponse();
+ GenericResponse response =
this.database.ReadGenericResponse();
- int responseLength = bufferLength;
+ int responseLength =
bufferLength;
- if (response.Data.Length < bufferLength)
- {
- responseLength = response.Data.Length;
- }
+ if (response.Data.Length <
bufferLength)
+ {
+ responseLength =
response.Data.Length;
+ }
- Buffer.BlockCopy(response.Data, 0, buffer, 0,
responseLength);
+ Buffer.BlockCopy(response.Data,
0, buffer, 0, responseLength);
+ }
}
catch (IOException)
{
Index: GdsTransaction.cs
===================================================================
--- GdsTransaction.cs (revision 53626)
+++ GdsTransaction.cs (working copy)
@@ -125,26 +125,29 @@
public void BeginTransaction(TransactionParameterBuffer tpb)
{
- if (this.state != TransactionState.NoTransaction)
+ lock (this)
{
- throw new IscException(IscCodes.isc_arg_gds,
IscCodes.isc_tra_state, this.handle, "no valid");
- }
+ if (this.state !=
TransactionState.NoTransaction)
+ {
+ throw new
IscException(IscCodes.isc_arg_gds, IscCodes.isc_tra_state, this.handle, "no
valid");
+ }
- lock (this.database.SyncObject)
- {
try
{
-
this.database.Write(IscCodes.op_transaction);
-
this.database.Write(this.database.Handle);
-
this.database.WriteBuffer(tpb.ToArray());
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_transaction);
+
this.database.Write(this.database.Handle);
+
this.database.WriteBuffer(tpb.ToArray());
+ this.database.Flush();
- GenericResponse response =
this.database.ReadGenericResponse();
+ GenericResponse response =
this.database.ReadGenericResponse();
- this.handle = response.ObjectHandle;
- this.state = TransactionState.Active;
+ this.handle =
response.ObjectHandle;
+ this.state =
TransactionState.Active;
- this.database.TransactionCount++;
+
this.database.TransactionCount++;
+ }
}
catch (IOException)
{
@@ -155,19 +158,22 @@
public void Commit()
{
- this.CheckTransactionState();
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
try
{
- this.database.Write(IscCodes.op_commit);
- this.database.Write(this.handle);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_commit);
+
this.database.Write(this.handle);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
- this.database.TransactionCount--;
+
this.database.TransactionCount--;
+ }
if (this.Update != null)
{
@@ -185,19 +191,22 @@
public void Rollback()
{
- this.CheckTransactionState();
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
try
{
-
this.database.Write(IscCodes.op_rollback);
- this.database.Write(this.handle);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_rollback);
+
this.database.Write(this.handle);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
- this.database.TransactionCount--;
+
this.database.TransactionCount--;
+ }
if (this.Update != null)
{
@@ -215,17 +224,20 @@
public void CommitRetaining()
{
- this.CheckTransactionState();
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
try
{
-
this.database.Write(IscCodes.op_commit_retaining);
- this.database.Write(this.handle);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_commit_retaining);
+
this.database.Write(this.handle);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
+ }
this.state = TransactionState.Active;
}
@@ -238,17 +250,20 @@
public void RollbackRetaining()
{
- this.CheckTransactionState();
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
try
{
-
this.database.Write(IscCodes.op_rollback_retaining);
- this.database.Write(this.handle);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_rollback_retaining);
+
this.database.Write(this.handle);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
+ }
this.state = TransactionState.Active;
}
@@ -263,56 +278,62 @@
#region · Two Phase Commit Methods ·
- public void Prepare()
- {
- this.CheckTransactionState();
+ public void Prepare()
+ {
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
- try
- {
- this.state = TransactionState.NoTransaction;
+ try
+ {
+ this.state =
TransactionState.NoTransaction;
- this.database.Write(IscCodes.op_prepare);
- this.database.Write(this.handle);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_prepare);
+
this.database.Write(this.handle);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
+ }
- this.state = TransactionState.Prepared;
- }
- catch (IOException)
- {
- throw new IscException(IscCodes.isc_net_read_err);
- }
- }
- }
+ this.state = TransactionState.Prepared;
+ }
+ catch (IOException)
+ {
+ throw new
IscException(IscCodes.isc_net_read_err);
+ }
+ }
+ }
- public void Prepare(byte[] buffer)
- {
- this.CheckTransactionState();
+ public void Prepare(byte[] buffer)
+ {
+ lock (this)
+ {
+ this.CheckTransactionState();
- lock (this.database.SyncObject)
- {
- try
- {
- this.state = TransactionState.NoTransaction;
+ try
+ {
+ this.state =
TransactionState.NoTransaction;
- this.database.Write(IscCodes.op_prepare2);
- this.database.Write(this.handle);
- this.database.WriteBuffer(buffer, buffer.Length);
- this.database.Flush();
+ lock (this.database.SyncObject)
+ {
+
this.database.Write(IscCodes.op_prepare2);
+
this.database.Write(this.handle);
+
this.database.WriteBuffer(buffer, buffer.Length);
+ this.database.Flush();
- this.database.ReadResponse();
+ this.database.ReadResponse();
+ }
- this.state = TransactionState.Prepared;
- }
- catch (IOException)
- {
- throw new IscException(IscCodes.isc_net_read_err);
- }
- }
- }
+ this.state = TransactionState.Prepared;
+ }
+ catch (IOException)
+ {
+ throw new
IscException(IscCodes.isc_net_read_err);
+ }
+ }
+ }
#endregion
------------------------------------------------------------------------------
RSA(R) Conference 2012
Save $700 by Nov 18
Register now
http://p.sf.net/sfu/rsa-sfdev2dev1
_______________________________________________
Firebird-net-provider mailing list
Firebird-net-provider@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider