Thread: Locks on temp table and PREPARE

Locks on temp table and PREPARE

From
Emmanuel Cecchet
Date:
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



Re: Locks on temp table and PREPARE

From
Tom Lane
Date:
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


Re: Locks on temp table and PREPARE

From
Tom Lane
Date:
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


Re: Locks on temp table and PREPARE

From
Emmanuel Cecchet
Date:
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


Re: Locks on temp table and PREPARE

From
Emmanuel Cecchet
Date:
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


Re: Locks on temp table and PREPARE

From
Tom Lane
Date:
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


Re: Locks on temp table and PREPARE

From
Alvaro Herrera
Date:
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.


Re: Locks on temp table and PREPARE

From
Emmanuel Cecchet
Date:
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)


Re: Locks on temp table and PREPARE

From
Tom Lane
Date:
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


Re: Locks on temp table and PREPARE

From
Emmanuel Cecchet
Date:
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