diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/libpq/pqcomm.c | 196 |
1 files changed, 96 insertions, 100 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index d9e49ca7028..c548d38c4df 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -171,9 +171,102 @@ WaitEventSet *FeBeWaitSet; void pq_init(void) { + Port *port = MyProcPort; int socket_pos PG_USED_FOR_ASSERTS_ONLY; int latch_pos PG_USED_FOR_ASSERTS_ONLY; + /* fill in the server (local) address */ + port->laddr.salen = sizeof(port->laddr.addr); + if (getsockname(port->sock, + (struct sockaddr *) &port->laddr.addr, + &port->laddr.salen) < 0) + { + ereport(FATAL, + (errmsg("%s() failed: %m", "getsockname"))); + } + + /* select NODELAY and KEEPALIVE options if it's a TCP connection */ + if (port->laddr.addr.ss_family != AF_UNIX) + { + int on; +#ifdef WIN32 + int oldopt; + int optlen; + int newopt; +#endif + +#ifdef TCP_NODELAY + on = 1; + if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, sizeof(on)) < 0) + { + ereport(FATAL, + (errmsg("%s(%s) failed: %m", "setsockopt", "TCP_NODELAY"))); + } +#endif + on = 1; + if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)) < 0) + { + ereport(FATAL, + (errmsg("%s(%s) failed: %m", "setsockopt", "SO_KEEPALIVE"))); + } + +#ifdef WIN32 + + /* + * This is a Win32 socket optimization. The OS send buffer should be + * large enough to send the whole Postgres send buffer in one go, or + * performance suffers. The Postgres send buffer can be enlarged if a + * very large message needs to be sent, but we won't attempt to + * enlarge the OS buffer if that happens, so somewhat arbitrarily + * ensure that the OS buffer is at least PQ_SEND_BUFFER_SIZE * 4. + * (That's 32kB with the current default). + * + * The default OS buffer size used to be 8kB in earlier Windows + * versions, but was raised to 64kB in Windows 2012. So it shouldn't + * be necessary to change it in later versions anymore. Changing it + * unnecessarily can even reduce performance, because setting + * SO_SNDBUF in the application disables the "dynamic send buffering" + * feature that was introduced in Windows 7. So before fiddling with + * SO_SNDBUF, check if the current buffer size is already large enough + * and only increase it if necessary. + * + * See https://support.microsoft.com/kb/823764/EN-US/ and + * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx + */ + optlen = sizeof(oldopt); + if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt, + &optlen) < 0) + { + ereport(FATAL, + (errmsg("%s(%s) failed: %m", "getsockopt", "SO_SNDBUF"))); + } + newopt = PQ_SEND_BUFFER_SIZE * 4; + if (oldopt < newopt) + { + if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt, + sizeof(newopt)) < 0) + { + ereport(FATAL, + (errmsg("%s(%s) failed: %m", "setsockopt", "SO_SNDBUF"))); + } + } +#endif + + /* + * Also apply the current keepalive parameters. If we fail to set a + * parameter, don't error out, because these aren't universally + * supported. (Note: you might think we need to reset the GUC + * variables to 0 in such a case, but it's not necessary because the + * show hooks for these variables report the truth anyway.) + */ + (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); + (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); + (void) pq_setkeepalivescount(tcp_keepalives_count, port); + (void) pq_settcpusertimeout(tcp_user_timeout, port); + } + /* initialize state variables */ PqSendBufferSize = PQ_SEND_BUFFER_SIZE; PqSendBuffer = MemoryContextAlloc(TopMemoryContext, PqSendBufferSize); @@ -191,7 +284,7 @@ pq_init(void) * writes. */ #ifndef WIN32 - if (!pg_set_noblock(MyProcPort->sock)) + if (!pg_set_noblock(port->sock)) ereport(FATAL, (errmsg("could not set socket to nonblocking mode: %m"))); #endif @@ -199,13 +292,13 @@ pq_init(void) #ifndef WIN32 /* Don't give the socket to any subprograms we execute. */ - if (fcntl(MyProcPort->sock, F_SETFD, FD_CLOEXEC) < 0) + if (fcntl(port->sock, F_SETFD, FD_CLOEXEC) < 0) elog(FATAL, "fcntl(F_SETFD) failed on socket: %m"); #endif FeBeWaitSet = CreateWaitEventSet(NULL, FeBeWaitSetNEvents); socket_pos = AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, - MyProcPort->sock, NULL, NULL); + port->sock, NULL, NULL); latch_pos = AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL); AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, PGINVALID_SOCKET, @@ -713,103 +806,6 @@ StreamConnection(pgsocket server_fd, Port *port) return STATUS_ERROR; } - /* fill in the server (local) address */ - port->laddr.salen = sizeof(port->laddr.addr); - if (getsockname(port->sock, - (struct sockaddr *) &port->laddr.addr, - &port->laddr.salen) < 0) - { - ereport(LOG, - (errmsg("%s() failed: %m", "getsockname"))); - return STATUS_ERROR; - } - - /* select NODELAY and KEEPALIVE options if it's a TCP connection */ - if (port->laddr.addr.ss_family != AF_UNIX) - { - int on; -#ifdef WIN32 - int oldopt; - int optlen; - int newopt; -#endif - -#ifdef TCP_NODELAY - on = 1; - if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, - (char *) &on, sizeof(on)) < 0) - { - ereport(LOG, - (errmsg("%s(%s) failed: %m", "setsockopt", "TCP_NODELAY"))); - return STATUS_ERROR; - } -#endif - on = 1; - if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof(on)) < 0) - { - ereport(LOG, - (errmsg("%s(%s) failed: %m", "setsockopt", "SO_KEEPALIVE"))); - return STATUS_ERROR; - } - -#ifdef WIN32 - - /* - * This is a Win32 socket optimization. The OS send buffer should be - * large enough to send the whole Postgres send buffer in one go, or - * performance suffers. The Postgres send buffer can be enlarged if a - * very large message needs to be sent, but we won't attempt to - * enlarge the OS buffer if that happens, so somewhat arbitrarily - * ensure that the OS buffer is at least PQ_SEND_BUFFER_SIZE * 4. - * (That's 32kB with the current default). - * - * The default OS buffer size used to be 8kB in earlier Windows - * versions, but was raised to 64kB in Windows 2012. So it shouldn't - * be necessary to change it in later versions anymore. Changing it - * unnecessarily can even reduce performance, because setting - * SO_SNDBUF in the application disables the "dynamic send buffering" - * feature that was introduced in Windows 7. So before fiddling with - * SO_SNDBUF, check if the current buffer size is already large enough - * and only increase it if necessary. - * - * See https://support.microsoft.com/kb/823764/EN-US/ and - * https://msdn.microsoft.com/en-us/library/bb736549%28v=vs.85%29.aspx - */ - optlen = sizeof(oldopt); - if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt, - &optlen) < 0) - { - ereport(LOG, - (errmsg("%s(%s) failed: %m", "getsockopt", "SO_SNDBUF"))); - return STATUS_ERROR; - } - newopt = PQ_SEND_BUFFER_SIZE * 4; - if (oldopt < newopt) - { - if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt, - sizeof(newopt)) < 0) - { - ereport(LOG, - (errmsg("%s(%s) failed: %m", "setsockopt", "SO_SNDBUF"))); - return STATUS_ERROR; - } - } -#endif - - /* - * Also apply the current keepalive parameters. If we fail to set a - * parameter, don't error out, because these aren't universally - * supported. (Note: you might think we need to reset the GUC - * variables to 0 in such a case, but it's not necessary because the - * show hooks for these variables report the truth anyway.) - */ - (void) pq_setkeepalivesidle(tcp_keepalives_idle, port); - (void) pq_setkeepalivesinterval(tcp_keepalives_interval, port); - (void) pq_setkeepalivescount(tcp_keepalives_count, port); - (void) pq_settcpusertimeout(tcp_user_timeout, port); - } - return STATUS_OK; } |