Commit 9727c583 authored by Tom Lane's avatar Tom Lane

Restructure CLUSTER/newstyle VACUUM FULL/ALTER TABLE support so that swapping

of old and new toast tables can be done either at the logical level (by
swapping the heaps' reltoastrelid links) or at the physical level (by swapping
the relfilenodes of the toast tables and their indexes).  This is necessary
infrastructure for upcoming changes to support CLUSTER/VAC FULL on shared
system catalogs, where we cannot change reltoastrelid.  The physical swap
saves a few catalog updates too.

We unfortunately have to keep the logical-level swap logic because in some
cases we will be adding or deleting a toast table, so there's no possibility
of a physical swap.  However, that only happens as a consequence of schema
changes in the table, which we do not need to support for system catalogs,
so such cases aren't an obstacle for that.

In passing, refactor the cluster support functions a little bit to eliminate
unnecessarily-duplicated code; and fix the problem that while CLUSTER had
been taught to rename the final toast table at need, ALTER TABLE had not.
parent fdac8cf9
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.96 2010/01/02 16:57:35 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.97 2010/02/04 00:09:13 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1185,10 +1185,25 @@ toast_save_datum(Relation rel, Datum value, int options) ...@@ -1185,10 +1185,25 @@ toast_save_datum(Relation rel, Datum value, int options)
toast_pointer.va_extsize = data_todo; toast_pointer.va_extsize = data_todo;
} }
/*
* Insert the correct table OID into the result TOAST pointer.
*
* Normally this is the actual OID of the target toast table, but during
* table-rewriting operations such as CLUSTER, we have to insert the OID
* of the table's real permanent toast table instead. rd_toastoid is
* set if we have to substitute such an OID.
*/
if (OidIsValid(rel->rd_toastoid))
toast_pointer.va_toastrelid = rel->rd_toastoid;
else
toast_pointer.va_toastrelid = RelationGetRelid(toastrel);
/*
* Choose an unused OID within the toast table for this toast value.
*/
toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, toast_pointer.va_valueid = GetNewOidWithIndex(toastrel,
RelationGetRelid(toastidx), RelationGetRelid(toastidx),
(AttrNumber) 1); (AttrNumber) 1);
toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid;
/* /*
* Initialize constant parts of the tuple data * Initialize constant parts of the tuple data
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.323 2010/02/03 10:01:29 heikki Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.324 2010/02/04 00:09:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2866,11 +2866,9 @@ ATRewriteTables(List **wqueue) ...@@ -2866,11 +2866,9 @@ ATRewriteTables(List **wqueue)
if (tab->newvals != NIL || tab->new_changeoids) if (tab->newvals != NIL || tab->new_changeoids)
{ {
/* Build a temporary relation and copy data */ /* Build a temporary relation and copy data */
Relation OldHeap;
Oid OIDNewHeap; Oid OIDNewHeap;
char NewHeapName[NAMEDATALEN];
Oid NewTableSpace; Oid NewTableSpace;
Relation OldHeap;
ObjectAddress object;
OldHeap = heap_open(tab->relid, NoLock); OldHeap = heap_open(tab->relid, NoLock);
...@@ -2905,18 +2903,8 @@ ATRewriteTables(List **wqueue) ...@@ -2905,18 +2903,8 @@ ATRewriteTables(List **wqueue)
heap_close(OldHeap, NoLock); heap_close(OldHeap, NoLock);
/* /* Create transient table that will receive the modified data */
* Create the new heap, using a temporary name in the same OIDNewHeap = make_new_heap(tab->relid, NewTableSpace);
* namespace as the existing table. NOTE: there is some risk of
* collision with user relnames. Working around this seems more
* trouble than it's worth; in particular, we can't create the new
* heap in a different namespace from the old, or we will have
* problems with the TEMP status of temp tables.
*/
snprintf(NewHeapName, sizeof(NewHeapName),
"pg_temp_%u", tab->relid);
OIDNewHeap = make_new_heap(tab->relid, NewHeapName, NewTableSpace);
/* /*
* Copy the heap data into the new table with the desired * Copy the heap data into the new table with the desired
...@@ -2929,30 +2917,14 @@ ATRewriteTables(List **wqueue) ...@@ -2929,30 +2917,14 @@ ATRewriteTables(List **wqueue)
* Swap the physical files of the old and new heaps. Since we are * Swap the physical files of the old and new heaps. Since we are
* generating a new heap, we can use RecentXmin for the table's * generating a new heap, we can use RecentXmin for the table's
* new relfrozenxid because we rewrote all the tuples on * new relfrozenxid because we rewrote all the tuples on
* ATRewriteTable, so no older Xid remains on the table. * ATRewriteTable, so no older Xid remains in the table. Also,
*/ * we never try to swap toast tables by content, since we have
swap_relation_files(tab->relid, OIDNewHeap, RecentXmin); * no interest in letting this code work on system catalogs.
CommandCounterIncrement();
/* Destroy new heap with old filenode */
object.classId = RelationRelationId;
object.objectId = OIDNewHeap;
object.objectSubId = 0;
/*
* The new relation is local to our transaction and we know
* nothing depends on it, so DROP_RESTRICT should be OK.
*/ */
performDeletion(&object, DROP_RESTRICT); swap_relation_files(tab->relid, OIDNewHeap, false, RecentXmin);
/* performDeletion does CommandCounterIncrement at end */
/* /* Destroy the new heap, removing the old data along with it. */
* Rebuild each index on the relation (but not the toast table, cleanup_heap_swap(tab->relid, OIDNewHeap, false);
* which is all-new anyway). We do not need
* CommandCounterIncrement() because reindex_relation does it.
*/
reindex_relation(tab->relid, false);
} }
else else
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.301 2010/02/03 01:14:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.302 2010/02/04 00:09:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1925,13 +1925,13 @@ RelationClearRelation(Relation relation, bool rebuild) ...@@ -1925,13 +1925,13 @@ RelationClearRelation(Relation relation, bool rebuild)
* new entry, and this shouldn't happen often enough for that to be * new entry, and this shouldn't happen often enough for that to be
* a big problem. * a big problem.
* *
* When rebuilding an open relcache entry, we must preserve ref count * When rebuilding an open relcache entry, we must preserve ref count,
* and rd_createSubid/rd_newRelfilenodeSubid state. Also attempt to * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state. Also
* preserve the pg_class entry (rd_rel), tupledesc, and rewrite-rule * attempt to preserve the pg_class entry (rd_rel), tupledesc, and
* substructures in place, because various places assume that these * rewrite-rule substructures in place, because various places assume
* structures won't move while they are working with an open relcache * that these structures won't move while they are working with an
* entry. (Note: the refcount mechanism for tupledescs might someday * open relcache entry. (Note: the refcount mechanism for tupledescs
* allow us to remove this hack for the tupledesc.) * might someday allow us to remove this hack for the tupledesc.)
* *
* Note that this process does not touch CurrentResourceOwner; which * Note that this process does not touch CurrentResourceOwner; which
* is good because whatever ref counts the entry may have do not * is good because whatever ref counts the entry may have do not
...@@ -2005,6 +2005,8 @@ RelationClearRelation(Relation relation, bool rebuild) ...@@ -2005,6 +2005,8 @@ RelationClearRelation(Relation relation, bool rebuild)
SWAPFIELD(RuleLock *, rd_rules); SWAPFIELD(RuleLock *, rd_rules);
SWAPFIELD(MemoryContext, rd_rulescxt); SWAPFIELD(MemoryContext, rd_rulescxt);
} }
/* toast OID override must be preserved */
SWAPFIELD(Oid, rd_toastoid);
/* pgstat_info must be preserved */ /* pgstat_info must be preserved */
SWAPFIELD(struct PgStat_TableStatus *, pgstat_info); SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.38 2010/01/06 05:31:14 itagaki Exp $ * $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.39 2010/02/04 00:09:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,8 +23,11 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck, ...@@ -23,8 +23,11 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
bool recheck); bool recheck);
extern void mark_index_clustered(Relation rel, Oid indexOid); extern void mark_index_clustered(Relation rel, Oid indexOid);
extern Oid make_new_heap(Oid OIDOldHeap, const char *NewName,
Oid NewTableSpace); extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
extern void swap_relation_files(Oid r1, Oid r2, TransactionId frozenXid); extern void swap_relation_files(Oid r1, Oid r2, bool swap_toast_by_content,
TransactionId frozenXid);
extern void cleanup_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
bool swap_toast_by_content);
#endif /* CLUSTER_H */ #endif /* CLUSTER_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.120 2010/01/17 22:56:23 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.121 2010/02/04 00:09:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -202,6 +202,16 @@ typedef struct RelationData ...@@ -202,6 +202,16 @@ typedef struct RelationData
uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */ uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */
void *rd_amcache; /* available for use by index AM */ void *rd_amcache; /* available for use by index AM */
/*
* Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new
* version of a table, we need to make any toast pointers inserted into it
* have the existing toast table's OID, not the OID of the transient toast
* table. If rd_toastoid isn't InvalidOid, it is the OID to place in
* toast pointers inserted into this rel. (Note it's set on the new
* version of the main heap, not the toast table itself.)
*/
Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */
/* /*
* sizes of the free space and visibility map forks, or InvalidBlockNumber * sizes of the free space and visibility map forks, or InvalidBlockNumber
* if not known yet * if not known yet
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment