*** a/doc/src/sgml/config.sgml --- b/doc/src/sgml/config.sgml *************** *** 1963,1968 **** SET ENABLE_SEQSCAN TO OFF; --- 1963,1974 ---- allow significantly less than max_standby_delay seconds before query cancellation is possible. + + In standby mode, ever since the failover is requested, this parameter + is treated as zero, and all the conflicting queries are canceled + immediately. This is for preventing the conflict from slowing a recovery + and increasing the failover time. + *** a/doc/src/sgml/high-availability.sgml --- b/doc/src/sgml/high-availability.sgml *************** *** 1527,1532 **** if (!triggered) --- 1527,1539 ---- heavy update load. + + Note that, in standby mode, ever since the failover is requested, + max_standby_delay is treated as zero, and all the + conflicting queries are canceled immediately. This is for preventing + the conflict from slowing a recovery and increasing the failover time. + + Be sure that the primary and standby servers' clocks are kept in sync; *** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 511,516 **** static bool InRedo = false; --- 511,519 ---- /* Have we launched bgwriter during recovery? */ static bool bgwriterLaunched = false; + /* Have we found the trigger file? */ + bool standbyIsTriggered = false; + /* * Information logged when we detect a change in one of the parameters * important for Hot Standby. *************** *** 589,595 **** static void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, static void WriteControlFile(void); static void ReadControlFile(void); static char *str_time(pg_time_t tnow); - static bool CheckForStandbyTrigger(void); #ifdef WAL_DEBUG static void xlog_outrec(StringInfo buf, XLogRecord *record); --- 592,597 ---- *************** *** 9576,9582 **** emode_for_corrupt_record(int emode, XLogRecPtr RecPtr) * to shut down walreceiver, wait for it to exit, remove the trigger * file, and return true. */ ! static bool CheckForStandbyTrigger(void) { struct stat stat_buf; --- 9578,9584 ---- * to shut down walreceiver, wait for it to exit, remove the trigger * file, and return true. */ ! bool CheckForStandbyTrigger(void) { struct stat stat_buf; *************** *** 9584,9595 **** CheckForStandbyTrigger(void) --- 9586,9602 ---- if (TriggerFile == NULL) return false; + /* Quick exit if already known triggered */ + if (standbyIsTriggered) + return true; + if (stat(TriggerFile, &stat_buf) == 0) { ereport(LOG, (errmsg("trigger file found: %s", TriggerFile))); ShutdownWalRcv(); unlink(TriggerFile); + standbyIsTriggered = true; return true; } return false; *** a/src/backend/storage/ipc/standby.c --- b/src/backend/storage/ipc/standby.c *************** *** 124,133 **** static int standbyWait_us = STANDBY_INITIAL_WAIT_US; static bool WaitExceedsMaxStandbyDelay(void) { ! /* Are we past max_standby_delay? */ ! if (MaxStandbyDelay >= 0 && ! TimestampDifferenceExceeds(GetLatestXLogTime(), GetCurrentTimestamp(), ! MaxStandbyDelay)) return true; /* --- 124,141 ---- static bool WaitExceedsMaxStandbyDelay(void) { ! /* ! * Are we past max_standby_delay? ! * ! * If we've already been triggered, we cancel all the conflicting queries ! * immediately to cause the recovery to end as soon as possible. Otherwise, ! * the lock contention between a recovery and queries might increase the ! * failover time significantly. ! */ ! if (standbyIsTriggered || MaxStandbyDelay == 0 || ! (MaxStandbyDelay > 0 && ! TimestampDifferenceExceeds(GetLatestXLogTime(), GetCurrentTimestamp(), ! MaxStandbyDelay))) return true; /* *************** *** 141,147 **** WaitExceedsMaxStandbyDelay(void) --- 149,159 ---- */ standbyWait_us *= 2; if (standbyWait_us > 1000000) + { standbyWait_us = 1000000; + if (CheckForStandbyTrigger()) + return true; + } return false; } *** a/src/include/access/xlog.h --- b/src/include/access/xlog.h *************** *** 196,201 **** extern bool EnableHotStandby; --- 196,203 ---- extern int MaxStandbyDelay; extern bool log_checkpoints; + extern bool standbyIsTriggered; + /* WAL levels */ typedef enum WalLevel { *************** *** 297,302 **** extern XLogRecPtr GetInsertRecPtr(void); --- 299,305 ---- extern XLogRecPtr GetWriteRecPtr(void); extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch); extern TimeLineID GetRecoveryTargetTLI(void); + extern bool CheckForStandbyTrigger(void); extern void HandleStartupProcInterrupts(void); extern void StartupProcessMain(void);