Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closing a pooled connection with an active transaction does not rollback transaction immediately #927

Closed
tastywheattasteslikechicken opened this issue Dec 30, 2015 · 2 comments
Assignees
Labels
Milestone

Comments

@tastywheattasteslikechicken

Example Code:
var connection = new NpgsqlConnection(ConnectionString);
var connection2 = new NpgsqlConnection(ConnectionString);
connection.Open();
connection2.Open(); //Make sure we get a different connection, not a reused pool one.

        using (var cmd = connection.CreateCommand())
        {
            cmd.CommandText = "create table CantTouchThis(floop integer, name varchar(10));";
            cmd.ExecuteNonQuery();
        }

        connection.BeginTransaction(); //Seems not to actually begin a transaction
        using (var cmd = connection.CreateCommand())
        {
            cmd.CommandText = "insert into CantTouchThis values (10, 'test');";
            cmd.ExecuteNonQuery(); //Actually begins the transaction
        }

        connection.Close(); //Send connection back to the pool, the transaction *should* be rolled back here
        using (var cmd = connection2.CreateCommand())
        {
            cmd.CommandText = "drop table CantTouchThis;";
            cmd.ExecuteNonQuery();
        }

Expected behaviour: 'connection' should perform a rollback prior to 'Close' returning.
Actual behaviour: transaction remains pending, causing a timeout, as seen: http://i.imgur.com/UemAvOb.png

It appears the problem is in NpgsqlConnector.cs : Reset(), where the "PrependInternalMessage" does not actually send the messages placed into the queue.

@roji
Copy link
Member

roji commented Dec 30, 2015

@tastywheattasteslikechicken this was actually done intentionally, as a performance optimization. When a pooled connection is closed, rather than immediately sending a rollback (meaning a network round-trip) we prepend it to the first statement sent after the connection is reopened.

I see now that this optimization has its negative consequences... Even without your scenario (trying to drop a table currently under a transaction), I'm guessing that leaving a transaction open in the way we do might have some other problematic consequences on the PostgreSQL side (resources left in-use because the transaction is still in progress).

@Emill, I think we discussed this optimization together at some point, do you have any thoughts here? I guess we went too far here and should undo this for 3.0.5..

@roji roji added the bug label Dec 30, 2015
@roji roji added this to the 3.0.5 milestone Dec 30, 2015
@roji roji self-assigned this Dec 30, 2015
@roji
Copy link
Member

roji commented Dec 30, 2015

If you need a temporary workaround, send some useless query (SELECT 1) after calling Rollback(), that will make sure the rollback gets to the database immediately.

@roji roji added the critical label Dec 30, 2015
@roji roji closed this as completed in 611f390 Dec 30, 2015
roji added a commit that referenced this issue Dec 30, 2015
When a pooled connection was closed while a transaction was still in
progress, Npgsql had an optimization whereby it didn't execute a rollback
immediately, but rather prepended a rollback message for execution the
next time the connection is opened and used. This created some issues as
the transaction kept locks etc. for an indefinite time.

Removed the optimization, closing a connection now immediately sends a
rollback.

Fixes #927

(cherry picked from commit 611f390)
@roji roji changed the title Closing a connection with an active transaction does not rollback transaction immediately if pooling is enabled Closing a pooled connection with an active transaction does not rollback transaction immediately Jan 1, 2016
friism pushed a commit to friism/npgsql that referenced this issue Jan 11, 2016
When a pooled connection was closed while a transaction was still in
progress, Npgsql had an optimization whereby it didn't execute a rollback
immediately, but rather prepended a rollback message for execution the
next time the connection is opened and used. This created some issues as
the transaction kept locks etc. for an indefinite time.

Removed the optimization, closing a connection now immediately sends a
rollback.

Fixes npgsql#927
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants