aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/cluster.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-11-29 14:50:31 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-11-29 14:51:46 -0500
commit1da5bef3174170a6768bea6621afcbf72dd02a87 (patch)
tree568b1fd5efbc0a4f53df09222cd9bcad81372ad1 /src/backend/commands/cluster.c
parent381c3b8f4cba2d7d30d7010c28b06c076093876f (diff)
downloadpostgresql-1da5bef3174170a6768bea6621afcbf72dd02a87.tar.gz
postgresql-1da5bef3174170a6768bea6621afcbf72dd02a87.zip
Fix assorted bugs in CREATE INDEX CONCURRENTLY.
This patch changes CREATE INDEX CONCURRENTLY so that the pg_index flag changes it makes without exclusive lock on the index are made via heap_inplace_update() rather than a normal transactional update. The latter is not very safe because moving the pg_index tuple could result in concurrent SnapshotNow scans finding it twice or not at all, thus possibly resulting in index corruption. In addition, fix various places in the code that ought to check to make sure that the indexes they are manipulating are valid and/or ready as appropriate. These represent bugs that have existed since 8.2, since a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid index behind, and we ought not try to do anything that might fail with such an index. Also fix RelationReloadIndexInfo to ensure it copies all the pg_index columns that are allowed to change after initial creation. Previously we could have been left with stale values of some fields in an index relcache entry. It's not clear whether this actually had any user-visible consequences, but it's at least a bug waiting to happen. This is a subset of a patch already applied in 9.2 and HEAD. Back-patch into all earlier supported branches. Tom Lane and Andres Freund
Diffstat (limited to 'src/backend/commands/cluster.c')
-rw-r--r--src/backend/commands/cluster.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 5dec4298e2c..81e72825269 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -454,7 +454,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
* might put recently-dead tuples out-of-order in the new table, and there
* is little harm in that.)
*/
- if (!OldIndex->rd_index->indisvalid)
+ if (!IndexIsValid(OldIndex->rd_index))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot cluster on invalid index \"%s\"",
@@ -468,6 +468,11 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
* mark_index_clustered: mark the specified index as the one clustered on
*
* With indexOid == InvalidOid, will mark all indexes of rel not-clustered.
+ *
+ * Note: we do transactional updates of the pg_index rows, which are unsafe
+ * against concurrent SnapshotNow scans of pg_index. Therefore this is unsafe
+ * to execute with less than full exclusive lock on the parent table;
+ * otherwise concurrent executions of RelationGetIndexList could miss indexes.
*/
void
mark_index_clustered(Relation rel, Oid indexOid)
@@ -523,6 +528,9 @@ mark_index_clustered(Relation rel, Oid indexOid)
}
else if (thisIndexOid == indexOid)
{
+ /* this was checked earlier, but let's be real sure */
+ if (!IndexIsValid(indexForm))
+ elog(ERROR, "cannot cluster on invalid index %u", indexOid);
indexForm->indisclustered = true;
simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
CatalogUpdateIndexes(pg_index, indexTuple);