Skip to content

Commit

Permalink
Fixed deadlocks and NullRefs on dispose (DNET-316).
Browse files Browse the repository at this point in the history
  • Loading branch information
cincuranet committed Nov 20, 2011
1 parent 999a2a6 commit f71e5d8
Show file tree
Hide file tree
Showing 2 changed files with 547 additions and 504 deletions.
Expand Up @@ -38,6 +38,7 @@ internal sealed class GdsTransaction : ITransaction, IDisposable
private bool disposed;
private GdsDatabase database;
private TransactionState state;
private object stateSyncRoot;

#endregion

Expand All @@ -57,15 +58,21 @@ public TransactionState State

#region · Constructors ·

private GdsTransaction()
{
stateSyncRoot = new object();
}

public GdsTransaction(IDatabase db)
: this()
{
if (!(db is GdsDatabase))
{
throw new ArgumentException("Specified argument is not of GdsDatabase type.");
}

this.database = (GdsDatabase)db;
this.state = TransactionState.NoTransaction;
this.database = (GdsDatabase)db;
this.state = TransactionState.NoTransaction;

GC.SuppressFinalize(this);
}
Expand All @@ -91,7 +98,7 @@ public void Dispose()

private void Dispose(bool disposing)
{
lock (this)
lock (stateSyncRoot)
{
if (!this.disposed)
{
Expand Down Expand Up @@ -125,26 +132,30 @@ private void Dispose(bool disposing)

public void BeginTransaction(TransactionParameterBuffer tpb)
{
if (this.state != TransactionState.NoTransaction)
lock (stateSyncRoot)
{
throw new IscException(IscCodes.isc_arg_gds, IscCodes.isc_tra_state, this.handle, "no valid");
}
if (this.state != TransactionState.NoTransaction)
{
throw GetNoValidTransactionException();
}

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();
GenericResponse response;
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();
response = this.database.ReadGenericResponse();

this.handle = response.ObjectHandle;
this.state = TransactionState.Active;
this.database.TransactionCount++;
}

this.database.TransactionCount++;
this.handle = response.ObjectHandle;
this.state = TransactionState.Active;
}
catch (IOException)
{
Expand All @@ -155,19 +166,22 @@ public void BeginTransaction(TransactionParameterBuffer tpb)

public void Commit()
{
this.CheckTransactionState();

lock (this.database.SyncObject)
lock (stateSyncRoot)
{
this.CheckTransactionState();

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)
{
Expand All @@ -185,19 +199,22 @@ public void Commit()

public void Rollback()
{
this.CheckTransactionState();

lock (this.database.SyncObject)
lock (stateSyncRoot)
{
this.CheckTransactionState();

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)
{
Expand All @@ -215,17 +232,20 @@ public void Rollback()

public void CommitRetaining()
{
this.CheckTransactionState();

lock (this.database.SyncObject)
lock (stateSyncRoot)
{
this.CheckTransactionState();

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;
}
Expand All @@ -238,17 +258,20 @@ public void CommitRetaining()

public void RollbackRetaining()
{
this.CheckTransactionState();

lock (this.database.SyncObject)
lock (stateSyncRoot)
{
this.CheckTransactionState();

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;
}
Expand All @@ -263,56 +286,62 @@ public void RollbackRetaining()

#region · Two Phase Commit Methods ·

public void Prepare()
{
this.CheckTransactionState();

lock (this.database.SyncObject)
{
try
{
this.state = TransactionState.NoTransaction;

this.database.Write(IscCodes.op_prepare);
this.database.Write(this.handle);
this.database.Flush();

this.database.ReadResponse();

this.state = TransactionState.Prepared;
}
catch (IOException)
{
throw new IscException(IscCodes.isc_net_read_err);
}
}
}

public void Prepare(byte[] buffer)
{
this.CheckTransactionState();

lock (this.database.SyncObject)
{
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();

this.database.ReadResponse();

this.state = TransactionState.Prepared;
}
catch (IOException)
{
throw new IscException(IscCodes.isc_net_read_err);
}
}
}
public void Prepare()
{
lock (stateSyncRoot)
{
this.CheckTransactionState();

try
{
this.state = TransactionState.NoTransaction;

lock (this.database.SyncObject)
{
this.database.Write(IscCodes.op_prepare);
this.database.Write(this.handle);
this.database.Flush();

this.database.ReadResponse();
}

this.state = TransactionState.Prepared;
}
catch (IOException)
{
throw new IscException(IscCodes.isc_net_read_err);
}
}
}

public void Prepare(byte[] buffer)
{
lock (stateSyncRoot)
{
this.CheckTransactionState();

try
{
this.state = TransactionState.NoTransaction;

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.state = TransactionState.Prepared;
}
catch (IOException)
{
throw new IscException(IscCodes.isc_net_read_err);
}
}
}

#endregion

Expand All @@ -322,10 +351,15 @@ private void CheckTransactionState()
{
if (this.state != TransactionState.Active)
{
throw new IscException(IscCodes.isc_arg_gds, IscCodes.isc_tra_state, this.handle, "no valid");
throw GetNoValidTransactionException();
}
}

private IscException GetNoValidTransactionException()
{
return new IscException(IscCodes.isc_arg_gds, IscCodes.isc_tra_state, this.handle, "no valid");
}

#endregion
}
}

0 comments on commit f71e5d8

Please sign in to comment.