break_socketblocking_on_termination_v1.patch
text/x-patch
Filename: break_socketblocking_on_termination_v1.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/libpq/be-secure.c | 52 | 0 |
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 59204cf..f01c140 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -76,6 +76,7 @@
#include "libpq/libpq.h"
#include "tcop/tcopprot.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
@@ -323,6 +324,41 @@ rloop:
}
/*
+ * Although we basically should try to send all data staying in our send
+ * buffer, we also should consider the possibility that hanging of clients or
+ * network cutoff has compelled send(2) to be blokced. We need to be allowed
+ * to exit from send() if such blocking states last for a while during process
+ * termination. Returns true if send blocking is detected.
+ *
+ * The worse side of this would be that extra-slow receiver (specifically
+ * under one packet per second) might fail to recive the result to the end,
+ * but pg_terminate_backend() is such a thing.
+ */
+static bool
+is_write_blocked(int fd)
+{
+#ifndef WIN32
+ fd_set wfds;
+ struct timeval tv;
+ int ret;
+ int save_errno = errno;
+
+ FD_ZERO(&wfds);
+ FD_SET(fd, &wfds);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ ret = select(fd + 1, NULL, &wfds, NULL, &tv);
+
+ /* The error of select here is safely ignorable. */
+ errno = save_errno;
+
+ return ret <= 0 ? true : false;
+#else
+ return false;
+#endif
+}
+
+/*
* Write data to a secure connection.
*/
ssize_t
@@ -457,6 +493,14 @@ wloop:
#endif
n = send(port->sock, ptr, len, 0);
+ /*
+ * Check for interrupt if the socket was blocked during process is
+ * being terminated.
+ */
+ if (ProcDiePending && is_write_blocked(port->sock))
+ CHECK_FOR_INTERRUPTS();
+
+
return n;
}
@@ -515,6 +559,14 @@ my_sock_write(BIO *h, const char *buf, int size)
res = send(h->num, buf, size, 0);
BIO_clear_retry_flags(h);
+
+ /*
+ * Check for interrupt if the socket was blocked during process is being
+ * terminated.
+ */
+ if (ProcDiePending && is_write_blocked(h->num))
+ CHECK_FOR_INTERRUPTS();
+
if (res <= 0)
{
if (errno == EINTR)