Skip to content

Commit

Permalink
Fix closing unpooled connection with transaction scope (#4964)
Browse files Browse the repository at this point in the history
Fixes #4963

(cherry picked from commit bceb9e1)
  • Loading branch information
vonzshik committed Mar 2, 2023
1 parent aed225e commit 5940643
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 45 deletions.
7 changes: 2 additions & 5 deletions src/Npgsql/NpgsqlConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -856,13 +856,10 @@ async Task CloseAsync(bool async)

connector.Connection = null;

// If pooled, close the connection and disconnect it from the resource manager but leave the
// connector in an enlisted pending list in the pool. If another connection is opened within
// Close the connection and disconnect it from the resource manager but leave the
// connector in an enlisted pending list in the data source. If another connection is opened within
// the same transaction scope, we will reuse this connector to avoid escalating to a distributed
// transaction
// If a *non-pooled* connection is being closed but is enlisted in an ongoing
// TransactionScope, we do nothing - simply detach the connector from the connection and leave
// it open. It will be closed when the TransactionScope is disposed.
_dataSource?.AddPendingEnlistedConnector(connector, EnlistedTransaction);

EnlistedTransaction = null;
Expand Down
9 changes: 0 additions & 9 deletions src/Npgsql/UnpooledDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,4 @@ internal override void Return(NpgsqlConnector connector)
}

internal override void Clear() {}

internal override bool TryRentEnlistedPending(Transaction transaction, NpgsqlConnection connection,
[NotNullWhen(true)] out NpgsqlConnector? connector)
{
connector = null;
return false;
}

internal override bool TryRemovePendingEnlistedConnector(NpgsqlConnector connector, Transaction transaction) => false;
}
31 changes: 0 additions & 31 deletions test/Npgsql.Tests/DistributedTransactionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,37 +111,6 @@ public void Two_connections_with_failure()
AssertNumberOfRows(adminConn, table, 0);
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/1737")]
public void Multiple_unpooled_connections_do_not_reuse()
{
var csb = new NpgsqlConnectionStringBuilder(ConnectionString)
{
Pooling = false,
Enlist = true
};

using var scope = new TransactionScope();

int processId;

using (var conn1 = OpenConnection(csb))
using (var cmd = new NpgsqlCommand("SELECT 1", conn1))
{
processId = conn1.ProcessID;
cmd.ExecuteNonQuery();
}

using (var conn2 = OpenConnection(csb))
using (var cmd = new NpgsqlCommand("SELECT 1", conn2))
{
// The connection reuse optimization isn't implemented for unpooled connections (though it could be)
Assert.That(conn2.ProcessID, Is.Not.EqualTo(processId));
cmd.ExecuteNonQuery();
}

scope.Complete();
}

[Test(Description = "Transaction race, bool distributed")]
[Explicit("Fails on Appveyor (https://ci.appveyor.com/project/roji/npgsql/build/3.3.0-250)")]
public void Transaction_race([Values(false, true)] bool distributed)
Expand Down
23 changes: 23 additions & 0 deletions test/Npgsql.Tests/SystemTransactionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,29 @@ public void Single_unpooled_connection()
scope.Complete();
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/4963")]
public void Single_unpooled_closed_connection()
{
var csb = new NpgsqlConnectionStringBuilder(ConnectionString)
{
Pooling = false,
Enlist = true
};
using var dataSource = NpgsqlDataSource.Create(csb);

using (var scope = new TransactionScope())
using (var conn = dataSource.OpenConnection())
using (var cmd = new NpgsqlCommand("SELECT 1", conn))
{
cmd.ExecuteNonQuery();
conn.Close();
Assert.That(dataSource.Statistics.Total, Is.EqualTo(1));
scope.Complete();
}

Assert.That(dataSource.Statistics.Total, Is.EqualTo(0));
}

[Test]
[IssueLink("https://github.com/npgsql/npgsql/issues/3863")]
public void Break_connector_while_in_transaction_scope_with_rollback([Values] bool pooling)
Expand Down

0 comments on commit 5940643

Please sign in to comment.