=== Applying patches on top of PostgreSQL commit ID c5d34f4a550f26583a0b92e294eff7d001e318d3 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sat Nov 8 02:50:23 UTC 2025 On branch cf/5919 nothing to commit, working tree clean === using 'git am' to apply patch ./v6-0001-Refactor-goto-into-for-loop-in-GetVictimBuffer.patch === Applying: Refactor goto into for loop in GetVictimBuffer() Using index info to reconstruct a base tree... M src/backend/storage/buffer/bufmgr.c M src/backend/storage/buffer/freelist.c M src/include/storage/buf_internals.h Falling back to patching base and 3-way merge... Auto-merging src/include/storage/buf_internals.h Auto-merging src/backend/storage/buffer/freelist.c Auto-merging src/backend/storage/buffer/bufmgr.c CONFLICT (content): Merge conflict in src/backend/storage/buffer/bufmgr.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Refactor goto into for loop in GetVictimBuffer() When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M src/backend/storage/buffer/bufmgr.c M src/backend/storage/buffer/freelist.c M src/include/storage/buf_internals.h === using patch(1) to apply patch ./v6-0001-Refactor-goto-into-for-loop-in-GetVictimBuffer.patch === patching file src/backend/storage/buffer/bufmgr.c Hunk #2 FAILED at 2321. 1 out of 2 hunks FAILED -- saving rejects to file src/backend/storage/buffer/bufmgr.c.rej patching file src/backend/storage/buffer/freelist.c Hunk #2 succeeded at 782 (offset 2 lines). Hunk #3 succeeded at 806 (offset 2 lines). patching file src/include/storage/buf_internals.h Hunk #1 succeeded at 486 (offset 65 lines). Unstaged changes after reset: M src/backend/storage/buffer/bufmgr.c M src/backend/storage/buffer/freelist.c M src/include/storage/buf_internals.h Removing src/backend/storage/buffer/bufmgr.c.rej === using 'git apply' to apply patch ./v6-0001-Refactor-goto-into-for-loop-in-GetVictimBuffer.patch === Applied patch to 'src/backend/storage/buffer/bufmgr.c' with conflicts. Applied patch to 'src/backend/storage/buffer/freelist.c' cleanly. Applied patch to 'src/include/storage/buf_internals.h' cleanly. U src/backend/storage/buffer/bufmgr.c diff --cc src/backend/storage/buffer/bufmgr.c index 327ddb7adc8,1fadeddf505..00000000000 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@@ -2331,78 -2321,67 +2327,74 @@@ GetVictimBuffer(BufferAccessStrategy st ReservePrivateRefCountEntry(); ResourceOwnerEnlarge(CurrentResourceOwner); - /* we return here if a prospective victim buffer gets used concurrently */ - again: - - /* - * Select a victim buffer. The buffer is returned pinned and owned by - * this backend. - */ - buf_hdr = StrategyGetBuffer(strategy, &buf_state, &from_ring); - buf = BufferDescriptorGetBuffer(buf_hdr); - - /* - * We shouldn't have any other pins for this buffer. - */ - CheckBufferIsPinnedOnce(buf); - - /* - * If the buffer was dirty, try to write it out. There is a race - * condition here, in that someone might dirty it after we released the - * buffer header lock above, or even while we are writing it out (since - * our share-lock won't prevent hint-bit updates). We will recheck the - * dirty bit after re-locking the buffer header. - */ - if (buf_state & BM_DIRTY) + /* Select a victim buffer using an optimistic locking scheme. */ + for (;;) { - LWLock *content_lock; - Assert(buf_state & BM_TAG_VALID); - Assert(buf_state & BM_VALID); + /* Attempt to claim a victim buffer. Buffer is returned pinned. */ + buf_hdr = StrategyGetBuffer(strategy, &buf_state, &from_ring); + buf = BufferDescriptorGetBuffer(buf_hdr); /* - * We need a share-lock on the buffer contents to write it out (else - * we might write invalid data, eg because someone else is compacting - * the page contents while we write). We must use a conditional lock - * acquisition here to avoid deadlock. Even though the buffer was not - * pinned (and therefore surely not locked) when StrategyGetBuffer - * returned it, someone else could have pinned and exclusive-locked it - * by the time we get here. If we try to get the lock unconditionally, - * we'd block waiting for them; if they later block waiting for us, - * deadlock ensues. (This has been observed to happen when two - * backends are both trying to split btree index pages, and the second - * one just happens to be trying to split the page the first one got - * from StrategyGetBuffer.) + * We shouldn't have any other pins for this buffer. */ - content_lock = BufferDescriptorGetContentLock(buf_hdr); - if (!LWLockConditionalAcquire(content_lock, LW_SHARED)) - { - /* - * Someone else has locked the buffer, so give it up and loop back - * to get another one. - */ - UnpinBuffer(buf_hdr); - goto again; - } + CheckBufferIsPinnedOnce(buf); /* - * If using a nondefault strategy, and writing the buffer would - * require a WAL flush, let the strategy decide whether to go ahead - * and write/reuse the buffer or to choose another victim. We need a - * lock to inspect the page LSN, so this can't be done inside - * StrategyGetBuffer. + * If the buffer was dirty, try to write it out. There is a race + * condition here, in that someone might dirty it after we released + * the buffer header lock above, or even while we are writing it out + * (since our share-lock won't prevent hint-bit updates). We will + * recheck the dirty bit after re-locking the buffer header. */ - if (strategy != NULL) + if (buf_state & BM_DIRTY) { - XLogRecPtr lsn; + LWLock *content_lock; ++<<<<<<< ours + /* Read the LSN while holding buffer header lock */ + buf_state = LockBufHdr(buf_hdr); + lsn = BufferGetLSN(buf_hdr); + UnlockBufHdr(buf_hdr); ++======= + Assert(buf_state & BM_TAG_VALID); + Assert(buf_state & BM_VALID); ++>>>>>>> theirs + + /* + * We need a share-lock on the buffer contents to write it out + * (else we might write invalid data, eg because someone else is + * compacting the page contents while we write). We must use a + * conditional lock acquisition here to avoid deadlock. Even + * though the buffer was not pinned (and therefore surely not + * locked) when StrategyGetBuffer returned it, someone else could + * have pinned and exclusive-locked it by the time we get here. If + * we try to get the lock unconditionally, we'd block waiting for + * them; if they later block waiting for us, deadlock ensues. + * (This has been observed to happen when two backends are both + * trying to split btree index pages, and the second one just + * happens to be trying to split the page the first one got from + * StrategyGetBuffer.) + */ + content_lock = BufferDescriptorGetContentLock(buf_hdr); + if (!LWLockConditionalAcquire(content_lock, LW_SHARED)) + { + /* + * Someone else has locked the buffer, so give it up and loop + * back to get another one. + */ + UnpinBuffer(buf_hdr); + continue; + } - if (XLogNeedsFlush(lsn) - && StrategyRejectBuffer(strategy, buf_hdr, from_ring)) + /* + * If using a nondefault strategy, and writing the buffer would + * require a WAL flush, let the strategy decide whether to go + * ahead and write/reuse the buffer or to choose another victim. + * We need the content lock to inspect the page LSN, so this can't + * be done inside StrategyGetBuffer. + */ + if (StrategyRejectBuffer(strategy, buf_hdr, from_ring)) { LWLockRelease(content_lock); UnpinBuffer(buf_hdr);