Diagnose !indisvalid in more SQL functions.
pgstatindex failed with ERRCODE_DATA_CORRUPTED, of the "can't-happen" class XX. The other functions succeeded on an empty index; they might have malfunctioned if the failed index build left torn I/O or other complex state. Report an ERROR in statistics functions pgstatindex, pgstatginindex, pgstathashindex, and pgstattuple. Report DEBUG1 and skip all index I/O in maintenance functions brin_desummarize_range, brin_summarize_new_values, brin_summarize_range, and gin_clean_pending_list. Back-patch to v11 (all supported versions). Discussion: https://postgr.es/m/20231001195309.a3@google.com
This commit is contained in:
parent
6ec9e9975e
commit
13503eb590
4 changed files with 74 additions and 9 deletions
|
@ -237,6 +237,18 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
|
|||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot access temporary tables of other sessions")));
|
||||
|
||||
/*
|
||||
* A !indisready index could lead to ERRCODE_DATA_CORRUPTED later, so exit
|
||||
* early. We're capable of assessing an indisready&&!indisvalid index,
|
||||
* but the results could be confusing. For example, the index's size
|
||||
* could be too low for a valid index of the table.
|
||||
*/
|
||||
if (!rel->rd_index->indisvalid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* Read metapage
|
||||
*/
|
||||
|
@ -523,6 +535,13 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
|
|||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot access temporary indexes of other sessions")));
|
||||
|
||||
/* see pgstatindex_impl */
|
||||
if (!rel->rd_index->indisvalid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* Read metapage
|
||||
*/
|
||||
|
@ -600,6 +619,13 @@ pgstathashindex(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot access temporary indexes of other sessions")));
|
||||
|
||||
/* see pgstatindex_impl */
|
||||
if (!rel->rd_index->indisvalid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
/* Get the information we need from the metapage. */
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
|
||||
|
|
|
@ -259,6 +259,13 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
|
|||
}
|
||||
else if (rel->rd_rel->relkind == RELKIND_INDEX)
|
||||
{
|
||||
/* see pgstatindex_impl */
|
||||
if (!rel->rd_index->indisvalid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
switch (rel->rd_rel->relam)
|
||||
{
|
||||
case BTREE_AM_OID:
|
||||
|
|
|
@ -1100,8 +1100,14 @@ brin_summarize_range(PG_FUNCTION_ARGS)
|
|||
errmsg("could not open parent table of index \"%s\"",
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
/* OK, do it */
|
||||
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
|
||||
/* see gin_clean_pending_list() */
|
||||
if (indexRel->rd_index->indisvalid)
|
||||
brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL);
|
||||
else
|
||||
ereport(DEBUG1,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
/* Roll back any GUC changes executed by index functions */
|
||||
AtEOXact_GUC(false, save_nestlevel);
|
||||
|
@ -1183,12 +1189,21 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
|
|||
errmsg("could not open parent table of index \"%s\"",
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
/* the revmap does the hard work */
|
||||
do
|
||||
/* see gin_clean_pending_list() */
|
||||
if (indexRel->rd_index->indisvalid)
|
||||
{
|
||||
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
|
||||
/* the revmap does the hard work */
|
||||
do
|
||||
{
|
||||
done = brinRevmapDesummarizeRange(indexRel, heapBlk);
|
||||
}
|
||||
while (!done);
|
||||
}
|
||||
while (!done);
|
||||
else
|
||||
ereport(DEBUG1,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
relation_close(indexRel, ShareUpdateExclusiveLock);
|
||||
relation_close(heapRel, ShareUpdateExclusiveLock);
|
||||
|
|
|
@ -1033,7 +1033,6 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
|
|||
Oid indexoid = PG_GETARG_OID(0);
|
||||
Relation indexRel = index_open(indexoid, RowExclusiveLock);
|
||||
IndexBulkDeleteResult stats;
|
||||
GinState ginstate;
|
||||
|
||||
if (RecoveryInProgress())
|
||||
ereport(ERROR,
|
||||
|
@ -1065,8 +1064,26 @@ gin_clean_pending_list(PG_FUNCTION_ARGS)
|
|||
RelationGetRelationName(indexRel));
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
initGinState(&ginstate, indexRel);
|
||||
ginInsertCleanup(&ginstate, true, true, true, &stats);
|
||||
|
||||
/*
|
||||
* Can't assume anything about the content of an !indisready index. Make
|
||||
* those a no-op, not an error, so users can just run this function on all
|
||||
* indexes of the access method. Since an indisready&&!indisvalid index
|
||||
* is merely awaiting missed aminsert calls, we're capable of processing
|
||||
* it. Decline to do so, out of an abundance of caution.
|
||||
*/
|
||||
if (indexRel->rd_index->indisvalid)
|
||||
{
|
||||
GinState ginstate;
|
||||
|
||||
initGinState(&ginstate, indexRel);
|
||||
ginInsertCleanup(&ginstate, true, true, true, &stats);
|
||||
}
|
||||
else
|
||||
ereport(DEBUG1,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("index \"%s\" is not valid",
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
index_close(indexRel, RowExclusiveLock);
|
||||
|
||||
|
|
Loading…
Reference in a new issue