You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by da...@apache.org on 2024/06/11 06:18:55 UTC

(doris) branch branch-2.0 updated: [fix](third-party) enable keepalive on socket created by libevent (#36097)

This is an automated email from the ASF dual-hosted git repository.

dataroaring pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new c58146e1b06 [fix](third-party) enable keepalive on socket created by libevent (#36097)
c58146e1b06 is described below

commit c58146e1b068d5ad89544be1f9bcbaebb0b87b92
Author: Yongqiang YANG <98...@users.noreply.github.com>
AuthorDate: Tue Jun 11 14:18:48 2024 +0800

    [fix](third-party) enable keepalive on socket created by libevent (#36097)
    
    pick #35805 #36026
---
 thirdparty/download-thirdparty.sh                  |   2 +
 thirdparty/patches/libevent-1532.patch             | 188 +++++++++++++++++++++
 .../libevent-keepalive-accepted-socket.patch       |  17 ++
 3 files changed, 207 insertions(+)

diff --git a/thirdparty/download-thirdparty.sh b/thirdparty/download-thirdparty.sh
index 783c6fab007..b020ec92fb2 100755
--- a/thirdparty/download-thirdparty.sh
+++ b/thirdparty/download-thirdparty.sh
@@ -261,6 +261,8 @@ echo "Finished patching ${MYSQL_SOURCE}"
 cd "${TP_SOURCE_DIR}/${LIBEVENT_SOURCE}"
 if [[ ! -f "${PATCHED_MARK}" ]]; then
     patch -p1 <"${TP_PATCH_DIR}/libevent.patch"
+    patch -p1 <"${TP_PATCH_DIR}/libevent-1532.patch"
+    patch -p1 <"${TP_PATCH_DIR}/libevent-keepalive-accepted-socket.patch"
     touch "${PATCHED_MARK}"
 fi
 cd -
diff --git a/thirdparty/patches/libevent-1532.patch b/thirdparty/patches/libevent-1532.patch
new file mode 100644
index 00000000000..d05c99accc2
--- /dev/null
+++ b/thirdparty/patches/libevent-1532.patch
@@ -0,0 +1,188 @@
+diff --git a/evutil.c b/evutil.c
+index 9817f08..e1803de 100644
+--- a/evutil.c
++++ b/evutil.c
+@@ -2763,3 +2763,137 @@ evutil_free_globals_(void)
+ 	evutil_free_secure_rng_globals_();
+ 	evutil_free_sock_err_globals();
+ }
++
++int
++evutil_set_tcp_keepalive(evutil_socket_t fd, int on, int timeout)
++{
++	int idle;
++	int intvl;
++	int cnt;
++
++	/* Prevent compiler from complaining unused variables warnings. */
++	(void) idle;
++	(void) intvl;
++	(void) cnt;
++
++	if (timeout <= 0) 
++		return 0;
++
++	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
++		return -1;
++	if (!on) 
++		return 0;
++
++	/* Unlike Unix-like OS's, TCP keep-alive mechanism on Windows is kind of a mess, 
++	 * setting TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT on Windows could be a bit tricky.
++	 * Check out https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals,
++	 * https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options.
++	 * These three options are not available until Windows 10, version 1709 where we set them
++	 * by `setsockopt` (slightly different from Unix-like OS's pattern), while on older Windows, 
++	 * we have to use `WSAIoctl` instead.
++	 * Therefore, we skip setting those three options on Windows for now.
++	 * TODO(panjf2000): enable the full TCP keep-alive mechanism on Windows when we find a feasible way to do it.
++	 */
++#ifndef _WIN32
++
++	/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual 
++	 * compared to other Unix-like systems. 
++	 * Thus, we need to specialize it on Solaris. 
++	 */
++#ifdef __sun
++	/* There are two keep-alive mechanisms on Solaris:
++	 * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours. 
++	 * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted. 
++	 * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD 
++	 * in milliseconds or TCP_KEEPIDLE in seconds.
++	 * The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds. 
++	 * The maximum is ten days, while the default is two hours. If you receive no response to the probe, 
++	 * you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection.
++	 * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and 
++	 * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval. 
++	 * The default is eight minutes.
++	 *
++	 * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set. 
++	 * The time between each consequent probes is set by TCP_KEEPINTVL in seconds. 
++	 * The minimum value is ten seconds. The maximum is ten days, while the default is two hours. 
++	 * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response.
++	 */
++
++	idle = timeout;
++	/* Kernel expects at least 10 seconds. */
++	if (idle < 10) 
++		idle = 10;
++	/* Kernel expects at most 10 days. */
++	if (idle > 10*24*60*60) 
++		idle = 10*24*60*60; 
++	
++	/* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris 
++	 * until version 11.4, but let's gamble here.
++	 */
++#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
++		return -1;
++	intvl = idle/3;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
++		return -1;
++	cnt = 3;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
++		return -1;
++	return 0;
++#endif
++
++	/* Fall back to the first implementation of tcp-alive mechanism for older Solaris, 
++	 * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
++	 */
++	idle *= 1000; /* kernel expects milliseconds */
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle)))
++		return -1;
++
++	/* Note that the consequent probes will not be sent at equal intervals on Solaris, 
++	 * but will be sent using the exponential backoff algorithm.
++	 */
++	intvl = idle/3;
++	cnt = 3;
++	int time_to_abort = intvl * cnt;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort)))
++		return -1;
++
++	return 0;
++#endif
++
++#ifdef TCP_KEEPIDLE
++	idle = timeout;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
++		return -1;
++#elif defined(TCP_KEEPALIVE)
++	/* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
++	idle = timeout;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle)))
++		return -1;
++#endif
++
++#ifdef TCP_KEEPINTVL
++	/* Set the interval between individual keep-alive probes as timeout / 3 
++	 * and the maximum number of keepalive probes as 3 to make it double timeout 
++	 * before aborting a dead connection. 
++	 */
++	intvl = timeout/3;
++	if (intvl == 0) 
++		intvl = 1;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
++		return -1;
++#endif
++
++#ifdef TCP_KEEPCNT
++	/* Set the maximum number of keepalive probes as 3 to collaborate with
++	 * TCP_KEEPINTVL, see the previous comment.
++	 */
++	cnt = 3;
++	if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
++		return -1;
++#endif
++
++#endif /* !_WIN32 */
++
++	return 0;
++}
+diff --git a/http.c b/http.c
+index 53951cb..1ad60f8 100644
+--- a/http.c
++++ b/http.c
+@@ -4417,7 +4417,7 @@ create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse)
+ {
+ 	evutil_socket_t fd;
+ 
+-	int on = 1, r;
++	int r;
+ 	int serrno;
+ 
+ 	/* Create listen socket */
+@@ -4428,7 +4428,8 @@ create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse)
+ 			return (-1);
+ 	}
+ 
+-	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
++	/* TODO(panjf2000): make this TCP keep-alive value configurable */
++	if (evutil_set_tcp_keepalive(fd, 1, 300) < 0)
+ 		goto out;
+ 	if (reuse) {
+ 		if (evutil_make_listen_socket_reuseable(fd) < 0)
+diff --git a/include/event2/util.h b/include/event2/util.h
+index 02aa7ba..688b641 100644
+--- a/include/event2/util.h
++++ b/include/event2/util.h
+@@ -469,6 +469,18 @@ int evutil_closesocket(evutil_socket_t sock);
+ EVENT2_EXPORT_SYMBOL
+ int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock);
+ 
++/** Do platform-specific operations to set/unset TCP keep-alive options
++ * TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT on a socket.
++ *  
++ *  @param sock The socket to be set TCP keep-alive 
++ *  @param on nonzero value to enable TCP keep-alive, 0 to disable
++ *  @param timeout The timeout in seconds with no activity until 
++ * 	   the first keepalive probe is sent
++ *  @return 0 on success, -1 on failure
++*/ 
++EVENT2_EXPORT_SYMBOL
++int evutil_set_tcp_keepalive(evutil_socket_t sock, int on, int timeout);
++
+ #ifdef _WIN32
+ /** Return the most recent socket error.  Not idempotent on all platforms. */
+ #define EVUTIL_SOCKET_ERROR() WSAGetLastError()
diff --git a/thirdparty/patches/libevent-keepalive-accepted-socket.patch b/thirdparty/patches/libevent-keepalive-accepted-socket.patch
new file mode 100644
index 00000000000..84a9d7b1ea6
--- /dev/null
+++ b/thirdparty/patches/libevent-keepalive-accepted-socket.patch
@@ -0,0 +1,17 @@
+diff --git a/http.c b/http.c
+index 1ad60f8..267fa1f 100644
+--- a/http.c
++++ b/http.c
+@@ -4265,6 +4265,12 @@ evhttp_get_request_connection(
+ 	event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
+ 		__func__, hostname, portname, EV_SOCK_ARG(fd)));
+ 
++	if (sa->sa_family != AF_UNIX) {
++		if (evutil_set_tcp_keepalive(fd, 1, 300) < 0) {
++			return (NULL);
++		}
++	}
++
+ 	/* we need a connection object to put the http request on */
+ 	if (http->bevcb != NULL) {
+ 		bev = (*http->bevcb)(http->base, http->bevcbarg);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org