Skip to content
Merged
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
6 changes: 3 additions & 3 deletions doc/src/sgml/config.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -1593,14 +1593,14 @@ include_dir 'conf.d'

<para>
Huge pages are known as large pages on Windows. To use them, you need to
assign the user right Lock Pages in Memory to the Windows user account
assign the user right <quote>Lock pages in memory</quote> to the Windows user account
that runs <productname>PostgreSQL</productname>.
You can use Windows Group Policy tool (gpedit.msc) to assign the user right
Lock Pages in Memory.
<quote>Lock pages in memory</quote>.
To start the database server on the command prompt as a standalone process,
not as a Windows service, the command prompt must be run as an administrator or
User Access Control (UAC) must be disabled. When the UAC is enabled, the normal
command prompt revokes the user right Lock Pages in Memory when started.
command prompt revokes the user right <quote>Lock pages in memory</quote> when started.
</para>

<para>
Expand Down
38 changes: 38 additions & 0 deletions doc/src/sgml/ref/reindex.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>

CONCURRENTLY [ <replaceable class="parameter">boolean</replaceable> ]
TABLESPACE <replaceable class="parameter">new_tablespace</replaceable>
VERBOSE [ <replaceable class="parameter">boolean</replaceable> ]
</synopsis>
</refsynopsisdiv>
Expand Down Expand Up @@ -187,6 +188,15 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
</listitem>
</varlistentry>

<varlistentry>
<term><literal>TABLESPACE</literal></term>
<listitem>
<para>
Specifies that indexes will be rebuilt on a new tablespace.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>VERBOSE</literal></term>
<listitem>
Expand All @@ -210,6 +220,14 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
</listitem>
</varlistentry>

<varlistentry>
<term><replaceable class="parameter">new_tablespace</replaceable></term>
<listitem>
<para>
The tablespace where indexes will be rebuilt.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

Expand Down Expand Up @@ -294,7 +312,27 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
reindexed in a separate transaction. Those commands cannot be used inside
a transaction block when working on a partitioned table or index.
</para>

<para>
When using the <literal>TABLESPACE</literal> clause with
<command>REINDEX</command> on a partitioned index or table, only the
tablespace references of the leaf partitions are updated. As partitioned
indexes are not updated, it is recommended to separately use
<command>ALTER TABLE ONLY</command> on them so as any new partitions
attached inherit the new tablespace. On failure, it may not have moved
all the indexes to the new tablespace. Re-running the command will rebuild
all the leaf partitions and move previously-unprocessed indexes to the new
tablespace.
</para>

<para>
If <literal>SCHEMA</literal>, <literal>DATABASE</literal> or
<literal>SYSTEM</literal> is used with <literal>TABLESPACE</literal>,
system relations are skipped and a single <literal>WARNING</literal>
will be generated. Indexes on TOAST tables are rebuilt, but not moved
to the new tablespace.
</para>

<refsect2 id="sql-reindex-concurrently" xreflabel="Rebuilding Indexes Concurrently">
<title>Rebuilding Indexes Concurrently</title>

Expand Down
53 changes: 50 additions & 3 deletions src/backend/catalog/index.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "commands/event_trigger.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "miscadmin.h"
Expand Down Expand Up @@ -1394,9 +1395,12 @@ index_update_collation_versions(Oid relid, Oid coll)
* 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 tablespace to use for this index.
*/
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 @@ -1526,7 +1530,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
newInfo,
indexColNames,
indexRelation->rd_rel->relam,
indexRelation->rd_rel->reltablespace,
tablespaceOid,
indexRelation->rd_indcollation,
indclass->values,
indcoloptions->values,
Expand Down Expand Up @@ -3603,6 +3607,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
volatile bool skipped_constraint = false;
PGRUsage ru0;
bool progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
bool set_tablespace = false;

pg_rusage_init(&ru0);

