Commit 00ba013e authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

Merge branch '11.4' into bb-11.4-release

parents 6f7efd69 2f5174e5
...@@ -53,7 +53,7 @@ SET_TARGET_PROPERTIES(mariadb-test PROPERTIES ENABLE_EXPORTS TRUE) ...@@ -53,7 +53,7 @@ SET_TARGET_PROPERTIES(mariadb-test PROPERTIES ENABLE_EXPORTS TRUE)
MYSQL_ADD_EXECUTABLE(mariadb-check mysqlcheck.c) MYSQL_ADD_EXECUTABLE(mariadb-check mysqlcheck.c)
TARGET_LINK_LIBRARIES(mariadb-check ${CLIENT_LIB}) TARGET_LINK_LIBRARIES(mariadb-check ${CLIENT_LIB})
MYSQL_ADD_EXECUTABLE(mariadb-dump mysqldump.c ../sql-common/my_user.c) MYSQL_ADD_EXECUTABLE(mariadb-dump mysqldump.cc ../sql-common/my_user.c connection_pool.cc)
TARGET_LINK_LIBRARIES(mariadb-dump ${CLIENT_LIB}) TARGET_LINK_LIBRARIES(mariadb-dump ${CLIENT_LIB})
MYSQL_ADD_EXECUTABLE(mariadb-import mysqlimport.c) MYSQL_ADD_EXECUTABLE(mariadb-import mysqlimport.c)
......
/*
Copyright (c) 2023, MariaDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335
USA
*/
/*
Connection pool, with parallel query execution
Does not use threads, but IO multiplexing via mysql_send_query and
poll/iocp to wait for completions
*/
#include <my_global.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <poll.h>
#endif
#include "connection_pool.h"
#include <my_compiler.h>
namespace async_pool
{
static ATTRIBUTE_NORETURN void die(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
abort();
}
pooled_connection *connection_pool::get_connection()
{
while (free_connections.empty())
wait_for_completions();
auto c= free_connections.front();
free_connections.pop();
return c;
}
#ifdef _WIN32
void connection_pool::add_to_pollset(pooled_connection *c)
{
DWORD err= ERROR_SUCCESS;
static char ch;
WSABUF buf;
buf.len= 0;
buf.buf= &ch;
if (!c->is_pipe)
{
/* Do async io (sockets). */
DWORD flags= 0;
if (WSARecv((SOCKET) c->handle, &buf, 1, 0, &flags, c, NULL))
err= WSAGetLastError();
}
else
{
/* Do async read (named pipe) */
if (!ReadFile(c->handle, buf.buf, buf.len, 0, c))
err= GetLastError();
}
if (err && err != ERROR_IO_PENDING)
die("%s failed: %d\n", c->is_pipe ? "ReadFile" : "WSARecv", err);
}
/*
Wait for completions of queries.Uses IOCP on windows to wait for completions.
(ReadFile/WSARecv with 0 bytes serves as readiness notification)
*/
void connection_pool::wait_for_completions()
{
ULONG n;
OVERLAPPED_ENTRY events[32];
if (!GetQueuedCompletionStatusEx(iocp, events, array_elements(events), &n, INFINITE,
FALSE))
{
die("GetQueuedCompletionStatusEx failed: %d\n", GetLastError());
}
for (ULONG i= 0; i < n; i++)
{
auto c= (pooled_connection *) events[i].lpOverlapped;
if (!c)
die("GetQueuedCompletionStatusEx unexpected return");
DBUG_ASSERT(c->mysql);
DBUG_ASSERT(!events[i].lpCompletionKey);
DBUG_ASSERT(!events[i].dwNumberOfBytesTransferred);
complete_query(c);
}
}
#else /* !_WIN32 */
void connection_pool::add_to_pollset(pooled_connection *c)
{
size_t idx= c - &all_connections[0];
pollfd *pfd= &pollset[idx];
pfd->fd= c->fd;
pfd->events= POLLIN;
pfd->revents= 0;
}
/* something Linux-ish, can be returned for POLLIN event*/
#ifndef POLLRDHUP
#define POLLRDHUP 0
#endif
void connection_pool::wait_for_completions()
{
int n;
while ((n= poll(pollset.data(), pollset.size(), -1)) <= 0)
{
if (errno == EINTR)
continue;
die("poll failed: %d\n", errno);
}
for (uint i= 0; n > 0 && i < pollset.size(); i++)
{
pollfd* pfd= &pollset[i];
if (pfd->revents &
(POLLIN | POLLPRI | POLLHUP | POLLRDHUP| POLLERR | POLLNVAL))
{
pfd->events= 0;
pfd->revents= 0;
pfd->fd= -1;
complete_query(&all_connections[i]);
n--;
}
}
if (n)
die("poll() failed to find free connection: %d\n");
}
#endif
void connection_pool::complete_query(pooled_connection *c)
{
int err= mysql_read_query_result(c->mysql);
if (c->on_completion)
c->on_completion(c->mysql, c->query.c_str(), !err, c->context);
if (c->release_connection)
{
c->in_use= false;
free_connections.push(c);
}
}
connection_pool::~connection_pool()
{
close();
}
void connection_pool::init(MYSQL *con[], size_t n)
{
#ifdef _WIN32
iocp= CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (!iocp)
die("CreateIoCompletionPort failed: %d\n", GetLastError());
#else
pollset.resize(n);
for (auto &pfd : pollset)
pfd.fd= -1;
#endif
for (size_t i= 0; i < n; i++)
all_connections.emplace_back(con[i]);
for (auto &con : all_connections)
{
free_connections.push(&con);
#ifdef _WIN32
if (!CreateIoCompletionPort(con.handle, iocp, 0, 0))
die("CreateIoCompletionPort failed: %d\n", GetLastError());
#endif
}
}
int connection_pool::execute_async(const char *query,
query_completion_handler on_completion,
void *context, bool release_connecton)
{
auto c= get_connection();
c->context= context;
c->on_completion= on_completion;
c->release_connection= release_connecton;
c->query= query;
int ret= mysql_send_query(c->mysql, query, (unsigned long) c->query.size());
if (ret)
{
free_connections.push(c);
return ret;
}
c->in_use= true;
add_to_pollset(c);
return 0;
}
/*
Wait until all queries are completed and all
connections are idle.
*/
void connection_pool::wait_all()
{
while (free_connections.size() != all_connections.size())
wait_for_completions();
}
void connection_pool::for_each_connection(void(*f)(MYSQL *mysql))
{
for (auto &c : all_connections)
f(c.mysql);
}
int connection_pool::close()
{
for (auto &c : all_connections)
mysql_close(c.mysql);
all_connections.clear();
while (!free_connections.empty())
free_connections.pop();
#ifdef _WIN32
if (iocp)
{
CloseHandle(iocp);
iocp= nullptr;
}
#endif
return 0;
}
pooled_connection::pooled_connection(MYSQL *c)
{
mysql= c;
#ifdef _WIN32
OVERLAPPED *ov= static_cast<OVERLAPPED *>(this);
memset(ov, 0, sizeof(OVERLAPPED));
mysql_protocol_type protocol;
if (c->host && !strcmp(c->host, "."))
protocol= MYSQL_PROTOCOL_PIPE;
else
protocol= (mysql_protocol_type) c->options.protocol;
is_pipe= protocol == MYSQL_PROTOCOL_PIPE;
handle= (HANDLE) mysql_get_socket(c);
#else
fd= mysql_get_socket(c);
#endif
}
} // namespace async_pool
/*
Copyright (c) 2023, MariaDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335
USA
*/
#pragma once
#include <mysql.h>
#include <vector>
#include <queue>
#include <string>
#ifdef _WIN32
#include <windows.h>
#else
#include <poll.h>
#endif
/*
Implementation of asynchronous mariadb connection pool.
This pool consists of set of MYSQL* connections, created by C API
function. The intention is that all connections have the same state
same server, by the same user etc.
The "asynchronous" means the queries are executed on the server
without waiting for the server reply. The queries are submitted
with mysql_send_query(), and completions are picked by poll/IOCP.
*/
namespace async_pool
{
typedef void (*query_completion_handler)(MYSQL *mysql, const char *query, bool success, void *context);
struct pooled_connection
#ifdef _WIN32
: OVERLAPPED
#endif
{
MYSQL *mysql;
query_completion_handler on_completion=NULL;
void *context=NULL;
std::string query;
bool in_use=false;
bool release_connection=false;
#ifdef _WIN32
bool is_pipe;
HANDLE handle;
#else
int fd;
#endif
pooled_connection(MYSQL *mysql);
};
struct connection_pool
{
private:
std::vector<pooled_connection> all_connections;
std::queue<pooled_connection *> free_connections;
pooled_connection *get_connection();
void wait_for_completions();
void complete_query(pooled_connection *c);
void add_to_pollset(pooled_connection *c);
#ifdef _WIN32
HANDLE iocp=nullptr;
#else
std::vector<pollfd> pollset;
#endif
public:
~connection_pool();
/**
Add connections to the connection pool
@param con - connections
@param n_connections - number of connections
*/
void init(MYSQL *con[], size_t n_connections);
/**
Send query to the connection pool
Executes query on a connection in the pool, using mysql_send_query
@param query - query string
@param on_completion - callback function to be called on completion
@param context - user context that will be passed to the callback function
@param release_connecton - if true, the connection should be released to the
pool after the query is executed. If you execute another
mysql_send_query() on the same connection, set this to false.
Note: the function will block if there are no free connections in the pool.
@return return code of mysql_send_query
*/
int execute_async(const char *query, query_completion_handler on_completion, void *context, bool release_connecton=true);
/** Waits for all outstanding queries to complete.*/
void wait_all();
/** Execute callback for each connection in the pool. */
void for_each_connection(void (*f)(MYSQL *mysql));
/**
Closes all connections in pool and frees all resources.
Does not wait for pending queries to complete
(use wait_all() for that)
*/
int close();
};
} // namespace async_pool
This diff is collapsed.
...@@ -148,6 +148,9 @@ static struct my_option my_long_options[] = ...@@ -148,6 +148,9 @@ static struct my_option my_long_options[] =
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0}, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif #endif
{"parallel", 'j', "Number of LOAD DATA jobs executed in parallel",
&opt_use_threads, &opt_use_threads, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0,
0, 0},
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
&opt_plugin_dir, &opt_plugin_dir, 0, &opt_plugin_dir, &opt_plugin_dir, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
...@@ -170,9 +173,7 @@ static struct my_option my_long_options[] = ...@@ -170,9 +173,7 @@ static struct my_option my_long_options[] =
&opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR, &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#include <sslopt-longopts.h> #include <sslopt-longopts.h>
{"use-threads", OPT_USE_THREADS, {"use-threads", OPT_USE_THREADS, "Synonym for --parallel option",
"Load files in parallel. The argument is the number "
"of threads to use for loading data.",
&opt_use_threads, &opt_use_threads, 0, &opt_use_threads, &opt_use_threads, 0,
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DONT_ALLOW_USER_CHANGE #ifndef DONT_ALLOW_USER_CHANGE
......
set @save_debug_dbug=@@global.debug_dbug;
set global debug_dbug='+d,select_export_kill';
mariadb-dump: Couldn't execute async query 'SELECT /*!40001 SQL_NO_CACHE */ `Host`, `User`, `Priv` INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/global_priv.txt' /*!50138 CHARACTER SET binary */ FROM `mysql`.`global_priv`' (Query execution was interrupted)
set global debug_dbug=@save_debug_dbug;
--source include/have_debug.inc
--source include/not_embedded.inc
# need to dump "mysql" schema
--source include/have_innodb.inc
# inject error on SELECT INTO OUTFILE
set @save_debug_dbug=@@global.debug_dbug;
set global debug_dbug='+d,select_export_kill';
# This one succeeds
--replace_result .\exe '' $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error 2
--exec $MYSQL_DUMP --tab=$MYSQLTEST_VARDIR/tmp/ --parallel=2 mysql global_priv 2>&1
set global debug_dbug=@save_debug_dbug;
--loose-enable-named-pipe
# Test mysqldump specific features (pipe connection, with parallel)
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES(1);
DROP TABLE t1;
test.t1: Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
SELECT * FROM t1;
i
1
DROP TABLE t1;
--source include/windows.inc
--source include/not_embedded.inc
--echo # Test mysqldump specific features (pipe connection, with parallel)
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES(1);
--exec $MYSQL_DUMP --host=. --tab=$MYSQLTEST_VARDIR/tmp/ test --parallel=2
DROP TABLE t1;
--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/t1.sql
--exec $MYSQL_IMPORT test $MYSQLTEST_VARDIR/tmp/t1.txt
SELECT * FROM t1;
DROP TABLE t1;
...@@ -5531,7 +5531,6 @@ proc ...@@ -5531,7 +5531,6 @@ proc
one one
DROP DATABASE bug25717383; DROP DATABASE bug25717383;
mariadb-dump: Got error: 2005: "Unknown server host 'unknownhost'" when trying to connect mariadb-dump: Got error: 2005: "Unknown server host 'unknownhost'" when trying to connect
mariadb-dump: Couldn't execute 'SHOW SLAVE STATUS': Server has gone away (2006)
Usage: mariadb-dump [OPTIONS] database [tables] Usage: mariadb-dump [OPTIONS] database [tables]
OR mariadb-dump [OPTIONS] --databases DB1 [DB2 DB3...] OR mariadb-dump [OPTIONS] --databases DB1 [DB2 DB3...]
OR mariadb-dump [OPTIONS] --all-databases OR mariadb-dump [OPTIONS] --all-databases
...@@ -6659,3 +6658,12 @@ drop table t1; ...@@ -6659,3 +6658,12 @@ drop table t1;
# End of 10.4 tests # End of 10.4 tests
# #
mariadb-dump: --xml can't be used with --tab. mariadb-dump: --xml can't be used with --tab.
select @@max_connections into @save_max_connections;
set global max_connections=10;
mariadb-dump: Got error: 1040: "Too many connections" when trying to connect
set global max_connections=300;
mariadb-dump: Too many connections
set global max_connections=@save_max_connections;
#
# End of 11.4 tests
#
...@@ -2482,12 +2482,12 @@ INSERT INTO t2 VALUES (3), (4); ...@@ -2482,12 +2482,12 @@ INSERT INTO t2 VALUES (3), (4);
SELECT * FROM t1; SELECT * FROM t1;
SELECT * FROM t2; SELECT * FROM t2;
--exec $MYSQL_DUMP --default-character-set=utf8mb4 --tab=$MYSQLTEST_VARDIR/tmp/ db_20772273 --exec $MYSQL_DUMP --default-character-set=utf8mb4 --tab=$MYSQLTEST_VARDIR/tmp/ --parallel=2 db_20772273
--exec $MYSQL db_20772273 < $MYSQLTEST_VARDIR/tmp/t1.sql --exec $MYSQL db_20772273 < $MYSQLTEST_VARDIR/tmp/t1.sql
--exec $MYSQL db_20772273 < $MYSQLTEST_VARDIR/tmp/t2.sql --exec $MYSQL db_20772273 < $MYSQLTEST_VARDIR/tmp/t2.sql
# Test mysqlimport with multiple threads # Test mysqlimport with multiple threads
--exec $MYSQL_IMPORT --silent --use-threads=2 db_20772273 $MYSQLTEST_VARDIR/tmp/t1.txt $MYSQLTEST_VARDIR/tmp/t2.txt --exec $MYSQL_IMPORT --silent --parallel=2 db_20772273 $MYSQLTEST_VARDIR/tmp/t1.txt $MYSQLTEST_VARDIR/tmp/t2.txt
SELECT * FROM t1; SELECT * FROM t1;
SELECT * FROM t2; SELECT * FROM t2;
...@@ -3023,3 +3023,24 @@ drop table t1; ...@@ -3023,3 +3023,24 @@ drop table t1;
--replace_result mariadb-dump.exe mariadb-dump --replace_result mariadb-dump.exe mariadb-dump
--error 1 --error 1
--exec $MYSQL_DUMP --xml --tab=$MYSQLTEST_VARDIR/tmp 2>&1 --exec $MYSQL_DUMP --xml --tab=$MYSQLTEST_VARDIR/tmp 2>&1
#
# MDEV-32589 parallel-mysqldump - test "too many connections"
#
select @@max_connections into @save_max_connections;
set global max_connections=10;
--replace_result mariadb-dump.exe mariadb-dump
--error 2
--exec $MYSQL_DUMP --tab=$MYSQLTEST_VARDIR/tmp/ --parallel=20 mysql 2>&1
#
# MDEV-32589 test builtin 256 connections limit
#
set global max_connections=300;
--replace_result mariadb-dump.exe mariadb-dump
--error 1
--exec $MYSQL_DUMP --tab=$MYSQLTEST_VARDIR/tmp/ --parallel=280 mysql 2>&1
set global max_connections=@save_max_connections;
--echo #
--echo # End of 11.4 tests
--echo #
...@@ -134,9 +134,6 @@ ...@@ -134,9 +134,6 @@
#endif #endif
#include <my_service_manager.h> #include <my_service_manager.h>
#ifdef __linux__
#include <sys/eventfd.h>
#endif
#include <source_revision.h> #include <source_revision.h>
...@@ -1396,6 +1393,8 @@ struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD() ...@@ -1396,6 +1393,8 @@ struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
Dynamic_array<MYSQL_SOCKET> listen_sockets(PSI_INSTRUMENT_MEM, 0); Dynamic_array<MYSQL_SOCKET> listen_sockets(PSI_INSTRUMENT_MEM, 0);
bool unix_sock_is_online= false; bool unix_sock_is_online= false;
static int systemd_sock_activation; /* systemd socket activation */ static int systemd_sock_activation; /* systemd socket activation */
/** wakeup listening(main) thread by writing to this descriptor */
static int termination_event_fd= -1; static int termination_event_fd= -1;
...@@ -1658,66 +1657,21 @@ static my_bool warn_threads_active_after_phase_2(THD *thd, void *) ...@@ -1658,66 +1657,21 @@ static my_bool warn_threads_active_after_phase_2(THD *thd, void *)
static void break_connect_loop() static void break_connect_loop()
{ {
#ifdef EXTRA_DEBUG
int count=0;
#endif
abort_loop= 1; abort_loop= 1;
#if defined(_WIN32) #if defined(_WIN32)
mysqld_win_initiate_shutdown(); mysqld_win_initiate_shutdown();
#else #else
/* Avoid waiting for ourselves when thread-handling=no-threads. */
if (pthread_equal(pthread_self(), select_thread))
return;
DBUG_PRINT("quit", ("waiting for select thread: %lu",
(ulong)select_thread));
mysql_mutex_lock(&LOCK_start_thread); mysql_mutex_lock(&LOCK_start_thread);
while (select_thread_in_use) if (termination_event_fd >= 0)
{
struct timespec abstime;
int UNINIT_VAR(error);
DBUG_PRINT("info",("Waiting for select thread"));
{
/*
Cannot call shutdown on systemd socket activated descriptors
as their clone in the pid 1 is reused.
*/
int lowest_fd, shutdowns= 0;
lowest_fd= sd_listen_fds(0) + SD_LISTEN_FDS_START;
for(size_t i= 0; i < listen_sockets.size(); i++)
{
int fd= mysql_socket_getfd(listen_sockets.at(i));
if (fd >= lowest_fd)
{
shutdowns++;
mysql_socket_shutdown(listen_sockets.at(i), SHUT_RDWR);
}
}
if (!shutdowns && termination_event_fd >=0)
{ {
uint64_t u= 1; uint64_t u= 1;
if (write(termination_event_fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) if(write(termination_event_fd, &u, sizeof(uint64_t)) < 0)
sql_print_error("Couldn't send event to terminate listen loop");
}
}
set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 && select_thread_in_use; tmp++)
{ {
error= mysql_cond_timedwait(&COND_start_thread, &LOCK_start_thread, sql_print_error("Couldn't send event to terminate listen loop");
&abstime); abort();
if (error != EINTR)
break;
} }
#ifdef EXTRA_DEBUG
if (error != 0 && error != ETIMEDOUT && !count++)
sql_print_error("Got error %d from mysql_cond_timedwait", error);
#endif
} }
if (termination_event_fd >= 0)
close(termination_event_fd);
mysql_mutex_unlock(&LOCK_start_thread); mysql_mutex_unlock(&LOCK_start_thread);
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
...@@ -1963,11 +1917,6 @@ extern "C" void unireg_abort(int exit_code) ...@@ -1963,11 +1917,6 @@ extern "C" void unireg_abort(int exit_code)
static void mysqld_exit(int exit_code) static void mysqld_exit(int exit_code)
{ {
DBUG_ENTER("mysqld_exit"); DBUG_ENTER("mysqld_exit");
/*
Important note: we wait for the signal thread to end,
but if a kill -15 signal was sent, the signal thread did
spawn the kill_server_thread thread, which is running concurrently.
*/
rpl_deinit_gtid_waiting(); rpl_deinit_gtid_waiting();
rpl_deinit_gtid_slave_state(); rpl_deinit_gtid_slave_state();
wait_for_signal_thread_to_end(); wait_for_signal_thread_to_end();
...@@ -2124,17 +2073,17 @@ static void clean_up(bool print_message) ...@@ -2124,17 +2073,17 @@ static void clean_up(bool print_message)
*/ */
static void wait_for_signal_thread_to_end() static void wait_for_signal_thread_to_end()
{ {
uint i; #ifndef _WIN32
/* /*
Wait up to 10 seconds for signal thread to die. We use this mainly to Wait up to 10 seconds for signal thread to die. We use this mainly to
avoid getting warnings that my_thread_end has not been called avoid getting warnings that my_thread_end has not been called
*/ */
for (i= 0 ; i < 100 && signal_thread_in_use; i++) for (uint i= 0 ; i < 100 && signal_thread_in_use; i++)
{ {
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL) == ESRCH) kill(getpid(), MYSQL_KILL_SIGNAL);
break;
my_sleep(100); // Give it time to die my_sleep(100); // Give it time to die
} }
#endif
} }
#endif /*EMBEDDED_LIBRARY*/ #endif /*EMBEDDED_LIBRARY*/
...@@ -2676,9 +2625,6 @@ static void use_systemd_activated_sockets() ...@@ -2676,9 +2625,6 @@ static void use_systemd_activated_sockets()
listen_sockets.push(sock); listen_sockets.push(sock);
} }
systemd_sock_activation= 1; systemd_sock_activation= 1;
termination_event_fd= eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
if (termination_event_fd == -1)
sql_print_warning("eventfd failed %d", errno);
free(names); free(names);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -3232,22 +3178,9 @@ static void start_signal_handler(void) ...@@ -3232,22 +3178,9 @@ static void start_signal_handler(void)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
#if defined(USE_ONE_SIGNAL_HAND)
pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
break_connect_loop();
my_thread_end();
pthread_exit(0);
return 0;
}
#endif
/** This threads handles all signals */ /** This threads handles all signals */
/* ARGSUSED */ /* ARGSUSED */
pthread_handler_t signal_hand(void *arg __attribute__((unused))) pthread_handler_t signal_hand(void *)
{ {
sigset_t set; sigset_t set;
int sig; int sig;
...@@ -3291,20 +3224,17 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) ...@@ -3291,20 +3224,17 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
int error; int error;
int origin; int origin;
if (abort_loop)
break;
while ((error= my_sigwait(&set, &sig, &origin)) == EINTR) /* no-op */; while ((error= my_sigwait(&set, &sig, &origin)) == EINTR) /* no-op */;
if (cleanup_done)
{ if (abort_loop)
DBUG_PRINT("quit",("signal_handler: calling my_thread_end()")); break;
my_thread_end();
DBUG_LEAVE; // Must match DBUG_ENTER()
signal_thread_in_use= 0;
pthread_exit(0); // Safety
return 0; // Avoid compiler warnings
}
switch (sig) { switch (sig) {
case SIGTERM: case SIGTERM:
case SIGQUIT: case SIGQUIT:
case SIGKILL:
#ifdef EXTRA_DEBUG #ifdef EXTRA_DEBUG
sql_print_information("Got signal %d to shutdown server",sig); sql_print_information("Got signal %d to shutdown server",sig);
#endif #endif
...@@ -3312,31 +3242,15 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) ...@@ -3312,31 +3242,15 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
logger.set_handlers(global_system_variables.sql_log_slow ? LOG_FILE:LOG_NONE, logger.set_handlers(global_system_variables.sql_log_slow ? LOG_FILE:LOG_NONE,
opt_log ? LOG_FILE:LOG_NONE); opt_log ? LOG_FILE:LOG_NONE);
DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop)); DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop));
if (!abort_loop)
{
/* Delete the instrumentation for the signal thread */
PSI_CALL_delete_current_thread();
#ifdef USE_ONE_SIGNAL_HAND
pthread_t tmp;
if (unlikely((error= mysql_thread_create(0, /* Not instrumented */
&tmp, &connection_attrib,
kill_server_thread,
(void*) &sig))))
sql_print_error("Can't create thread to kill server (errno= %d)",
error);
#else
my_sigset(sig, SIG_IGN);
break_connect_loop(); break_connect_loop();
#endif DBUG_ASSERT(abort_loop);
}
break; break;
case SIGHUP: case SIGHUP:
#if defined(SI_KERNEL) #if defined(SI_KERNEL)
if (!abort_loop && origin != SI_KERNEL) if (origin != SI_KERNEL)
#elif defined(SI_USER) #elif defined(SI_USER)
if (!abort_loop && origin <= SI_USER) if (origin <= SI_USER)
#else
if (!abort_loop)
#endif #endif
{ {
int not_used; int not_used;
...@@ -3363,6 +3277,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) ...@@ -3363,6 +3277,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
break; /* purecov: tested */ break; /* purecov: tested */
} }
} }
DBUG_PRINT("quit", ("signal_handler: calling my_thread_end()"));
my_thread_end();
DBUG_LEAVE; // Must match DBUG_ENTER()
signal_thread_in_use= 0;
pthread_exit(0); // Safety
return(0); /* purecov: deadcode */ return(0); /* purecov: deadcode */
} }
...@@ -6285,16 +6204,11 @@ void handle_connections_sockets() ...@@ -6285,16 +6204,11 @@ void handle_connections_sockets()
uint error_count=0; uint error_count=0;
struct sockaddr_storage cAddr; struct sockaddr_storage cAddr;
int retval; int retval;
#ifdef HAVE_POLL
// for ip_sock, unix_sock and extra_ip_sock // for ip_sock, unix_sock and extra_ip_sock
Dynamic_array<struct pollfd> fds(PSI_INSTRUMENT_MEM); Dynamic_array<struct pollfd> fds(PSI_INSTRUMENT_MEM);
#else
fd_set readFDs,clientFDs;
#endif
DBUG_ENTER("handle_connections_sockets"); DBUG_ENTER("handle_connections_sockets");
#ifdef HAVE_POLL
for (size_t i= 0; i < listen_sockets.size(); i++) for (size_t i= 0; i < listen_sockets.size(); i++)
{ {
struct pollfd local_fds; struct pollfd local_fds;
...@@ -6304,27 +6218,25 @@ void handle_connections_sockets() ...@@ -6304,27 +6218,25 @@ void handle_connections_sockets()
fds.push(local_fds); fds.push(local_fds);
set_non_blocking_if_supported(listen_sockets.at(i)); set_non_blocking_if_supported(listen_sockets.at(i));
} }
#else int termination_fds[2];
FD_ZERO(&clientFDs); if (pipe(termination_fds))
for (size_t i= 0; i < listen_sockets.size(); i++)
{ {
int fd= mysql_socket_getfd(listen_sockets.at(i)); sql_print_error("pipe() failed %d", errno);
FD_SET(fd, &clientFDs); DBUG_VOID_RETURN;
set_non_blocking_if_supported(listen_sockets.at(i));
} }
#ifdef FD_CLOEXEC
for (int fd : termination_fds)
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif #endif
if (termination_event_fd >= 0)
{ mysql_mutex_lock(&LOCK_start_thread);
#ifdef HAVE_POLL termination_event_fd= termination_fds[1];
mysql_mutex_unlock(&LOCK_start_thread);
struct pollfd event_fd; struct pollfd event_fd;
event_fd.fd= termination_event_fd; event_fd.fd= termination_fds[0];
event_fd.events= POLLIN; event_fd.events= POLLIN;
fds.push(event_fd); fds.push(event_fd);
#else
FD_SET(termination_event_fd, &clientFDs);
#endif
/* no need to read this fd, abrt_loop is set before it gets a chance */
}
sd_notify(0, "READY=1\n" sd_notify(0, "READY=1\n"
"STATUS=Taking your SQL requests now...\n"); "STATUS=Taking your SQL requests now...\n");
...@@ -6332,12 +6244,7 @@ void handle_connections_sockets() ...@@ -6332,12 +6244,7 @@ void handle_connections_sockets()
DBUG_PRINT("general",("Waiting for connections.")); DBUG_PRINT("general",("Waiting for connections."));
while (!abort_loop) while (!abort_loop)
{ {
#ifdef HAVE_POLL
retval= poll(fds.get_pos(0), fds.size(), -1); retval= poll(fds.get_pos(0), fds.size(), -1);
#else
readFDs=clientFDs;
retval= select(FD_SETSIZE, &readFDs, NULL, NULL, NULL);
#endif
if (retval < 0) if (retval < 0)
{ {
...@@ -6359,7 +6266,6 @@ void handle_connections_sockets() ...@@ -6359,7 +6266,6 @@ void handle_connections_sockets()
break; break;
/* Is this a new connection request ? */ /* Is this a new connection request ? */
#ifdef HAVE_POLL
for (size_t i= 0; i < fds.size(); ++i) for (size_t i= 0; i < fds.size(); ++i)
{ {
if (fds.at(i).revents & POLLIN) if (fds.at(i).revents & POLLIN)
...@@ -6368,16 +6274,6 @@ void handle_connections_sockets() ...@@ -6368,16 +6274,6 @@ void handle_connections_sockets()
break; break;
} }
} }
#else // HAVE_POLL
for (size_t i=0; i < listen_sockets.size(); i++)
{
if (FD_ISSET(mysql_socket_getfd(listen_sockets.at(i)), &readFDs))
{
sock= listen_sockets.at(i);
break;
}
}
#endif // HAVE_POLL
for (uint retry=0; retry < MAX_ACCEPT_RETRY && !abort_loop; retry++) for (uint retry=0; retry < MAX_ACCEPT_RETRY && !abort_loop; retry++)
{ {
...@@ -6405,6 +6301,12 @@ void handle_connections_sockets() ...@@ -6405,6 +6301,12 @@ void handle_connections_sockets()
} }
} }
} }
mysql_mutex_lock(&LOCK_start_thread);
for(int fd : termination_fds)
close(fd);
termination_event_fd= -1;
mysql_mutex_unlock(&LOCK_start_thread);
sd_notify(0, "STOPPING=1\n" sd_notify(0, "STOPPING=1\n"
"STATUS=Shutdown in progress\n"); "STATUS=Shutdown in progress\n");
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
...@@ -3450,6 +3450,9 @@ int select_export::send_data(List<Item> &items) ...@@ -3450,6 +3450,9 @@ int select_export::send_data(List<Item> &items)
uint used_length=0,items_left=items.elements; uint used_length=0,items_left=items.elements;
List_iterator_fast<Item> li(items); List_iterator_fast<Item> li(items);
DBUG_EXECUTE_IF("select_export_kill", {
thd->killed= KILL_QUERY;
});
if (my_b_write(&cache,(uchar*) exchange->line_start->ptr(), if (my_b_write(&cache,(uchar*) exchange->line_start->ptr(),
exchange->line_start->length())) exchange->line_start->length()))
goto err; goto err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment