aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/nbtree/nbtpage.c62
-rw-r--r--src/backend/access/nbtree/nbtree.c3
2 files changed, 45 insertions, 20 deletions
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 6be8915229e..486d1563d8a 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -2404,24 +2404,22 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
if (!leftsibvalid)
{
- if (target != leafblkno)
- {
- /* we have only a pin on target, but pin+lock on leafbuf */
- ReleaseBuffer(buf);
- _bt_relbuf(rel, leafbuf);
- }
- else
- {
- /* we have only a pin on leafbuf */
- ReleaseBuffer(leafbuf);
- }
-
+ /*
+ * This is known to fail in the field; sibling link corruption
+ * is relatively common. Press on with vacuuming rather than
+ * just throwing an ERROR.
+ */
ereport(LOG,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg_internal("valid left sibling for deletion target could not be located: "
- "left sibling %u of target %u with leafblkno %u and scanblkno %u in index \"%s\"",
+ "left sibling %u of target %u with leafblkno %u and scanblkno %u on level %u of index \"%s\"",
leftsib, target, leafblkno, scanblkno,
- RelationGetRelationName(rel))));
+ targetlevel, RelationGetRelationName(rel))));
+
+ /* Must release all pins and locks on failure exit */
+ ReleaseBuffer(buf);
+ if (target != leafblkno)
+ _bt_relbuf(rel, leafbuf);
return false;
}
@@ -2496,13 +2494,40 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
rbuf = _bt_getbuf(rel, vstate->info->heaprel, rightsib, BT_WRITE);
page = BufferGetPage(rbuf);
opaque = BTPageGetOpaque(page);
+
+ /*
+ * Validate target's right sibling page. Its left link must point back to
+ * the target page.
+ */
if (opaque->btpo_prev != target)
- ereport(ERROR,
+ {
+ /*
+ * This is known to fail in the field; sibling link corruption is
+ * relatively common. Press on with vacuuming rather than just
+ * throwing an ERROR (same approach used for left-sibling's-right-link
+ * validation check a moment ago).
+ */
+ ereport(LOG,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg_internal("right sibling's left-link doesn't match: "
- "block %u links to %u instead of expected %u in index \"%s\"",
- rightsib, opaque->btpo_prev, target,
- RelationGetRelationName(rel))));
+ "right sibling %u of target %u with leafblkno %u "
+ "and scanblkno %u spuriously links to non-target %u "
+ "on level %u of index \"%s\"",
+ rightsib, target, leafblkno,
+ scanblkno, opaque->btpo_prev,
+ targetlevel, RelationGetRelationName(rel))));
+
+ /* Must release all pins and locks on failure exit */
+ if (BufferIsValid(lbuf))
+ _bt_relbuf(rel, lbuf);
+ _bt_relbuf(rel, rbuf);
+ _bt_relbuf(rel, buf);
+ if (target != leafblkno)
+ _bt_relbuf(rel, leafbuf);
+
+ return false;
+ }
+
rightsib_is_rightmost = P_RIGHTMOST(opaque);
*rightsib_empty = (P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
@@ -2727,6 +2752,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
*/
_bt_pendingfsm_add(vstate, target, safexid);
+ /* Success - hold on to lock on leafbuf (might also have been target) */
return true;
}
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 2df8849858e..1ce5b15199a 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1093,8 +1093,7 @@ backtrack:
* can't be half-dead because only an interrupted VACUUM process can
* leave pages in that state, so we'd definitely have dealt with it
* back when the page was the scanblkno page (half-dead pages are
- * always marked fully deleted by _bt_pagedel()). This assumes that
- * there can be only one vacuum process running at a time.
+ * always marked fully deleted by _bt_pagedel(), barring corruption).
*/
if (!opaque || !P_ISLEAF(opaque) || P_ISHALFDEAD(opaque))
{