From 64d646105383e8f47394f4ee7e169ffde727da3c Mon Sep 17 00:00:00 2001 From: Gurjeet Singh Date: Wed, 29 Nov 2023 13:17:39 -0800 Subject: [PATCH v2] Reindex the toast table before the main table This helps in cases where a corruption in toast table's index would otherwise error and stop REINDEX TABLE command when it tries to fetch a toasted datum. This way toast table's index is rebuilt and fixed before it is used for reindexing the main table. --- src/backend/catalog/index.c | 58 ++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 143fae01eb..ea751299c2 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3871,7 +3871,7 @@ reindex_relation(Oid relid, int flags, const ReindexParams *params) Oid toast_relid; List *indexIds; char persistence; - bool result; + bool result = false; ListCell *indexId; int i; @@ -3901,7 +3901,7 @@ reindex_relation(Oid relid, int flags, const ReindexParams *params) toast_relid = rel->rd_rel->reltoastrelid; /* - * Get the list of index OIDs for this relation. (We trust to the + * Get the list of index OIDs for this relation. (We trust the * relcache to get this with a sequential scan if ignoring system * indexes.) */ @@ -3919,6 +3919,35 @@ reindex_relation(Oid relid, int flags, const ReindexParams *params) CommandCounterIncrement(); } + /* + * Reindex the toast table, if any, before the main table. + * + * This helps in cases where a corruption in toast table's index would + * otherwise error and stop REINDEX TABLE command when it tries to fetch a + * toasted datum. This way toast table's index is rebuilt and fixed before + * it is used for reindexing the main table. + * + * We must call reindex_relation() _after_ the RelationGetIndexList(), + * because the reindex_relation() will call CommandCounterIncrement() after + * every reindex_index(). Performing CCI before the RelationGetIndexList() + * call may produce wrong results. Refer to the description of + * REINDEX_REL_SUPPRESS_INDEX_USE flag. + */ + if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid)) + { + /* + * Note that this should fail if the toast relation is missing, so + * 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); + } + /* * Compute persistence of indexes: same as that of owning rel, unless * caller specified otherwise. @@ -3934,8 +3963,8 @@ reindex_relation(Oid relid, int flags, const ReindexParams *params) i = 1; foreach(indexId, indexIds) { - Oid indexOid = lfirst_oid(indexId); - Oid indexNamespaceId = get_rel_namespace(indexOid); + Oid indexOid = lfirst_oid(indexId); + Oid indexNamespaceId = get_rel_namespace(indexOid); /* * Skip any invalid indexes on a TOAST table. These can only be @@ -3972,26 +4001,7 @@ reindex_relation(Oid relid, int flags, const ReindexParams *params) */ table_close(rel, NoLock); - result = (indexIds != NIL); - - /* - * If the relation has a secondary toast rel, reindex that too while we - * still hold the lock on the main table. - */ - if ((flags & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid)) - { - /* - * Note that this should fail if the toast relation is missing, so - * 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); - } + result |= (indexIds != NIL); return result; } -- 2.34.1