From dc896964de1bdb2e6ad419fc53edb54360b3afb1 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 25 Feb 2020 16:58:56 +0900 Subject: [PATCH v2 1/2] Fix process title update during recovery conflicts --- src/backend/storage/ipc/standby.c | 106 +++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 3090e57fa4..4f12f598ab 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -47,6 +47,7 @@ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlis static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason); static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts); static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks); +static char *set_process_title_waiting(void); /* * Keep track of all the locks owned by a given transaction. @@ -221,16 +222,10 @@ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason) { - TimestampTz waitStart; - char *new_status; - /* Fast exit, to avoid a kernel call if there's no work to be done. */ if (!VirtualTransactionIdIsValid(*waitlist)) return; - waitStart = GetCurrentTimestamp(); - new_status = NULL; /* we haven't changed the ps display */ - while (VirtualTransactionIdIsValid(*waitlist)) { /* reset standbyWait_us for each xact we wait for */ @@ -239,25 +234,6 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, /* wait until the virtual xid is gone */ while (!VirtualXactLock(*waitlist, false)) { - /* - * Report via ps if we have been waiting for more than 500 msec - * (should that be configurable?) - */ - if (update_process_title && new_status == NULL && - TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(), - 500)) - { - const char *old_status; - int len; - - old_status = get_ps_display(&len); - new_status = (char *) palloc(len + 8 + 1); - memcpy(new_status, old_status, len); - strcpy(new_status + len, " waiting"); - set_ps_display(new_status, false); - new_status[len] = '\0'; /* truncate off " waiting" */ - } - /* Is it time to kill it? */ if (WaitExceedsMaxStandbyDelay()) { @@ -281,19 +257,13 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, /* The virtual transaction is gone now, wait for the next one */ waitlist++; } - - /* Reset ps display if we changed it */ - if (new_status) - { - set_ps_display(new_status, false); - pfree(new_status); - } } void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node) { VirtualTransactionId *backends; + char *new_status = NULL; /* * If we get passed InvalidTransactionId then we are a little surprised, @@ -307,17 +277,31 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode if (!TransactionIdIsValid(latestRemovedXid)) return; + /* Report via ps we are waiting */ + new_status = set_process_title_waiting(); + backends = GetConflictingVirtualXIDs(latestRemovedXid, node.dbNode); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); + + /* Reset ps display if we changed it */ + if (new_status) + { + set_ps_display(new_status, false); + pfree(new_status); + } } void ResolveRecoveryConflictWithTablespace(Oid tsid) { VirtualTransactionId *temp_file_users; + char *new_status = NULL; + + /* Report via ps we are waiting */ + new_status = set_process_title_waiting(); /* * Standby users may be currently using this tablespace for their @@ -340,11 +324,23 @@ ResolveRecoveryConflictWithTablespace(Oid tsid) InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, PROCSIG_RECOVERY_CONFLICT_TABLESPACE); + + /* Reset ps display if we changed it */ + if (new_status) + { + set_ps_display(new_status, false); + pfree(new_status); + } } void ResolveRecoveryConflictWithDatabase(Oid dbid) { + char *new_status = NULL; + + /* Report via ps we are waiting */ + new_status = set_process_title_waiting(); + /* * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that * only waits for transactions and completely idle sessions would block @@ -366,6 +362,13 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) */ pg_usleep(10000); } + + /* Reset ps display if we changed it */ + if (new_status) + { + set_ps_display(new_status, false); + pfree(new_status); + } } /* @@ -384,6 +387,10 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) * * Deadlocks involving the Startup process and an ordinary backend process * will be detected by the deadlock detector within the ordinary backend. + * + * Unlike other recovery conflict resolution functions, this function + * doesn't update the process title since we have already updated it at + * WaitOnLock(). */ void ResolveRecoveryConflictWithLock(LOCKTAG locktag) @@ -461,9 +468,13 @@ void ResolveRecoveryConflictWithBufferPin(void) { TimestampTz ltime; + char *new_status = NULL; Assert(InHotStandby); + /* Report via ps we are waiting */ + new_status = set_process_title_waiting(); + ltime = GetStandbyLimitTime(); if (ltime == 0) @@ -508,6 +519,13 @@ ResolveRecoveryConflictWithBufferPin(void) * individually, but that'd be slower. */ disable_all_timeouts(false); + + /* Reset ps display if we changed it */ + if (new_status) + { + set_ps_display(new_status, false); + pfree(new_status); + } } static void @@ -1094,3 +1112,27 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, nmsgs * sizeof(SharedInvalidationMessage)); XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS); } + +/* + * Append " waiting" to the process title, and return palloc'd + * original process title. + */ +static char * +set_process_title_waiting(void) +{ + const char *old_status; + char *ret_status; + int len; + + if (!update_process_title) + return NULL; + + old_status = get_ps_display(&len); + ret_status = (char *) palloc(len + 8 + 1); + memcpy(ret_status, old_status, len); + strcpy(ret_status + len, " waiting"); + set_ps_display(ret_status, false); + ret_status[len] = '\0'; /* truncate off " waiting" */ + + return ret_status; +} -- 2.23.0