From b878ffe74a10d34d312a7be66df7a53b423aaaec Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Mon, 26 Oct 2020 01:55:31 +0300 Subject: [PATCH 3/3] Add conditional variable to wait for next MultXact offset in corner case GetMultiXactIdMembers() has a corner case, when the next multixact offset is not yet set. In this case GetMultiXactIdMembers() has to sleep till this offset is set. Currently the sleeping is implemented in naive way using pg_sleep() and retry. This commit implements sleeping with conditional variable, which provides more efficient way for waiting till the event. Discussion: https://postgr.es/m/a7f1c4e1-1015-92a4-2bd4-6736bd13d03e%40postgrespro.ru#c496c4e75fc0605094a0e1f763e6a6ec Author: Andrey Borodin Reviewed-by: Kyotaro Horiguchi, Daniel Gustafsson Reviewed-by: Anastasia Lubennikova, Alexander Korotkov --- src/backend/access/transam/multixact.c | 29 +++++++++++++++++++++++++++-- src/backend/postmaster/pgstat.c | 2 ++ src/include/pgstat.h | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 57be24c0cc1..09df91899ec 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -82,6 +82,7 @@ #include "lib/ilist.h" #include "miscadmin.h" #include "pg_trace.h" +#include "pgstat.h" #include "postmaster/autovacuum.h" #include "storage/lmgr.h" #include "storage/pmsignal.h" @@ -233,6 +234,7 @@ typedef struct MultiXactStateData /* support for members anti-wraparound measures */ MultiXactOffset offsetStopLimit; /* known if oldestOffsetKnown */ + ConditionVariable nextoff_cv; /* * Per-backend data starts here. We have two arrays stored in the area * immediately following the MultiXactStateData struct. Each is indexed by @@ -892,6 +894,14 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, /* Exchange our lock */ LWLockRelease(MultiXactOffsetSLRULock); + /* + * Let everybody know the offset of this mxid is recorded now. The waiters + * are waiting for the offset of the mxid next of the target to know the + * number of members of the target mxid, so we don't need to wait for + * members of this mxid are recorded. + */ + ConditionVariableBroadcast(&MultiXactState->nextoff_cv); + LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE); prev_pageno = -1; @@ -1389,9 +1399,23 @@ retry: if (nextMXOffset == 0) { /* Corner case 2: next multixact is still being filled in */ + + /* + * The recorder of the next mxid is just before writing the offset. + * Wait for the offset to be written. + */ + ConditionVariablePrepareToSleep(&MultiXactState->nextoff_cv); + + /* + * We don't have to recheck if multixact was filled in during + * ConditionVariablePrepareToSleep(), because we were holding + * MultiXactOffsetSLRULock. + */ LWLockRelease(MultiXactOffsetSLRULock); - CHECK_FOR_INTERRUPTS(); - pg_usleep(1000L); + + ConditionVariableSleep(&MultiXactState->nextoff_cv, + WAIT_EVENT_WAIT_NEXT_MXMEMBERS); + ConditionVariableCancelSleep(); goto retry; } @@ -1873,6 +1897,7 @@ MultiXactShmemInit(void) /* Make sure we zero out the per-backend state */ MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE); + ConditionVariableInit(&MultiXactState->nextoff_cv); } else Assert(found); diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 822f0ebc628..b99398a97e9 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -4020,6 +4020,8 @@ pgstat_get_wait_ipc(WaitEventIPC w) break; case WAIT_EVENT_XACT_GROUP_UPDATE: event_name = "XactGroupUpdate"; + case WAIT_EVENT_WAIT_NEXT_MXMEMBERS: + event_name = "MultiXactWaitNextMembers"; break; /* no default case, so that compiler will warn */ } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index a821ff4f158..75ede141ab7 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -952,6 +952,7 @@ typedef enum WAIT_EVENT_REPLICATION_SLOT_DROP, WAIT_EVENT_SAFE_SNAPSHOT, WAIT_EVENT_SYNC_REP, + WAIT_EVENT_WAIT_NEXT_MXMEMBERS, WAIT_EVENT_XACT_GROUP_UPDATE } WaitEventIPC; -- 2.14.3