aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/nbtree/README14
-rw-r--r--src/backend/access/nbtree/nbtpage.c23
2 files changed, 20 insertions, 17 deletions
diff --git a/src/backend/access/nbtree/README b/src/backend/access/nbtree/README
index 266c1cd4cd9..c5b0a30e4eb 100644
--- a/src/backend/access/nbtree/README
+++ b/src/backend/access/nbtree/README
@@ -262,11 +262,15 @@ long as we're keeping the leaf locked. The internal pages in the chain
cannot acquire new children afterwards either, because the leaf page is
marked as half-dead and won't be split.
-Removing the downlink to the top of the to-be-deleted chain effectively
-transfers the key space to the right sibling for all the intermediate levels
-too, in one atomic operation. A concurrent search might still visit the
-intermediate pages, but it will move right when it reaches the half-dead page
-at the leaf level.
+Removing the downlink to the top of the to-be-deleted subtree/chain
+effectively transfers the key space to the right sibling for all the
+intermediate levels too, in one atomic operation. A concurrent search might
+still visit the intermediate pages, but it will move right when it reaches
+the half-dead page at the leaf level. In particular, the search will move to
+the subtree to the right of the half-dead leaf page/to-be-deleted subtree,
+since the half-dead leaf page's right sibling must be a "cousin" page, not a
+"true" sibling page (or a second cousin page when the to-be-deleted chain
+starts at leaf page's grandparent page, and so on).
In the second stage, the topmost page in the chain is unlinked from its
siblings, and the half-dead leaf page is updated to point to the next page
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 8ade165f7a4..e7c40cba973 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -1301,17 +1301,6 @@ _bt_lock_branch_parent(Relation rel, BlockNumber child, BTStack stack,
_bt_relbuf(rel, lbuf);
}
- /*
- * Perform the same check on this internal level that
- * _bt_mark_page_halfdead performed on the leaf level.
- */
- if (_bt_is_page_halfdead(rel, *rightsib))
- {
- elog(DEBUG1, "could not delete page %u because its right sibling %u is half-dead",
- parent, *rightsib);
- return false;
- }
-
return _bt_lock_branch_parent(rel, parent, stack->bts_parent,
topparent, topoff, target, rightsib);
}
@@ -1621,7 +1610,17 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
* parent, unless it is the only child --- in which case the parent has to
* be deleted too, and the same condition applies recursively to it. We
* have to check this condition all the way up before trying to delete,
- * and lock the final parent of the to-be-deleted branch.
+ * and lock the final parent of the to-be-deleted subtree.
+ *
+ * However, we won't need to repeat the above _bt_is_page_halfdead() check
+ * for parent/ancestor pages because of the rightmost restriction. The
+ * leaf check will apply to a right "cousin" leaf page rather than a
+ * simple right sibling leaf page in cases where we actually go on to
+ * perform internal page deletion. The right cousin leaf page is
+ * representative of the left edge of the subtree to the right of the
+ * to-be-deleted subtree as a whole. (Besides, internal pages are never
+ * marked half-dead, so it isn't even possible to directly assess if an
+ * internal page is part of some other to-be-deleted subtree.)
*/
rightsib = leafrightsib;
target = leafblkno;