Skip to content

Allow CLUSTER, VACUUM FULL and REINDEX to change tablespace #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master_ci
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion doc/src/sgml/ref/cluster.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PostgreSQL documentation

<refsynopsisdiv>
<synopsis>
CLUSTER [VERBOSE] <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">index_name</replaceable> ]
CLUSTER [VERBOSE] <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">index_name</replaceable> ] [ TABLESPACE <replaceable class="parameter">new_tablespace</replaceable> ]
CLUSTER [VERBOSE]
</synopsis>
</refsynopsisdiv>
Expand Down Expand Up @@ -99,6 +99,15 @@ CLUSTER [VERBOSE]
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The name of a specific tablespace to store clustered relations.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>VERBOSE</literal></term>
<listitem>
Expand Down
24 changes: 23 additions & 1 deletion doc/src/sgml/ref/reindex.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PostgreSQL documentation

<refsynopsisdiv>
<synopsis>
REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] <replaceable class="parameter">name</replaceable>
REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] <replaceable class="parameter">name</replaceable> [ TABLESPACE <replaceable class="parameter">new_tablespace</replaceable> ]

<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>

Expand Down Expand Up @@ -174,6 +174,28 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
</listitem>
</varlistentry>

<varlistentry>
<term><literal>TABLESPACE</literal></term>
<listitem>
<para>
This specifies a tablespace, where all rebuilt indexes will be created.
Cannot be used with "mapped" relations. If <literal>SCHEMA</literal>,
<literal>DATABASE</literal> or <literal>SYSTEM</literal> is specified, then
all unsuitable relations will be skipped and a single <literal>WARNING</literal>
will be generated.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The name of a specific tablespace to store rebuilt indexes.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>VERBOSE</literal></term>
<listitem>
Expand Down
11 changes: 11 additions & 0 deletions doc/src/sgml/ref/vacuum.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PostgreSQL documentation
<synopsis>
VACUUM [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]
VACUUM ( FULL [, ...] ) [ TABLESPACE <replaceable class="parameter">new_tablespace</replaceable> ] [ <replaceable class="parameter">table_and_columns</replaceable> [, ...] ]

<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>

Expand Down Expand Up @@ -299,6 +300,16 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The name of a specific tablespace to write a new copy of the table.
</para>
</listitem>
</varlistentry>

</variablelist>
</refsect1>

Expand Down
101 changes: 94 additions & 7 deletions src/backend/catalog/index.c
Original file line number Diff line number Diff line change
Expand Up @@ -1235,9 +1235,13 @@ index_create(Relation heapRelation,
* Create concurrently an index based on the definition of the one provided by
* caller. The index is inserted into catalogs and needs to be built later
* on. This is called during concurrent reindex processing.
*
* "tablespaceOid" is the new tablespace to use for this index. If
* InvalidOid, use the tablespace in-use instead.
*/
Oid
index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName)
index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
Oid tablespaceOid, const char *newName)
{
Relation indexRelation;
IndexInfo *oldInfo,
Expand Down Expand Up @@ -1367,7 +1371,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
newInfo,
indexColNames,
indexRelation->rd_rel->relam,
indexRelation->rd_rel->reltablespace,
OidIsValid(tablespaceOid) ?
tablespaceOid : indexRelation->rd_rel->reltablespace,
indexRelation->rd_indcollation,
indclass->values,
indcoloptions->values,
Expand Down Expand Up @@ -3415,10 +3420,12 @@ IndexGetRelation(Oid indexId, bool missing_ok)

/*
* reindex_index - This routine is used to recreate a single index
*
* See comments of reindex_relation() for details about "tablespaceOid".
*/
void
reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
int options)
reindex_index(Oid indexId, Oid tablespaceOid, bool skip_constraint_checks,
char persistence, int options)
{
Relation iRel,
heapRelation;
Expand All @@ -3427,6 +3434,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
volatile bool skipped_constraint = false;
PGRUsage ru0;
bool progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0;
bool set_tablespace = OidIsValid(tablespaceOid);

pg_rusage_init(&ru0);

Expand Down Expand Up @@ -3465,6 +3473,39 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
elog(ERROR, "unsupported relation kind for index \"%s\"",
RelationGetRelationName(iRel));

/*
* Skip tablespace change of all indexes on TOAST tables, unless
* allow_system_table_mods=1, but error out on system catalog.
*/
if (set_tablespace && IsToastRelation(iRel))
{
if (!allowSystemTableMods)
{
ereport(WARNING,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("skipping tablespace change of \"%s\"",
RelationGetRelationName(iRel)),
errdetail("Cannot move system relation, only REINDEX is performed.")));
set_tablespace = false;
}
}
else if (set_tablespace &&
IsCatalogRelationOid(indexId) && !allowSystemTableMods)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied: \"%s\" is a system catalog",
RelationGetRelationName(iRel))));

