From 02b645796972b5b1aff0eef0ca343ef3e78528ca Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 12 Mar 2015 07:21:51 +1100 Subject: [PATCH 1/4] Add base SYSTEMD library to cmake Add systemd detection (autoenabled) and configuration option. Enable systemd for debian and ubuntu --- config.h.cmake | 1 + configure.cmake | 25 +++++++++++++++++++++++++ debian/dist/Debian/control | 4 ++-- debian/dist/Ubuntu/control | 3 ++- sql/CMakeLists.txt | 9 ++++++++- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/config.h.cmake b/config.h.cmake index 6a0527719f9cf..a269a65cddf78 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -118,6 +118,7 @@ #cmakedefine HAVE_LIBCRYPT 1 #cmakedefine HAVE_LIBMTMALLOC 1 #cmakedefine HAVE_LIBWRAP 1 +#cmakedefine HAVE_SYSTEMD 1 /* Does "struct timespec" have a "sec" and "nsec" field? */ #cmakedefine HAVE_TIMESPEC_TS_SEC 1 diff --git a/configure.cmake b/configure.cmake index 215b0dc32b4b6..98686182a6af9 100644 --- a/configure.cmake +++ b/configure.cmake @@ -161,6 +161,22 @@ IF(UNIX) SET(LIBWRAP "wrap") ENDIF() ENDIF() + + OPTION(WITH_SYSTEMD "Compile with systemd notification on ready" ON) + IF(WITH_SYSTEMD) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} systemd-daemon) + CHECK_C_SOURCE_COMPILES( + " + #include + int main() + { + sd_listen_fds(0); + }" + HAVE_SYSTEMD) + IF(HAVE_SYSTEMD) + SET(LIBSYSTEMD "systemd-daemon") + ENDIF() + ENDIF() ENDIF() # @@ -251,6 +267,9 @@ CHECK_INCLUDE_FILES (wchar.h HAVE_WCHAR_H) CHECK_INCLUDE_FILES (wctype.h HAVE_WCTYPE_H) CHECK_INCLUDE_FILES (sys/sockio.h HAVE_SYS_SOCKIO_H) CHECK_INCLUDE_FILES (sys/utsname.h HAVE_SYS_UTSNAME_H) +IF(WITH_SYSTEMD) +CHECK_INCLUDE_FILES (systemd/sd-daemon.h HAVE_SYSTEMD_SD_DAEMON_H) +ENDIF() IF(BFD_H_EXISTS) IF(NOT_FOR_DISTRIBUTION) @@ -458,6 +477,12 @@ IF(HAVE_SYS_EVENT_H) CHECK_FUNCTION_EXISTS (kqueue HAVE_KQUEUE) ENDIF() +IF(WITH_SYSTEMD) +CHECK_FUNCTION_EXISTS (sd_listen_fds HAVE_SYSTEMD_SD_DAEMON_H) +CHECK_FUNCTION_EXISTS (sd_notify HAVE_SYSTEMD_SD_DAEMON_H) +CHECK_FUNCTION_EXISTS (sd_notifyf HAVE_SYSTEMD_SD_DAEMON_H) +ENDIF() + #-------------------------------------------------------------------- # Support for WL#2373 (Use cycle counter for timing) #-------------------------------------------------------------------- diff --git a/debian/dist/Debian/control b/debian/dist/Debian/control index ffede25ccc400..45a35fe0ddd57 100644 --- a/debian/dist/Debian/control +++ b/debian/dist/Debian/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: MariaDB Developers XSBC-Original-Maintainer: Maria Developers Uploaders: MariaDB Developers -Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper, ${CMAKE_DEP}libaio-dev, libjemalloc-dev (>= 3.0.0) +Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper, ${CMAKE_DEP}libaio-dev, libjemalloc-dev (>= 3.0.0), libsystemd-daemon-dev, dh-systemd Standards-Version: 3.8.3 Homepage: http://mariadb.org/ Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/10.0/files @@ -147,7 +147,7 @@ Description: MariaDB database client binaries Package: mariadb-server-core-10.0 Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version}) +Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version}), libsystemd-daemon0 Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5 Conflicts: mariadb-server-5.1 (<< 5.1.60), mariadb-server-5.2 (<< 5.2.10), diff --git a/debian/dist/Ubuntu/control b/debian/dist/Ubuntu/control index 02ace29b67bdf..65d390797d5d5 100644 --- a/debian/dist/Ubuntu/control +++ b/debian/dist/Ubuntu/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: MariaDB Developers XSBC-Original-Maintainer: Maria Developers Uploaders: MariaDB Developers -Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper, ${CMAKE_DEP}libaio-dev, libjemalloc-dev (>= 3.0.0) +Build-Depends: libtool (>= 1.4.2-7), procps | hurd, debhelper, file (>= 3.28), libncurses5-dev (>= 5.0-6), perl (>= 5.6.0), libwrap0-dev (>= 7.6-8.3), zlib1g-dev (>= 1:1.1.3-5), ${LIBREADLINE_DEV}, libssl-dev, libpam0g-dev, psmisc, po-debconf, chrpath, automake1.9, doxygen, texlive-latex-base, ghostscript | gs-gpl, dpatch, gawk, bison, lsb-release, hardening-wrapper, ${CMAKE_DEP}libaio-dev, libjemalloc-dev (>= 3.0.0), libsystemd-daemon-dev, dh-systemd Standards-Version: 3.8.2 Homepage: http://mariadb.org/ Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/10.0/files @@ -148,6 +148,7 @@ Description: MariaDB database client binaries Package: mariadb-server-core-10.0 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version}) + libsystemd-daemon0 Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5 Conflicts: mysql-server-5.0, mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5, diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index fba1a68fa46ab..da965e5bbe9c3 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -120,7 +120,7 @@ DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC} ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} - ${SSL_LIBRARIES}) + ${LIBSYSTEMD} ${SSL_LIBRARIES}) IF(WIN32) SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc) @@ -180,6 +180,13 @@ IF(INTERFACE_LIBS) "${INTERFACE_LIBS}") ENDIF() +IF(WITH_SYSTEMD) +# Used for notify systemd's feature +IF(HAVE_SYSTEMD_SD_DAEMON_H) + TARGET_LINK_LIBRARIES(mysqld systemd-daemon) +ENDIF() +ENDIF() + # On Solaris, some extra effort is required in order to get dtrace probes # from static libraries DTRACE_INSTRUMENT_STATIC_LIBS(mysqld From 63d2b930abc74513bd021703ab506aa3b1dcd7b4 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 12 Mar 2015 07:26:04 +1100 Subject: [PATCH 2/4] extend psi adding mysql_socket_fd function mysql_socket_fd mirrors the functionality of mysql_socket_socket. Needed for systemd socket activation. --- include/mysql/psi/mysql_socket.h | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/include/mysql/psi/mysql_socket.h b/include/mysql/psi/mysql_socket.h index e1d56539f853c..ea44d49ea8773 100644 --- a/include/mysql/psi/mysql_socket.h +++ b/include/mysql/psi/mysql_socket.h @@ -281,6 +281,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_socket 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. @@ -542,6 +558,28 @@ 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; +#ifdef HAVE_PSI_SOCKET_INTERFACE + if (likely(mysql_socket.fd != INVALID_SOCKET)) + { + mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) + (key, (const my_socket*)&mysql_socket.fd, NULL, 0); + } +#endif + return mysql_socket; +} + /** mysql_socket_socket */ static inline MYSQL_SOCKET From ebb3153e496e1e5ec516a08559384aa949b76dff Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 12 Mar 2015 07:45:55 +1100 Subject: [PATCH 3/4] MDEV-5536 add systemd socket activation This adds systemd socket activation functionality to MariaDB where the system libraries exist for it. When started from init scripts mysqld functions the same as it does before this patch. When systemd socket activation starts mysqld, systemd does the listening and leaves these listening file descriptors open. Assisted by sd_listen_fds, the sockets are populated into arrays. Configuration options ignored by mysqld when instigated from systemd socket activation include: * bind-address * port * extra-port * socket * skip-networking * max-connections Systemd socket activation definations (e.g. support-files/mariadb.socket) provide an arbitary number of sockets for MariaDB to listen on. 10 was chosen as an arbitary number bigger than the currently supported 2 TCP ports and one unix socket for the maximium number supported. The support-files/mariadb-socket-convert script can be used to convert my.cnf files and extract the needed config files to create a mariadb.socket file. The functionalty provided by extra_port isn't supported on MariaDB under socket activation as all sockets are treated equal. support-files/mariadb.service provides a systemd service file. This replaces mysqld_safe. Inside this file there are examples on how to replace specific mysqld_safe variables. --- debian/dist/Debian/rules | 2 + debian/dist/Ubuntu/rules | 2 + sql/mysqld.cc | 266 ++++++++++++++++++++++++--- sql/share/errmsg-utf8.txt | 2 + support-files/mariadb-socket-convert | 150 +++++++++++++++ support-files/mariadb-systemd-start | 44 +++++ support-files/mariadb.service | 104 +++++++++++ support-files/mariadb.socket | 41 +++++ 8 files changed, 590 insertions(+), 21 deletions(-) create mode 100644 support-files/mariadb-socket-convert create mode 100644 support-files/mariadb-systemd-start create mode 100644 support-files/mariadb.service create mode 100644 support-files/mariadb.socket diff --git a/debian/dist/Debian/rules b/debian/dist/Debian/rules index 2122a3c815455..5dba5d1c79302 100755 --- a/debian/dist/Debian/rules +++ b/debian/dist/Debian/rules @@ -216,7 +216,9 @@ binary-indep: build install dh_installexamples -i dh_installmenu -i dh_installlogrotate -i + dh_systemd_enable -i support-files/mariadb.service support-files/mariadb.socket dh_installinit -i + dh_systemd_start -i --restart-after-upgrade mariadb.socket dh_installcron -i dh_installman -i dh_installinfo -i diff --git a/debian/dist/Ubuntu/rules b/debian/dist/Ubuntu/rules index 8d993124b56c8..6cd2a15b90ac3 100755 --- a/debian/dist/Ubuntu/rules +++ b/debian/dist/Ubuntu/rules @@ -221,7 +221,9 @@ binary-indep: build install dh_installexamples -i dh_installmenu -i dh_installlogrotate -i + dh_systemd_enable -i support-files/mariadb.service support-files/mariadb.socket dh_installinit -i + dh_systemd_start -i --restart-after-upgrade mariadb.socket dh_installcron -i dh_installman -i dh_installinfo -i diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7138027ff0a77..6b26846072090 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -105,6 +105,24 @@ #include #endif +#ifdef HAVE_SYSTEMD +#include +#include +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +#ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +#endif + struct sockaddr_storage ss; +}; +#define MAX_LISTEN_SOCKETS 10 +static int systemd_listen_cnt=0; +#else /* HAVE_SYSTEMD */ +#define MAX_LISTEN_SOCKETS 3 +#endif + #define mysqld_charset &my_charset_latin1 /* We have HAVE_valgrind below as this speeds up the shutdown of MySQL */ @@ -1840,6 +1858,9 @@ static void __cdecl kill_server(int sig_ptr) else sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */ +#ifdef HAVE_SYSTEMD + sd_notify(0, "STOPPING=1"); +#endif #ifdef HAVE_SMEM /* Send event to smem_event_connect_request for aborting @@ -2517,8 +2538,13 @@ static void network_init(void) struct sockaddr_un UNIXaddr; int arg; #endif + int systemd_n = 0; DBUG_ENTER("network_init"); +#ifdef HAVE_SYSTEMD + systemd_n = sd_listen_fds(0); + DBUG_PRINT("general",("Systemd listen_fds is %d",systemd_n)); +#endif if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0)) unireg_abort(1); /* purecov: inspected */ @@ -2532,7 +2558,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_n==0) { if (mysqld_port) base_ip_sock= activate_tcp_port(mysqld_port); @@ -2592,7 +2618,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_n==0) { DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port)); @@ -6058,6 +6084,14 @@ inline void kill_broken_server() #ifndef EMBEDDED_LIBRARY +#ifdef HAVE_SYSTEMD +static MYSQL_SOCKET systemd_sock[MAX_LISTEN_SOCKETS]; +static PSI_socket_key all_systemd_key[MAX_LISTEN_SOCKETS]; +#ifdef HAVE_PSI_SOCKET_INTERFACE +static PSI_socket_info all_systemd_sockets[MAX_LISTEN_SOCKETS+1]; +#endif +#endif + void handle_connections_sockets() { MYSQL_SOCKET sock= mysql_socket_invalid(); @@ -6071,38 +6105,198 @@ void handle_connections_sockets() int flags=0,retval; st_vio *vio_tmp; bool is_unix_sock; -#ifdef HAVE_POLL +#ifdef HAVE_SYSTEMD + int systemd_n, systemd_fd; + union sockaddr_union socketpeer; + socklen_t socketpeer_len; + char const *family; +#ifndef HAVE_POLL + int pfs_flags[MAX_LISTEN_SOCKETS]; + // systemd wants these too + MYSQL_SOCKET pfs_fds[MAX_LISTEN_SOCKETS]; // used for non-polling interfaces +#endif +#endif // HAVE_SYSTEMD int socket_count= 0; - struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock - MYSQL_SOCKET pfs_fds[3]; // for performance schema -#define setup_fds(X) \ + short fd_type[MAX_LISTEN_SOCKETS]; +#ifdef HAVE_POLL + struct pollfd fds[MAX_LISTEN_SOCKETS]; // for ip_sock, extra_ip_sock and unix_sock (could be any order for systemd) + MYSQL_SOCKET pfs_fds[MAX_LISTEN_SOCKETS]; // for performance schema +#define setup_fds(X,T) \ mysql_socket_set_thread_owner(X); \ pfs_fds[socket_count]= (X); \ fds[socket_count].fd= mysql_socket_getfd(X); \ fds[socket_count].events= POLLIN; \ + fd_type[socket_count]= T; \ socket_count++ #else -#define setup_fds(X) FD_SET(mysql_socket_getfd(X),&clientFDs) +#ifdef HAVE_SYSTEMD +#define setup_fds(X,T) FD_SET(mysql_socket_getfd(X),&clientFDs); \ + pfs_fds[socket_count]= (X); \ + fd_type[socket_count]= T; \ + socket_count++ +#else +#define setup_fds(X,T) FD_SET(mysql_socket_getfd(X),&clientFDs); \ + fd_type[socket_count]= T; \ + socket_count++ +#endif // HAVE_SYSTEMD fd_set readFDs,clientFDs; FD_ZERO(&clientFDs); #endif DBUG_ENTER("handle_connections_sockets"); - if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) +#ifdef HAVE_SYSTEMD + systemd_n = sd_listen_fds(1); + if (systemd_n < 0) { - setup_fds(base_ip_sock); - ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); + my_error(ER_SYSTEMD_LISTEN_FDS, MYF(0), 0, -systemd_n); } - if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) + else + if (systemd_n > 0) { - setup_fds(extra_ip_sock); - extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); + systemd_fd = SD_LISTEN_FDS_START; + while (systemd_n-- && systemd_listen_cnt < MAX_LISTEN_SOCKETS) + { + /* grab socket info */ + socketpeer_len = sizeof(socketpeer); + if (getsockname(systemd_fd, (struct sockaddr *) &socketpeer, + &socketpeer_len) < 0) + { + sql_print_error("getsockname for fd %d failed (errno= %d).", + systemd_fd, errno); + sd_notifyf(0, "ERRNO=%d", errno); + systemd_fd++; + continue; + } + if (socketpeer_len >=sizeof(socketpeer)) + { + sql_print_error("getsockname for fd %d unsufficient space", systemd_fd); + sd_notifyf(0, "ERRNO=%d", EINVAL); + systemd_fd++; + continue; + } + + /* Get listening sockets from systemd library calls + and set them up the same as other sockets. */ +#ifdef HAVE_SYS_UN_H + if (socketpeer.ss.ss_family == AF_UNIX) + { + sql_print_information("Listening on systemd unix socket for %s.", + socketpeer.un.sun_path); + family= "systemd_unix_socket"; + } + else +#endif + if (socketpeer.ss.ss_family == AF_INET || + socketpeer.ss.ss_family == AF_INET6) + { + sql_print_information("Listening on systemd family %s port %d.", + socketpeer.ss.ss_family == AF_INET ? "IPv4" : "IPv6", + ntohs(socketpeer.ss.ss_family == AF_INET ? + socketpeer.in.sin_port : socketpeer.in6.sin6_port)); + family= socketpeer.ss.ss_family == AF_INET ? "systemd_IPv4" : + "systemd_IPv6"; + } + else + { + sql_print_error("Unrecognised socket family: %d.", + socketpeer.ss.ss_family); + systemd_fd++; + continue; + } + systemd_sock[systemd_listen_cnt]= mysql_socket_fd(all_systemd_key[systemd_listen_cnt], systemd_fd); + mysql_socket_set_thread_owner(systemd_sock[systemd_listen_cnt]); +#ifndef HAVE_POLL + pfs_flags[socket_count]= +#endif + fcntl(systemd_fd, F_GETFL, 0); +#ifdef HAVE_PSI_SOCKET_INTERFACE + all_systemd_sockets[systemd_listen_cnt]= (PSI_socket_info) { &all_systemd_key[systemd_listen_cnt], family, PSI_FLAG_GLOBAL }; +#endif + setup_fds(systemd_sock[systemd_listen_cnt], socketpeer.ss.ss_family); + systemd_fd++; + systemd_listen_cnt++; + } +#ifdef HAVE_PSI_SOCKET_INTERFACE + all_systemd_sockets[systemd_listen_cnt]= (PSI_socket_info) { &key_socket_client_connection, "client_connection", 0}; + mysql_socket_register("sql", all_systemd_sockets, systemd_listen_cnt + 1); +#endif + /* print out unused ones */ + while (systemd_n-- > 0) + { + socketpeer_len = sizeof(socketpeer); + if (getsockname(systemd_fd, (struct sockaddr *) &socketpeer, + &socketpeer_len) < 0) + { + sql_print_error("getsockname for fd %d failed (errno= %d).", + systemd_fd, errno); + sd_notifyf(0, "ERRNO=%d", errno); + systemd_fd++; + continue; + } + if (socketpeer_len >=sizeof(socketpeer)) + { + sql_print_error("getsockname for fd %d unsufficient space", systemd_fd); + sd_notifyf(0, "ERRNO=%d", EINVAL); + systemd_fd++; + continue; + } +#ifdef HAVE_SYS_UN_H + if (socketpeer.ss.ss_family == AF_UNIX) + { + sql_print_error("Exceeded %d sockets NOT listening on systemd unix socket for %s.", + MAX_LISTEN_SOCKETS, socketpeer.un.sun_path); + } + else +#endif + if (socketpeer.ss.ss_family == AF_INET || + socketpeer.ss.ss_family == AF_INET6) + { + sql_print_error("Exceeded %d sockets NOT listening on systemd family %s port %d.", + MAX_LISTEN_SOCKETS, + socketpeer.ss.ss_family == AF_INET ? "IPv4" : "IPv6", + ntohs(socketpeer.ss.ss_family == AF_INET ? + socketpeer.in.sin_port : socketpeer.in6.sin6_port)); + } + systemd_fd++; + } } + else + { +#endif /* HAVE_SYSTEMD */ + if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET) + { + setup_fds(base_ip_sock, AF_INET); + ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0); + } + if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET) + { + setup_fds(extra_ip_sock, AF_INET); + extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0); + } #ifdef HAVE_SYS_UN_H - setup_fds(unix_sock); - socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); + setup_fds(unix_sock, AF_UNIX); + socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0); +#endif + +#ifdef HAVE_SYSTEMD + } + +#ifdef HAVE_POLL + if (systemd_listen_cnt == 0) + { + sd_notify(0, "STATUS=No listening sockets"); + abort_loop=1; + } + else + { #endif + sd_notify(0, "READY=1\n" + "STATUS=Taking your SQL requests now..."); +#ifdef HAVE_POLL + } +#endif /* HAVE_POLL */ +#endif /* HAVE_SYSTEMD */ DBUG_PRINT("general",("Waiting for connections.")); MAYBE_BROKEN_SYSCALL; @@ -6146,6 +6340,7 @@ void handle_connections_sockets() { sock= pfs_fds[i]; flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0); + is_unix_sock= fd_type[i] == AF_UNIX; break; } } @@ -6154,18 +6349,39 @@ void handle_connections_sockets() { sock= base_ip_sock; flags= ip_flags; + is_unix_sock= FALSE; } else if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs)) { sock= extra_ip_sock; flags= extra_ip_flags; + is_unix_sock= FALSE; } +#ifdef HAVE_SYS_UN_H else + if (FD_ISSET(mysql_socket_getfd(unix_sock),&readFDs)) { sock = unix_sock; flags= socket_flags; + is_unix_sock= TRUE; + } +#endif +#ifdef HAVE_SYSTEMD + else + { + for (int i= 0; i < socket_count; ++i) + { + if (FD_ISSET(mysql_socket_getfd(pfs_fds[i]),&readFDs)) + { + sock= pfs_fds[i]; + flags= pfs_flags[i]; + is_unix_sock= fd_type[i] == AF_UNIX; + break; + } + } } +#endif // HAVE_SYSTEMD #endif // HAVE_POLL #if !defined(NO_FCNTL_NONBLOCK) @@ -6277,9 +6493,6 @@ void handle_connections_sockets() /* Set to get io buffers to be part of THD */ set_current_thd(thd); - is_unix_sock= (mysql_socket_getfd(sock) == - mysql_socket_getfd(unix_sock)); - if (!(vio_tmp= mysql_socket_vio_new(new_sock, is_unix_sock ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, @@ -6316,6 +6529,9 @@ void handle_connections_sockets() create_new_thread(thd); set_current_thd(0); } +#ifdef HAVE_SYSTEMD + sd_notify(0, "STOPPING=1"); +#endif DBUG_VOID_RETURN; } @@ -9665,9 +9881,17 @@ void init_server_psi_keys(void) count= array_elements(all_server_stages); mysql_stage_register(category, all_server_stages, count); - - count= array_elements(all_server_sockets); - mysql_socket_register(category, all_server_sockets, count); +#ifdef HAVE_PSI_SOCKET_INTERFACE +#ifdef HAVE_SYSTEMD + if (systemd_listen_cnt == 0) + { +#endif + count= array_elements(all_server_sockets); + mysql_socket_register(category, all_server_sockets, count); +#ifdef HAVE_SYSTEMD + } +#endif +#endif #ifdef HAVE_PSI_STATEMENT_INTERFACE init_sql_statement_info(); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 4980ba06604f5..aa62bdbbe2286 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7111,3 +7111,5 @@ ER_SLAVE_SKIP_NOT_IN_GTID eng "When using GTID, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position." ER_TABLE_DEFINITION_TOO_BIG eng "The definition for table %`s is too big" +ER_SYSTEMD_LISTEN_FDS + eng "Systemd error for configured ListenStream" diff --git a/support-files/mariadb-socket-convert b/support-files/mariadb-socket-convert new file mode 100644 index 0000000000000..7e62391aa8891 --- /dev/null +++ b/support-files/mariadb-socket-convert @@ -0,0 +1,150 @@ +#! /bin/bash +# +# Used to generate a mariadb.socket file based on the curent mysql/maridb settings +# +# This is to assist distro maintainers in migrating to systemd socket activation from +# a user system with networking settings somewhere in the my.cnf files. +# +# Redirect output to user directory like /etc/systemd/system/mariadb.socket.d/migrated-from-my.cnf-settings.conf + + +print_ports() +{ +if [ -n "${port}" ]; then + echo "ListenStream=${bind}${port}" +fi +if [ -n "${extraport}" ]; then + echo "ListenStream=${bind}${extraport}" +fi +} + +bindaddress= +port= +extraport= +backlog= +maxconnections= +skip_networking= +socket= + +coproc mysqldefaults { /usr/bin/my_print_defaults --mysqld ; } +while read var; do + key=${var%%=*} + val=${var#*=} + case "${key}" in + --bind-address) + bindaddress=$val + ;; + --bind_address) + bindaddress=$val + ;; + --port) + port=$val + ;; + --extra-port) + extraport=$val + ;; + --extra_port) + extraport=$val + ;; + --backlog) + backlog=$val + ;; + --max-connections) + maxconnections=$val + ;; + --max_connections) + maxconnections=$val + ;; + --skip-networking) + if [ -z "${val}" ]; then + skipnetworking=1 + else + skipnetworking=$val + fi + ;; + --skip_networking) + if [ -z "${val}" ]; then + skipnetworking=1 + else + skipnetworking=$val + fi + ;; + --socket) + socket=$val + ;; + esac +done < /dev/fd/${mysqldefaults[0]} + +echo '[Socket]' + +if [ -n "${backlog}" ]; then + echo "Backlog=${backlog}" +elif [ -n "${maxconnections}" ]; then + if [ $maxconnections -gt 150 ]; then + echo "Backlog=150" + else + echo "Backlog=${maxconnections}" + fi +fi + +if [ -n "${port}" -o \ + -n "${extraport}" -o \ + "${skipnetworking}" = '0' -o \ + -n "${bindaddress}" -o \ + -n "${socket}" ]; then + # we've set unix or inet sockets to non default + # reset the ListenStream list to empty + echo "ListenStream=" + # if port isn't set it really needs to be to + # fill out the details + [ -z "${port}" ] && port=3306 + # socket has a default value so ensure that is set + [ -z "${socket}" ] && socket=/var/lib/mysql/mysql.sock +else + exit 0 +fi + +if [ -n "${socket}" ]; then + echo "ListenStream=${socket}" +fi + +if [ -n "${skipnetworking}" ]; then + [ "${skipnetworking}" = '0' ] && exit 0 +fi + +if [ -n "${bindaddress}" ]; then + if [ "${bindaddress}" = "*" ]; then + # old wildcard + bind= + print_ports + elif [[ "${bindaddress}" =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]; then + # roughly IPv4 + bind=${bindaddress}: + print_ports + elif [[ "${bindaddress}" =~ ([0-9a-fA-F]{0,4}::?){1,7}[0-9a-fA-F]{0,4} ]]; then + # roughly IPv6 + bind=[${bindaddress}]: + print_ports + else + # hostname + # Systemd.sockets don't support it so look it up + coproc hosts { host ${bindaddress}; } + while read var; do + if [[ "${var}" = *IPv6\ address* ]]; then + bind=[${var##* }]: + print_ports + break + else + bind=${var##* }: + print_ports + fi + done < /dev/fd/${hosts[0]} + fi +else + bind='' + print_ports +fi + + +exit 0 + diff --git a/support-files/mariadb-systemd-start b/support-files/mariadb-systemd-start new file mode 100644 index 0000000000000..08f0c87007e0b --- /dev/null +++ b/support-files/mariadb-systemd-start @@ -0,0 +1,44 @@ +#! /bin/bash +# +# Scripts to run by MySQL systemd service +# +# +# try to run mysql_install_db and fix perms and SELinux contexts + +install_db () { + # Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode) + datadir=/var/lib/mysql + log=/var/log/mysqld.log + coproc mysqldefaults { /usr/bin/my_print_defaults --mysqld ; } + while read var; do + key=${var%%=*} + if [ "${key}" = '--datadir' ]; then + datadir=${var#*=} + fi + if [ "${key}" = '--log-error' ] || [ "${key}" = '--log_error' ]; then + log=${var#*=} + fi + done < /dev/fd/${mysqldefaults[0]} + + # Restore log, dir, perms and SELinux contexts + [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 + [ -e $log ] || touch $log + chmod 0640 $log + chown mysql:mysql $log || exit 1 + if [ -x /usr/sbin/restorecon ]; then + /usr/sbin/restorecon "$datadir" + /usr/sbin/restorecon $log + fi + + # If special mysql dir is in place, skip db install + [ -d "$datadir/mysql" ] && exit 0 + + # Create initial db + /usr/bin/mysql_install_db --rpm --datadir="$datadir" --user=mysql + exit 0 +} + +install_db + +exit 0 + diff --git a/support-files/mariadb.service b/support-files/mariadb.service new file mode 100644 index 0000000000000..09e321f6d7f03 --- /dev/null +++ b/support-files/mariadb.service @@ -0,0 +1,104 @@ +# +# /etc/systemd/system/mariadb.service +# + +[Unit] +Description=MariaDB database server +After=network.target +After=syslog.target +Requires=%p.socket + +[Install] +WantedBy=multi-user.target +Alias=mysql.service +Alias=mysqld.service + + +[Service] + +############################################################################## +## Core requirements +## + +Type=Notify + +# Setting this to true can break replication and the Type=Notify settings +PrivateNetwork=false + +############################################################################## +## Package maintainers +## + +User=mysql + +# Execute pre and post scripts as root +PermissionsStartOnly=true + +# Needed to create system tables etc. +ExecStartPre=/usr/bin/mariadb-systemd-start + +# Start main service +# skip-networking as its socket activation based +ExecStart=/usr/sbin/mysqld $OPTIONS + +KillMode=process +KillSignal=SIGTERM +# Don't want to see an automated SIGKILL ever +SendSIGKILL=no + +RestartPreventExitStatus=1 +Restart=on-fail +RestartSec=5s + +PrivateTmp=true +PrivateDevices=true + +UMask=077 +WorkingDirectory=/ +# To avoid mysql reading /root/.my.cnf which according to debian init script is +# problematic +Environment="HOME=" + +############################################################################## +## USERs can override +## +## +## by creating a file in /etc/systemd/system/mariadb.server.d/MY_SPECIAL.conf + +# Useful options not previously available in [mysqld_safe] + +OOMScoreAdjust=-600 + +BlockIOWeight=1000 + +## +## Options previously available to be set via [mysqld_safe] +## that now needs to be set by systemd config files as mysqld_safe +## isn't executed. +## + +# Number of files limit. previously [mysqld_safe] open-file-limit +LimitNOFILE=16364 + +# Maximium core size. previously [mysqld_safe] core-file-size +# LimitCore= + +# Nice priority. previously [mysqld_safe] nice +# Nice=-5 + +# Timezone. previously [mysqld_safe] timezone +# Environment="TZ=UTC" + +# Library substitutions. previously [mysqld_safe] malloc-lib with explict paths +# (in LD_LIBRARY_PATH) and library name (in LD_PRELOAD). +# Environment="LD_LIBRARY_PATH=/path1 /path2" "LD_PRELOAD= + +# Flush caches. previously [mysqld_safe] flush-caches=1 +# ExecStartPre=sync +# ExecStartPre=sysctl -q -w vm.drop_caches=3 + +# numa-interleave=1 equalivant +# Change ExecStart=numactl --interleave=all /usr/sbin/mysqld...... + +# crash-script equalivent +# FailureAction= diff --git a/support-files/mariadb.socket b/support-files/mariadb.socket new file mode 100644 index 0000000000000..5b71ca562f99d --- /dev/null +++ b/support-files/mariadb.socket @@ -0,0 +1,41 @@ +[Unit] +Description=MySQL/MariaDB Sockets + +[Install] +WantedBy=sockets.target +Alias=mysql.socket +Alias=mysqld.socket + +[Socket] +############################################################################## +## Core requirements +## + +KeepAlive=true + +# +# NonBlocking=true and NoDelay=true (if NonBlocking=true is unavailable) are +# already set by MariaDB + +############################################################################## +## DISTRIBUTION maintainers +## + +SocketUser=mysql +SocketMode=777 + +############################################################################## +## +## USERs can override +## +## See man systemd.socket.5 for meanings +## +## Override by creating a file in /etc/systemd/system/mariadb.socket.d/MY_SPECIAL.conf +## see man systemd.unit.5 + +ListenStream=/var/lib/mysql/mysql.sock +ListenStream=[::1]:3306 +ListenStream=127.0.0.1:3306 +BindToDevice= + +Backlog=150 From 3c9c925f9245f5f88feb68e2a893544b1778d0b0 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 12 Mar 2015 08:08:25 +1100 Subject: [PATCH 4/4] systemd notification messages for innodb status Add systemd notification for long and intrustive innodb events to report to systemd status monitoring' --- storage/innobase/buf/buf0dump.cc | 10 ++++++++++ storage/innobase/log/log0recv.cc | 30 ++++++++++++++++++++++++------ storage/xtradb/buf/buf0dump.cc | 10 ++++++++++ storage/xtradb/log/log0recv.cc | 30 ++++++++++++++++++++++++------ 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index 467f817a2d1a7..50769e594b22a 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -27,6 +27,9 @@ Created April 08, 2011 Vasil Dimov #include /* va_* */ #include /* strerror() */ +#ifdef HAVE_SYSTEMD +#include +#endif #include "buf0buf.h" /* buf_pool_mutex_enter(), srv_buf_pool_instances */ #include "buf0dump.h" @@ -198,6 +201,10 @@ buf_dump( buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s", full_filename); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Dumping buffer pool(s) to %s", full_filename); +#endif + f = fopen(tmp_filename, "w"); if (f == NULL) { @@ -322,6 +329,9 @@ buf_dump( buf_dump_status(STATUS_NOTICE, "Buffer pool(s) dump completed at %s", now); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Buffer pool(s) dump completed at %s", full_filename); +#endif } /*****************************************************************//** diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index aa6c81483d719..6590b47e22d09 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -29,6 +29,10 @@ Created 9/20/1997 Heikki Tuuri #include // Solaris/x86 header file bug #include +#ifdef HAVE_SYSTEMD +#include +#endif + #include "log0recv.h" #ifdef UNIV_NONINL @@ -1849,6 +1853,7 @@ recv_apply_hashed_log_recs( recv_addr_t* recv_addr; ulint i; ibool has_printed = FALSE; + ulong progress; mtr_t mtr; loop: mutex_enter(&(recv_sys->mutex)); @@ -1918,14 +1923,17 @@ recv_apply_hashed_log_recs( } } + progress=(ulong) (i * 100) / hash_get_n_cells(recv_sys->addr_hash); if (has_printed - && (i * 100) / hash_get_n_cells(recv_sys->addr_hash) - != ((i + 1) * 100) - / hash_get_n_cells(recv_sys->addr_hash)) { + && progress != ((i + 1) * 100) + / hash_get_n_cells(recv_sys->addr_hash)) { + + fprintf(stderr, "%lu ", progress); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Applying batch of log records for Innodb: " + "Progress %lu", progress); +#endif - fprintf(stderr, "%lu ", (ulong) - ((i * 100) - / hash_get_n_cells(recv_sys->addr_hash))); } } @@ -1987,6 +1995,9 @@ recv_apply_hashed_log_recs( if (has_printed) { fprintf(stderr, "InnoDB: Apply batch completed\n"); +#ifdef HAVE_SYSTEMD + sd_notify(0, "STATUS=InnoDB: Apply batch completed"); +#endif } mutex_exit(&(recv_sys->mutex)); @@ -2134,8 +2145,15 @@ recv_apply_log_recs_for_backup(void) fprintf(stderr, "%lu ", (ulong) ((100 * i) / n_hash_cells)); fflush(stderr); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Applying batch of log records for backup Innodb: " + "Progress %lu", (ulong) (100 * i) / n_hash_cells); +#endif } } +#ifdef HAVE_SYSTEMD + sd_notify(0, "STATUS=InnoDB: Apply batch for backup completed"); +#endif recv_sys_empty_hash(); } diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc index 090e8cac63be0..0c45bf92e8994 100644 --- a/storage/xtradb/buf/buf0dump.cc +++ b/storage/xtradb/buf/buf0dump.cc @@ -27,6 +27,9 @@ Created April 08, 2011 Vasil Dimov #include /* va_* */ #include /* strerror() */ +#ifdef HAVE_SYSTEMD +#include +#endif #include "buf0buf.h" /* srv_buf_pool_instances */ #include "buf0dump.h" @@ -198,6 +201,10 @@ buf_dump( buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s", full_filename); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Dumping buffer pool(s) to %s", full_filename); +#endif + f = fopen(tmp_filename, "w"); if (f == NULL) { @@ -322,6 +329,9 @@ buf_dump( buf_dump_status(STATUS_NOTICE, "Buffer pool(s) dump completed at %s", now); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Buffer pool(s) dump completed at %s", full_filename); +#endif } /*****************************************************************//** diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index f3c4887874d89..d74733eb3189d 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -29,6 +29,10 @@ Created 9/20/1997 Heikki Tuuri #include // Solaris/x86 header file bug #include +#ifdef HAVE_SYSTEMD +#include +#endif + #include "log0recv.h" #ifdef UNIV_NONINL @@ -1920,6 +1924,7 @@ recv_apply_hashed_log_recs( recv_addr_t* recv_addr; ulint i; ibool has_printed = FALSE; + ulong progress; mtr_t mtr; loop: mutex_enter(&(recv_sys->mutex)); @@ -1989,14 +1994,17 @@ recv_apply_hashed_log_recs( } } + progress=(ulong) (i * 100) / hash_get_n_cells(recv_sys->addr_hash); if (has_printed - && (i * 100) / hash_get_n_cells(recv_sys->addr_hash) - != ((i + 1) * 100) - / hash_get_n_cells(recv_sys->addr_hash)) { + && progress != ((i + 1) * 100) + / hash_get_n_cells(recv_sys->addr_hash)) { + + fprintf(stderr, "%lu ", progress); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Applying batch of log records for Innodb: " + "Progress %lu", progress); +#endif - fprintf(stderr, "%lu ", (ulong) - ((i * 100) - / hash_get_n_cells(recv_sys->addr_hash))); } } @@ -2058,6 +2066,9 @@ recv_apply_hashed_log_recs( if (has_printed) { fprintf(stderr, "InnoDB: Apply batch completed\n"); +#ifdef HAVE_SYSTEMD + sd_notify(0, "STATUS=InnoDB: Apply batch completed"); +#endif } mutex_exit(&(recv_sys->mutex)); @@ -2205,8 +2216,15 @@ recv_apply_log_recs_for_backup(void) fprintf(stderr, "%lu ", (ulong) ((100 * i) / n_hash_cells)); fflush(stderr); +#ifdef HAVE_SYSTEMD + sd_notifyf(0, "STATUS=Applying batch of log records for backup Innodb: " + "Progress %lu", (ulong) (100 * i) / n_hash_cells); +#endif } } +#ifdef HAVE_SYSTEMD + sd_notify(0, "STATUS=InnoDB: Apply batch for backup completed"); +#endif recv_sys_empty_hash(); }