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/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/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/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/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 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 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/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(); } 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