From 9d8dbbf978cf681daf13f6c3bc7768709d6fa5d9 Mon Sep 17 00:00:00 2001 From: Hayato Kuroda Date: Fri, 27 Jan 2023 03:17:18 +0000 Subject: [PATCH v32 1/3] Add PQconnCheck and PQconnCheckable to libpq PQconnCheck() function allows to check the status of the socket by polling the socket. This function is currently available only on systems that support the non-standard POLLRDHUP extension to the poll system call, including Linux. PQconnCheckable() checks whether the above function is available or not. --- doc/src/sgml/libpq.sgml | 38 ++++++++++++++++++++ src/interfaces/libpq/exports.txt | 2 ++ src/interfaces/libpq/fe-misc.c | 62 ++++++++++++++++++++++++++------ src/interfaces/libpq/libpq-fe.h | 4 +++ 4 files changed, 96 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 0e7ae70c70..e5e2662996 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2679,6 +2679,44 @@ void *PQgetssl(const PGconn *conn); + + PQconnCheckPQconnCheck + + + Returns the health of the connection. + + +int PQconnCheck(PGconn *conn); + + + + + This function check the health of the connection. Unlike , + this check is performed by polling the corresponding socket. This + function is currently available only on systems that support the + non-standard POLLRDHUP extension to the poll + system call, including Linux. + returns greater than zero if the remote peer seems to be closed, returns + 0 if the socket is valid, and returns -1 + if the connection has already been closed or an error has occurred. + + + + + + PQconnCheckablePQconnCheckable + + + Returns true (1) or false (0) to indicate if the PQconnCheck function + is supported on this platform. + + +int PQconnCheckable(void); + + + + + diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index e8bcc88370..a06dea9acd 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -186,3 +186,5 @@ PQpipelineStatus 183 PQsetTraceFlags 184 PQmblenBounded 185 PQsendFlushRequest 186 +PQconnCheck 187 +PQconnCheckable 188 diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 3653a1a8a6..4311d1d21c 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -53,8 +53,8 @@ static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn); static int pqSendSome(PGconn *conn, int len); -static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, - time_t end_time); +static int pqSocketCheck(PGconn *conn, int forRead, + int forWrite, time_t end_time); static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time); /* @@ -1027,9 +1027,39 @@ pqWriteReady(PGconn *conn) return pqSocketCheck(conn, 0, 1, (time_t) 0); } +/* + * Check whether the socket peer closed connection or not. + * + * Returns >0 if remote peer seems to be closed, 0 if it is valid, + * -1 if the input connection is bad or an error occurred. + */ +int +PQconnCheck(PGconn *conn) +{ + return pqSocketCheck(conn, 0, 0, (time_t) 0); +} + +/* + * Check whether PQconnCheck() works well on this platform. + * + * Returns true (1) if this can use PQconnCheck(), otherwise false (0). + */ +int +PQconnCheckable(void) +{ +#if (defined(HAVE_POLL) && defined(POLLRDHUP)) + return true; +#else + return false; +#endif +} + /* * Checks a socket, using poll or select, for data to be read, written, - * or both. Returns >0 if one or more conditions are met, 0 if it timed + * or both. Moreover, when neither forRead nor forWrite is requested and + * timeout is disabled, try to check the health of socket. + * + * Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * * If SSL is in use, the SSL buffer is checked prior to checking the socket @@ -1076,9 +1106,13 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) /* * Check a file descriptor for read and/or write data, possibly waiting. - * If neither forRead nor forWrite are set, immediately return a timeout - * condition (without waiting). Return >0 if condition is met, 0 - * if a timeout occurred, -1 if an error or interrupt occurred. + * When neither forRead nor forWrite are set and timeout is disabled, + * + * - If the timeout is disabled, try to check the health of the socket + * - Otherwise this immediately returns 0 + * + * Return >0 if condition is met, 0 if a timeout occurred, -1 if an error + * or interrupt occurred. * * Timeout is infinite if end_time is -1. Timeout is immediate (no blocking) * if end_time is 0 (or indeed, any time before now). @@ -1088,14 +1122,23 @@ pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time) { /* We use poll(2) if available, otherwise select(2) */ #ifdef HAVE_POLL - struct pollfd input_fd; + struct pollfd input_fd = {0}; int timeout_ms; if (!forRead && !forWrite) - return 0; + { + if (!PQconnCheckable() || end_time != 0) + return 0; + + /* Check the connection health when end_time is 0 */ + Assert(PQconnCheckable() && end_time == 0); +#if defined(POLLRDHUP) + input_fd.events = POLLRDHUP; +#endif + } input_fd.fd = sock; - input_fd.events = POLLERR; + input_fd.events |= POLLERR; input_fd.revents = 0; if (forRead) @@ -1218,7 +1261,6 @@ PQenv2encoding(void) return encoding; } - #ifdef ENABLE_NLS static void diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index f3d9220496..e1bd0cd7b7 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -648,6 +648,10 @@ extern int PQdsplen(const char *s, int encoding); /* Get encoding id from environment variable PGCLIENTENCODING */ extern int PQenv2encoding(void); +/* Check whether the postgres server is still alive or not */ +extern int PQconnCheck(PGconn *conn); +extern int PQconnCheckable(void); + /* === in fe-auth.c === */ extern char *PQencryptPassword(const char *passwd, const char *user); -- 2.27.0