Skip to content

Scope without prepared transactions #8

merged 4 commits into from Nov 21, 2012

3 participants

Npgsql member
roji commented Nov 15, 2012

Hey Francisco and Josh, sorry for disappearing, had some busy times at work.

Here's an attempt at a patch which would remove the dependency on prepared transactions when a connection is closed within a TransactionScope. I added a unit test which reproduced the problem on stock Postgres installations: SystemTransactionTests.SimpleTransactionScopeWithImplicitEnlist.

My general approach was to check whether a local (non-prepared) transaction is still active in the NpgsqlPromotableSinglePhaseNotification when Close() is called. If so, we enter the "postponingClose" state instead of actually closing. Then, when the local transaction is terminated (because of a commit, rollback or promote) the connection is notified and does the real close. There are a few more tweaks (Dispose and reopen after close) but it should be pretty straightforward.

Note that this takes care of the pattern:
using (var conn1 = new NpgsqlConnection(...) {
conn1.Open(); conn1.Close();
conn1.Open(); conn1.Close();

But does not take care of the pattern:
using (var conn1 = new NpgsqlConnection(connString1) { ... }
using (var conn2 = new NpgsqlConnection(connString1) { ... }
As Josh suggested, since I think that would require handling stuff at the pool. Maybe a second commit?

Anyway, let me know what you think...

Note that there are also two tiny build cleanup commits before the real one...

Shay Rojansky and others added some commits Nov 15, 2012
Shay Rojansky Removed unneeded NUnit references in unit tests
NUnit.Core, NUnit.Core.Interfaces, NUnit.Util, was causing build build
Shay Rojansky Corrected unit test project references
NpgsqlTests2010 now references Npgsql2010 instead of Npgsql2008
@roji roji Conn can be closed in TransactionScope without prepared transaction
Previously closing a connection within a TransactionScope triggered an
automatic promotion to a prepared transaction. Since by default Postgres
disables these, this made the TransactionScope unusable for many cases.
This is reproduced in
SystemTransactionTests.SimpleTransactionScopeWithImplicitEnlist, which was
failing in stock Postgres installations.

Instead of promoting, we now postpone the close until the (local)
transaction is terminated, i.e. until the TransactionScope ends.
@roji roji Removed connection leak detection and handling
By Francisco's request
@franciscojunior franciscojunior merged commit 55d7f3f into npgsql:master Nov 21, 2012
Npgsql member

Thank you very much for your patches, Shay! Good work. I'll get your changes in our cvs repository too.

Npgsql member
roji commented Nov 21, 2012

Great Francisco, it's a pleasure to help!

Npgsql member

Finally could apply your patch to cvs. Thanks again for your help!

Npgsql member
roji commented Feb 17, 2013

Thanks Francisco :)

FYI Some support for ambient transactions was missing in mono and my patch for that was accepted a while ago (mono/mono#484), so in the next npgsql it should all work nicely together...

@roji roji deleted the roji:scope_without_prepared_transactions branch Mar 12, 2013
omatrot commented May 7, 2013

Hi all,
This fix solved a problem where, in a WCF service, a local transaction was treated as a distributed transaction.
Now, in this same WCF service, when the transaction comes from the client, so it is now distributed, and should be treated with a prepared transaction, it is treated local instead.
Could we work on this together ?

Npgsql member
roji commented May 7, 2013

I can try to find some time and look at this. To help out, can you please:

  • Open a separate issue for this on github, and
  • If possible, try to submit a testcase reproducing this?

Are you on mono or MS.NET? Which version?

omatrot commented May 10, 2013

Hi, Sorry for the late reply.
I'm using MS .NET4.5.

For a WCF service sample, please go the follwing link (MSDN Magazine article about Transactions in WCF) :, use the code found in figure 5, and add some Npgsql code in the service.

Create a simple console client, use 'add service reference' to connect to the service. You could now make a call to the service inside a Transaction Scope as shown in figure 8.

I'll create a Git issue ASAP.

omatrot commented May 10, 2013

Just so you know, I've managed to create a fix that is working fine in my context. I'll do more regression testing before suggesting it.
NpgsqlConnection.cs :

  • Introduced a new method called DistributedTransactionPreparePhaseEnded to mirror PromotableLocalTransactionEnded for the specific case of a pending distributed transaction.
  • Modified Close() to check if a distributed transaction is pending in order to postpone the call to RealClose(). NpgsqlTransactionCallbacks.cs :
  • PrepareTransaction() is modified to call connection.DistributedTransactionPreparePhaseEnded() once the transaction is prepared on the database. NpgsqlPromotableSinglePhaseNotification.cs :
  • Added a boolean named InDistributedTransaction.
  • Modified Enlist() to set InDistributedTransaction to true if the call to EnlistPromotableSinglePhase return false. NpgsqlResourceManager.cs :
  • Modified Enlist(Transaction tx) to call EnlistDurable on the transaction to specify EnlistmentOptions.EnlistDuringPrepareRequired instead of EnlistmentOptions.None. This has the effect of calling IEnlistmentNotification.Prepare.
  • Also assigned a new Guid each time a resource manager is created because for now, it is not implemented in a Windows Service to act as a proxy, and could be created multiple times in a server environment.
Npgsql member
roji commented May 10, 2013
@roji roji added a commit to roji/Npgsql that referenced this pull request Dec 7, 2013
@roji roji Work on ambient transaction and related refactoring
- Removed the previous "postponed close" state on Connection, which allowed for partial connection
  reuse within an ambient transaction (see npgsql#8 and
  discussion on the list).
- When a Connection is closed while a TransactionScope is still active, its connector is detached
  and returned to the pool, but specially marked as AvailableWithTransaction. Any subsequent
  Connection within the same transaction and connection string will now preferably be attached to
  that connector, preventing escalation to prepared transactions.
- When an ambient transaction completes, all the connectors involved it in are notified. If a
  connector is detached (i.e. its connection has already been closed), it is returned to the pool
  and marked as Available.
- A similar flow has been implemented for non-pooled connections/connectors.
- The above required a refactor of Connector, Connection and some associated classes. In particular,
  to allow connections to be smoothly detached and reattached to connectors, many Npgsql components
  now references the connector instead of the connection, and the connection has been made as bare
  a frontend as possible.
- SSL callbacks are now always registered just before Connector.Open(), and removed right
@gencer gencer pushed a commit to gencer/Npgsql2 that referenced this pull request Apr 11, 2014
fxjr Applied Shay Rojansky patch. [#1011305] Scope without prepared transa…
…ctions. Check npgsql#8 for more info.
@kenjiuno kenjiuno added a commit to kenjiuno/Npgsql that referenced this pull request May 19, 2014
@kenjiuno kenjiuno Step #8: Add the VSIXManifestSchema.xsd to allow VsixManifest validat…
…ion on the build server
@kenjiuno kenjiuno added a commit to kenjiuno/Npgsql that referenced this pull request May 21, 2014
@kenjiuno kenjiuno Step #8: Add the VSIXManifestSchema.xsd to allow VsixManifest validat…
…ion on the build server
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.