Should we cacheline align PGXACT?
Started by Alexander Korotkovover 9 years ago84 messages
Hackers,
originally this idea was proposed by Andres Freund while experimenting with
lockfree Pin/UnpinBuffer [1].
The patch is attached as well as results of pgbench -S on 72-cores
machine. As before it shows huge benefit in this case.
For sure, we should validate that it doesn't cause performance regression
in other cases. At least we should test read-write and smaller machines.
Any other ideas?
1.
/messages/by-id/20160411214029.ce3fw6zxim5k6a2r@alap3.anarazel.de
------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
Attachments:
pgxact-align-1.patchapplication/octet-stream; name=pgxact-align-1.patchDownload
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
new file mode 100644
index 9f55adc..c4d5efa
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
*************** MarkAsPreparing(TransactionId xid, const
*** 403,409 ****
TwoPhaseState->freeGXacts = gxact->next;
proc = &ProcGlobal->allProcs[gxact->pgprocno];
! pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
/* Initialize the PGPROC entry */
MemSet(proc, 0, sizeof(PGPROC));
--- 403,409 ----
TwoPhaseState->freeGXacts = gxact->next;
proc = &ProcGlobal->allProcs[gxact->pgprocno];
! pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
/* Initialize the PGPROC entry */
MemSet(proc, 0, sizeof(PGPROC));
*************** GXactLoadSubxactData(GlobalTransaction g
*** 467,473 ****
TransactionId *children)
{
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
/* We need no extra lock since the GXACT isn't valid yet */
if (nsubxacts > PGPROC_MAX_CACHED_SUBXIDS)
--- 467,473 ----
TransactionId *children)
{
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
/* We need no extra lock since the GXACT isn't valid yet */
if (nsubxacts > PGPROC_MAX_CACHED_SUBXIDS)
*************** pg_prepared_xact(PG_FUNCTION_ARGS)
*** 725,731 ****
{
GlobalTransaction gxact = &status->array[status->currIdx++];
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
Datum values[5];
bool nulls[5];
HeapTuple tuple;
--- 725,731 ----
{
GlobalTransaction gxact = &status->array[status->currIdx++];
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
Datum values[5];
bool nulls[5];
HeapTuple tuple;
*************** TwoPhaseGetGXact(TransactionId xid)
*** 780,786 ****
for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
{
GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
if (pgxact->xid == xid)
{
--- 780,786 ----
for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
{
GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
if (pgxact->xid == xid)
{
*************** void
*** 947,953 ****
StartPrepare(GlobalTransaction gxact)
{
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
TransactionId xid = pgxact->xid;
TwoPhaseFileHeader hdr;
TransactionId *children;
--- 947,953 ----
StartPrepare(GlobalTransaction gxact)
{
PGPROC *proc = &ProcGlobal->allProcs[gxact->pgprocno];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
TransactionId xid = pgxact->xid;
TwoPhaseFileHeader hdr;
TransactionId *children;
*************** FinishPreparedTransaction(const char *gi
*** 1343,1349 ****
*/
gxact = LockGXact(gid, GetUserId());
proc = &ProcGlobal->allProcs[gxact->pgprocno];
! pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
xid = pgxact->xid;
/*
--- 1343,1349 ----
*/
gxact = LockGXact(gid, GetUserId());
proc = &ProcGlobal->allProcs[gxact->pgprocno];
! pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
xid = pgxact->xid;
/*
*************** CheckPointTwoPhase(XLogRecPtr redo_horiz
*** 1623,1629 ****
for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
{
GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
if (gxact->valid &&
!gxact->ondisk &&
--- 1623,1629 ----
for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
{
GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
! PGXACT *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno].xact;
if (gxact->valid &&
!gxact->ondisk &&
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
new file mode 100644
index e5d487d..4af233e
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
*************** typedef struct ProcArrayStruct
*** 97,103 ****
static ProcArrayStruct *procArray;
static PGPROC *allProcs;
! static PGXACT *allPgXact;
/*
* Bookkeeping for tracking emulated transactions in recovery
--- 97,103 ----
static ProcArrayStruct *procArray;
static PGPROC *allProcs;
! static PGXACTPadded *allPgXact;
/*
* Bookkeeping for tracking emulated transactions in recovery
*************** ProcArrayRemove(PGPROC *proc, Transactio
*** 350,356 ****
if (TransactionIdIsValid(latestXid))
{
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
/* Advance global latestCompletedXid while holding the lock */
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
--- 350,356 ----
if (TransactionIdIsValid(latestXid))
{
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xact.xid));
/* Advance global latestCompletedXid while holding the lock */
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
*************** ProcArrayRemove(PGPROC *proc, Transactio
*** 360,366 ****
else
{
/* Shouldn't be trying to remove a live transaction here */
! Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
}
for (index = 0; index < arrayP->numProcs; index++)
--- 360,366 ----
else
{
/* Shouldn't be trying to remove a live transaction here */
! Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xact.xid));
}
for (index = 0; index < arrayP->numProcs; index++)
*************** ProcArrayRemove(PGPROC *proc, Transactio
*** 400,406 ****
void
ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
{
! PGXACT *pgxact = &allPgXact[proc->pgprocno];
if (TransactionIdIsValid(latestXid))
{
--- 400,406 ----
void
ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
{
! PGXACT *pgxact = &allPgXact[proc->pgprocno].xact;
if (TransactionIdIsValid(latestXid))
{
*************** ProcArrayEndTransaction(PGPROC *proc, Tr
*** 410,416 ****
* else is taking a snapshot. See discussion in
* src/backend/access/transam/README.
*/
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
/*
* If we can immediately acquire ProcArrayLock, we clear our own XID
--- 410,416 ----
* else is taking a snapshot. See discussion in
* src/backend/access/transam/README.
*/
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xact.xid));
/*
* If we can immediately acquire ProcArrayLock, we clear our own XID
*************** ProcArrayEndTransaction(PGPROC *proc, Tr
*** 432,438 ****
* anyone else's calculation of a snapshot. We might change their
* estimate of global xmin, but that's OK.
*/
! Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
proc->lxid = InvalidLocalTransactionId;
pgxact->xmin = InvalidTransactionId;
--- 432,438 ----
* anyone else's calculation of a snapshot. We might change their
* estimate of global xmin, but that's OK.
*/
! Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xact.xid));
proc->lxid = InvalidLocalTransactionId;
pgxact->xmin = InvalidTransactionId;
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 494,500 ****
int extraWaits = -1;
/* We should definitely have an XID to clear. */
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
/* Add ourselves to the list of processes needing a group XID clear. */
proc->procArrayGroupMember = true;
--- 494,500 ----
int extraWaits = -1;
/* We should definitely have an XID to clear. */
! Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xact.xid));
/* Add ourselves to the list of processes needing a group XID clear. */
proc->procArrayGroupMember = true;
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 560,566 ****
while (nextidx != INVALID_PGPROCNO)
{
PGPROC *proc = &allProcs[nextidx];
! PGXACT *pgxact = &allPgXact[nextidx];
ProcArrayEndTransactionInternal(proc, pgxact, proc->procArrayGroupMemberXid);
--- 560,566 ----
while (nextidx != INVALID_PGPROCNO)
{
PGPROC *proc = &allProcs[nextidx];
! PGXACT *pgxact = &allPgXact[nextidx].xact;
ProcArrayEndTransactionInternal(proc, pgxact, proc->procArrayGroupMemberXid);
*************** ProcArrayGroupClearXid(PGPROC *proc, Tra
*** 606,612 ****
void
ProcArrayClearTransaction(PGPROC *proc)
{
! PGXACT *pgxact = &allPgXact[proc->pgprocno];
/*
* We can skip locking ProcArrayLock here, because this action does not
--- 606,612 ----
void
ProcArrayClearTransaction(PGPROC *proc)
{
! PGXACT *pgxact = &allPgXact[proc->pgprocno].xact;
/*
* We can skip locking ProcArrayLock here, because this action does not
*************** TransactionIdIsInProgress(TransactionId
*** 1078,1084 ****
{
int pgprocno = arrayP->pgprocnos[i];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId pxid;
/* Ignore my own proc --- dealt with it above */
--- 1078,1084 ----
{
int pgprocno = arrayP->pgprocnos[i];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId pxid;
/* Ignore my own proc --- dealt with it above */
*************** TransactionIdIsActive(TransactionId xid)
*** 1234,1240 ****
{
int pgprocno = arrayP->pgprocnos[i];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId pxid;
/* Fetch xid just once - see GetNewTransactionId */
--- 1234,1240 ----
{
int pgprocno = arrayP->pgprocnos[i];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId pxid;
/* Fetch xid just once - see GetNewTransactionId */
*************** GetOldestXmin(Relation rel, bool ignoreV
*** 1344,1350 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
/*
* Backend is doing logical decoding which manages xmin separately,
--- 1344,1350 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
/*
* Backend is doing logical decoding which manages xmin separately,
*************** GetSnapshotData(Snapshot snapshot)
*** 1583,1589 ****
for (index = 0; index < numProcs; index++)
{
int pgprocno = pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/*
--- 1583,1589 ----
for (index = 0; index < numProcs; index++)
{
int pgprocno = pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId xid;
/*
*************** ProcArrayInstallImportedXmin(Transaction
*** 1811,1817 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/* Ignore procs running LAZY VACUUM */
--- 1811,1817 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId xid;
/* Ignore procs running LAZY VACUUM */
*************** ProcArrayInstallRestoredXmin(Transaction
*** 1878,1884 ****
/* Get lock so source xact can't end while we're doing this */
LWLockAcquire(ProcArrayLock, LW_SHARED);
! pgxact = &allPgXact[proc->pgprocno];
/*
* Be certain that the referenced PGPROC has an advertised xmin which is
--- 1878,1884 ----
/* Get lock so source xact can't end while we're doing this */
LWLockAcquire(ProcArrayLock, LW_SHARED);
! pgxact = &allPgXact[proc->pgprocno].xact;
/*
* Be certain that the referenced PGPROC has an advertised xmin which is
*************** GetRunningTransactionData(void)
*** 1989,1995 ****
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
--- 1989,1995 ----
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
*************** GetRunningTransactionData(void)
*** 2021,2027 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
int nxids;
/*
--- 2021,2027 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
int nxids;
/*
*************** GetOldestActiveTransactionId(void)
*** 2111,2117 ****
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
--- 2111,2117 ----
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
*************** GetOldestSafeDecodingTransactionId(void)
*** 2202,2208 ****
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
--- 2202,2208 ----
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
*************** GetVirtualXIDsDelayingChkpt(int *nvxids)
*** 2257,2263 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
if (pgxact->delayChkpt)
{
--- 2257,2263 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
if (pgxact->delayChkpt)
{
*************** HaveVirtualXIDsDelayingChkpt(VirtualTran
*** 2297,2303 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
VirtualTransactionId vxid;
GET_VXID_FROM_PGPROC(vxid, *proc);
--- 2297,2303 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
VirtualTransactionId vxid;
GET_VXID_FROM_PGPROC(vxid, *proc);
*************** BackendXidGetPid(TransactionId xid)
*** 2407,2413 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
if (pgxact->xid == xid)
{
--- 2407,2413 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
if (pgxact->xid == xid)
{
*************** GetCurrentVirtualXIDs(TransactionId limi
*** 2479,2485 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
if (proc == MyProc)
continue;
--- 2479,2485 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
if (proc == MyProc)
continue;
*************** GetConflictingVirtualXIDs(TransactionId
*** 2576,2582 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
/* Exclude prepared transactions */
if (proc->pid == 0)
--- 2576,2582 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
/* Exclude prepared transactions */
if (proc->pid == 0)
*************** MinimumActiveBackends(int min)
*** 2690,2696 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
/*
* Since we're not holding a lock, need to be prepared to deal with
--- 2690,2696 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
/*
* Since we're not holding a lock, need to be prepared to deal with
*************** CountOtherDBBackends(Oid databaseId, int
*** 2867,2873 ****
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno];
if (proc->databaseId != databaseId)
continue;
--- 2867,2873 ----
{
int pgprocno = arrayP->pgprocnos[index];
volatile PGPROC *proc = &allProcs[pgprocno];
! volatile PGXACT *pgxact = &allPgXact[pgprocno].xact;
if (proc->databaseId != databaseId)
continue;
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
new file mode 100644
index 44a9f2c..9a1d106
*** a/src/backend/storage/ipc/sinvaladt.c
--- b/src/backend/storage/ipc/sinvaladt.c
*************** BackendIdGetTransactionIds(int backendID
*** 418,424 ****
if (proc != NULL)
{
! PGXACT *xact = &ProcGlobal->allPgXact[proc->pgprocno];
*xid = xact->xid;
*xmin = xact->xmin;
--- 418,424 ----
if (proc != NULL)
{
! PGXACT *xact = &ProcGlobal->allPgXact[proc->pgprocno].xact;
*xid = xact->xid;
*xmin = xact->xmin;
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
new file mode 100644
index 3f3e24f..1f5528e
*** a/src/backend/storage/lmgr/deadlock.c
--- b/src/backend/storage/lmgr/deadlock.c
*************** FindLockCycleRecurseMember(PGPROC *check
*** 573,579 ****
PGPROC *leader;
proc = proclock->tag.myProc;
! pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
/* A proc never blocks itself or any other lock group member */
--- 573,579 ----
PGPROC *leader;
proc = proclock->tag.myProc;
! pgxact = &ProcGlobal->allPgXact[proc->pgprocno].xact;
leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
/* A proc never blocks itself or any other lock group member */
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
new file mode 100644
index dba3809..714b6bf
*** a/src/backend/storage/lmgr/lock.c
--- b/src/backend/storage/lmgr/lock.c
*************** GetRunningTransactionLocks(int *nlocks)
*** 3806,3812 ****
proclock->tag.myLock->tag.locktag_type == LOCKTAG_RELATION)
{
PGPROC *proc = proclock->tag.myProc;
! PGXACT *pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
LOCK *lock = proclock->tag.myLock;
TransactionId xid = pgxact->xid;
--- 3806,3812 ----
proclock->tag.myLock->tag.locktag_type == LOCKTAG_RELATION)
{
PGPROC *proc = proclock->tag.myProc;
! PGXACT *pgxact = &ProcGlobal->allPgXact[proc->pgprocno].xact;
LOCK *lock = proclock->tag.myLock;
TransactionId xid = pgxact->xid;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
new file mode 100644
index 9a758bd..a555b2a
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
*************** void
*** 160,166 ****
InitProcGlobal(void)
{
PGPROC *procs;
! PGXACT *pgxacts;
int i,
j;
bool found;
--- 160,166 ----
InitProcGlobal(void)
{
PGPROC *procs;
! PGXACTPadded *pgxacts;
int i,
j;
bool found;
*************** InitProcGlobal(void)
*** 211,218 ****
* multiprocessor system. There is one PGXACT structure for every PGPROC
* structure.
*/
! pgxacts = (PGXACT *) ShmemAlloc(TotalProcs * sizeof(PGXACT));
! MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
ProcGlobal->allPgXact = pgxacts;
for (i = 0; i < TotalProcs; i++)
--- 211,218 ----
* multiprocessor system. There is one PGXACT structure for every PGPROC
* structure.
*/
! pgxacts = (PGXACTPadded *) ShmemAlloc(TotalProcs * sizeof(PGXACTPadded));
! MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACTPadded));
ProcGlobal->allPgXact = pgxacts;
for (i = 0; i < TotalProcs; i++)
*************** InitProcess(void)
*** 339,345 ****
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
}
! MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];
/*
* Cross-check that the PGPROC is of the type we expect; if this were not
--- 339,345 ----
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
}
! MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno].xact;
/*
* Cross-check that the PGPROC is of the type we expect; if this were not
*************** InitAuxiliaryProcess(void)
*** 526,532 ****
((volatile PGPROC *) auxproc)->pid = MyProcPid;
MyProc = auxproc;
! MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno];
SpinLockRelease(ProcStructLock);
--- 526,532 ----
((volatile PGPROC *) auxproc)->pid = MyProcPid;
MyProc = auxproc;
! MyPgXact = &ProcGlobal->allPgXact[auxproc->pgprocno].xact;
SpinLockRelease(ProcStructLock);
*************** ProcSleep(LOCALLOCK *locallock, LockMeth
*** 1241,1247 ****
if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
{
PGPROC *autovac = GetBlockingAutoVacuumPgproc();
! PGXACT *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
--- 1241,1247 ----
if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
{
PGPROC *autovac = GetBlockingAutoVacuumPgproc();
! PGXACT *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno].xact;
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
new file mode 100644
index f576f05..0686426
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
*************** typedef struct PGXACT
*** 209,214 ****
--- 209,225 ----
} PGXACT;
/*
+ * Cacheline aligned PGXACT which allows us to put each PGXACT to individual
+ * cacheline. Assuming PGXACTs are under intensive write, cacheline alignment
+ * reduce cache misses during GetSnapshotData().
+ */
+ typedef union PGXACTPadded
+ {
+ PGXACT xact;
+ char pad[PG_CACHE_LINE_SIZE];
+ } PGXACTPadded;
+
+ /*
* There is one ProcGlobal struct for the whole database cluster.
*/
typedef struct PROC_HDR
*************** typedef struct PROC_HDR
*** 216,222 ****
/* Array of PGPROC structures (not including dummies for prepared txns) */
PGPROC *allProcs;
/* Array of PGXACT structures (not including dummies for prepared txns) */
! PGXACT *allPgXact;
/* Length of allProcs array */
uint32 allProcCount;
/* Head of list of free PGPROC structures */
--- 227,233 ----
/* Array of PGPROC structures (not including dummies for prepared txns) */
PGPROC *allProcs;
/* Array of PGXACT structures (not including dummies for prepared txns) */
! PGXACTPadded *allPgXact;
/* Length of allProcs array */
uint32 allProcCount;
/* Head of list of free PGPROC structures */
scalability_pgxact_align.pngimage/png; name=scalability_pgxact_align.pngDownload
�PNG
IHDR � @ �1Q� sBIT|d� pHYs ��~� IDATx���wT�����.��t�JTD{W�%��X"T�`����{K41Fb�KLb�I4�wc�
�E����������aaY,A���3��s�<�?s��$!�@ LBU�
�@ o���@
�0��@ � h�@ �� Z �@ ( ���@
�0��@ � h�@ �� Z �@ ( ���@
�0��@ � �����Y�f�� 88���+l5�:
���������k������Dddda�!��}��A�R���+���@`��+W�����������$I�$��� P��\�v
!!!�P�����4H�^����;���������p��M�LFFF�777�t:��_�N�2k���([�,�Z-�����w�����|�
6l�`�,�z��������T*���g�l��!P�To��eQ`���Z�*lmmacc��������������I�T*�]����������U�T�F����_�r�O�F�-��� [[[��W�v�z��.\�J���Q j��V�z-:5i�
64hs��m�������g���A�R�z
4����v��=�h�YYY�2e
����������������
��|��������BCCq��
����KQ�bEXZZ����'O6HWS�O���0�s�6T�O�<���>��4m�4WC>++m��Azz:v���;v )) ���W�}���X�|9/^���(����i���~��,�y�f���a���8s������={b��m�������Fe�����C��]������/:u��G��}���{��n��2d�����b��;v�k{�$I(U��,Y�p��1V�^
OO���A����W�����+W"<<}�����'q��)|��������u���)S`ii �%�333ann���>��>D���aoo�C����
��������W��1
�|�D����O�Z�
����9s������b���X�v-�j�kyoA�?>�]���f�� �[�������
*�
�;w6�������_b��YHHH��%K�a�6L�Y�~=�����#>>������'��gOYf��%4hF����8��7�-����eS��WAVV����
5n,"4l��}�����#���H�����?�e>|�~���������8p G�E___Y�W�^l��)g��Mwww�t:v�������}���c`` �Z-���8l�0>x�@�OXX�L�BWWW/^�={������|����R�
�Z-��U+��s�$lR�p��A��S�������f`` �o�n�_}��d����$�III�[\\%I��}�H�����V���%Kd���L���r��I�[�����S�N.P<����z���Z�j��i;t�����s����w��,cj���y����Osss:;;�����S���;���f��=9e�N�6�[�n��3r�$q�����;��������>����������#iee�c�����W�����I�*I�����;��������;w��LDD?������k��$�;v�N�:������;{�����o��L��'O�d��-���L+++V�^���mS��������cxx8X�V-���'��Y3ZYY����;vdzz��oDD���-Z022��$��?�,@J����c�N�
��$�>}��#G����������w�}��y�2�g�zzz�����$�k��5*��ukV�^�$���&M��A������}'NT��zN�>MI�+���w��$��_~1���;Y�^=�t:����a��LMM��������F�a������_+��h��t�;v�HGGGZXX����_|�E�z���Q�$>|Xq���?�M�6��t������+�I�$_*�J~��~+V��Z�6�v$��?P�����SLLL���%,X��������&L��A�X�xq���p���|���Q�L)�9�S���i��\�v���a���r�������Y�jU�LDD������u�2<<\!3g�ZZZ����$M�?sC_g��]Koooj�Z6k��.\0����X�lY��j&$$���+������haa���`�8qB~JJ
��}/^�:���*U��-[��/[6o���� �t:����F�<}������#�_�>-,,hoo�n�������-66���7���---������W�����"e@���������tvv���Ce����tqq�������$�=��������ez��E�k�������o�����CYf�������5k�����R�J����B;;;6������c�/�����2��/����M����x�9s��u���a���g�hoo�O>��)))LII����y��A���e8M�0��K�6p/Y�$�O�N�y�,I/]���������'OhfffP��.]J�V���,����f����������y������*����|�VVVV�?>���y��)9�r#**��$111�+W�Tt���$�...\�t)��?����S�$�����:zyyq��icXX��^�~}��9����&�����y������s�R�V���V�888p���<�<SRR�{�n�t:��7�)))���b�F���A��)us��}�����s�����q��Q��(:)OOO���p���LNNf||<���hee�I�&111���������)#�o���j��s��arr2�-[Fggg�T��������R�e
�����7l����d��1�*�J��/Z&�]�F���_'?C����tww����I���M���#/_�lR|�2�<x@WWW6��=���O9k�,:::����y��s�N+V�C���3g�������3!!����X.Y��)))\�h�Z-�-[&������w�e�f����t������}���e@���p���LMM��1c�V��rr��M��jFDD�����~�:I����4Iv������g�j���uk�3S����loo��3g2%%�?��#���2�!I��YcR<H���3�$����k��_~�%]]]y���djj*���m��
����o�>fee����l������V���{����$� i���6mZ�:N�8�����_�>O�8���(��Y�U�TQ��t:����LNN�?���5j�r��<|�0��=�.]����^�9�^�Jggg6k����������?���~#iZ9���[�N����_|�/\�����[��g����[[[3$$����<t�+U��������+2$$����LKK�����0�_E�����V[�/�V����y��}���s���
�j�20����#�;v��$I�(���'���[E8����$I�{���O``�B&<<��k���K�,����F��_���_��Uk���~���n�����W��L�\�v-%I�G��>�$�?����$q���
�-[�P�$�r����i�����i��~���}j�Z��=�d?��������kW�3��=x�`����?G�] ������y��qZYY��������F���7L�������[�n�P�$��N>O��:���S�$����4�n�F``��c���� �z��G��<~��:�N6��������+d��B#���]c�z�(I�����K.^�X�+VN<x@sss.\�P���C6n�X��2�9�8q�"SF����K�Z�I�&���L���y�$����
*P�RQ�V����'O�4^�z�����������#G�T�
:�>>>�������@��j���=g�Y&33������F�V322�d�6o�L�`���w���hcc#�zL����s�v�2�Z��|`T7I���jiee��~���\�?��#�,Y����i��Q�V�����$q��2K�.�N��e�}�]>y�D~>~�x/^��fVV��;�2e�P�$�����37&N�h��%%%Q�$���G�Q�T���]�vQ�$����nO�<a�%8e����q�X�D y�<'/[N�:EI����7nK�,��bbb(I�<��[�H���6�~�uQ��@��QC1��N�:x�� RSS�����O��V�Z
?�j�2�OV�|yX[[+��s�������x�"�
kkk�j��5$IBJJ��/((Hn�%�y�7n�������y�<�#I��0rc��
�>{{{����E�h��5f������<�(9�.���a�����r����]������q��j�*��o�Q��U�\\�<yb4�sbee�={� ##,��~���c����9utss3X���V�Z)t�I�����������/F��m���d���k�V���Sqqq
�5j(����0g��^�$ ������� 7o�������{{{X[[#../^��H������'���������������[�hZ<xP��� pqq���q��9�=���1b*T���""}��A�{�
���eb��x�� &L� ���u^�;;������O0y�d���m����O~<z��{�F@@ �9�c����w�E�6mp���<��:u*�zv��=�����������c /^>��3f�V�Z5j<�Bq��w*�
���F�.?���I��z�j ���GEE��X]-H:�}�3c����(���[�=|�k��AXX�����X�~=,X��+W����X�~=~��7�7N�{��A�;_~�%N�:��~�
iii����,3n�8t���5�F�A��
��G @�b�d��?������#�������Q�������C���������+'�i4��YSn?O�<�:u����"���l=D�-P�Bt���|��B�Z�j)��W�T ���F� ��GXX5j���'����F��U�f�xE�,��������X��OV���@�F�d���eY�F��S�1%������k������ `���<x0v����;wb����7o�K��/Q�v��m�~��5����2z�������3GGG��j\�vM����ann{{����O>�C��;���!C��������Od�W��g�����
*`��
��������C���;���?|Au\�l����E�~��`�\�|��wC�C� ��Ej�eF�%w2�qqqQ���>���P\�|_|������j��kW��`���g��5j�A��1����#&&F��Y���+�r�����?~<��)����ln��!��-h���{7�9sss�{�^�0}�t������L:tj�Z���2�[�g������e�c��E��{7/^��S���7�<�-�rR��Q�xq ��^��-�m�6����Z�B�dc�T
�w��g* 9r$"""���0����� �����)��S���H\���n@���u�������)���;��AHH �=B�>}0a�h4�;������<o������AL�2>>>�h4X�p������E�(]�4 �������Y����FVV�������J���QQQ��k6n��Q�Fa���x��w���_������l��
{����30b��m��R�F�����O�!��������`���G�dZ||<����^����...(Y�$���cp�������/���1����h�Z�Y@@ ���~�
}������M7��]�^=���)F8���q��e��W P�jU���+�����]�v�2���W7H�m���v��yV*cq-vvv�;����P�t*_�<�Z�K����7f�� GG�o{�777�����{w������Z�u�)
��#G���/o�O�j��k���X��������M�6���+RSS���Z�j�������]��/�C�)�����V�U���� xzz���"�h___���c��}
��B�
���+V���3g�����h �G�~��W�~'M����T>|QQQ�5k�K� <�uO��x�U�j�<����
<<<rM���c����N�suuEhh("##�t�R�]�����'�C���FjA���������Y�f���/>��38::b���w��/����o��m��1\���x��a�e�����?T*���P�X1|��w���A���������7q��y�>)) �o�������[�/�=y���G@@ ��y{��a�m����zP�zu�=���G��
�b�
Y�#G� ##C�������-�hooo���c����<y2.\�������-�z�/"����-[����U1���A,Q��l����D�3�vvv,S��,�_���}{���r������c���e���WS��p���<{�,��O?)�J�wp����S���%�/]��fff�:u*��;���X~��7�E���a
)))1b:�.��?�`@@��\���>}��O������Z�j1::Z�Z6++�U�Ve��5y��q=z�U�Ve�:u�2�NNN��eccc��W//^���]�e����������=�j��`S0e�n�>}x��q����G���g�����`��K���.�"���DFGG����S�4i�d�.X���-�J������Sm��I���������+|��=��#���vpp��y���������jyf^:����fff6lO�>����������/=z$�?��Y�Z5��W�g��������"=r��$�����+�������g�<����'I���OrMJJ��������Bs�?��CN�<���x�� ����*���v�����#�������3))���O�J���>���/R&L��o�>���q��$����S������F��������0` K�*%�-O�>%�|N���CCC���:�fffF���c�+�!C�0&&� \�bI�,��%%%������y����G���~cJJ������3O]�����S�tiN�<Y�`���y��yA�)��2z��QtuuU,�����F���U�H�VW_4�������K�$q����z�����^�G?����7^��������~bZZ�m�Fooo�m�V��:u*u:###y��y8p�U�TaPP�,�����+W211�'N�`xx8���;_���D���A�<y�$���X�V-�N!y�-�Y�&����E��;wf����T���6m*/"���_�4|�zp��aN�2���czz:w��E777N�0�$y��u����[�n������Y�bE����v��}8�{������y��)6l�P��uPd���`�����~�)hmm�~��)��{�����O������>��!CX�bEYF����_~�%JP������7��n����]����"((�S�NU���_?��i�����[��v�Z����l��
������W�^e�����Asss��������X��s����&��������icc��]��������#���J�V�z����h���,S�5
��+W�����b��=�*T���%�+F:T�x�U����s��l���h4tqqa������z�*���+o��h���������i��){��]`�������M����o��:��nnn�EQy�L>�j�i�������!����>_����g���ky{{s�����W<��=�v��������������;�������`�f��B�pl���m��������7o��cFFG�%oc �p����D~����Y�dI~���
���������v�^^^��-�����o���iooO[[[��]��U���og���iaaA[[[6n��iii�s��jfff,]���6�-z����>b�2ehaa!������S���4�T*���^��������m�����h�q~�w��433�S��R�V����}������[��U���9,,��5�SGR�/e�r.0`@�;<x�O?��>>>�j�,U�?��#�q����3f�l���������w��X�����j������VVVl��q��^���$�6v^^^�j�l���ba��I��#d_��]����������C���R��1((H��2� ..��[����+�������#F(���G��A�������CBBi�[�?~�n�����9;;�k��&���Hd�89�Q�F���+�� h��1�~���������>��'O�i��|e���1i�$�'�7���HH���N�M� IDAT��ME�Ra��5����+;44��'v��������I�&a����l����)2��m�R^��������]�6�>}���Wc��}�����%-����$%%��������I~�����EO�@ �:�'��,Z��FVV����y�f�h��_�R�:9|�0��i�F�a���&����z�G���1P�1��AQF��oEf
�@ �@�oP����@ ^7���@
�0��r�����_?����.��Y�~=J�.
�Z�8��m$44Tq�����R��=�p���033+�w��L�4 ~~~&���t9{�,j�����K�.�I�&���RI,�(H]}����sA������W_�F�Off&�����]����K�;wn�r�W�F��UQ�xq�t:�/_��8C�R)�R�J��h�|��7��a�+w��5����_���kx����{�Z�U�V�F�Oa,1b���������( �O&�u�bbbp���]�����Kh��9�����j����^�z��?��e��=�=z���[�x:t(���o���=�N�:���*U
��5��5k��eo��j5�����G��2
�:t*�
/^T����8v�X!i�j1��=v�������a��1��_�z�;w���-lmm���y�jQ����!xNA�m}�\�r<@�V�P�D�<�\\\0q�D�-[���8p� �Z�A���O�$���`���������~ma�N�={���������{I���m�222^jd�0�����^�z)>J���Q�zu�.]���~��xQ�������c���prrBzz:��w�}�N� �>}666X�l|||�����>����������V�X�����c��X�j|||p��]���a��%���A�:ud��������Cff&RRR��G�G���k�����Y�,--aiiYH��ZL�w/]��f���S�NX�l�����O��g�} ���B�6m�V��k�.deea���h��=>\�Q|���cZ��4l��}�����c���L;;;�;�YYY�<y2]\\�����c�*�eddp����I:���o2.\`�-haa�R�J1""�������s?�c�6l�������-6lhp�$I\�`�w�Nkkkzxx=fZ��#GX�~}ZXX������u��7H>?�*�IQ���79��o��;����mS��hAwwwZYY1,,�\�p!===ioo�����Gg�����o�e�R�hcc��m������Ln��<x��$1==�{��5H��'�EDD�l���j���������}�D���[Y�n]j�Z.\�0�c|/]������;w�~����t,_���Q���O����������-Z�G��d��%�������w��]v[�x1������'�yzz��I�����f������X�jUFEE��6$�������N>Am����w�W��]�5j�������|��w���d��k��U�V�����Q�H����c`` �Z-���8l�0>x�@����c~���������=���9j��\���
}���������V�e��5m ���eA��k��Iy������
���;u:+W��M�6��:t�|c�%��kW���*��y3%I2z2��M��R���?��$/_�Lsss~���&�#�S#""hkk[ ]�u���~c�Z�haa��U�2..�����[�.u:k���8���; a�R�haa��e�r�������3((������>|��� �����[FF'O�,�
�������'?�r�
�t��8���q3������?��6m�P������+W�T��_�$�Jj�Z�-[���/�����t�����+W������������q�m����2e
]]]Y�xq���SqRg~���E�����C�~���,Y��Bf���������I>?�S�$EGI��o��G�BB����
�����F�brr2�/_NI���uk�9��������$I���W�^���;y����������e�H�YYY�\�2k������3::���5���������O���O\�~=���x��9����x���}��,#I]\\�t�R�?�����$I��{w���z�*������X:t��*Ub���I>?6=**��$��_�����h^dee���ctvv�7�|cT688�trrb�2e��/���^�z�������LHH�/��B�V���[�W�^LHH���[iaa����re��[�n�����#G����=z�2'N48v4����S9��_���������������7�������X�T)�?>���;�r��q��-�p�/_�\ :00���ogJJ
{��M����7����[�l��K���s��i@�?^��.]�����tww�e�v��H������7�V�!���T�Tl��!:����j�����F?0*V�������3--�������bS���+�e��?����l��-��������=<<�v�Z^�p�iii\�b����f��������T��"�C����3��&&&r��������X����K��Uy���9s�m�������G�����L^�v�%K�����y��u�����]c�:u��{w��fee188��5����������S���i�Wz��=���?/]����(���s��eKZYY�:dRZ����{���j���[�l������I��3g%I���WMz�$I\�f�|���u��&�J��R�
����s���v���T�4h�={�0>>����c��5e��]������O���\�f
����b�
Y&))�����7o���j����
���gO:;;s��5<�<�=�������v�F��\�2>��g��K�.�����[�q3���������_���T�3�j�ZncL)�>d�r�X�jU����iii��c��fff��_~�$I<q��_�.�?��e�+V���9�����?���^�F7l��vvv6l�c�/^\!�_�����t�����
*��o�4���m�������MII�$I���&L`���
�,Y�$�M�f�o#��~�4l���+WV��R�J
���@>��s#C�R111Q!3y�d�$w��II����,?�y�&-,,��9�������b4D�$<X!������G���q�X�dI��111�$� ��������������F��Z�6��}���������[��f��tvv��k������]\\����;trrR�����������s���Y�g���,Q��|��4I�^���$)d<x@�N����+�###igg�g���P�����h�����~�e�_�NI��c���W_}�2e�(�.?�����n��q�������������#�9Z�V�iI�x��i����c#!9���5��������oS�$���$����,�����*�����$������>�Z-�.]���V�Z�hI��g�����;����?�M)��|�>}�B.g��w�^j�Z����
���{���y�������qc������+LMM5z��1���]�R��Q�$��[�7o��S����������~*������3g�(��3f��$I�V���������++~�2}����e����S�$��O?�DI��n�d��A��y���j9~�xj4��1���)I7n����]�vQ�$����nO�<a�%8e�E���?��4g�Y&33����\�x�N~er����j����?s�7g�'g{^�^=v��E!3w�\ZXX�md��
�� g���������<{�,�z`�`R~�n�2e~-��>%I��
H����c��u
��^���������K�I��psuuE�J�����O�8��Z�*�������>CJJ
���sptt�������#��-kT���4���~~~������`qDPP�����
7n��3���8��UK1��R�J�����s����6668s�N�<�y��a���X�|�Q?���G��-Q�|y�n���m���Oek��U���u�d����
�]\\P�lY��L�i�'��%J�����{n������G����"~�!������o�_�F�~w������b���q���222������{c��5�����5j���w ����-Z�~����{7���p��u4n���z��k�y������C�F�0y�d�>}�@&���:���666��� ���+�e���7o����:t�"?[�n
I�������T<y�D1o ���[�9��k�������������������O��������k��KO�2��wo�={�����M��r�D����1zi��|��������$��kW��Q p��
4o�AAA��O�����yR�\9�9s���ppp0���3�3g�`��]077G�r}o~d/�... ��c�n�r�����?�AAAprr���5���[�~�g��h��-�M��i���j��&���?��y�\������������4
j�����8����'7�JgggY��2y��I���������s���A�[�
���c�����/`�O��.e�X�b����%K���������6��>����Eo9�H����}���{���t:����[a��cm��
����`��,Yfff�W��>}���h4�5���/Ri$I����P������c�h�;���7d��k�0$�/N���N��\����r���y�R��(?#��2�a��)S������Q�9����G^z�,��qssCBB����={�`���9r$�;�\�k����s�����A��5��qc�����=�������R�eM���<7nBBB�m�6���3f���#0u��<���<|���7G�
�r�J����$�T�<�����@�F��rwwGBB�"����,9���S������'��L��e200iii��s'������c���8z�h�v[�j�C��i��m�[��Q���������pss��]�������Y3�)S6lP,P.W�����+W��F��������������K�.�����k���}�
��=|}����/w�g�����9s��J�*����W_}��[�*���>N�:�Z�����������,��h���K&{-H�|������nh�����.e����(_�������g���Wwc�n�%v��v�����z� IN9�LQE�@���+?==��+��� ��7o*Fun������<�q��m���c��Qh����+ss�|GUM! G�Qt�111�������gff$�q��}$&&�_�VVV������e_���_8����q���������7��
��� h�Z����:�P�m�����������z��F�A�-0s�L�={>��?���|�F���_a��9h��!T*7n�}��a��=h��I�����|!]s������X�~=&O�����7>>�n�������A�-[��W��...(Y�$r�Osss���B�����G����#G��������D���x�e�z���{�.=zd��>��cii����c���8q����q���<��-[��������z�e���'�[jj*����
*`��M����ss�<
S~1���G�H����h��z�����@��� ))��\������;w��������?�~�*U ��o��y@@ n�����x����'8~��+�/�S�Z�|�d�j����0;�69�v' ���S�8p :�N6LM� ����;��9c�d�1�Tr��u�����;�y��m��t�\�2 �^�zHKKS�&����|�2���W`�&��+&����s���E�>}��_?��5�j���p��I��u#F�@��M������o����F� �Z�;{����prr�������#�eaa�B������s�"44c����;w0p�@��_?����L�8
4���7222p����5�������)�����c��I�$ �{�6)~����i��1>|� &�w��8u�,X���$�����[�.t:���0f��3�$�I�&x����=���h|�����f�������Q�0z�h���b��)�,�0$Q�zu���a������P�|�<�xxx�t��������3<}$��[�������7�����-[������� <x�#F�����������m�����g����077GDD�
�.`��Q&���OG��}aoo��m���������m-ZKKK|���7n\\\P�L,[�����O�� IF����g���c�����
�u�����[���.4n�M�6E��1k�,T�Xw����������_|wwwB��a��uP�������er��i<x���+�������8q"J�,)��;wNno���������*�
����7o�[�n���(]�4>|�����[j��{��]I\�x#G���������A�r��z�j���nnnX�j�?��%k��5��a���P�BL�>@��5�iJy������8�?F�Z���_���#4h�4i�5j�[�n�?>lll0u�T<}����/��e�I�&���>� �f�B��m1k�,��������}�6:w�OOO�T*l���;w���9lmm
�;z�h�����9s&:t����hL�<�|����f~}����1r���K�)/�)�nxx8����~��a���HMM�� 0h� ��h��)�T�"�&YYY����P�vm��-E��7���In���6m����|��<�����L��5�����F����#��������m��7oN�V��%K���[D��~y��r��q����������e���X�M��=z�
4�������X����F�J��"��C����W��Z�j\�`�����s��%6j��NNN�h4���d������j�]��n�������|�����"���-���W�[��Y�|9}||haa���[�����J�R,P����}{0������ j�Z����V�Z\�hQ�q��w/U*U��c�n�JZXX�^�z��};U*�ban~�/���i���C{{{�t:V�X���/�S=�J�Rl���{�Q�R,��Y�m�Fj4�6vfff
�.]R�''�?f�n���"�����kW^�|9�w��ua��
����V�e�*U��~E+��7of������hcc��� N�:U~���#0���������8z��-"433���;���j���XlI�_H��u5j�����h����V�Zq���F���o�e��UiccC+++��Q�����I�|Q�l��Z�j����Z���K����e@�e�J�2�B1���?������]]]iffF{{{6j���-R,.������k��g�*��$I�6�$�:z��A��9B�J%����7;w�L:88���?�������M��"@��?_���-[�n��Fw���������������:t����������b��'O�I��V�>-�2I>���g��ttt�V�����b���Y�����b���}��I��bdd��>���s��q�n-d�uf��ir���.�L�w�=�:u�P������c��1��z�*;u�Dkkk����k��F�$�-?�@ ����������R��o&b�@ ����[��W/a<o bZ ������o=v�X�5�_�H�_`���m��#I����/k$>�������������>��
����;�s�N��_vA�@�6"h�@ �� �9��@ A�@ �@P �-�@ a@�@ @��@ A�@ �@P �-�@ a@�@ �P
��O��o��������
�T��m����w���r������7����gO�<A�>}`kk�%J`��9����@ ��hS���g�P�T)8p ������S��sg\�x�n�B��1}�t��s��UC�.]d��&MBjj*.^���{�b��Y��}; ���[x����u��@ ���w�w`` &N��[�na��U8t� ����pttDtt4��)�\�M�6 L�0���X�n/^\(~�@ E�7j��������
* ..����3��Y IDATN���K#..w����+W�+U����8 (4��@ ���c@gdd $$���(S�<x ����-�����_��� ���_(~�@ Eua+ YYY����Z-��� �����{�r������5����{GGG�3 ���.���$�SC ����
���(�h����/n����7�X�b ��� ����r<@jj*`oo�%J ::Z~�
*����&������W�� .���yYT/��E��/Q�txx8��/����\v���bcc�i�&<~�S�LA`` ��) ���'�M���w�"!!K�.Ehh( �}����WP4���*l���E��E�����B5�����x�b��������������u������7b���(^�8��������~'O����K������1b�7o prr*��@ �����]QA�����E����C�)l5� ��E��E��E����S�S8�7�����VA��yYtyYty)x#�����W�@ ���#����u�����b��A�$q�K��+q��@ o(��.��[�a��a��5x��Q�o;#�7�z����Y�a�� #��o���VA��yYty)xt!0v�Xl��u���F�)luo�u�����1n���VG A����$�=�X�bx���0�Fy��),,,���Y���@�/�l���0�_�
��� ^QV�@���_����@��A��,:��,:����Z �@ ( b
�k� S86���O{�������������0�6m�-[�����V�P�/�&����R�%F�� �vs���6_9O_-�vs���+*<}���U�@P��Z-�����}<�j�����'88aaa7n\\\`oo�q���$�L�WWW8;;+�^����P�fM������ m��Arr�"�3f�t���j�pvvF��-���c�\�&L@zz:T*T*�L� x��&M�XXX�B�
X�x�"\�J�o����u���z��er\E1��� ��� �R�6�.l�i����^Fz��<e>��b����x���
6 <<������o_�>}+V��C��� 44���C��-���SL�0�����{�0a����;������6m���3g����C`` n������ �v����D�]�'N� XYY ��������������V���OY���'c��)�>}:���^A� �@ ��#�@�&^d���]~Y^d�spp0����S�N�n*T@�b�#��Y�f���/������������v���3g-Z���8����s���NKK���/���Q�L�}��)����p��i �G�����%K�(�o���d�@ x��/�Yb
���s�_�}�$ ���
7WWWT�T������ ���ht��>>>������'