mirror of
https://github.com/postgres/postgres.git
synced 2025-11-24 00:23:06 +03:00
Fix reindexing of pg_class indexes some more.
Commits3dbb317d3et al failed under CLOBBER_CACHE_ALWAYS testing. Investigation showed that to reindex pg_class_oid_index, we must suppress accesses to the index (via SetReindexProcessing) before we call RelationSetNewRelfilenode, or at least before we do CommandCounterIncrement therein; otherwise, relcache reloads happening within the CCI may try to fetch pg_class rows using the index's new relfilenode value, which is as yet an empty file. Of course, the point of3dbb317d3was that that ordering didn't work either, because then RelationSetNewRelfilenode's own update of the index's pg_class row cannot access the index, should it need to. There are various ways we might have got around that, but Andres Freund came up with a brilliant solution: for a mapped index, we can really just skip the pg_class update altogether. The only fields it was actually changing were relpages etc, but it was just setting them to zeroes which is useless make-work. (Correct new values will be installed at the end of index build.) All pg_class indexes are mapped and probably always will be, so this eliminates the problem by removing work rather than adding it, always a pleasant outcome. Having taught RelationSetNewRelfilenode to do it that way, we can revert the code reordering in reindex_index. (But I left the moved setup code where it was; there seems no reason why it has to run without use of the old index. If you're trying to fix a busted pg_class index, you'll have had to disable system index use altogether to get this far.) Moreover, this means we don't need RelationSetIndexList at all, because reindex_relation's hacking to make "REINDEX TABLE pg_class" work is likewise now unnecessary. We'll leave that code in place in the back branches, but a follow-on patch will remove it in HEAD. In passing, do some minor cleanup for commit5c1560606(in HEAD only), notably removing a duplicate newrnode assignment. Patch by me, using a core idea due to Andres Freund. Back-patch to all supported branches, as3dbb317d3was. Discussion: https://postgr.es/m/28926.1556664156@sss.pgh.pa.us
This commit is contained in:
@@ -3330,20 +3330,15 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
|
||||
indexInfo->ii_ExclusionStrats = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a new physical relation for the index. Need to do that before
|
||||
* "officially" starting the reindexing with SetReindexProcessing -
|
||||
* otherwise the necessary pg_class changes cannot be made with
|
||||
* encountering assertions.
|
||||
*/
|
||||
RelationSetNewRelfilenode(iRel, persistence);
|
||||
|
||||
/* ensure SetReindexProcessing state isn't leaked */
|
||||
PG_TRY();
|
||||
{
|
||||
/* Suppress use of the target index while rebuilding it */
|
||||
SetReindexProcessing(heapId, indexId);
|
||||
|
||||
/* Create a new physical relation for the index */
|
||||
RelationSetNewRelfilenode(iRel, persistence);
|
||||
|
||||
/* Initialize the index and rebuild */
|
||||
/* Note: we do not need to re-establish pkey setting */
|
||||
index_build(heapRelation, iRel, indexInfo, true, true);
|
||||
@@ -3491,7 +3486,6 @@ reindex_relation(Oid relid, int flags, int options)
|
||||
Relation rel;
|
||||
Oid toast_relid;
|
||||
List *indexIds;
|
||||
bool is_pg_class;
|
||||
bool result;
|
||||
int i;
|
||||
|
||||
@@ -3527,32 +3521,8 @@ reindex_relation(Oid relid, int flags, int options)
|
||||
*/
|
||||
indexIds = RelationGetIndexList(rel);
|
||||
|
||||
/*
|
||||
* reindex_index will attempt to update the pg_class rows for the relation
|
||||
* and index. If we are processing pg_class itself, we want to make sure
|
||||
* that the updates do not try to insert index entries into indexes we
|
||||
* have not processed yet. (When we are trying to recover from corrupted
|
||||
* indexes, that could easily cause a crash.) We can accomplish this
|
||||
* because CatalogTupleInsert/CatalogTupleUpdate will use the relcache's
|
||||
* index list to know which indexes to update. We just force the index
|
||||
* list to be only the stuff we've processed.
|
||||
*
|
||||
* It is okay to not insert entries into the indexes we have not processed
|
||||
* yet because all of this is transaction-safe. If we fail partway
|
||||
* through, the updated rows are dead and it doesn't matter whether they
|
||||
* have index entries. Also, a new pg_class index will be created with a
|
||||
* correct entry for its own pg_class row because we do
|
||||
* RelationSetNewRelfilenode() before we do index_build().
|
||||
*/
|
||||
is_pg_class = (RelationGetRelid(rel) == RelationRelationId);
|
||||
|
||||
/* Ensure rd_indexattr is valid; see comments for RelationSetIndexList */
|
||||
if (is_pg_class)
|
||||
(void) RelationGetIndexAttrBitmap(rel, INDEX_ATTR_BITMAP_ALL);
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
List *doneIndexes;
|
||||
ListCell *indexId;
|
||||
char persistence;
|
||||
|
||||
@@ -3580,15 +3550,11 @@ reindex_relation(Oid relid, int flags, int options)
|
||||
persistence = rel->rd_rel->relpersistence;
|
||||
|
||||
/* Reindex all the indexes. */
|
||||
doneIndexes = NIL;
|
||||
i = 1;
|
||||
foreach(indexId, indexIds)
|
||||
{
|
||||
Oid indexOid = lfirst_oid(indexId);
|
||||
|
||||
if (is_pg_class)
|
||||
RelationSetIndexList(rel, doneIndexes);
|
||||
|
||||
reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
|
||||
persistence, options);
|
||||
|
||||
@@ -3597,9 +3563,6 @@ reindex_relation(Oid relid, int flags, int options)
|
||||
/* Index should no longer be in the pending list */
|
||||
Assert(!ReindexIsProcessingIndex(indexOid));
|
||||
|
||||
if (is_pg_class)
|
||||
doneIndexes = lappend_oid(doneIndexes, indexOid);
|
||||
|
||||
/* Set index rebuild count */
|
||||
pgstat_progress_update_param(PROGRESS_CLUSTER_INDEX_REBUILD_COUNT,
|
||||
i);
|
||||
@@ -3615,9 +3578,6 @@ reindex_relation(Oid relid, int flags, int options)
|
||||
PG_END_TRY();
|
||||
ResetReindexPending();
|
||||
|
||||
if (is_pg_class)
|
||||
RelationSetIndexList(rel, indexIds);
|
||||
|
||||
/*
|
||||
* Close rel, but continue to hold the lock.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user