1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Create a "relation mapping" infrastructure to support changing the relfilenodes

of shared or nailed system catalogs.  This has two key benefits:

* The new CLUSTER-based VACUUM FULL can be applied safely to all catalogs.

* We no longer have to use an unsafe reindex-in-place approach for reindexing
  shared catalogs.

CLUSTER on nailed catalogs now works too, although I left it disabled on
shared catalogs because the resulting pg_index.indisclustered update would
only be visible in one database.

Since reindexing shared system catalogs is now fully transactional and
crash-safe, the former special cases in REINDEX behavior have been removed;
shared catalogs are treated the same as non-shared.

This commit does not do anything about the recently-discussed problem of
deadlocks between VACUUM FULL/CLUSTER on a system catalog and other
concurrent queries; will address that in a separate patch.  As a stopgap,
parallel_schedule has been tweaked to run vacuum.sql by itself, to avoid
such failures during the regression tests.
This commit is contained in:
Tom Lane
2010-02-07 20:48:13 +00:00
parent 7fc30c488f
commit b9b8831ad6
54 changed files with 2316 additions and 585 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.324 2010/02/04 00:09:14 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.325 2010/02/07 20:48:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -436,6 +436,12 @@ DefineRelation(CreateStmt *stmt, char relkind)
get_tablespace_name(tablespaceId));
}
/* In all cases disallow placing user relations in pg_global */
if (tablespaceId == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("only shared relations can be placed in pg_global tablespace")));
/*
* Parse and validate reloptions, if any.
*/
@ -534,6 +540,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
old_constraints),
relkind,
false,
false,
localHasOids,
parentOidCount,
stmt->oncommit,
@ -1014,7 +1021,7 @@ ExecuteTruncate(TruncateStmt *stmt)
/*
* Reconstruct the indexes to match, and we're done.
*/
reindex_relation(heap_relid, true);
reindex_relation(heap_relid, true, false);
}
}
@ -1091,16 +1098,6 @@ truncate_check_rel(Relation rel)
errmsg("permission denied: \"%s\" is a system catalog",
RelationGetRelationName(rel))));
/*
* We can never allow truncation of shared or nailed-in-cache relations,
* because we can't support changing their relfilenode values.
*/
if (rel->rd_rel->relisshared || rel->rd_isnailed)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot truncate system relation \"%s\"",
RelationGetRelationName(rel))));
/*
* Don't allow truncate on temp tables of other backends ... their local
* buffer manager is not going to cope.
@ -2873,11 +2870,11 @@ ATRewriteTables(List **wqueue)
OldHeap = heap_open(tab->relid, NoLock);
/*
* We can never allow rewriting of shared or nailed-in-cache
* relations, because we can't support changing their relfilenode
* values.
* We don't support rewriting of system catalogs; there are
* too many corner cases and too little benefit. In particular
* this is certainly not going to work for mapped catalogs.
*/
if (OldHeap->rd_rel->relisshared || OldHeap->rd_isnailed)
if (IsSystemRelation(OldHeap))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot rewrite system relation \"%s\"",
@ -2914,17 +2911,14 @@ ATRewriteTables(List **wqueue)
ATRewriteTable(tab, OIDNewHeap);
/*
* 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
* new relfrozenxid because we rewrote all the tuples on
* ATRewriteTable, so no older Xid remains in the table. Also,
* we never try to swap toast tables by content, since we have
* no interest in letting this code work on system catalogs.
* Swap the physical files of the old and new heaps, then rebuild
* indexes and discard the new heap. We can use RecentXmin for
* the table's new relfrozenxid because we rewrote all the tuples
* in ATRewriteTable, so no older Xid remains in the table. Also,
* we never try to swap toast tables by content, since we have no
* interest in letting this code work on system catalogs.
*/
swap_relation_files(tab->relid, OIDNewHeap, false, RecentXmin);
/* Destroy the new heap, removing the old data along with it. */
cleanup_heap_swap(tab->relid, OIDNewHeap, false);
finish_heap_swap(tab->relid, OIDNewHeap, false, false, RecentXmin);
}
else
{
@ -3715,7 +3709,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeOid = HeapTupleGetOid(typeTuple);
/* make sure datatype is legal for a column */
CheckAttributeType(colDef->colname, typeOid);
CheckAttributeType(colDef->colname, typeOid, false);
/* construct new attribute's pg_attribute entry */
attribute.attrelid = myrelid;
@ -5825,7 +5819,7 @@ ATPrepAlterColumnType(List **wqueue,
targettype = typenameTypeId(NULL, typeName, &targettypmod);
/* make sure datatype is legal for a column */
CheckAttributeType(colName, targettype);
CheckAttributeType(colName, targettype, false);
/*
* Set up an expression to transform the old data value to the new type.
@ -6925,10 +6919,21 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
rel = relation_open(tableOid, AccessExclusiveLock);
/*
* We can never allow moving of shared or nailed-in-cache relations,
* because we can't support changing their reltablespace values.
* No work if no change in tablespace.
*/
if (rel->rd_rel->relisshared || rel->rd_isnailed)
oldTableSpace = rel->rd_rel->reltablespace;
if (newTableSpace == oldTableSpace ||
(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
{
relation_close(rel, NoLock);
return;
}
/*
* We cannot support moving mapped relations into different tablespaces.
* (In particular this eliminates all shared catalogs.)
*/
if (RelationIsMapped(rel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move system relation \"%s\"",
@ -6949,17 +6954,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move temporary tables of other sessions")));
/*
* No work if no change in tablespace.
*/
oldTableSpace = rel->rd_rel->reltablespace;
if (newTableSpace == oldTableSpace ||
(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
{
relation_close(rel, NoLock);
return;
}
reltoastrelid = rel->rd_rel->reltoastrelid;
reltoastidxid = rel->rd_rel->reltoastidxid;
@ -6985,9 +6979,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
* Relfilenodes are not unique across tablespaces, so we need to allocate
* a new one in the new tablespace.
*/
newrelfilenode = GetNewRelFileNode(newTableSpace,
rel->rd_rel->relisshared,
NULL);
newrelfilenode = GetNewRelFileNode(newTableSpace, NULL);
/* Open old and new relation */
newrnode = rel->rd_node;