Re: Transactions over pathological TCP connections

Lists: pgsql-hackers
From: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: Transactions over pathological TCP connections
Date: 2012-06-18 19:33:02
Message-ID: CAPwAf1ksnfps0z=3VwsCojwX4ui-V1-u-u-TA9UH_7xgAvvFAw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Out of (mostly idle) curiousity, when exactly does a transaction commit,
especially with respect to a TCP connection that a pathological demon will
cut off at the worst possible moment?

The thing is, I'm using PostgreSQL as a queue, using asynchronous
notifications and following the advice of Marko Tiikkaja in this post:

http://johtopg.blogspot.com/2010/12/queues-in-sql.html

I'm using a stored procedure to reduce the round trips between the database
and client, and then running it in a "bare transaction", that is, as
"SELECT dequeue_element();" with an implicit BEGIN/COMMIT to mark a row in
the queue as taken and return it.

My question is, would it be theoretically possible for an element of a
queue to become marked but not delivered, or delivered and not marked, if
the TCP connection between the backend and client was interrupted at the
worst possible moment? Will the backend wait for the delivery of the row
be acknowledged before the transaction is committed? Or should the
truly paranoid use an explicit transaction block and not consider the row
taken until confirmation that the transaction has committed has been
received?

Best,
Leon


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Transactions over pathological TCP connections
Date: 2012-06-19 05:56:33
Message-ID: 4474.1340085393@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com> writes:
> Out of (mostly idle) curiousity, when exactly does a transaction commit,
> especially with respect to a TCP connection that a pathological demon will
> cut off at the worst possible moment?

It's committed when the XLOG_XACT_COMMIT WAL record reaches disk,
if by "committed" you mean "is guaranteed to still be visible following
recovery from a subsequent database or operating system crash". If you
have some other definition of "committed" in mind, please say what.

> My question is, would it be theoretically possible for an element of a
> queue to become marked but not delivered, or delivered and not marked, if
> the TCP connection between the backend and client was interrupted at the
> worst possible moment?

The transaction would be committed before a command success report is
delivered to the client, so I don't think delivered-and-not-marked is
possible. The other direction is possible, if the connection drops
after the transaction is committed but before the completion report
can be delivered to the client.

regards, tom lane


