1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +03:00

Fix zeroing of pg_serial page without SLRU bank lock

Bug in commit 53c2a97a92: we failed to acquire the correct SLRU bank
lock when iterating to zero-out intermediate pages in predicate.c.
Rewrite the code block so that we follow the locking protocol correctly.

Also update an outdated comment in the same file -- SerialSLRULock
exists no more.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Discussion: https://postgr.es/m/2a25eaf4-a3a4-5fd1-6241-9d7c73142085@gmail.com
This commit is contained in:
Alvaro Herrera
2024-04-03 17:49:44 +02:00
parent bf1e650806
commit be2f073100

View File

@ -137,7 +137,7 @@
* SerialControlLock * SerialControlLock
* - Protects SerialControlData members * - Protects SerialControlData members
* *
* SerialSLRULock * SLRU per-bank locks
* - Protects SerialSlruCtl * - Protects SerialSlruCtl
* *
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
@ -908,20 +908,25 @@ SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
if (isNewPage) if (isNewPage)
serialControl->headPage = targetPage; serialControl->headPage = targetPage;
LWLockAcquire(lock, LW_EXCLUSIVE);
if (isNewPage) if (isNewPage)
{ {
/* Initialize intervening pages. */ /* Initialize intervening pages; might involve trading locks */
while (firstZeroPage != targetPage) for (;;)
{ {
(void) SimpleLruZeroPage(SerialSlruCtl, firstZeroPage); lock = SimpleLruGetBankLock(SerialSlruCtl, firstZeroPage);
LWLockAcquire(lock, LW_EXCLUSIVE);
slotno = SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
if (firstZeroPage == targetPage)
break;
firstZeroPage = SerialNextPage(firstZeroPage); firstZeroPage = SerialNextPage(firstZeroPage);
LWLockRelease(lock);
} }
slotno = SimpleLruZeroPage(SerialSlruCtl, targetPage);
} }
else else
{
LWLockAcquire(lock, LW_EXCLUSIVE);
slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid); slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
}
SerialValue(slotno, xid) = minConflictCommitSeqNo; SerialValue(slotno, xid) = minConflictCommitSeqNo;
SerialSlruCtl->shared->page_dirty[slotno] = true; SerialSlruCtl->shared->page_dirty[slotno] = true;