Commit d8f5d2be authored by Yuchen Pei's avatar Yuchen Pei

MDEV-22979 MDEV-27233 MDEV-28218 Fixing spider init bugs

Fix spider init bugs (MDEV-22979, MDEV-27233, MDEV-28218) while
preventing regression on old ones (MDEV-30370, MDEV-29904)

Two things are changed:

First, Spider initialisation is made fully synchronous, i.e. it no
longer happens in a background thread. Adapted from the original fix
by nayuta for MDEV-27233. This change itself would cause failure when
spider is initialised early, by plugin-load-add, due to dependency on
Aria and udf function creation, which are fixed in the second and
third parts below. Requires SQL Service, thus porting earlier versions
requires MDEV-27595

Second, if spider is initialised before udf_init(), create udf by
inserting into `mysql.func`, otherwise do it by `CREATE FUNCTION` as
usual. This change may be generalised in MDEV-31401.

Also factor out some clean-up queries from deinit_spider.inc for use
of spider init tests.

A minor caveat is that early spider initialisation will fail if the
server is bootstrapped for the first time, due to missing `mysql`
database which needs to be created by the bootstrap script.
parent afe63ec6
MDEV-22979 "mysqld --bootstrap" / mysql_install_db hangs when Spider is installed
# Kill the server
# restart
Warnings:
Note 1305 SONAME ha_spider.so does not exist
#
# MDEV-27233 Server hangs when using --init-file which loads Spider and creates a Spider table
#
show create table t;
Table Create Table
t CREATE TABLE `t` (
`c` int(11) DEFAULT NULL
) ENGINE=SPIDER DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
Warnings:
Error 1429 Unable to connect to foreign data source: localhost
Error 1429 Unable to connect to foreign data source: localhost
#
# MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
#
INSTALL SONAME 'ha_spider.so';
DROP TABLE IF EXISTS mysql.spider_tables;
show create table mysql.spider_tables;
ERROR 42S02: Table 'mysql.spider_tables' doesn't exist
Warnings:
Note 1051 Unknown table 'mysql.spider_tables'
#
# MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
#
show create table mysql.spider_tables;
ERROR 42S02: Table 'mysql.spider_tables' doesn't exist
#
# MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
#
show create table mysql.spider_tables;
ERROR 42S02: Table 'mysql.spider_tables' doesn't exist
#
# MDEV-30370 mariadbd hangs when running with --wsrep-recover and --plugin-load-add=ha_spider.so
#
# Kill the server
# restart
Warnings:
Note 1305 SONAME ha_spider.so does not exist
#
# plugin-load-add=ha_spider
#
select * from mysql.plugin;
name dl
create table t (c int) Engine=SPIDER;
drop table t;
#
# plugin-load-add=ha_spider
#
select * from mysql.plugin;
name dl
create table t (c int) Engine=SPIDER;
drop table t;
#
# Test that udf created by inserting into mysql_func works as expected
#
CREATE SERVER s_1 FOREIGN DATA WRAPPER mysql OPTIONS (
HOST 'localhost',
DATABASE 'auto_test_local',
USER 'root',
PASSWORD '',
SOCKET '$MASTER_1_MYSOCK'
);
CREATE SERVER s_2_1 FOREIGN DATA WRAPPER mysql OPTIONS (
HOST 'localhost',
DATABASE 'auto_test_remote',
USER 'root',
PASSWORD '',
SOCKET '$CHILD2_1_MYSOCK'
);
connect master_1, localhost, root, , , $MASTER_1_MYPORT, $MASTER_1_MYSOCK;
connect child2_1, localhost, root, , , $CHILD2_1_MYPORT, $CHILD2_1_MYSOCK;
connection child2_1;
CREATE DATABASE auto_test_remote;
USE auto_test_remote;
CREATE TABLE tbl_a (
a INT
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into tbl_a values (42);
connection master_1;
CREATE DATABASE auto_test_local;
USE auto_test_local;
CREATE TABLE tbl_a (
a INT
) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_a", srv "s_2_1"';
create temporary table results (a int);
SELECT SPIDER_DIRECT_SQL('select * from tbl_a', 'results', 'srv "s_2_1", database "auto_test_remote"');
SPIDER_DIRECT_SQL('select * from tbl_a', 'results', 'srv "s_2_1", database "auto_test_remote"')
1
select * from results;
a
42
connection master_1;
DROP DATABASE IF EXISTS auto_test_local;
connection child2_1;
DROP DATABASE IF EXISTS auto_test_remote;
udf_mysql_func_early.result
\ No newline at end of file
--echo MDEV-22979 "mysqld --bootstrap" / mysql_install_db hangs when Spider is installed
# This test is not the most faithful, as it does not have any
# dependency problems on the existence of the `mysql` database. To
# test MDEV-22979 faithfully, a mysql_install_db invocation with
# --plugin-load-add=ha_spider should be run. We cannot run it in mtr
# because we do not have access to --srcdir.
let $MYSQLD_DATADIR= `select @@datadir`;
let $PLUGIN_DIR=`select @@plugin_dir`;
--source include/kill_mysqld.inc
--write_file $MYSQLTEST_VARDIR/tmp/mdev_22979.sql
drop table if exists foo.bar;
EOF
--exec $MYSQLD_CMD --datadir=$MYSQLD_DATADIR --bootstrap --plugin-dir=$PLUGIN_DIR --plugin-load-add=ha_spider < $MYSQLTEST_VARDIR/tmp/mdev_22979.sql
--source include/start_mysqld.inc
--disable_query_log
--source ../../include/clean_up_spider.inc
--init-file=$MYSQL_TEST_DIR/../storage/spider/mysql-test/spider/bugfix/t/mdev_27233.sql
INSTALL SONAME 'ha_spider.so';
USE test;
CREATE TABLE t (c INT) ENGINE=SPIDER;
--echo #
--echo # MDEV-27233 Server hangs when using --init-file which loads Spider and creates a Spider table
--echo #
# ps protocol eats warnings
--disable_ps_protocol
show create table t;
--enable_ps_protocol
--echo #
--echo # MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
--echo #
INSTALL SONAME 'ha_spider.so';
DROP TABLE IF EXISTS mysql.spider_tables;
--error ER_NO_SUCH_TABLE
show create table mysql.spider_tables;
--disable_query_log
--source ../../include/clean_up_spider.inc
--init-file=$MYSQL_TEST_DIR/../storage/spider/mysql-test/spider/bugfix/t/mdev_28218_init_file.sql
INSTALL PLUGIN spider SONAME 'ha_spider.so';
DROP TABLE IF EXISTS mysql.spider_tables;
--echo #
--echo # MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
--echo #
# This is a variant of the testcase in MDEV-28218, where we put the
# queries are in an init file
--error ER_NO_SUCH_TABLE
show create table mysql.spider_tables;
--plugin-load-add=ha_spider
--init-file=$MYSQL_TEST_DIR/../storage/spider/mysql-test/spider/bugfix/t/mdev_28218_mixed.sql
--echo #
--echo # MDEV-28218 Spider: thread hang/deadlock as result of INSTALL PLUGIN and DROP TABLE
--echo #
# this is a variant of the testcase in MDEV-28218, where we load
# spider early with --plugin_load_add, and execute the drop table
# query in an init file
--error ER_NO_SUCH_TABLE
show create table mysql.spider_tables;
......@@ -3,4 +3,10 @@
--echo # MDEV-30370 mariadbd hangs when running with --wsrep-recover and --plugin-load-add=ha_spider.so
--echo #
--exec $MYSQLD_BOOTSTRAP_CMD --wsrep-recover --plugin-load-add=ha_spider.so
let $MYSQLD_DATADIR= `select @@datadir`;
let $PLUGIN_DIR=`select @@plugin_dir`;
--source include/kill_mysqld.inc
--exec $MYSQLD_CMD --datadir=$MYSQLD_DATADIR --wsrep-recover --plugin-dir=$PLUGIN_DIR --plugin-load-add=ha_spider
--source include/start_mysqld.inc
--disable_query_log
--source ../../include/clean_up_spider.inc
--echo #
--echo # plugin-load-add=ha_spider
--echo #
# A simple test that tests plugin-load-add=ha_spider
select * from mysql.plugin;
create table t (c int) Engine=SPIDER;
drop table t;
--echo #
--echo # plugin-load-add=ha_spider
--echo #
# A simple test that tests plugin-load-add=SPIDER=ha_spider
select * from mysql.plugin;
create table t (c int) Engine=SPIDER;
drop table t;
!include include/default_mysqld.cnf
!include ../my_1_1.cnf
!include ../my_2_1.cnf
--plugin-load-add=ha_spider
\ No newline at end of file
--echo #
--echo # Test that udf created by inserting into mysql_func works as expected
--echo #
evalp CREATE SERVER s_1 FOREIGN DATA WRAPPER mysql OPTIONS (
HOST 'localhost',
DATABASE 'auto_test_local',
USER 'root',
PASSWORD '',
SOCKET '$MASTER_1_MYSOCK'
);
evalp CREATE SERVER s_2_1 FOREIGN DATA WRAPPER mysql OPTIONS (
HOST 'localhost',
DATABASE 'auto_test_remote',
USER 'root',
PASSWORD '',
SOCKET '$CHILD2_1_MYSOCK'
);
--connect (master_1, localhost, root, , , $MASTER_1_MYPORT, $MASTER_1_MYSOCK)
--connect (child2_1, localhost, root, , , $CHILD2_1_MYPORT, $CHILD2_1_MYSOCK)
--connection child2_1
CREATE DATABASE auto_test_remote;
USE auto_test_remote;
eval CREATE TABLE tbl_a (
a INT
) $CHILD2_1_ENGINE $CHILD2_1_CHARSET;
insert into tbl_a values (42);
--connection master_1
CREATE DATABASE auto_test_local;
USE auto_test_local;
eval CREATE TABLE tbl_a (
a INT
) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_a", srv "s_2_1"';
create temporary table results (a int);
--disable_ps_protocol
SELECT SPIDER_DIRECT_SQL('select * from tbl_a', 'results', 'srv "s_2_1", database "auto_test_remote"');
--enable_ps_protocol
select * from results;
--connection master_1
DROP DATABASE IF EXISTS auto_test_local;
--connection child2_1
DROP DATABASE IF EXISTS auto_test_remote;
!include include/default_mysqld.cnf
!include ../my_1_1.cnf
!include ../my_2_1.cnf
--init-file=$MYSQL_TEST_DIR/../storage/spider/mysql-test/spider/bugfix/t/udf_mysql_func_early_init_file.sql
# Same as udf_mysql_func_early.test, except that we load spider in
# init_file, which is after udf_init() and before
# mysqld_server_started is on.
--source udf_mysql_func_early.test
......@@ -568,7 +568,6 @@ typedef struct st_spider_thread
volatile bool killed;
volatile bool thd_wait;
volatile bool first_free_wait;
volatile bool init_command;
volatile int error;
pthread_t thread;
pthread_cond_t cond;
......
......@@ -585,56 +585,52 @@ static LEX_STRING spider_init_queries[] = {
" engine=Aria transactional=1;"
"end if;"
)},
/*
Install UDFs
*/
{C_STRING_WITH_LEN(
"set @win_plugin := IF(@@version_compile_os like 'Win%', 1, 0);"
)},
/* Install UDFs. If udf is not initialised, then install by
inserting into mysql.func */
{C_STRING_WITH_LEN(
"if @win_plugin = 0 then"
" create function if not exists spider_direct_sql returns int"
" soname 'ha_spider.so';"
"else"
" create function if not exists spider_direct_sql returns int"
" soname 'ha_spider.dll';"
"end if;"
)},
{C_STRING_WITH_LEN(
"if @win_plugin = 0 then"
" create aggregate function if not exists spider_bg_direct_sql returns int"
" soname 'ha_spider.so';"
"else"
" create aggregate function if not exists spider_bg_direct_sql returns int"
" soname 'ha_spider.dll';"
"end if;"
)},
{C_STRING_WITH_LEN(
"if @win_plugin = 0 then"
" create function if not exists spider_ping_table returns int"
" soname 'ha_spider.so';"
" begin not atomic"
" declare exit handler for 1041, 1123"
" insert into mysql.func values"
" ('spider_direct_sql', 2, 'ha_spider.so', 'function'),"
" ('spider_bg_direct_sql', 2, 'ha_spider.so', 'aggregate'),"
" ('spider_ping_table', 2, 'ha_spider.so', 'function'),"
" ('spider_copy_tables', 2, 'ha_spider.so', 'function'),"
" ('spider_flush_table_mon_cache', 2, 'ha_spider.so', 'function');"
" create function if not exists spider_direct_sql returns int"
" soname 'ha_spider.so';"
" create aggregate function if not exists spider_bg_direct_sql returns int"
" soname 'ha_spider.so';"
" create function if not exists spider_ping_table returns int"
" soname 'ha_spider.so';"
" create function if not exists spider_copy_tables returns int"
" soname 'ha_spider.so';"
" create function if not exists spider_flush_table_mon_cache returns int"
" soname 'ha_spider.so';"
" end;"
"else"
" create function if not exists spider_ping_table returns int"
" soname 'ha_spider.dll';"
" begin not atomic"
" declare exit handler for 1041, 1123"
" insert into mysql.func values"
" ('spider_direct_sql', 2, 'ha_spider.dll', 'function'),"
" ('spider_bg_direct_sql', 2, 'ha_spider.dll', 'aggregate'),"
" ('spider_ping_table', 2, 'ha_spider.dll', 'function'),"
" ('spider_copy_tables', 2, 'ha_spider.dll', 'function'),"
" ('spider_flush_table_mon_cache', 2, 'ha_spider.dll', 'function');"
" create function if not exists spider_direct_sql returns int"
" soname 'ha_spider.dll';"
" create aggregate function if not exists spider_bg_direct_sql returns int"
" soname 'ha_spider.dll';"
" create function if not exists spider_ping_table returns int"
" soname 'ha_spider.dll';"
" create function if not exists spider_copy_tables returns int"
" soname 'ha_spider.dll';"
" create function if not exists spider_flush_table_mon_cache returns int"
" soname 'ha_spider.dll';"
" end;"
"end if;"
)},
{C_STRING_WITH_LEN(
"if @win_plugin = 0 then"
" create function if not exists spider_copy_tables returns int"
" soname 'ha_spider.so';"
"else"
" create function if not exists spider_copy_tables returns int"
" soname 'ha_spider.dll';"
"end if;"
)},
{C_STRING_WITH_LEN(
"if @win_plugin = 0 then"
" create function if not exists spider_flush_table_mon_cache returns int"
" soname 'ha_spider.so';"
"else"
" create function if not exists spider_flush_table_mon_cache returns int"
" soname 'ha_spider.dll';"
"end if;"
)},
{C_STRING_WITH_LEN("")}
)}
};
......@@ -129,9 +129,6 @@ const char **spd_mysqld_unix_port;
uint *spd_mysqld_port;
bool volatile *spd_abort_loop;
Time_zone *spd_tz_system;
static int *spd_mysqld_server_started;
static pthread_mutex_t *spd_LOCK_server_started;
static pthread_cond_t *spd_COND_server_started;
extern long spider_conn_mutex_id;
handlerton *spider_hton_ptr;
SPIDER_DBTON spider_dbton[SPIDER_DBTON_SIZE];
......@@ -6316,30 +6313,6 @@ handler* spider_create_handler(
MEM_ROOT *mem_root
) {
DBUG_ENTER("spider_create_handler");
#ifndef WITHOUT_SPIDER_BG_SEARCH
SPIDER_THREAD *thread = &spider_table_sts_threads[0];
if (unlikely(thread->init_command))
{
THD *thd = current_thd;
pthread_cond_t *cond = thd->mysys_var->current_cond;
pthread_mutex_t *mutex = thd->mysys_var->current_mutex;
/* wait for finishing init_command */
pthread_mutex_lock(&thread->mutex);
if (unlikely(thread->init_command))
{
thd->mysys_var->current_cond = &thread->sync_cond;
thd->mysys_var->current_mutex = &thread->mutex;
pthread_cond_wait(&thread->sync_cond, &thread->mutex);
}
pthread_mutex_unlock(&thread->mutex);
thd->mysys_var->current_cond = cond;
thd->mysys_var->current_mutex = mutex;
if (thd->killed)
{
DBUG_RETURN(NULL);
}
}
#endif
DBUG_RETURN(new (mem_root) ha_spider(hton, table));
}
......@@ -6640,6 +6613,50 @@ int spider_panic(
DBUG_RETURN(0);
}
/*
Create or fix the system tables. See spd_init_query.h for the details.
*/
bool spider_init_system_tables()
{
DBUG_ENTER("spider_init_system_tables");
MYSQL *mysql= mysql_init(NULL);
if (!mysql)
{
DBUG_RETURN(TRUE);
}
if (!mysql_real_connect_local(mysql))
{
mysql_close(mysql);
DBUG_RETURN(TRUE);
}
const int size= sizeof(spider_init_queries) / sizeof(spider_init_queries[0]);
for (int i= 0; i < size; i++)
{
const LEX_STRING *query= &spider_init_queries[i];
if (mysql_real_query(mysql, query->str, query->length))
{
fprintf(stderr,
"[ERROR] SPIDER plugin initialization failed at '%s' by '%s'\n",
query->str, mysql_error(mysql));
mysql_close(mysql);
DBUG_RETURN(TRUE);
}
if (MYSQL_RES *res= mysql_store_result(mysql))
{
mysql_free_result(res);
}
}
mysql_close(mysql);
DBUG_RETURN(FALSE);
}
int spider_db_init(
void *p
) {
......@@ -6647,6 +6664,11 @@ int spider_db_init(
uint dbton_id = 0;
handlerton *spider_hton = (handlerton *)p;
DBUG_ENTER("spider_db_init");
const LEX_CSTRING aria_name={STRING_WITH_LEN("Aria")};
if (!plugin_is_ready(&aria_name, MYSQL_STORAGE_ENGINE_PLUGIN))
DBUG_RETURN(HA_ERR_RETRY_INIT);
spider_hton_ptr = spider_hton;
spider_hton->state = SHOW_OPTION_YES;
......@@ -6743,13 +6765,6 @@ int spider_db_init(
#else
GetProcAddress(current_module, "?my_tz_SYSTEM@@3PAVTime_zone@@A");
#endif
spd_mysqld_server_started = (int *)
GetProcAddress(current_module, "?mysqld_server_started@@3HA");
spd_LOCK_server_started = (pthread_mutex_t *)
GetProcAddress(current_module,
"?LOCK_server_started@@3Ust_mysql_mutex@@A");
spd_COND_server_started = (pthread_cond_t *)
GetProcAddress(current_module, "?COND_server_started@@3Ust_mysql_cond@@A");
#else
#ifndef SPIDER_HAS_NEXT_THREAD_ID
spd_db_att_thread_id = &thread_id;
......@@ -6772,9 +6787,6 @@ int spider_db_init(
spd_mysqld_port = &mysqld_port;
spd_abort_loop = &abort_loop;
spd_tz_system = my_tz_SYSTEM;
spd_mysqld_server_started = &mysqld_server_started;
spd_LOCK_server_started = &LOCK_server_started;
spd_COND_server_started = &COND_server_started;
#endif
#ifdef HAVE_PSI_INTERFACE
......@@ -7050,6 +7062,11 @@ int spider_db_init(
spider_udf_table_mon_list_hash[roop_count].array.size_of_element);
}
if (spider_init_system_tables())
{
goto error_system_table_creation;
}
#ifndef WITHOUT_SPIDER_BG_SEARCH
if (!(spider_table_sts_threads = (SPIDER_THREAD *)
spider_bulk_malloc(NULL, SPD_MID_DB_INIT_12, MYF(MY_WME | MY_ZEROFILL),
......@@ -7060,7 +7077,6 @@ int spider_db_init(
NullS))
)
goto error_alloc_mon_mutxes;
spider_table_sts_threads[0].init_command = TRUE;
for (roop_count = 0;
roop_count < (int) spider_param_table_sts_thread_count();
......@@ -7151,6 +7167,7 @@ int spider_db_init(
error_init_udf_table_mon_cond:
for (; roop_count >= 0; roop_count--)
pthread_cond_destroy(&spider_udf_table_mon_conds[roop_count]);
error_system_table_creation:
roop_count = spider_param_udf_table_mon_mutex_count() - 1;
error_init_udf_table_mon_mutex:
for (; roop_count >= 0; roop_count--)
......@@ -9557,7 +9574,6 @@ void spider_free_sts_threads(
) {
bool thread_killed;
DBUG_ENTER("spider_free_sts_threads");
spider_thread->init_command = FALSE;
pthread_mutex_lock(&spider_thread->mutex);
thread_killed = spider_thread->killed;
spider_thread->killed = TRUE;
......@@ -9708,59 +9724,6 @@ void *spider_table_bg_sts_action(
trx->thd = thd;
/* init end */
if (thread->init_command)
{
uint i = 0;
tmp_disable_binlog(thd);
thd->security_ctx->skip_grants();
thd->client_capabilities |= CLIENT_MULTI_RESULTS;
if (!(*spd_mysqld_server_started) && !thd->killed && !thread->killed)
{
pthread_mutex_lock(spd_LOCK_server_started);
thd->mysys_var->current_cond = spd_COND_server_started;
thd->mysys_var->current_mutex = spd_LOCK_server_started;
if (!(*spd_mysqld_server_started) && !thd->killed && !thread->killed &&
thread->init_command)
{
do
{
struct timespec abstime;
set_timespec_nsec(abstime, 1000);
error_num = pthread_cond_timedwait(spd_COND_server_started,
spd_LOCK_server_started, &abstime);
} while (
(error_num == ETIMEDOUT || error_num == ETIME) &&
!(*spd_mysqld_server_started) && !thd->killed && !thread->killed &&
thread->init_command
);
}
pthread_mutex_unlock(spd_LOCK_server_started);
thd->mysys_var->current_cond = &thread->cond;
thd->mysys_var->current_mutex = &thread->mutex;
}
bool spd_wsrep_on = thd->variables.wsrep_on;
thd->variables.wsrep_on = false;
while (spider_init_queries[i].length && !thd->killed && !thread->killed &&
thread->init_command)
{
dispatch_command(COM_QUERY, thd, spider_init_queries[i].str,
(uint) spider_init_queries[i].length, FALSE, FALSE);
if (unlikely(thd->is_error()))
{
fprintf(stderr, "[ERROR] %s\n", spider_stmt_da_message(thd));
thd->clear_error();
break;
}
++i;
}
thd->variables.wsrep_on = spd_wsrep_on;
thd->mysys_var->current_cond = &thread->cond;
thd->mysys_var->current_mutex = &thread->mutex;
thd->client_capabilities -= CLIENT_MULTI_RESULTS;
reenable_binlog(thd);
thread->init_command = FALSE;
pthread_cond_broadcast(&thread->sync_cond);
}
if (thd->killed)
{
thread->killed = TRUE;
......
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