diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | cmake/systemd.cmake | 1 | ||||
-rw-r--r-- | config.h.cmake | 1 | ||||
-rwxr-xr-x | debian/rules | 2 | ||||
-rw-r--r-- | include/my_service_manager.h | 8 | ||||
-rw-r--r-- | include/mysql/psi/mysql_socket.h | 49 | ||||
-rw-r--r-- | sql/mysqld.cc | 157 | ||||
-rw-r--r-- | support-files/CMakeLists.txt | 19 | ||||
-rw-r--r-- | support-files/mariadb-extra.socket.in | 20 | ||||
-rw-r--r-- | support-files/mariadb-extra@.socket.in | 20 | ||||
-rw-r--r-- | support-files/mariadb.socket.in | 24 | ||||
-rw-r--r-- | support-files/mariadb@.socket.in | 23 |
12 files changed, 321 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore index 9eb935f127c..4fee2deaea5 100644 --- a/.gitignore +++ b/.gitignore @@ -241,7 +241,11 @@ support-files/config.small.ini support-files/mariadb.pc support-files/mariadb.pp support-files/mariadb.service +support-files/mariadb.socket +support-files/mariadb-extra.socket support-files/mariadb@.service +support-files/mariadb@.socket +support-files/mariadb-extra@.socket support-files/my-huge.cnf support-files/my-innodb-heavy-4G.cnf support-files/my-large.cnf diff --git a/cmake/systemd.cmake b/cmake/systemd.cmake index 84d0cba94d9..c223716faeb 100644 --- a/cmake/systemd.cmake +++ b/cmake/systemd.cmake @@ -37,6 +37,7 @@ MACRO(CHECK_SYSTEMD) ENDIF() SET(CMAKE_REQUIRED_LIBRARIES ${LIBSYSTEMD}) CHECK_LIBRARY_EXISTS(systemd sd_listen_fds "" HAVE_SYSTEMD_SD_LISTEN_FDS) + CHECK_LIBRARY_EXISTS(systemd sd_listen_fds_with_names "" HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES) CHECK_INCLUDE_FILES(systemd/sd-daemon.h HAVE_SYSTEMD_SD_DAEMON_H) CHECK_FUNCTION_EXISTS(sd_notify HAVE_SYSTEMD_SD_NOTIFY) CHECK_FUNCTION_EXISTS(sd_notifyf HAVE_SYSTEMD_SD_NOTIFYF) diff --git a/config.h.cmake b/config.h.cmake index 2af94f96d9a..698ea65efd5 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -103,6 +103,7 @@ /* Libraries */ #cmakedefine HAVE_LIBWRAP 1 #cmakedefine HAVE_SYSTEMD 1 +#cmakedefine HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES 1 /* Does "struct timespec" have a "sec" and "nsec" field? */ #cmakedefine HAVE_TIMESPEC_TS_SEC 1 diff --git a/debian/rules b/debian/rules index a8bd26d43df..758831fcdf6 100755 --- a/debian/rules +++ b/debian/rules @@ -190,7 +190,7 @@ override_dh_systemd_enable: dh_systemd_enable --name=mariadb dh_systemd_enable --no-enable --name=mariadb@ -# Start mysql at sequence number 19 before 20 where apache, proftpd etc gets +# Start MariaDB at sequence number 19 before 20 where apache, proftpd etc gets # started which might depend on a running database server. override_dh_installinit-arch: dh_installinit --name=mariadb --no-start -- defaults 19 21 diff --git a/include/my_service_manager.h b/include/my_service_manager.h index 95b5235e755..3eff1253f20 100644 --- a/include/my_service_manager.h +++ b/include/my_service_manager.h @@ -31,8 +31,16 @@ /** INTERVAL in seconds followed by printf style status */ #define service_manager_extend_timeout(INTERVAL, FMTSTR, ...) \ sd_notifyf(0, "STATUS=" FMTSTR "\nEXTEND_TIMEOUT_USEC=%u\n", ##__VA_ARGS__, INTERVAL * 1000000) +/* sd_listen_fds_with_names added v227 however RHEL/Centos7 has v219, fallback to sd_listen_fds */ +#ifndef HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES +#define sd_listen_fds_with_names(FD, NAMES) sd_listen_fds(FD) +#endif #else +#define sd_listen_fds_with_names(FD, NAMES) (0) +#define sd_is_socket_unix(FD, TYPE, LISTENING, PATH, SIZE) (0) +#define sd_is_socket_inet(FD, FAMILY, TYPE, LISTENING, PORT) (0) +#define SD_LISTEN_FDS_START (0) #define sd_notify(X, Y) #define sd_notifyf(E, F, ...) #define service_manager_extend_timeout(I, FMTSTR, ...) diff --git a/include/mysql/psi/mysql_socket.h b/include/mysql/psi/mysql_socket.h index 59489fabe25..d70e1c8fc5a 100644 --- a/include/mysql/psi/mysql_socket.h +++ b/include/mysql/psi/mysql_socket.h @@ -305,6 +305,22 @@ inline_mysql_socket_set_state(MYSQL_SOCKET socket, enum PSI_socket_state state) #endif /* HAVE_PSI_SOCKET_INTERFACE */ /** + @def mysql_socket_fd(K, F) + Create a socket. + @c mysql_socket_fd is a replacement for @c socket. + @param K PSI_socket_key for this instrumented socket + @param F File descriptor +*/ + +#ifdef HAVE_PSI_SOCKET_INTERFACE + #define mysql_socket_fd(K, F) \ + inline_mysql_socket_fd(K, F) +#else + #define mysql_socket_fd(K, F) \ + inline_mysql_socket_fd(F) +#endif + +/** @def mysql_socket_socket(K, D, T, P) Create a socket. @c mysql_socket_socket is a replacement for @c socket. @@ -578,6 +594,39 @@ static inline void inline_mysql_socket_register( } #endif +/** mysql_socket_fd */ + +static inline MYSQL_SOCKET +inline_mysql_socket_fd +( +#ifdef HAVE_PSI_SOCKET_INTERFACE + PSI_socket_key key, +#endif + int fd) +{ + MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; + mysql_socket.fd= fd; + + DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); +#ifdef HAVE_PSI_SOCKET_INTERFACE + mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) + (key, (const my_socket*)&mysql_socket.fd, NULL, 0); +#endif + /** + Currently systemd socket activation is the user of this + function. Its API (man sd_listen_fds) says FD_CLOSE_EXEC + is already called. If there becomes another user, we + can call it again without detriment. + + If needed later: + #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC); + #endif + */ + + return mysql_socket; +} + /** mysql_socket_socket */ static inline MYSQL_SOCKET diff --git a/sql/mysqld.cc b/sql/mysqld.cc index adb6ff82662..7a1d56e7ff9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1346,6 +1346,9 @@ struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD() Dynamic_array<MYSQL_SOCKET> listen_sockets(PSI_INSTRUMENT_MEM, 0); bool unix_sock_is_online= false; +static int systemd_sock_activation; /* systemd socket activation */ + + /** Error reporter that buffer log messages. @param level log message level @@ -1690,8 +1693,10 @@ static void close_connections(void) { MYSQL_SOCKET *sock= listen_sockets.get_pos(i); (void) mysql_socket_close(*sock); - if (sock->is_unix_domain_socket) + if (sock->is_unix_domain_socket && !systemd_sock_activation) + { (void) unlink(mysqld_unix_port); + } } listen_sockets.free_memory(); mysql_mutex_unlock(&LOCK_start_thread); @@ -2342,6 +2347,144 @@ static void activate_tcp_port(uint port, DBUG_VOID_RETURN; } + +/** + Activate usage of a systemd activated sockets + i.e started by mariadb.socket +*/ + +static void use_systemd_activated_sockets() +{ +#ifndef __linux__ + return; +#else + char **names = NULL; + int sd_sockets; + DBUG_ENTER("use_systemd_activated_sockets"); + + sd_sockets= sd_listen_fds_with_names(0, &names); + + if (!sd_sockets) + DBUG_VOID_RETURN; + + DBUG_PRINT("general",("Systemd listen_fds is %d", sd_sockets)); + while (sd_sockets--) + { + MYSQL_SOCKET sock; + int stype= 0, accepting= 0, getnameinfo_err; + socklen_t l; + union + { + struct sockaddr sa; + struct sockaddr_storage storage; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + } addr; + SOCKET_SIZE_TYPE addrlen= sizeof(addr); + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + int fd= SD_LISTEN_FDS_START + sd_sockets; + + if (getsockname(fd, &addr.sa, &addrlen)) + { + sql_print_error("Unable to getsockname on systemd socket activation socket %d," + " errno %d", fd, errno); + goto err; + } + + l= sizeof(stype); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &stype, &l) < 0) + { + sql_print_error("Unable to getsockopt(SOL_SOCKET, SO_TYPE) on" + " systemd socket activation socket %d," + " errno %d", fd, errno); + goto err; + } + + if (stype != SOCK_STREAM) + { + sql_print_error("Unknown systemd socket activation socket %d," + " not of type SOCK_STREAM - type %d", fd, stype); + goto err; + } + + l= sizeof(accepting); + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) + { + sql_print_error("Unable to getsockopt(SOL_SOCKET, SO_ACCEPTCONN) on" + " systemd socket activation socket %d," + " errno %d", fd, errno); + goto err; + } + + if (!accepting) + { + sql_print_error("Unknown systemd socket activation socket %d," + " is not listening", fd); + goto err; + } + + switch (addr.sa.sa_family) + { + case AF_INET: + sock= mysql_socket_fd(key_socket_tcpip, fd); + sock.is_unix_domain_socket= 0; + mysqld_port= ntohs(addr.in.sin_port); + break; + case AF_INET6: + sock= mysql_socket_fd(key_socket_tcpip, fd); + sock.is_unix_domain_socket= 0; + mysqld_port= ntohs(addr.in6.sin6_port); + break; + case AF_UNIX: + sock= mysql_socket_fd(key_socket_unix, fd); + sock.is_unix_domain_socket= 1; + break; + default: + sql_print_error("Unknown systemd socket activation socket %d," + " not UNIX or INET socket", fd); + goto err; + } + + getnameinfo_err= getnameinfo(&addr.sa, addrlen, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); + if (getnameinfo_err) + sql_print_warning("getnameinfo() on systemd socket activation socket %d" + " failed with error %d", fd, getnameinfo_err); + else + { + /* + Handle abstract sockets and present them in @ form. + We don't just use sbuf because of https://sourceware.org/bugzilla/show_bug.cgi?id=27634. + */ + if (sbuf[0] == '\0') + addr.un.sun_path[0] = '@'; + sql_print_information("Using systemd activated socket %s port %s", hbuf, + sbuf[0] == '\0' ? addr.un.sun_path : sbuf); + } + + /* + We check names!=NULL here because sd_listen_fds_with_names maybe + just sd_listen_fds on older pre v227 systemd + */ + sock.is_extra_port= names && strcmp(names[sd_sockets], "extra") == 0; + mysql_socket_set_thread_owner(sock); + listen_sockets.push(sock); + } + systemd_sock_activation= 1; + free(names); + + DBUG_VOID_RETURN; + +err: + free(names); + unireg_abort(1); + DBUG_VOID_RETURN; +#endif /* __linux__ */ +} + + static void network_init(void) { #ifdef HAVE_SYS_UN_H @@ -2350,6 +2493,8 @@ static void network_init(void) #endif DBUG_ENTER("network_init"); + use_systemd_activated_sockets(); + if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0)) unireg_abort(1); /* purecov: inspected */ @@ -2366,7 +2511,7 @@ static void network_init(void) if (!opt_disable_networking) DBUG_ASSERT(report_port != 0); #endif - if (!opt_disable_networking && !opt_bootstrap) + if (!opt_disable_networking && !opt_bootstrap && !systemd_sock_activation) { if (mysqld_port) activate_tcp_port(mysqld_port, &listen_sockets, @@ -2380,7 +2525,7 @@ static void network_init(void) /* ** Create the UNIX socket */ - if (mysqld_unix_port[0] && !opt_bootstrap) + if (mysqld_unix_port[0] && !opt_bootstrap && systemd_sock_activation==0) { MYSQL_SOCKET unix_sock= MYSQL_INVALID_SOCKET; size_t port_len; @@ -5589,7 +5734,8 @@ int mysqld_main(int argc, char **argv) if (IS_SYSVAR_AUTOSIZE(&server_version_ptr)) sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, server_version, - (unix_sock_is_online ? mysqld_unix_port : (char*) ""), + (systemd_sock_activation ? "Systemd socket activated ports" : + (unix_sock_is_online ? mysqld_unix_port : (char*) "")), mysqld_port, MYSQL_COMPILATION_COMMENT); else { @@ -5601,7 +5747,8 @@ int mysqld_main(int argc, char **argv) sql_print_information(ER_DEFAULT(ER_STARTUP), my_progname, real_server_version, - (unix_sock_is_online ? mysqld_unix_port : (char*) ""), + (systemd_sock_activation ? "Systemd socket activated ports" : + (unix_sock_is_online ? mysqld_unix_port : (char*) "")), mysqld_port, MYSQL_COMPILATION_COMMENT); } diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 338ae90cd42..851f0394f4a 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -120,6 +120,10 @@ IF(UNIX AND NOT WITHOUT_SERVER) IF(HAVE_SYSTEMD) CONFIGURE_FILE(mariadb.service.in ${CMAKE_CURRENT_BINARY_DIR}/mariadb.service @ONLY) + CONFIGURE_FILE(mariadb.socket.in + ${CMAKE_CURRENT_BINARY_DIR}/mariadb.socket @ONLY) + CONFIGURE_FILE(mariadb-extra.socket.in + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-extra.socket @ONLY) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -E create_symlink ./mariadb.service mysql.service COMMAND ${CMAKE_COMMAND} -E create_symlink ./mariadb.service mysqld.service @@ -136,13 +140,24 @@ IF(UNIX AND NOT WITHOUT_SERVER) IF(NOT CMAKE_VERSION VERSION_LESS 3.3.0 OR NOT RPM) CONFIGURE_FILE(mariadb@.service.in ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.service @ONLY) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.service + CONFIGURE_FILE(mariadb@.socket.in + ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.socket @ONLY) + CONFIGURE_FILE(mariadb-extra@.socket.in + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-extra@.socket @ONLY) + INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.service + ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.socket + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-extra@.socket + ${CMAKE_CURRENT_BINARY_DIR}/mysql.service + ${CMAKE_CURRENT_BINARY_DIR}/mysqld.service DESTINATION ${inst_location}/systemd COMPONENT SupportFiles) ENDIF() IF(INSTALL_SYSTEMD_UNITDIR) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mariadb.service + ${CMAKE_CURRENT_BINARY_DIR}/mariadb.socket + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-extra.socket ${CMAKE_CURRENT_BINARY_DIR}/mysql.service ${CMAKE_CURRENT_BINARY_DIR}/mysqld.service DESTINATION ${INSTALL_SYSTEMD_UNITDIR} COMPONENT Server) @@ -154,6 +169,8 @@ IF(UNIX AND NOT WITHOUT_SERVER) "${INSTALL_SYSTEMD_UNITDIR}/mariadb@bootstrap.service.d" COMPONENT Server) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.service + ${CMAKE_CURRENT_BINARY_DIR}/mariadb@.socket + ${CMAKE_CURRENT_BINARY_DIR}/mariadb-extra@.socket DESTINATION ${INSTALL_SYSTEMD_UNITDIR} COMPONENT Server) ENDIF() diff --git a/support-files/mariadb-extra.socket.in b/support-files/mariadb-extra.socket.in new file mode 100644 index 00000000000..f268a0ad2a8 --- /dev/null +++ b/support-files/mariadb-extra.socket.in @@ -0,0 +1,20 @@ + +[Unit] + +Description=MariaDB @VERSION@ database server (socket activation extra port) +Documentation=man:mariadbd(8) +Documentation=https://mariadb.com/kb/en/library/systemd/ + +[Socket] + +Service=mariadb.service + +# An "extra" as a descriptor name that means treat these ListenStreams as +# the same as an extra_port. +# Ref: https://mariadb.com/kb/en/thread-pool-system-status-variables/#extra_port + +FileDescriptorName=extra + +ListenStream=@mariadb-extra +ListenStream=@MYSQL_UNIX_ADDR@-extra + diff --git a/support-files/mariadb-extra@.socket.in b/support-files/mariadb-extra@.socket.in new file mode 100644 index 00000000000..f33344f2abd --- /dev/null +++ b/support-files/mariadb-extra@.socket.in @@ -0,0 +1,20 @@ + +[Unit] + +Description=MariaDB @VERSION@ database server (socket activation extra port multi-instance %I) +Documentation=man:mariadbd(8) +Documentation=https://mariadb.com/kb/en/library/systemd/ + +[Socket] + +Service=mariadb@%i.service + +# An "extra" as a descriptor name that means treat these ListenStreams as +# the same as an extra_port. +# Ref: https://mariadb.com/kb/en/thread-pool-system-status-variables/#extra_port + +FileDescriptorName=extra + +ListenStream=@mariadb-extra-%I +ListenStream=@MYSQL_UNIX_ADDR@-extra-%I + diff --git a/support-files/mariadb.socket.in b/support-files/mariadb.socket.in new file mode 100644 index 00000000000..d99fdee0334 --- /dev/null +++ b/support-files/mariadb.socket.in @@ -0,0 +1,24 @@ + +[Unit] +Description=MariaDB @VERSION@ database server (socket activation) +Documentation=man:mariadbd(8) +Documentation=https://mariadb.com/kb/en/library/systemd/ + +[Socket] + +############################################################################## +## USERs can override +## +## +## by creating a file in /etc/systemd/system/mariadb.socket.d/MY_SPECIAL.conf +## and adding/setting the following under [Socket] will override this file's +## settings. + +SocketUser=@MYSQLD_USER@ +SocketMode=777 + +ListenStream=@mariadb +ListenStream=@MYSQL_UNIX_ADDR@ +ListenStream=@MYSQL_TCP_PORT@ + +# Backlog=150 diff --git a/support-files/mariadb@.socket.in b/support-files/mariadb@.socket.in new file mode 100644 index 00000000000..561a44443c9 --- /dev/null +++ b/support-files/mariadb@.socket.in @@ -0,0 +1,23 @@ + +[Unit] +Description=MariaDB @VERSION@ database server (socket activation multi-instance %I)) +Documentation=man:mariadbd(8) +Documentation=https://mariadb.com/kb/en/library/systemd/ + +[Socket] + +############################################################################## +## USERs can override +## +## +## by creating a file in /etc/systemd/system/mariadb.socket.d/MY_SPECIAL.conf +## and adding/setting the following under [Socket] will override this file's +## settings. + +SocketUser=@MYSQLD_USER@ +SocketMode=777 + +ListenStream=@mariadb-%I +ListenStream=@MYSQL_UNIX_ADDR@-%I + +# Backlog=150 |