Expand Down Expand Up @@ -3674,12 +3679,51 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot reindex invalid index on TOAST table")));

/*
* System relations cannot be moved even if allow_system_table_mods is
* enabled to keep things consistent with the concurrent case where all
* the indexes of a relation are processed in series, including indexes of
* toast relations.
*
* Note that this check is not part of CheckRelationTableSpaceMove() as it
* gets used for ALTER TABLE SET TABLESPACE that could cascade across
* toast relations.
*/
if (OidIsValid(params->tablespaceOid) &&
IsSystemRelation(iRel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move system relation \"%s\"",
RelationGetRelationName(iRel))));

/* Check if the tablespace of this index needs to be changed */
if (OidIsValid(params->tablespaceOid) &&
CheckRelationTableSpaceMove(iRel, params->tablespaceOid))
set_tablespace = true;

/*
* Also check for active uses of the index in the current transaction; we
* don't want to reindex underneath an open indexscan.
*/
CheckTableNotInUse(iRel, "REINDEX INDEX");

/* Set new tablespace, if requested */
if (set_tablespace)
{
/* Update its pg_class row */
SetRelationTableSpace(iRel, params->tablespaceOid, InvalidOid);

/*
* Schedule unlinking of the old index storage at transaction
* commit.
*/
RelationDropStorage(iRel);
RelationAssumeNewRelfilenode(iRel);

/* 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 @@ -3963,11 +4007,14 @@ reindex_relation(Oid relid, int flags, ReindexParams *params)
{
/*
* Note that this should fail if the toast relation is missing, so
* reset REINDEXOPT_MISSING_OK.
* reset REINDEXOPT_MISSING_OK. Even if a new tablespace is set for
* the parent relation, the indexes on its toast table are not moved.
* This rule is enforced by setting tablespaceOid to InvalidOid.
*/
ReindexParams newparams = *params;

newparams.options &= ~(REINDEXOPT_MISSING_OK);
newparams.tablespaceOid = InvalidOid;
result |= reindex_relation(toast_relid, flags, &newparams);
}

Expand Down
2 changes: 1 addition & 1 deletion src/backend/commands/copyfromparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ CopyLoadRawBuf(CopyFromState cstate)
cstate->raw_buf[nbytes] = '\0';
cstate->raw_buf_index = 0;
cstate->raw_buf_len = nbytes;
cstate->bytes_processed += nbytes;
cstate->bytes_processed += inbytes;
pgstat_progress_update_param(PROGRESS_COPY_BYTES_PROCESSED, cstate->bytes_processed);
return (inbytes > 0);
}
Expand Down
111 changes: 111 additions & 0 deletions src/backend/commands/indexcmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -2474,6 +2474,7 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
ListCell *lc;
bool concurrently = false;
bool verbose = false;
char *tablespacename = NULL;

/* Parse option list */
foreach(lc, stmt->params)
Expand All @@ -2484,6 +2485,8 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
verbose = defGetBoolean(opt);
else if (strcmp(opt->defname, "concurrently") == 0)
concurrently = defGetBoolean(opt);
else if (strcmp(opt->defname, "tablespace") == 0)
tablespacename = defGetString(opt);
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
Expand All @@ -2500,6 +2503,30 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
(verbose ? REINDEXOPT_VERBOSE : 0) |
(concurrently ? REINDEXOPT_CONCURRENTLY : 0);

/*
* Assign the tablespace OID to move indexes to, with InvalidOid to do
* nothing.
*/
if (tablespacename != NULL)
{
params.tablespaceOid = get_tablespace_oid(tablespacename, false);

/* Check permissions except when moving to database's default */
if (OidIsValid(params.tablespaceOid) &&
params.tablespaceOid != MyDatabaseTableSpace)
{
AclResult aclresult;

aclresult = pg_tablespace_aclcheck(params.tablespaceOid,
GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_TABLESPACE,
get_tablespace_name(params.tablespaceOid));
}
}
else
params.tablespaceOid = InvalidOid;

