mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
nbtree VACUUM: cope with topparent inconsistencies.
Avoid "right sibling %u of block %u is not next child" errors when vacuuming a corrupt nbtree index. Just LOG the issue and press on. That way VACUUM will have a decent chance of finishing off all required processing for the index (and for the table as a whole). This is similar to recent work from commit5abff197
, as well as work from commit5b861baa
(later backpatched as commit43e409ce
), which taught nbtree VACUUM to keep going when its "re-find" check fails. The hardening added by this commit takes place directly after the "re-find" check, right before the critical section for the first stage of page deletion. Author: Peter Geoghegan <pg@bowt.ie> Discussion: https://postgr.es/m/CAH2-Wz=dayg0vjs4+er84TS9ami=csdzjpuiCGbEw=idhwqhzQ@mail.gmail.com Backpatch: 11- (all supported versions).
This commit is contained in:
@ -2148,12 +2148,6 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
|
|||||||
&topparent, &topparentrightsib))
|
&topparent, &topparentrightsib))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that the parent-page index items we're about to delete/overwrite
|
|
||||||
* in subtree parent page contain what we expect. This can fail if the
|
|
||||||
* index has become corrupt for some reason. We want to throw any error
|
|
||||||
* before entering the critical section --- otherwise it'd be a PANIC.
|
|
||||||
*/
|
|
||||||
page = BufferGetPage(subtreeparent);
|
page = BufferGetPage(subtreeparent);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
@ -2171,8 +2165,17 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
|
|||||||
nextoffset = OffsetNumberNext(poffset);
|
nextoffset = OffsetNumberNext(poffset);
|
||||||
itemid = PageGetItemId(page, nextoffset);
|
itemid = PageGetItemId(page, nextoffset);
|
||||||
itup = (IndexTuple) PageGetItem(page, itemid);
|
itup = (IndexTuple) PageGetItem(page, itemid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the parent-page index items we're about to delete/overwrite
|
||||||
|
* in subtree parent page contain what we expect. This can fail if the
|
||||||
|
* index has become corrupt for some reason. When that happens we back
|
||||||
|
* out of deletion of the leafbuf subtree. (This is just like the case
|
||||||
|
* where _bt_lock_subtree_parent() cannot "re-find" leafbuf's downlink.)
|
||||||
|
*/
|
||||||
if (BTreeTupleGetDownLink(itup) != topparentrightsib)
|
if (BTreeTupleGetDownLink(itup) != topparentrightsib)
|
||||||
ereport(ERROR,
|
{
|
||||||
|
ereport(LOG,
|
||||||
(errcode(ERRCODE_INDEX_CORRUPTED),
|
(errcode(ERRCODE_INDEX_CORRUPTED),
|
||||||
errmsg_internal("right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
|
errmsg_internal("right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
|
||||||
topparentrightsib, topparent,
|
topparentrightsib, topparent,
|
||||||
@ -2180,6 +2183,11 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
|
|||||||
BufferGetBlockNumber(subtreeparent),
|
BufferGetBlockNumber(subtreeparent),
|
||||||
RelationGetRelationName(rel))));
|
RelationGetRelationName(rel))));
|
||||||
|
|
||||||
|
_bt_relbuf(rel, subtreeparent);
|
||||||
|
Assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Any insert which would have gone on the leaf block will now go to its
|
* Any insert which would have gone on the leaf block will now go to its
|
||||||
* right sibling. In other words, the key space moves right.
|
* right sibling. In other words, the key space moves right.
|
||||||
@ -2834,6 +2842,7 @@ _bt_lock_subtree_parent(Relation rel, BlockNumber child, BTStack stack,
|
|||||||
(errcode(ERRCODE_INDEX_CORRUPTED),
|
(errcode(ERRCODE_INDEX_CORRUPTED),
|
||||||
errmsg_internal("failed to re-find parent key in index \"%s\" for deletion target page %u",
|
errmsg_internal("failed to re-find parent key in index \"%s\" for deletion target page %u",
|
||||||
RelationGetRelationName(rel), child)));
|
RelationGetRelationName(rel), child)));
|
||||||
|
Assert(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user