From bbcf92ed6d17e2c6f4a8e8607a34534869d5edd6 Mon Sep 17 00:00:00 2001 From: "suyu.cmj" Date: Sun, 22 Aug 2021 19:16:21 +0800 Subject: [PATCH] Set max client write delay timeout for query which is supposed to be canceled on a hot standby server --- src/backend/libpq/be-secure.c | 19 +++++++++++++++++++ src/backend/utils/misc/guc.c | 11 +++++++++++ src/include/libpq/libpq.h | 1 + 3 files changed, 31 insertions(+) diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index 8ef083200a..bb5b39e527 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -36,6 +36,7 @@ #include "storage/proc.h" #include "tcop/tcopprot.h" #include "utils/memutils.h" +#include "utils/timestamp.h" char *ssl_library; char *ssl_cert_file; @@ -63,6 +64,9 @@ bool SSLPreferServerCiphers; int ssl_min_protocol_version; int ssl_max_protocol_version; +/* GUC variable: Max client write delay for a standby query which is supposed to be canceled */ +int max_standby_client_write_delay = 30 * 1000; + /* ------------------------------------------------------------ */ /* Procedures common to all secure sessions */ /* ------------------------------------------------------------ */ @@ -261,6 +265,7 @@ secure_write(Port *port, void *ptr, size_t len) { ssize_t n; int waitfor; + TimestampTz waitstart = GetCurrentTimestamp(); /* Deal with any already-pending interrupt condition. */ ProcessClientWriteInterrupt(false); @@ -287,6 +292,9 @@ retry: waitfor = WL_SOCKET_WRITEABLE; } + if (n >= 0) + waitstart = GetCurrentTimestamp(); + if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN)) { WaitEvent event; @@ -298,6 +306,17 @@ retry: WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1, WAIT_EVENT_CLIENT_WRITE); + /* + * if current query is supposed to be canceled, + * and the time delayed by a client exceeds max_standby_client_write_delay, then set + * ProcDiePending as true to handle interrupt, avoid being delayed indefinitely by a stuck client + */ + if (!ProcDiePending && + QueryCancelPending && + (max_standby_client_write_delay >= 0) && + TimestampDifferenceExceeds(waitstart, GetCurrentTimestamp(), max_standby_client_write_delay)) + ProcDiePending = true; + /* See comments in secure_read. */ if (event.events & WL_POSTMASTER_DEATH) ereport(FATAL, diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index a2e0f8de7e..69f65ae73e 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2257,6 +2257,17 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"max_standby_client_write_delay", PGC_SIGHUP, REPLICATION_STANDBY, + gettext_noop("Sets the maximum delay for query which is waiting for client write and is supposed to be canceled on a hot standby server."), + NULL, + GUC_UNIT_MS + }, + &max_standby_client_write_delay, + 30 * 1000, -1, INT_MAX, + NULL, NULL, NULL + }, + { {"recovery_min_apply_delay", PGC_SIGHUP, REPLICATION_STANDBY, gettext_noop("Sets the minimum delay for applying changes during recovery."), diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index 6c51b2f20f..1776553f43 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -121,6 +121,7 @@ extern char *SSLECDHCurve; extern bool SSLPreferServerCiphers; extern int ssl_min_protocol_version; extern int ssl_max_protocol_version; +extern int max_standby_client_write_delay; enum ssl_protocol_versions { -- 2.24.3 (Apple Git-128)