From 7c3c4cc47eb0916d7aa6334df952a9c284cab2fa Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 25 Feb 2020 16:58:56 +0900 Subject: [PATCH 2/2] Fix process title update during recovery conflicts --- src/backend/storage/ipc/standby.c | 105 +++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index c85def7317..b45a83c54c 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -48,6 +48,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. @@ -218,40 +219,15 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info) { - 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)) { /* 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(wait_event_info)) { @@ -275,19 +251,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, @@ -301,18 +271,32 @@ 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, PG_WAIT_LOCK | LOCKTAG_TRANSACTION); + + /* 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 @@ -336,11 +320,23 @@ ResolveRecoveryConflictWithTablespace(Oid tsid) ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, PROCSIG_RECOVERY_CONFLICT_TABLESPACE, PG_WAIT_LOCK | LOCKTAG_TRANSACTION); + + /* 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 @@ -362,6 +358,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); + } } /* @@ -380,6 +383,9 @@ 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. */ void ResolveRecoveryConflictWithLock(LOCKTAG locktag) @@ -458,9 +464,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) @@ -505,6 +515,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 @@ -1091,3 +1108,27 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, nmsgs * sizeof(SharedInvalidationMessage)); XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS); } + +/* + * Add " 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