Skip to content

Commit 8c8c9f3

Browse files
committed
Check for interrupts inside the nbtree page deletion code.
When deleting pages the nbtree code has to walk through siblings of a tree node. When those sibling links are corrupted that can lead to endless loops - which are currently not interruptible. This is especially problematic if autovacuum is repeatedly blocked on such indexes, as it can be hard to get out of that situation without resorting to single user mode. Thus add interrupt checks to appropriate places in such loops. Unfortunately in one of the cases it's it's not easy to do so. Between 9.3 and 9.4 the page deletion (and page split) code changed significantly. Before it was significantly less robust against interruptions. Therefore don't backpatch to 9.3. Author: Andres Freund Discussion: https://postgr.es/m/20180627191629.wkunw2qbibnvlz53@alap3.anarazel.de Backpatch: 9.4-
1 parent 62c2fe6 commit 8c8c9f3

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

src/backend/access/nbtree/nbtpage.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,7 @@ _bt_pagedel(Relation rel, Buffer buf)
13161316
rightsib_empty = false;
13171317
while (P_ISHALFDEAD(opaque))
13181318
{
1319+
/* will check for interrupts, once lock is released */
13191320
if (!_bt_unlink_halfdead_page(rel, buf, &rightsib_empty))
13201321
{
13211322
/* _bt_unlink_halfdead_page already released buffer */
@@ -1328,6 +1329,12 @@ _bt_pagedel(Relation rel, Buffer buf)
13281329

13291330
_bt_relbuf(rel, buf);
13301331

1332+
/*
1333+
* Check here, as calling loops will have locks held, preventing
1334+
* interrupts from being processed.
1335+
*/
1336+
CHECK_FOR_INTERRUPTS();
1337+
13311338
/*
13321339
* The page has now been deleted. If its right sibling is completely
13331340
* empty, it's possible that the reason we haven't deleted it earlier
@@ -1586,6 +1593,12 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
15861593

15871594
LockBuffer(leafbuf, BUFFER_LOCK_UNLOCK);
15881595

1596+
/*
1597+
* Check here, as calling loops will have locks held, preventing
1598+
* interrupts from being processed.
1599+
*/
1600+
CHECK_FOR_INTERRUPTS();
1601+
15891602
/*
15901603
* If the leaf page still has a parent pointing to it (or a chain of
15911604
* parents), we don't unlink the leaf page yet, but the topmost remaining
@@ -1644,6 +1657,14 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty)
16441657
/* step right one page */
16451658
leftsib = opaque->btpo_next;
16461659
_bt_relbuf(rel, lbuf);
1660+
1661+
/*
1662+
* It'd be good to check for interrupts here, but it's not easy to
1663+
* do so because a lock is always held. This block isn't
1664+
* frequently reached, so hopefully the consequences of not
1665+
* checking interrupts aren't too bad.
1666+
*/
1667+
16471668
if (leftsib == P_NONE)
16481669
{
16491670
elog(LOG, "no left sibling (concurrent deletion?) of block %u in \"%s\"",

0 commit comments

Comments
 (0)