Locks on temp table and PREPARE

Started by Emmanuel Cecchetover 16 years ago10 messages
#1Emmanuel Cecchet
manu@frogthinker.org

Hi,

As we discussed during PGCon, we are using temp tables in 2PC
transactions. The temp tables are dropped before PREPARE (or have an ON
COMMIT DROP option) and never cross transaction boundaries.
In 8.3.1, a patch was introduced to disallow temp tables in 2PC
transactions and we tried to provide a fix for it (see the long thread
with Heikki on this list). I am still working on a cleaner patch to
allow temp tables to be used in 2PC transactions but I did hit a new
problem that I don't know how to solve cleanly.

Take PG 8.3.0 and try:
BEGIN;
CREATE TEMP TABLE foo (x int) ON COMMIT DROP;
PREPARE TRANSACTION 't1';
[BEGIN;] <-- doesn't really matter if you start a new transaction or not
CREATE TEMP TABLE foo (x int); <-- blocks until t1 commits

I have been tracking down the problem and it looks like
PostPrepare_Locks is holding the locks on 'foo' for some reason I don't
really get.

Any suggestion on what should be done differently for temp tables there?

Thanks,
Emmanuel

--
Emmanuel Cecchet
FTO @ Frog Thinker
Open Source Development & Consulting
--
Web: http://www.frogthinker.org
email: manu@frogthinker.org
Skype: emmanuel_cecchet

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emmanuel Cecchet (#1)
Re: Locks on temp table and PREPARE

Emmanuel Cecchet <manu@frogthinker.org> writes:

Take PG 8.3.0 and try:
BEGIN;
CREATE TEMP TABLE foo (x int) ON COMMIT DROP;
PREPARE TRANSACTION 't1';
[BEGIN;] <-- doesn't really matter if you start a new transaction or not
CREATE TEMP TABLE foo (x int); <-- blocks until t1 commits

I have been tracking down the problem and it looks like
PostPrepare_Locks is holding the locks on 'foo' for some reason I don't
really get.

AFAIK that doesn't really have anything to do with the temp-ness of the
table; it'd be the same with a regular table. The problem is you have
an in-doubt tuple in pg_class for pg_temp_NNN.foo, and you are trying
to create another one for the same schema/relname, and so the unique
index check is blocking to see what happens to the other transaction
that's creating/deleting the conflicting tuple.

regards, tom lane

#3Emmanuel Cecchet
manu@frogthinker.org
In reply to: Tom Lane (#2)
Re: Locks on temp table and PREPARE

Tom Lane wrote:

Emmanuel Cecchet <manu@frogthinker.org> writes:

Take PG 8.3.0 and try:
BEGIN;
CREATE TEMP TABLE foo (x int) ON COMMIT DROP;
PREPARE TRANSACTION 't1';
[BEGIN;] <-- doesn't really matter if you start a new transaction or not
CREATE TEMP TABLE foo (x int); <-- blocks until t1 commits

I have been tracking down the problem and it looks like
PostPrepare_Locks is holding the locks on 'foo' for some reason I don't
really get.

AFAIK that doesn't really have anything to do with the temp-ness of the
table; it'd be the same with a regular table. The problem is you have
an in-doubt tuple in pg_class for pg_temp_NNN.foo, and you are trying
to create another one for the same schema/relname, and so the unique
index check is blocking to see what happens to the other transaction
that's creating/deleting the conflicting tuple.

You are right (of course!), I tried:

BEGIN;
CREATE TABLE foo (x int);
DROP TABLE foo;
PREPARE TRANSACTION 't1';
[BEGIN;]
CREATE TABLE foo (x int); <-- blocks

There should not be a doubt about table foo because whether the
transaction commits or rollbacks, that table will not exist anymore (we
can get rid of it at prepare time actually).
I guess Postgres does not handle the special case of tables (temp or
not) whose lifespan is limited to the scope of a transaction and
therefore cannot optimize that case. Is that correct?

Thanks for your help.
Emmanuel

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emmanuel Cecchet (#3)
Re: Locks on temp table and PREPARE

Emmanuel Cecchet <manu@frogthinker.org> writes:

Tom Lane wrote:

AFAIK that doesn't really have anything to do with the temp-ness of the
table; it'd be the same with a regular table. The problem is you have
an in-doubt tuple in pg_class for pg_temp_NNN.foo, and you are trying
to create another one for the same schema/relname, and so the unique
index check is blocking to see what happens to the other transaction
that's creating/deleting the conflicting tuple.

There should not be a doubt about table foo because whether the
transaction commits or rollbacks, that table will not exist anymore (we
can get rid of it at prepare time actually).

True, but the problem is that the tuple might still be live to (some
snapshots in) that transaction, so we can't inject a duplicate tuple
without risking confusing it. In this particular case that isn't an
issue because the transaction is done executing, but the tqual.c
rules don't know that.

regards, tom lane

#5Emmanuel Cecchet
manu@frogthinker.org
In reply to: Tom Lane (#4)
Re: Locks on temp table and PREPARE

Tom Lane wrote:

True, but the problem is that the tuple might still be live to (some
snapshots in) that transaction, so we can't inject a duplicate tuple
without risking confusing it. In this particular case that isn't an
issue because the transaction is done executing, but the tqual.c
rules don't know that.

Please excuse my ignorance. I am not sure to get how the tuple could
still be live to some snapshots after the transaction has prepared. What
could still happen to objects that were only visible to a transaction
after it has prepared? An example would definitely help.
Is it possible in Postgres for a transaction to see an object that was
created inside another transaction before it commits (assuming at least
'read committed' of course)?

Thanks again,
Emmanuel

#6Alvaro Herrera
alvherre@commandprompt.com
In reply to: Emmanuel Cecchet (#5)
Re: Locks on temp table and PREPARE

Emmanuel Cecchet wrote:

Tom Lane wrote:

True, but the problem is that the tuple might still be live to (some
snapshots in) that transaction, so we can't inject a duplicate tuple
without risking confusing it. In this particular case that isn't an
issue because the transaction is done executing, but the tqual.c
rules don't know that.

Please excuse my ignorance. I am not sure to get how the tuple could
still be live to some snapshots after the transaction has prepared. What
could still happen to objects that were only visible to a transaction
after it has prepared? An example would definitely help.

The classic example is having an open cursor that references the table.
(In this case it doesn't work, but the snapshot management module and
tqual.c don't know it.) If you want this to work you need to improve
those modules, and who knows what else ...

--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emmanuel Cecchet (#5)
Re: Locks on temp table and PREPARE

Emmanuel Cecchet <manu@frogthinker.org> writes:

Tom Lane wrote:

True, but the problem is that the tuple might still be live to (some
snapshots in) that transaction, so we can't inject a duplicate tuple
without risking confusing it. In this particular case that isn't an
issue because the transaction is done executing, but the tqual.c
rules don't know that.

Please excuse my ignorance. I am not sure to get how the tuple could
still be live to some snapshots after the transaction has prepared.

Well, it couldn't be because there are no snapshots in that transaction
anymore. The problem is that the *other* transaction doesn't have a
good way to know that. It just sees an open transaction with
conflicting unique-index changes.

regards, tom lane

#8Emmanuel Cecchet
manu@frogthinker.org
In reply to: Tom Lane (#7)
Re: Locks on temp table and PREPARE

Tom Lane wrote:

Emmanuel Cecchet <manu@frogthinker.org> writes:

Tom Lane wrote:

True, but the problem is that the tuple might still be live to (some
snapshots in) that transaction, so we can't inject a duplicate tuple
without risking confusing it. In this particular case that isn't an
issue because the transaction is done executing, but the tqual.c
rules don't know that.

Please excuse my ignorance. I am not sure to get how the tuple could
still be live to some snapshots after the transaction has prepared.

Well, it couldn't be because there are no snapshots in that transaction
anymore. The problem is that the *other* transaction doesn't have a
good way to know that. It just sees an open transaction with
conflicting unique-index changes.

But when the transaction prepares, we know that. What would prevent us
to do at prepare time the same cleanup that commit does?

regards, manu (indentation (C) tom lane)

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Emmanuel Cecchet (#8)
Re: Locks on temp table and PREPARE

Emmanuel Cecchet <manu@frogthinker.org> writes:

But when the transaction prepares, we know that. What would prevent us
to do at prepare time the same cleanup that commit does?

The entire point of PREPARE is that it's *not* committed yet.

regards, tom lane

#10Emmanuel Cecchet
manu@frogthinker.org
In reply to: Tom Lane (#9)
Re: Locks on temp table and PREPARE

Tom Lane wrote:

Emmanuel Cecchet <manu@frogthinker.org> writes:

But when the transaction prepares, we know that. What would prevent us
to do at prepare time the same cleanup that commit does?

The entire point of PREPARE is that it's *not* committed yet.

Agreed but all objects that were created and dropped in the transaction
are going to be cleaned up whether the transaction commits or rollbacks.
It seems that releasing these resources at PREPARE time would help for
these 'temporary' objects that only have a transaction scope, right?

regards, manu