/*
* We cannot support moving mapped relations into different tablespaces.
* (In particular this eliminates all shared catalogs.)
*/
if (set_tablespace && RelationIsMapped(iRel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot change tablespace of mapped relation \"%s\"",
RelationGetRelationName(iRel))));

/*
* Don't allow reindex on temp tables of other backends ... their local
* buffer manager is not going to cope.
Expand All @@ -3491,6 +3532,47 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
*/
CheckTableNotInUse(iRel, "REINDEX INDEX");

if (tablespaceOid == MyDatabaseTableSpace)
tablespaceOid = InvalidOid;

/*
* Set the new tablespace for the relation. Do that only in the
* case where the reindex caller wishes to enforce a new tablespace.
*/
if (set_tablespace &&
tablespaceOid != iRel->rd_rel->reltablespace)
{
Relation pg_class;
Form_pg_class rd_rel;
HeapTuple tuple;

/* First get a modifiable copy of the relation's pg_class row */
pg_class = table_open(RelationRelationId, RowExclusiveLock);

tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexId));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", indexId);
rd_rel = (Form_pg_class) GETSTRUCT(tuple);

/*
* Mark the relation as ready to be dropped at transaction commit,
* before making visible the new tablespace change so as this won't
* miss things.
*/
RelationDropStorage(iRel);

/* Update the pg_class row */
rd_rel->reltablespace = tablespaceOid;
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);

heap_freetuple(tuple);

table_close(pg_class, RowExclusiveLock);

/* Make sure the reltablespace change is visible */
CommandCounterIncrement();
}

/*
* All predicate locks on the index are about to be made invalid. Promote
* them to relation locks on the heap.
Expand Down Expand Up @@ -3629,6 +3711,10 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
* reindex_relation - This routine is used to recreate all indexes
* of a relation (and optionally its toast relation too, if any).
*
* "tablespaceOid" defines the new tablespace where the indexes of
* the relation will be rebuilt. If InvalidOid is used, the current
* tablespace of each index is used instead.
*
* "flags" is a bitmask that can include any combination of these bits:
*
* REINDEX_REL_PROCESS_TOAST: if true, process the toast table too (if any).
Expand Down Expand Up @@ -3661,7 +3747,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
* index rebuild.
*/
bool
reindex_relation(Oid relid, int flags, int options)
reindex_relation(Oid relid, Oid tablespaceOid, int flags, int options)
{
Relation rel;
Oid toast_relid;
Expand Down Expand Up @@ -3752,7 +3838,8 @@ reindex_relation(Oid relid, int flags, int options)
continue;
}

reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
reindex_index(indexOid, tablespaceOid,
!(flags & REINDEX_REL_CHECK_CONSTRAINTS),
persistence, options);

CommandCounterIncrement();
Expand Down Expand Up @@ -3785,7 +3872,7 @@ reindex_relation(Oid relid, int flags, int options)
* still hold the lock on the master table.
*/
if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
result |= reindex_relation(toast_relid, flags, options);
result |= reindex_relation(toast_relid, tablespaceOid, flags, options);

return result;
}
Expand Down
Loading