aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2020-05-15 16:50:34 -0400
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2020-05-15 16:50:34 -0400
commit0a319699d59c26538bd78742cdfc3817509d82bf (patch)
tree60e5c04bcf4d8a3e8fe7e03526b6f938b1064a79
parent87ca0f94d6ea27cc8db83cab8e7bb652ef383168 (diff)
downloadpostgresql-0a319699d59c26538bd78742cdfc3817509d82bf.tar.gz
postgresql-0a319699d59c26538bd78742cdfc3817509d82bf.zip
Avoid killing btree items that are already dead
_bt_killitems marks btree items dead when a scan leaves the page where they live, but it does so with only share lock (to improve concurrency). This was historicall okay, since killing a dead item has no consequences. However, with the advent of data checksums and wal_log_hints, this action incurs a WAL full-page-image record of the page. Multiple concurrent processes would write the same page several times, leading to WAL bloat. The probability of this happening can be reduced by only killing items if they're not already dead, so change the code to do that. The problem could eliminated completely by having _bt_killitems upgrade to exclusive lock upon seeing a killable item, but that would reduce concurrency so it's considered a cure worse than the disease. Backpatch all the way back to 9.5, since wal_log_hints was introduced in 9.4. Author: Masahiko Sawada <masahiko.sawada@2ndquadrant.com> Discussion: https://postgr.es/m/CA+fd4k6PeRj2CkzapWNrERkja5G0-6D-YQiKfbukJV+qZGFZ_Q@mail.gmail.com
-rw-r--r--src/backend/access/nbtree/nbtutils.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 88d0b12f93f..a23d693f0de 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -1801,9 +1801,19 @@ _bt_killitems(IndexScanDesc scan)
if (ItemPointerEquals(&ituple->t_tid, &kitem->heapTid))
{
- /* found the item */
- ItemIdMarkDead(iid);
- killedsomething = true;
+ /*
+ * Found the item. Mark it as dead, if it isn't already.
+ * Since this happens while holding a buffer lock possibly in
+ * shared mode, it's possible that multiple processes attempt
+ * to do this simultaneously, leading to multiple full-page
+ * images being sent to WAL (if wal_log_hints or data checksums
+ * are enabled), which is undesirable.
+ */
+ if (!ItemIdIsDead(iid))
+ {
+ ItemIdMarkDead(iid);
+ killedsomething = true;
+ }
break; /* out of inner search loop */
}
offnum = OffsetNumberNext(offnum);