]> granicus.if.org Git - postgresql/commitdiff
Make CLUSTER lock the old table's toast table before copying data.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 May 2011 21:57:33 +0000 (17:57 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 May 2011 21:57:33 +0000 (17:57 -0400)
We must lock out autovacuuming of the old toast table before computing the
OldestXmin horizon we will use.  Otherwise, autovacuum could start on the
toast table later, compute a later OldestXmin horizon, and remove as DEAD
toast tuples that we still need (because we think their parent tuples are
only RECENTLY_DEAD).  Per further thought about bug #5998.

src/backend/commands/cluster.c

index 191ef543cd20f3dcf1633d67a3ba4425bb889438..bcc7d1eb536bc2425e94e495ff79de69ade1603c 100644 (file)
@@ -38,6 +38,7 @@
 #include "miscadmin.h"
 #include "optimizer/planner.h"
 #include "storage/bufmgr.h"
+#include "storage/lmgr.h"
 #include "storage/procarray.h"
 #include "storage/smgr.h"
 #include "utils/acl.h"
@@ -750,6 +751,22 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
        values = (Datum *) palloc(natts * sizeof(Datum));
        isnull = (bool *) palloc(natts * sizeof(bool));
 
+       /*
+        * If the OldHeap has a toast table, get lock on the toast table to keep
+        * it from being vacuumed.  This is needed because autovacuum processes
+        * toast tables independently of their main tables, with no lock on the
+        * latter.  If an autovacuum were to start on the toast table after we
+        * compute our OldestXmin below, it would use a later OldestXmin, and then
+        * possibly remove as DEAD toast tuples belonging to main tuples we think
+        * are only RECENTLY_DEAD.  Then we'd fail while trying to copy those
+        * tuples.
+        *
+        * We don't need to open the toast relation here, just lock it.  The lock
+        * will be held till end of transaction.
+        */
+       if (OldHeap->rd_rel->reltoastrelid)
+               LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock);
+
        /*
         * We need to log the copied data in WAL iff WAL archiving/streaming is
         * enabled AND it's not a WAL-logged rel.