From bb01996f2c91f615285eaa916984d3c136c1deb5 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Wed, 26 Feb 2020 12:43:41 +0900 Subject: [PATCH v2 2/2] Improve wait events for recovery conflict resolution --- doc/src/sgml/monitoring.sgml | 28 ++++++++++++++++ src/backend/postmaster/pgstat.c | 47 +++++++++++++++++++++++++++ src/backend/storage/ipc/standby.c | 53 ++++++++++++++++--------------- src/include/pgstat.h | 17 ++++++++++ 4 files changed, 119 insertions(+), 26 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 987580d6df..479a9000cb 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -789,6 +789,13 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser wait_event will identify the specific wait point. + + + RecoveryConflict: The server process is waiting for a + recovery conflict resolution. wait_event will identify + the specific wait point. + + @@ -1781,6 +1788,27 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser WALWrite Waiting for a write to a WAL file. + + RecoveryConflict + Snapshot + Waiting for recovery conflict resolution on a physical cleanup. + + + Tablespace + Waiting for recovery conflict resolution on dropping tablespace. + + + Lock + Waiting for recovery conflict resolution on acquiring a lock. + + + BufferPin + Waiting for recovery conflict resolution on acquiring a buffer pin. + + + Database + Waiting for recovery conflict resolution on dropping a database. + diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 462b4d7e06..5276300216 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -308,6 +308,7 @@ static const char *pgstat_get_wait_client(WaitEventClient w); static const char *pgstat_get_wait_ipc(WaitEventIPC w); static const char *pgstat_get_wait_timeout(WaitEventTimeout w); static const char *pgstat_get_wait_io(WaitEventIO w); +static const char *pgstat_get_wait_recovery_conflict(WaitEventRecoveryConflict w); static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype); static void pgstat_send(void *msg, int len); @@ -3535,6 +3536,9 @@ pgstat_get_wait_event_type(uint32 wait_event_info) case PG_WAIT_IO: event_type = "IO"; break; + case PG_WAIT_RECOVERY_CONFLICT: + event_type = "RecoveryConflict"; + break; default: event_type = "???"; break; @@ -3612,6 +3616,14 @@ pgstat_get_wait_event(uint32 wait_event_info) event_name = pgstat_get_wait_io(w); break; } + case PG_WAIT_RECOVERY_CONFLICT: + { + WaitEventRecoveryConflict w = + (WaitEventRecoveryConflict) wait_event_info; + + event_name = pgstat_get_wait_recovery_conflict(w); + break; + } default: event_name = "unknown wait event"; break; @@ -4112,6 +4124,41 @@ pgstat_get_wait_io(WaitEventIO w) return event_name; } +/* ---------- + * pgstat_get_wait_recovery_conflict() - + * + * Convert WaitEventRecoveryConflict to string. + * ---------- + */ +static const char * +pgstat_get_wait_recovery_conflict(WaitEventRecoveryConflict w) +{ + const char *event_name = "unknown wait event"; + + switch (w) + { + case WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT: + event_name = "Snapshot"; + break; + case WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE: + event_name = "Tablespace"; + break; + case WAIT_EVENT_RECOVERY_CONFLICT_LOCK: + event_name = "Lock"; + break; + case WAIT_EVENT_RECOVERY_CONFLICT_BUFFER_PIN: + event_name = "BufferPin"; + break; + case WAIT_EVENT_RECOVERY_CONFLICT_DATABASE: + event_name = "Database"; + break; + default: + event_name = "unknown wait event"; + break; + } + + return event_name; +} /* ---------- * pgstat_get_backend_current_activity() - diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 4f12f598ab..bd95598a41 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -43,7 +43,8 @@ int max_standby_streaming_delay = 30 * 1000; static HTAB *RecoveryLockLists; static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, - ProcSignalReason reason); + ProcSignalReason reason, + uint32 wait_event_info); static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason); static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts); static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks); @@ -176,8 +177,7 @@ GetStandbyLimitTime(void) } } -#define STANDBY_INITIAL_WAIT_US 1000 -static int standbyWait_us = STANDBY_INITIAL_WAIT_US; +#define STANDBY_WAIT_MS 1000 /* * Standby wait logic for ResolveRecoveryConflictWithVirtualXIDs. @@ -185,7 +185,7 @@ static int standbyWait_us = STANDBY_INITIAL_WAIT_US; * more then we return true, if we can wait some more return false. */ static bool -WaitExceedsMaxStandbyDelay(void) +WaitExceedsMaxStandbyDelay(uint32 wait_event_info) { TimestampTz ltime; @@ -199,15 +199,11 @@ WaitExceedsMaxStandbyDelay(void) /* * Sleep a bit (this is essential to avoid busy-waiting). */ - pg_usleep(standbyWait_us); - - /* - * Progressively increase the sleep times, but not to more than 1s, since - * pg_usleep isn't interruptible on some platforms. - */ - standbyWait_us *= 2; - if (standbyWait_us > 1000000) - standbyWait_us = 1000000; + WaitLatch(MyLatch, + WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT, + STANDBY_WAIT_MS, + wait_event_info); + ResetLatch(MyLatch); return false; } @@ -220,7 +216,8 @@ WaitExceedsMaxStandbyDelay(void) */ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, - ProcSignalReason reason) + ProcSignalReason reason, + uint32 wait_event_info) { /* Fast exit, to avoid a kernel call if there's no work to be done. */ if (!VirtualTransactionIdIsValid(*waitlist)) @@ -228,14 +225,11 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, while (VirtualTransactionIdIsValid(*waitlist)) { - /* reset standbyWait_us for each xact we wait for */ - standbyWait_us = STANDBY_INITIAL_WAIT_US; - /* wait until the virtual xid is gone */ while (!VirtualXactLock(*waitlist, false)) { /* Is it time to kill it? */ - if (WaitExceedsMaxStandbyDelay()) + if (WaitExceedsMaxStandbyDelay(wait_event_info)) { pid_t pid; @@ -284,7 +278,8 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node.dbNode); ResolveRecoveryConflictWithVirtualXIDs(backends, - PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); + PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, + WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT); /* Reset ps display if we changed it */ if (new_status) @@ -323,7 +318,8 @@ ResolveRecoveryConflictWithTablespace(Oid tsid) temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId, InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, - PROCSIG_RECOVERY_CONFLICT_TABLESPACE); + PROCSIG_RECOVERY_CONFLICT_TABLESPACE, + WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE); /* Reset ps display if we changed it */ if (new_status) @@ -360,7 +356,11 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) * Wait awhile for them to die so that we avoid flooding an * unresponsive backend when system is heavily loaded. */ - pg_usleep(10000); + WaitLatch(MyLatch, + WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT, + 10, + WAIT_EVENT_RECOVERY_CONFLICT_DATABASE); + ResetLatch(MyLatch); } /* Reset ps display if we changed it */ @@ -410,7 +410,8 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL); ResolveRecoveryConflictWithVirtualXIDs(backends, - PROCSIG_RECOVERY_CONFLICT_LOCK); + PROCSIG_RECOVERY_CONFLICT_LOCK, + WAIT_EVENT_RECOVERY_CONFLICT_LOCK); } else { @@ -423,10 +424,10 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) timeouts[0].type = TMPARAM_AT; timeouts[0].fin_time = ltime; enable_timeouts(timeouts, 1); - } - /* Wait to be signaled by the release of the Relation Lock */ - ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type); + /* Wait to be signaled by the release of the Relation Lock */ + ProcWaitForSignal(WAIT_EVENT_RECOVERY_CONFLICT_LOCK); + } /* * Clear any timeout requests established above. We assume here that the @@ -510,7 +511,7 @@ ResolveRecoveryConflictWithBufferPin(void) } /* Wait to be signaled by UnpinBuffer() */ - ProcWaitForSignal(PG_WAIT_BUFFER_PIN); + ProcWaitForSignal(WAIT_EVENT_RECOVERY_CONFLICT_BUFFER_PIN); /* * Clear any timeout requests established above. We assume here that the diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 7bc36c6583..b1eda8cc32 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -760,6 +760,7 @@ typedef enum BackendState #define PG_WAIT_IPC 0x08000000U #define PG_WAIT_TIMEOUT 0x09000000U #define PG_WAIT_IO 0x0A000000U +#define PG_WAIT_RECOVERY_CONFLICT 0x0B000000U /* ---------- * Wait Events - Activity @@ -948,6 +949,22 @@ typedef enum WAIT_EVENT_WAL_WRITE } WaitEventIO; +/* ---------- + * Wait Events - Recovery Conflict + * + * Use this category when a process is waiting for a recovery conflict + * resolution. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT = PG_WAIT_RECOVERY_CONFLICT, + WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE, + WAIT_EVENT_RECOVERY_CONFLICT_LOCK, + WAIT_EVENT_RECOVERY_CONFLICT_BUFFER_PIN, + WAIT_EVENT_RECOVERY_CONFLICT_DATABASE +} WaitEventRecoveryConflict; + /* ---------- * Command type for progress reporting purposes * ---------- -- 2.23.0