switch (stmt->kind)
{
case REINDEX_OBJECT_INDEX:
Expand Down Expand Up @@ -2730,6 +2757,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
List *relids = NIL;
int num_keys;
bool concurrent_warning = false;
bool tablespace_warning = false;

AssertArg(objectName);
Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
Expand Down Expand Up @@ -2856,6 +2884,40 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
continue;
}

/*
* If a new tablespace is set, check if this relation has to be
* skipped.
*/
if (OidIsValid(params->tablespaceOid))
{
bool skip_rel = false;

/*
* Mapped relations cannot be moved to different tablespaces (in
* particular this eliminates all shared catalogs.).
*/
if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
!OidIsValid(classtuple->relfilenode))
skip_rel = true;

/*
* A system relation is always skipped, even with
* allow_system_table_mods enabled.
*/
if (IsSystemClass(relid, classtuple))
skip_rel = true;

if (skip_rel)
{
if (!tablespace_warning)
ereport(WARNING,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("cannot move system relations, skipping all")));
tablespace_warning = true;
continue;
}
}

/* Save the list of relation OIDs in private context */
old = MemoryContextSwitchTo(private_context);

Expand Down Expand Up @@ -3032,6 +3094,24 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
continue;
}

/*
* Check permissions except when moving to database's default if a new
* tablespace is chosen. Note that this check also happens in
* ExecReindex(), but we do an extra check here as this runs across
* multiple transactions.
*/
if (OidIsValid(params->tablespaceOid) &&
params->tablespaceOid != MyDatabaseTableSpace)
{
AclResult aclresult;

aclresult = pg_tablespace_aclcheck(params->tablespaceOid,
GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_TABLESPACE,
get_tablespace_name(params->tablespaceOid));
}

relkind = get_rel_relkind(relid);
relpersistence = get_rel_persistence(relid);

Expand Down Expand Up @@ -3210,6 +3290,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
heapRelation = table_open(relationOid,
ShareUpdateExclusiveLock);

if (OidIsValid(params->tablespaceOid) &&
IsSystemRelation(heapRelation))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move system relation \"%s\"",
RelationGetRelationName(heapRelation))));

/* Add all the valid indexes of relation to list */
foreach(lc, RelationGetIndexList(heapRelation))
{
Expand Down Expand Up @@ -3346,6 +3433,14 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
else
heapRelation = table_open(heapId,
ShareUpdateExclusiveLock);

if (OidIsValid(params->tablespaceOid) &&
IsSystemRelation(heapRelation))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move system relation \"%s\"",
get_rel_name(relationOid))));

table_close(heapRelation, NoLock);

/* Save the list of relation OIDs in private context */
Expand Down Expand Up @@ -3390,6 +3485,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
return false;
}

/* It's not a shared catalog, so refuse to move it to shared tablespace */
if (params->tablespaceOid == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot move non-shared relation to tablespace \"%s\"",
get_tablespace_name(params->tablespaceOid))));

Assert(heapRelationIds != NIL);

/*-----
Expand Down Expand Up @@ -3427,6 +3529,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Relation heapRel;
Relation newIndexRel;
LockRelId *lockrelid;
Oid tablespaceid;

indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
heapRel = table_open(indexRel->rd_index->indrelid,
Expand Down Expand Up @@ -3458,9 +3561,17 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
get_rel_namespace(indexRel->rd_index->indrelid),
false);

/* Choose the new tablespace, indexes of toast tables are not moved */
if (OidIsValid(params->tablespaceOid) &&
heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
tablespaceid = params->tablespaceOid;
else
tablespaceid = indexRel->rd_rel->reltablespace;

/* Create new index definition based on given index */
newIndexId = index_concurrently_create_copy(heapRel,
idx->indexId,
tablespaceid,
concurrentName);

/*
Expand Down
Loading