From: Robert Haas <robertmhaas(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Transactions over pathological TCP connections
Date: 2012-06-19 15:59:43
Message-ID: CA+TgmoanfeGDdyFkFBx7WCnMv64u6Zoz+-gKUrL-K-=AU7NE+w@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

On Tue, Jun 19, 2012 at 1:56 AM, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> The transaction would be committed before a command success report is
> delivered to the client, so I don't think delivered-and-not-marked is
> possible.

...unless you have configured synchronous_commit=off, or fsync=off.

Or unless your disk melts into a heap of slag and you have to restore
from backup. You can protect against that last case using synchronous
replication.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


From: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>
To: Robert Haas <robertmhaas(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Transactions over pathological TCP connections
Date: 2012-06-19 21:50:32
Message-ID: CAPwAf1ksL3ewRsrwKp2C2tQpYOhaGHB8d1TSmXz+rADPiq0rzQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

On Tue, Jun 19, 2012 at 11:59 AM, Robert Haas <robertmhaas(at)gmail(dot)com> wrote:

> On Tue, Jun 19, 2012 at 1:56 AM, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> > The transaction would be committed before a command success report is
> > delivered to the client, so I don't think delivered-and-not-marked is
> > possible.
>
> ...unless you have configured synchronous_commit=off, or fsync=off.
>
> Or unless your disk melts into a heap of slag and you have to restore
> from backup. You can protect against that last case using synchronous
> replication.
>

But hard disk failure isn't in the failure model I was concerned about.
=) To be perfectly honest, I'm not too concerned with either hard drive
failure or network failure, as we are deploying on Raid 1+0 database
server talking to the client over a redundant LAN, and using asynchronous
(Slony) replication to an identical database server just in case. No
single point of failure is a key philosophy of this app from top to bottom.
Like I said, this is mostly idle curiosity.

But I'm also accustomed to trying to get work done on shockingly unreliable
internet connections. As a result, network failure is something I think
about quite a lot when writing networked applications. So this is not
entirely idle curiosity either.

And thinking about this a bit more, it's clear that the database has to
commit before the result is sent, on the off chance that the transaction
fails and needs to be retried. And that an explicit transaction block
isn't really a solution either, because a "BEGIN; SELECT dequeue_row()"
would get the row to the client without marking it as taken, but the
pathological TCP disconnect could then attack the following "COMMIT;",
leaving the client to think that the row has not been actually taken when
it in fact has.

It's not clear to me that this is even a solvable problem without modifying
the schema to include both a "taken" and a "finished processing" state,
and then letting elements be re-delievered after a period of time. But
this would then allow a pathological demon with the power to cause TCP
connects have a single element delivered and processed multiple times.

In any case, thanks for the responses...

Best,
Leon


From: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>
To: Robert Haas <robertmhaas(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Transactions over pathological TCP connections
Date: 2012-06-19 22:06:55
Message-ID: CAPwAf1kGXm6YVKgAumdPR+Hu98Lpbzf8fWxwf4xwS6bmk9DRHg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

I just realized this is essentially an instance of the Two General's
Problem; which is something I feel should have been more obvious to me.

On Tue, Jun 19, 2012 at 5:50 PM, Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com> wrote:

> On Tue, Jun 19, 2012 at 11:59 AM, Robert Haas <robertmhaas(at)gmail(dot)com>wrote:
>
>> On Tue, Jun 19, 2012 at 1:56 AM, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
>> > The transaction would be committed before a command success report is
>> > delivered to the client, so I don't think delivered-and-not-marked is
>> > possible.
>>
>> ...unless you have configured synchronous_commit=off, or fsync=off.
>>
>> Or unless your disk melts into a heap of slag and you have to restore
>> from backup. You can protect against that last case using synchronous
>> replication.
>>
>
>
> But hard disk failure isn't in the failure model I was concerned about.
> =) To be perfectly honest, I'm not too concerned with either hard drive
> failure or network failure, as we are deploying on Raid 1+0 database
> server talking to the client over a redundant LAN, and using asynchronous
> (Slony) replication to an identical database server just in case. No
> single point of failure is a key philosophy of this app from top to bottom.
> Like I said, this is mostly idle curiosity.
>
> But I'm also accustomed to trying to get work done on shockingly
> unreliable internet connections. As a result, network failure is
> something I think about quite a lot when writing networked applications.
> So this is not entirely idle curiosity either.
>
> And thinking about this a bit more, it's clear that the database has to
> commit before the result is sent, on the off chance that the transaction
> fails and needs to be retried. And that an explicit transaction block
> isn't really a solution either, because a "BEGIN; SELECT dequeue_row()"
> would get the row to the client without marking it as taken, but the
> pathological TCP disconnect could then attack the following "COMMIT;",
> leaving the client to think that the row has not been actually taken when
> it in fact has.
>
> It's not clear to me that this is even a solvable problem without
> modifying the schema to include both a "taken" and a "finished processing"
> state, and then letting elements be re-delievered after a period of time.
> But this would then allow a pathological demon with the power to cause
> TCP connects have a single element delivered and processed multiple times.
>
> In any case, thanks for the responses...
>
> Best,
> Leon
>


From: Dimitri Fontaine <dimitri(at)2ndQuadrant(dot)fr>
To: Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com>
Cc: Robert Haas <robertmhaas(at)gmail(dot)com>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Transactions over pathological TCP connections
Date: 2012-06-22 12:28:26
Message-ID: m2d34rfs45.fsf@2ndQuadrant.fr
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Leon Smith <leon(dot)p(dot)smith(at)gmail(dot)com> writes:
> It's not clear to me that this is even a solvable problem without modifying
> the schema to include both a "taken" and a "finished processing" state,
> and then letting elements be re-delievered after a period of time.

You maybe should have a look at PGQ from Skytools before reinventing it.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support