mirror of
https://github.com/postgres/postgres.git
synced 2025-12-21 05:21:08 +03:00
Improve performance of subsystems on top of SLRU
More precisely, what we do here is make the SLRU cache sizes
configurable with new GUCs, so that sites with high concurrency and big
ranges of transactions in flight (resp. multixacts/subtransactions) can
benefit from bigger caches. In order for this to work with good
performance, two additional changes are made:
1. the cache is divided in "banks" (to borrow terminology from CPU
caches), and algorithms such as eviction buffer search only affect
one specific bank. This forestalls the problem that linear searching
for a specific buffer across the whole cache takes too long: we only
have to search the specific bank, whose size is small. This work is
authored by Andrey Borodin.
2. Change the locking regime for the SLRU banks, so that each bank uses
a separate LWLock. This allows for increased scalability. This work
is authored by Dilip Kumar. (A part of this was previously committed as
d172b717c6f4.)
Special care is taken so that the algorithms that can potentially
traverse more than one bank release one bank's lock before acquiring the
next. This should happen rarely, but particularly clog.c's group commit
feature needed code adjustment to cope with this. I (Álvaro) also added
lots of comments to make sure the design is sound.
The new GUCs match the names introduced by bcdfa5f2e2 in the
pg_stat_slru view.
The default values for these parameters are similar to the previous
sizes of each SLRU. commit_ts, clog and subtrans accept value 0, which
means to adjust by dividing shared_buffers by 512 (so 2MB for every 1GB
of shared_buffers), with a cap of 8MB. (A new slru.c function
SimpleLruAutotuneBuffers() was added to support this.) The cap was
previously 1MB for clog, so for sites with more than 512MB of shared
memory the total memory used increases, which is likely a good tradeoff.
However, other SLRUs (notably multixact ones) retain smaller sizes and
don't support a configured value of 0. These values based on
shared_buffers may need to be revisited, but that's an easy change.
There was some resistance to adding these new GUCs: it would be better
to adjust to memory pressure automatically somehow, for example by
stealing memory from shared_buffers (where the caches can grow and
shrink naturally). However, doing that seems to be a much larger
project and one which has made virtually no progress in several years,
and because this is such a pain point for so many users, here we take
the pragmatic approach.
Author: Andrey Borodin <x4mmm@yandex-team.ru>
Author: Dilip Kumar <dilipbalaut@gmail.com>
Reviewed-by: Amul Sul, Gilles Darold, Anastasia Lubennikova,
Ivan Lazarev, Robert Haas, Thomas Munro, Tomas Vondra,
Yura Sokolov, Васильев Дмитрий (Dmitry Vasiliev).
Discussion: https://postgr.es/m/2BEC2B3F-9B61-4C1D-9FB5-5FAB0F05EF86@yandex-team.ru
Discussion: https://postgr.es/m/CAFiTN-vzDvNz=ExGXz6gdyjtzGixKSqs0mKHMmaQ8sOSEFZ33A@mail.gmail.com
This commit is contained in:
@@ -88,6 +88,7 @@
|
||||
#include "storage/proc.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc_hooks.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/snapmgr.h"
|
||||
|
||||
@@ -192,10 +193,10 @@ static SlruCtlData MultiXactMemberCtlData;
|
||||
|
||||
/*
|
||||
* MultiXact state shared across all backends. All this state is protected
|
||||
* by MultiXactGenLock. (We also use MultiXactOffsetSLRULock and
|
||||
* MultiXactMemberSLRULock to guard accesses to the two sets of SLRU
|
||||
* buffers. For concurrency's sake, we avoid holding more than one of these
|
||||
* locks at a time.)
|
||||
* by MultiXactGenLock. (We also use SLRU bank's lock of MultiXactOffset and
|
||||
* MultiXactMember to guard accesses to the two sets of SLRU buffers. For
|
||||
* concurrency's sake, we avoid holding more than one of these locks at a
|
||||
* time.)
|
||||
*/
|
||||
typedef struct MultiXactStateData
|
||||
{
|
||||
@@ -870,12 +871,15 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
|
||||
int slotno;
|
||||
MultiXactOffset *offptr;
|
||||
int i;
|
||||
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
LWLock *lock;
|
||||
LWLock *prevlock = NULL;
|
||||
|
||||
pageno = MultiXactIdToOffsetPage(multi);
|
||||
entryno = MultiXactIdToOffsetEntry(multi);
|
||||
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
|
||||
* to complain about if there's any I/O error. This is kinda bogus, but
|
||||
@@ -891,10 +895,8 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
|
||||
|
||||
MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
|
||||
|
||||
/* Exchange our lock */
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
/* Release MultiXactOffset SLRU lock. */
|
||||
LWLockRelease(lock);
|
||||
|
||||
prev_pageno = -1;
|
||||
|
||||
@@ -916,6 +918,20 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
|
||||
|
||||
if (pageno != prev_pageno)
|
||||
{
|
||||
/*
|
||||
* MultiXactMember SLRU page is changed so check if this new page
|
||||
* fall into the different SLRU bank then release the old bank's
|
||||
* lock and acquire lock on the new bank.
|
||||
*/
|
||||
lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
|
||||
if (lock != prevlock)
|
||||
{
|
||||
if (prevlock != NULL)
|
||||
LWLockRelease(prevlock);
|
||||
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
prevlock = lock;
|
||||
}
|
||||
slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
|
||||
prev_pageno = pageno;
|
||||
}
|
||||
@@ -936,7 +952,8 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
|
||||
MultiXactMemberCtl->shared->page_dirty[slotno] = true;
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
if (prevlock != NULL)
|
||||
LWLockRelease(prevlock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1239,6 +1256,8 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
||||
MultiXactId tmpMXact;
|
||||
MultiXactOffset nextOffset;
|
||||
MultiXactMember *ptr;
|
||||
LWLock *lock;
|
||||
LWLock *prevlock = NULL;
|
||||
|
||||
debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
|
||||
|
||||
@@ -1342,11 +1361,22 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
|
||||
* time on every multixact creation.
|
||||
*/
|
||||
retry:
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
|
||||
pageno = MultiXactIdToOffsetPage(multi);
|
||||
entryno = MultiXactIdToOffsetEntry(multi);
|
||||
|
||||
/*
|
||||
* If this page falls under a different bank, release the old bank's lock
|
||||
* and acquire the lock of the new bank.
|
||||
*/
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
if (lock != prevlock)
|
||||
{
|
||||
if (prevlock != NULL)
|
||||
LWLockRelease(prevlock);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
prevlock = lock;
|
||||
}
|
||||
|
||||
slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
|
||||
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
||||
offptr += entryno;
|
||||
@@ -1379,7 +1409,21 @@ retry:
|
||||
entryno = MultiXactIdToOffsetEntry(tmpMXact);
|
||||
|
||||
if (pageno != prev_pageno)
|
||||
{
|
||||
/*
|
||||
* Since we're going to access a different SLRU page, if this page
|
||||
* falls under a different bank, release the old bank's lock and
|
||||
* acquire the lock of the new bank.
|
||||
*/
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
if (prevlock != lock)
|
||||
{
|
||||
LWLockRelease(prevlock);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
prevlock = lock;
|
||||
}
|
||||
slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
|
||||
}
|
||||
|
||||
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
||||
offptr += entryno;
|
||||
@@ -1388,7 +1432,8 @@ retry:
|
||||
if (nextMXOffset == 0)
|
||||
{
|
||||
/* Corner case 2: next multixact is still being filled in */
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(prevlock);
|
||||
prevlock = NULL;
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
pg_usleep(1000L);
|
||||
goto retry;
|
||||
@@ -1397,13 +1442,11 @@ retry:
|
||||
length = nextMXOffset - offset;
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(prevlock);
|
||||
prevlock = NULL;
|
||||
|
||||
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
|
||||
|
||||
/* Now get the members themselves. */
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
|
||||
truelength = 0;
|
||||
prev_pageno = -1;
|
||||
for (i = 0; i < length; i++, offset++)
|
||||
@@ -1419,6 +1462,20 @@ retry:
|
||||
|
||||
if (pageno != prev_pageno)
|
||||
{
|
||||
/*
|
||||
* Since we're going to access a different SLRU page, if this page
|
||||
* falls under a different bank, release the old bank's lock and
|
||||
* acquire the lock of the new bank.
|
||||
*/
|
||||
lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
|
||||
if (lock != prevlock)
|
||||
{
|
||||
if (prevlock)
|
||||
LWLockRelease(prevlock);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
prevlock = lock;
|
||||
}
|
||||
|
||||
slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
|
||||
prev_pageno = pageno;
|
||||
}
|
||||
@@ -1442,7 +1499,8 @@ retry:
|
||||
truelength++;
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
if (prevlock)
|
||||
LWLockRelease(prevlock);
|
||||
|
||||
/* A multixid with zero members should not happen */
|
||||
Assert(truelength > 0);
|
||||
@@ -1834,8 +1892,8 @@ MultiXactShmemSize(void)
|
||||
mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
|
||||
|
||||
size = SHARED_MULTIXACT_STATE_SIZE;
|
||||
size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTOFFSET_BUFFERS, 0));
|
||||
size = add_size(size, SimpleLruShmemSize(NUM_MULTIXACTMEMBER_BUFFERS, 0));
|
||||
size = add_size(size, SimpleLruShmemSize(multixact_offset_buffers, 0));
|
||||
size = add_size(size, SimpleLruShmemSize(multixact_member_buffers, 0));
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -1851,16 +1909,16 @@ MultiXactShmemInit(void)
|
||||
MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
|
||||
|
||||
SimpleLruInit(MultiXactOffsetCtl,
|
||||
"multixact_offset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
|
||||
MultiXactOffsetSLRULock, "pg_multixact/offsets",
|
||||
LWTRANCHE_MULTIXACTOFFSET_BUFFER,
|
||||
"multixact_offset", multixact_offset_buffers, 0,
|
||||
"pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
|
||||
LWTRANCHE_MULTIXACTOFFSET_SLRU,
|
||||
SYNC_HANDLER_MULTIXACT_OFFSET,
|
||||
false);
|
||||
SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
|
||||
SimpleLruInit(MultiXactMemberCtl,
|
||||
"multixact_member", NUM_MULTIXACTMEMBER_BUFFERS, 0,
|
||||
MultiXactMemberSLRULock, "pg_multixact/members",
|
||||
LWTRANCHE_MULTIXACTMEMBER_BUFFER,
|
||||
"multixact_member", multixact_member_buffers, 0,
|
||||
"pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
|
||||
LWTRANCHE_MULTIXACTMEMBER_SLRU,
|
||||
SYNC_HANDLER_MULTIXACT_MEMBER,
|
||||
false);
|
||||
/* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
|
||||
@@ -1887,6 +1945,24 @@ MultiXactShmemInit(void)
|
||||
OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
|
||||
}
|
||||
|
||||
/*
|
||||
* GUC check_hook for multixact_offset_buffers
|
||||
*/
|
||||
bool
|
||||
check_multixact_offset_buffers(int *newval, void **extra, GucSource source)
|
||||
{
|
||||
return check_slru_buffers("multixact_offset_buffers", newval);
|
||||
}
|
||||
|
||||
/*
|
||||
* GUC check_hook for multixact_member_buffer
|
||||
*/
|
||||
bool
|
||||
check_multixact_member_buffers(int *newval, void **extra, GucSource source)
|
||||
{
|
||||
return check_slru_buffers("multixact_member_buffers", newval);
|
||||
}
|
||||
|
||||
/*
|
||||
* This func must be called ONCE on system install. It creates the initial
|
||||
* MultiXact segments. (The MultiXacts directories are assumed to have been
|
||||
@@ -1896,8 +1972,10 @@ void
|
||||
BootStrapMultiXact(void)
|
||||
{
|
||||
int slotno;
|
||||
LWLock *lock;
|
||||
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, 0);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
/* Create and zero the first page of the offsets log */
|
||||
slotno = ZeroMultiXactOffsetPage(0, false);
|
||||
@@ -1906,9 +1984,10 @@ BootStrapMultiXact(void)
|
||||
SimpleLruWritePage(MultiXactOffsetCtl, slotno);
|
||||
Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(lock);
|
||||
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
lock = SimpleLruGetBankLock(MultiXactMemberCtl, 0);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
/* Create and zero the first page of the members log */
|
||||
slotno = ZeroMultiXactMemberPage(0, false);
|
||||
@@ -1917,7 +1996,7 @@ BootStrapMultiXact(void)
|
||||
SimpleLruWritePage(MultiXactMemberCtl, slotno);
|
||||
Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1977,10 +2056,12 @@ static void
|
||||
MaybeExtendOffsetSlru(void)
|
||||
{
|
||||
int64 pageno;
|
||||
LWLock *lock;
|
||||
|
||||
pageno = MultiXactIdToOffsetPage(MultiXactState->nextMXact);
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
|
||||
{
|
||||
@@ -1995,7 +2076,7 @@ MaybeExtendOffsetSlru(void)
|
||||
SimpleLruWritePage(MultiXactOffsetCtl, slotno);
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2049,6 +2130,8 @@ TrimMultiXact(void)
|
||||
oldestMXactDB = MultiXactState->oldestMultiXactDB;
|
||||
LWLockRelease(MultiXactGenLock);
|
||||
|
||||
/* Clean up offsets state */
|
||||
|
||||
/*
|
||||
* (Re-)Initialize our idea of the latest page number for offsets.
|
||||
*/
|
||||
@@ -2056,9 +2139,6 @@ TrimMultiXact(void)
|
||||
pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
|
||||
pageno);
|
||||
|
||||
/* Clean up offsets state */
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Zero out the remainder of the current offsets page. See notes in
|
||||
* TrimCLOG() for background. Unlike CLOG, some WAL record covers every
|
||||
@@ -2072,7 +2152,9 @@ TrimMultiXact(void)
|
||||
{
|
||||
int slotno;
|
||||
MultiXactOffset *offptr;
|
||||
LWLock *lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
|
||||
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
||||
offptr += entryno;
|
||||
@@ -2080,10 +2162,9 @@ TrimMultiXact(void)
|
||||
MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
|
||||
|
||||
MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
|
||||
/*
|
||||
* And the same for members.
|
||||
*
|
||||
@@ -2093,8 +2174,6 @@ TrimMultiXact(void)
|
||||
pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
|
||||
pageno);
|
||||
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Zero out the remainder of the current members page. See notes in
|
||||
* TrimCLOG() for motivation.
|
||||
@@ -2105,7 +2184,9 @@ TrimMultiXact(void)
|
||||
int slotno;
|
||||
TransactionId *xidptr;
|
||||
int memberoff;
|
||||
LWLock *lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
|
||||
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
memberoff = MXOffsetToMemberOffset(offset);
|
||||
slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
|
||||
xidptr = (TransactionId *)
|
||||
@@ -2120,10 +2201,9 @@ TrimMultiXact(void)
|
||||
*/
|
||||
|
||||
MultiXactMemberCtl->shared->page_dirty[slotno] = true;
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
|
||||
/* signal that we're officially up */
|
||||
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
|
||||
MultiXactState->finishedStartup = true;
|
||||
@@ -2411,6 +2491,7 @@ static void
|
||||
ExtendMultiXactOffset(MultiXactId multi)
|
||||
{
|
||||
int64 pageno;
|
||||
LWLock *lock;
|
||||
|
||||
/*
|
||||
* No work except at first MultiXactId of a page. But beware: just after
|
||||
@@ -2421,13 +2502,14 @@ ExtendMultiXactOffset(MultiXactId multi)
|
||||
return;
|
||||
|
||||
pageno = MultiXactIdToOffsetPage(multi);
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
/* Zero the page and make an XLOG entry about it */
|
||||
ZeroMultiXactOffsetPage(pageno, true);
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2460,15 +2542,17 @@ ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
|
||||
if (flagsoff == 0 && flagsbit == 0)
|
||||
{
|
||||
int64 pageno;
|
||||
LWLock *lock;
|
||||
|
||||
pageno = MXOffsetToMemberPage(offset);
|
||||
lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
|
||||
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
/* Zero the page and make an XLOG entry about it */
|
||||
ZeroMultiXactMemberPage(pageno, true);
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2766,7 +2850,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
|
||||
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
|
||||
offptr += entryno;
|
||||
offset = *offptr;
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(SimpleLruGetBankLock(MultiXactOffsetCtl, pageno));
|
||||
|
||||
*result = offset;
|
||||
return true;
|
||||
@@ -3248,31 +3332,35 @@ multixact_redo(XLogReaderState *record)
|
||||
{
|
||||
int64 pageno;
|
||||
int slotno;
|
||||
LWLock *lock;
|
||||
|
||||
memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
|
||||
|
||||
LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
|
||||
lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
slotno = ZeroMultiXactOffsetPage(pageno, false);
|
||||
SimpleLruWritePage(MultiXactOffsetCtl, slotno);
|
||||
Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
|
||||
|
||||
LWLockRelease(MultiXactOffsetSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
|
||||
{
|
||||
int64 pageno;
|
||||
int slotno;
|
||||
LWLock *lock;
|
||||
|
||||
memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
|
||||
|
||||
LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
|
||||
lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
|
||||
LWLockAcquire(lock, LW_EXCLUSIVE);
|
||||
|
||||
slotno = ZeroMultiXactMemberPage(pageno, false);
|
||||
SimpleLruWritePage(MultiXactMemberCtl, slotno);
|
||||
Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
|
||||
|
||||
LWLockRelease(MultiXactMemberSLRULock);
|
||||
LWLockRelease(lock);
|
||||
}
|
||||
else if (info == XLOG_MULTIXACT_CREATE_ID)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user