amcheck: Skip unlogged relations during recovery.
contrib/amcheck failed to consider the possibility that unlogged relations will not have any main relation fork files when running in hot standby mode. This led to low-level "can't happen" errors that complain about the absence of a relfilenode file. To fix, simply skip verification of unlogged index relations during recovery. In passing, add a direct check for the presence of a main fork just before verification proper begins, so that we cleanly verify the presence of the main relation fork file. Author: Andrey Borodin, Peter Geoghegan Reported-By: Andrey Borodin Diagnosed-By: Andrey Borodin Discussion: https://postgr.es/m/DA9B33AC-53CB-4643-96D4-7A0BBC037FA1@yandex-team.ru Backpatch: 10-, where amcheck was introduced.
This commit is contained in:
parent
03c811a483
commit
6754fe65a4
@ -35,6 +35,7 @@
|
|||||||
#include "lib/bloomfilter.h"
|
#include "lib/bloomfilter.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
|
#include "storage/smgr.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
|
|
||||||
@ -128,6 +129,7 @@ PG_FUNCTION_INFO_V1(bt_index_parent_check);
|
|||||||
static void bt_index_check_internal(Oid indrelid, bool parentcheck,
|
static void bt_index_check_internal(Oid indrelid, bool parentcheck,
|
||||||
bool heapallindexed, bool rootdescend);
|
bool heapallindexed, bool rootdescend);
|
||||||
static inline void btree_index_checkable(Relation rel);
|
static inline void btree_index_checkable(Relation rel);
|
||||||
|
static inline bool btree_index_mainfork_expected(Relation rel);
|
||||||
static void bt_check_every_level(Relation rel, Relation heaprel,
|
static void bt_check_every_level(Relation rel, Relation heaprel,
|
||||||
bool heapkeyspace, bool readonly, bool heapallindexed,
|
bool heapkeyspace, bool readonly, bool heapallindexed,
|
||||||
bool rootdescend);
|
bool rootdescend);
|
||||||
@ -225,7 +227,6 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
|
|||||||
Oid heapid;
|
Oid heapid;
|
||||||
Relation indrel;
|
Relation indrel;
|
||||||
Relation heaprel;
|
Relation heaprel;
|
||||||
bool heapkeyspace;
|
|
||||||
LOCKMODE lockmode;
|
LOCKMODE lockmode;
|
||||||
|
|
||||||
if (parentcheck)
|
if (parentcheck)
|
||||||
@ -275,10 +276,22 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
|
|||||||
/* Relation suitable for checking as B-Tree? */
|
/* Relation suitable for checking as B-Tree? */
|
||||||
btree_index_checkable(indrel);
|
btree_index_checkable(indrel);
|
||||||
|
|
||||||
/* Check index, possibly against table it is an index on */
|
if (btree_index_mainfork_expected(indrel))
|
||||||
heapkeyspace = _bt_heapkeyspace(indrel);
|
{
|
||||||
bt_check_every_level(indrel, heaprel, heapkeyspace, parentcheck,
|
bool heapkeyspace;
|
||||||
heapallindexed, rootdescend);
|
|
||||||
|
RelationOpenSmgr(indrel);
|
||||||
|
if (!smgrexists(indrel->rd_smgr, MAIN_FORKNUM))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INDEX_CORRUPTED),
|
||||||
|
errmsg("index \"%s\" lacks a main relation fork",
|
||||||
|
RelationGetRelationName(indrel))));
|
||||||
|
|
||||||
|
/* Check index, possibly against table it is an index on */
|
||||||
|
heapkeyspace = _bt_heapkeyspace(indrel);
|
||||||
|
bt_check_every_level(indrel, heaprel, heapkeyspace, parentcheck,
|
||||||
|
heapallindexed, rootdescend);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release locks early. That's ok here because nothing in the called
|
* Release locks early. That's ok here because nothing in the called
|
||||||
@ -324,6 +337,28 @@ btree_index_checkable(Relation rel)
|
|||||||
errdetail("Index is not valid.")));
|
errdetail("Index is not valid.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if B-Tree index relation should have a file for its main relation
|
||||||
|
* fork. Verification uses this to skip unlogged indexes when in hot standby
|
||||||
|
* mode, where there is simply nothing to verify.
|
||||||
|
*
|
||||||
|
* NB: Caller should call btree_index_checkable() before calling here.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
btree_index_mainfork_expected(Relation rel)
|
||||||
|
{
|
||||||
|
if (rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED ||
|
||||||
|
!RecoveryInProgress())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ereport(NOTICE,
|
||||||
|
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
|
||||||
|
errmsg("cannot verify unlogged index \"%s\" during recovery, skipping",
|
||||||
|
RelationGetRelationName(rel))));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main entry point for B-Tree SQL-callable functions. Walks the B-Tree in
|
* Main entry point for B-Tree SQL-callable functions. Walks the B-Tree in
|
||||||
* logical order, verifying invariants as it goes. Optionally, verification
|
* logical order, verifying invariants as it goes. Optionally, verification
|
||||||
|
Loading…
x
Reference in New Issue
Block a user