mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-27161: Add option for SQL thread to limit maximum execution time per query replicated
New Feature: ============ This patch adds a new system variable, @@slave_max_statement_time, which limits the execution time of s slave’s events that implements an equivalent to @@max_statement_time for slave applier. Reviewed By: ============ Andrei Elkin <andrei.elkin@mariadb.com>
This commit is contained in:
committed by
Andrei
parent
7864d955f3
commit
360d99429c
@@ -1223,6 +1223,11 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
--slave-max-allowed-packet=#
|
--slave-max-allowed-packet=#
|
||||||
The maximum packet length to sent successfully from the
|
The maximum packet length to sent successfully from the
|
||||||
master to slave.
|
master to slave.
|
||||||
|
--slave-max-statement-time=#
|
||||||
|
A query that has taken more than slave_max_statement_time
|
||||||
|
seconds to run on the slave will be aborted. The argument
|
||||||
|
will be treated as a decimal value with microsecond
|
||||||
|
precision. A value of 0 (default) means no timeout
|
||||||
--slave-net-timeout=#
|
--slave-net-timeout=#
|
||||||
Number of seconds to wait for more data from any
|
Number of seconds to wait for more data from any
|
||||||
master/slave connection before aborting the read
|
master/slave connection before aborting the read
|
||||||
@@ -1800,6 +1805,7 @@ slave-ddl-exec-mode IDEMPOTENT
|
|||||||
slave-domain-parallel-threads 0
|
slave-domain-parallel-threads 0
|
||||||
slave-exec-mode STRICT
|
slave-exec-mode STRICT
|
||||||
slave-max-allowed-packet 1073741824
|
slave-max-allowed-packet 1073741824
|
||||||
|
slave-max-statement-time 0
|
||||||
slave-net-timeout 60
|
slave-net-timeout 60
|
||||||
slave-parallel-max-queued 131072
|
slave-parallel-max-queued 131072
|
||||||
slave-parallel-mode conservative
|
slave-parallel-mode conservative
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
#
|
||||||
|
# Helper test file to ensure that an event running on a slave which executes
|
||||||
|
# for longer than @@slave_max_statement_time will time out. By default, it will
|
||||||
|
# use the sleep function to imitate a long running function. This can be
|
||||||
|
# changed to use locks using the parameter with_lock.
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# with_lock (boolean, in) : Changes the long running command from using SLEEP
|
||||||
|
# to using locks. In particular, the MTR test will take the table level
|
||||||
|
# write lock on the slave side, while the slave concurrently tries to
|
||||||
|
# execute an insert statement.
|
||||||
|
#
|
||||||
|
# use_load_data (boolean, in) : If in row logging format, uses LOAD DATA
|
||||||
|
# INFILLE command to create Load_log_events to create the events which
|
||||||
|
# should time out
|
||||||
|
#
|
||||||
|
|
||||||
|
--connection master
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a)) engine=InnoDB;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET GLOBAL slave_max_statement_time=0.75;
|
||||||
|
|
||||||
|
--connection master
|
||||||
|
--echo # Long running command due to a lock conflict
|
||||||
|
if (!$use_load_data)
|
||||||
|
{
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
}
|
||||||
|
if ($use_load_data)
|
||||||
|
{
|
||||||
|
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
|
||||||
|
}
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
BEGIN; INSERT INTO t1(b) VALUES (1);
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
|
||||||
|
--echo # Starting slave to receive event which will take longer to execute
|
||||||
|
--echo # than slave_max_statement_time
|
||||||
|
START SLAVE;
|
||||||
|
|
||||||
|
# ER_SLAVE_STATEMENT_TIMEOUT
|
||||||
|
--let $slave_sql_errno= 4192
|
||||||
|
--source include/wait_for_slave_sql_error.inc
|
||||||
|
|
||||||
|
--echo # Ensuring event was not processed..
|
||||||
|
--let $t1_count= `select count(*) from t1`
|
||||||
|
if ($t1_count != 0)
|
||||||
|
{
|
||||||
|
--die Event should have timed out on the slave and not been executed
|
||||||
|
}
|
||||||
|
--echo # ..success
|
||||||
|
|
||||||
|
--echo # Remove slave timeout and catch up to master
|
||||||
|
SET GLOBAL slave_max_statement_time=0;
|
||||||
|
|
||||||
|
--connection slave1
|
||||||
|
ROLLBACK;
|
||||||
|
|
||||||
|
--source include/start_slave.inc
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
|
||||||
|
--echo # Test case cleanup
|
||||||
|
--connection master
|
||||||
|
DROP TABLE t1;
|
||||||
|
--source include/save_master_gtid.inc
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/sync_with_master_gtid.inc
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
--source include/start_slave.inc
|
170
mysql-test/suite/rpl/r/rpl_slave_max_statement_time.result
Normal file
170
mysql-test/suite/rpl/r/rpl_slave_max_statement_time.result
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
include/master-slave.inc
|
||||||
|
[connection master]
|
||||||
|
#
|
||||||
|
# Set up
|
||||||
|
#
|
||||||
|
connection master;
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
connection slave;
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Slave log event execution was interrupted");
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
SET @save_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
#
|
||||||
|
# Test Case 1) Using a serial slave, the SQL thread should time out when
|
||||||
|
# its underlying event executes for longer than @@slave_max_statement_time.
|
||||||
|
#
|
||||||
|
connection master;
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a)) engine=InnoDB;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET GLOBAL slave_max_statement_time=0.75;
|
||||||
|
connection master;
|
||||||
|
# Long running command due to a lock conflict
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
connection slave;
|
||||||
|
# Starting slave to receive event which will take longer to execute
|
||||||
|
# than slave_max_statement_time
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_sql_error.inc [errno=4192]
|
||||||
|
# Ensuring event was not processed..
|
||||||
|
# ..success
|
||||||
|
# Remove slave timeout and catch up to master
|
||||||
|
SET GLOBAL slave_max_statement_time=0;
|
||||||
|
connection slave1;
|
||||||
|
ROLLBACK;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
# Test case cleanup
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
include/start_slave.inc
|
||||||
|
#
|
||||||
|
# Test Case 2) Using a parallel slave, a worker thread should time out
|
||||||
|
# when its underlying event executes for longer than
|
||||||
|
# @@slave_max_statement_time
|
||||||
|
#
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
|
||||||
|
SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=2;
|
||||||
|
SET GLOBAL slave_parallel_mode='optimistic';
|
||||||
|
include/start_slave.inc
|
||||||
|
connection master;
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a)) engine=InnoDB;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET GLOBAL slave_max_statement_time=0.75;
|
||||||
|
connection master;
|
||||||
|
# Long running command due to a lock conflict
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
connection slave;
|
||||||
|
# Starting slave to receive event which will take longer to execute
|
||||||
|
# than slave_max_statement_time
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_sql_error.inc [errno=4192]
|
||||||
|
# Ensuring event was not processed..
|
||||||
|
# ..success
|
||||||
|
# Remove slave timeout and catch up to master
|
||||||
|
SET GLOBAL slave_max_statement_time=0;
|
||||||
|
connection slave1;
|
||||||
|
ROLLBACK;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
# Test case cleanup
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=@old_parallel_threads;
|
||||||
|
include/start_slave.inc
|
||||||
|
#
|
||||||
|
# Test Case 3) Load-based log events (from LOAD DATA INFILE) should time
|
||||||
|
# out if their execution time exceeds @@slave_max_statement_time
|
||||||
|
#
|
||||||
|
connection master;
|
||||||
|
create table t1(a int not null auto_increment, b int, primary key(a)) engine=InnoDB;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET GLOBAL slave_max_statement_time=0.75;
|
||||||
|
connection master;
|
||||||
|
# Long running command due to a lock conflict
|
||||||
|
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave1;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1(b) VALUES (1);
|
||||||
|
connection slave;
|
||||||
|
# Starting slave to receive event which will take longer to execute
|
||||||
|
# than slave_max_statement_time
|
||||||
|
START SLAVE;
|
||||||
|
include/wait_for_slave_sql_error.inc [errno=4192]
|
||||||
|
# Ensuring event was not processed..
|
||||||
|
# ..success
|
||||||
|
# Remove slave timeout and catch up to master
|
||||||
|
SET GLOBAL slave_max_statement_time=0;
|
||||||
|
connection slave1;
|
||||||
|
ROLLBACK;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
# Test case cleanup
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1;
|
||||||
|
include/save_master_gtid.inc
|
||||||
|
connection slave;
|
||||||
|
include/sync_with_master_gtid.inc
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
include/start_slave.inc
|
||||||
|
#
|
||||||
|
# Test Case 4) Locally executed long running statements should not time
|
||||||
|
# out due to @@slave_max_statement_time
|
||||||
|
#
|
||||||
|
connection slave;
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET @old_gtid_domain_id=@@GLOBAL.gtid_domain_id;
|
||||||
|
SET @@GLOBAL.slave_max_statement_time=0.75;
|
||||||
|
SET @@GLOBAL.gtid_domain_id=1;
|
||||||
|
include/start_slave.inc
|
||||||
|
CREATE TABLE t2 (a int);
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR INSERT INTO t2 SELECT SLEEP(1);
|
||||||
|
DROP TABLE t2;
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_domain_id=@old_gtid_domain_id;
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
include/start_slave.inc
|
||||||
|
# Cleanup
|
||||||
|
include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@save_slave_max_statement_time;
|
||||||
|
include/start_slave.inc
|
||||||
|
include/rpl_end.inc
|
||||||
|
# End of rpl_slave_max_statement_time.test
|
110
mysql-test/suite/rpl/t/rpl_slave_max_statement_time.test
Normal file
110
mysql-test/suite/rpl/t/rpl_slave_max_statement_time.test
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#
|
||||||
|
# Purpose:
|
||||||
|
# This test ensures that the slave can limit the execution time of its
|
||||||
|
# events via the global system variable @@slave_max_statement_time.
|
||||||
|
#
|
||||||
|
# Methodology:
|
||||||
|
# This test uses the following test cases to ensure that a slave will
|
||||||
|
# correctly limit the execution time of its events:
|
||||||
|
# 1) Using a serial slave, the SQL thread should time out when its underlying
|
||||||
|
# event executes for longer than @@slave_max_statement_time.
|
||||||
|
# 2) Using a parallel slave, a worker thread should time out when its
|
||||||
|
# underlying event executes for longer than @@slave_max_statement_time.
|
||||||
|
# 3) Load-based log events (from LOAD DATA INFILE) should time out if their
|
||||||
|
# execution time exceeds @@slave_max_statement_time
|
||||||
|
# 4) Locally executed long running statements should not time out due to
|
||||||
|
# @@slave_max_statement_time.
|
||||||
|
#
|
||||||
|
# References:
|
||||||
|
# MDEV-27161: Add option for SQL thread to limit maximum execution time per
|
||||||
|
# query replicated
|
||||||
|
#
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/master-slave.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Set up
|
||||||
|
--echo #
|
||||||
|
--connection master
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
--connection slave
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Slave log event execution was interrupted");
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||||
|
SET @save_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
|
||||||
|
--let $with_lock= 1
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test Case 1) Using a serial slave, the SQL thread should time out when
|
||||||
|
--echo # its underlying event executes for longer than @@slave_max_statement_time.
|
||||||
|
--echo #
|
||||||
|
--source include/rpl_slave_max_statement_time.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test Case 2) Using a parallel slave, a worker thread should time out
|
||||||
|
--echo # when its underlying event executes for longer than
|
||||||
|
--echo # @@slave_max_statement_time
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
|
||||||
|
SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=2;
|
||||||
|
SET GLOBAL slave_parallel_mode='optimistic';
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--source include/rpl_slave_max_statement_time.inc
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||||
|
SET GLOBAL slave_parallel_threads=@old_parallel_threads;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test Case 3) Load-based log events (from LOAD DATA INFILE) should time
|
||||||
|
--echo # out if their execution time exceeds @@slave_max_statement_time
|
||||||
|
--echo #
|
||||||
|
--let $use_load_data= 1
|
||||||
|
--source include/rpl_slave_max_statement_time.inc
|
||||||
|
--let $use_load_data=
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test Case 4) Locally executed long running statements should not time
|
||||||
|
--echo # out due to @@slave_max_statement_time
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--connection slave
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time;
|
||||||
|
SET @old_gtid_domain_id=@@GLOBAL.gtid_domain_id;
|
||||||
|
SET @@GLOBAL.slave_max_statement_time=0.75;
|
||||||
|
SET @@GLOBAL.gtid_domain_id=1;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
CREATE TABLE t2 (a int);
|
||||||
|
SET STATEMENT sql_log_bin=0 FOR INSERT INTO t2 SELECT SLEEP(1);
|
||||||
|
--let $t2_count= `SELECT COUNT(*) FROM t2`
|
||||||
|
if ($t2_count != 1)
|
||||||
|
{
|
||||||
|
--die Local long running insert statement should have completed
|
||||||
|
}
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL gtid_domain_id=@old_gtid_domain_id;
|
||||||
|
SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo # Cleanup
|
||||||
|
--source include/stop_slave.inc
|
||||||
|
SET GLOBAL slave_max_statement_time=@save_slave_max_statement_time;
|
||||||
|
--source include/start_slave.inc
|
||||||
|
|
||||||
|
--source include/rpl_end.inc
|
||||||
|
|
||||||
|
--echo # End of rpl_slave_max_statement_time.test
|
@@ -3722,6 +3722,16 @@ NUMERIC_BLOCK_SIZE 1024
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY NO
|
READ_ONLY NO
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME SLAVE_MAX_STATEMENT_TIME
|
||||||
|
VARIABLE_SCOPE GLOBAL
|
||||||
|
VARIABLE_TYPE DOUBLE
|
||||||
|
VARIABLE_COMMENT A query that has taken more than slave_max_statement_time seconds to run on the slave will be aborted. The argument will be treated as a decimal value with microsecond precision. A value of 0 (default) means no timeout
|
||||||
|
NUMERIC_MIN_VALUE 0
|
||||||
|
NUMERIC_MAX_VALUE 31536000
|
||||||
|
NUMERIC_BLOCK_SIZE NULL
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME SLAVE_NET_TIMEOUT
|
VARIABLE_NAME SLAVE_NET_TIMEOUT
|
||||||
VARIABLE_SCOPE GLOBAL
|
VARIABLE_SCOPE GLOBAL
|
||||||
VARIABLE_TYPE INT UNSIGNED
|
VARIABLE_TYPE INT UNSIGNED
|
||||||
|
@@ -200,7 +200,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
|
|||||||
err->get_sql_errno());
|
err->get_sql_errno());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ha_error != 0)
|
if (ha_error != 0 && !thd->killed)
|
||||||
rli->report(level, errcode, rgi->gtid_info(),
|
rli->report(level, errcode, rgi->gtid_info(),
|
||||||
"Could not execute %s event on table %s.%s;"
|
"Could not execute %s event on table %s.%s;"
|
||||||
"%s handler error %s; "
|
"%s handler error %s; "
|
||||||
@@ -5728,6 +5728,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
*/
|
*/
|
||||||
DBUG_ASSERT(rgi->thd == thd);
|
DBUG_ASSERT(rgi->thd == thd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Where a Query_log_event can rely on the normal command execution logic to
|
||||||
|
set/reset the slave thread's timer; a Rows_log_event update needs to set
|
||||||
|
the timer itself
|
||||||
|
*/
|
||||||
|
thd->set_query_timer();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If there is no locks taken, this is the first binrow event seen
|
If there is no locks taken, this is the first binrow event seen
|
||||||
after the table map events. We should then lock all the tables
|
after the table map events. We should then lock all the tables
|
||||||
@@ -6120,6 +6127,12 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
if (likely(error == 0) && !transactional_table)
|
if (likely(error == 0) && !transactional_table)
|
||||||
thd->transaction->all.modified_non_trans_table=
|
thd->transaction->all.modified_non_trans_table=
|
||||||
thd->transaction->stmt.modified_non_trans_table= TRUE;
|
thd->transaction->stmt.modified_non_trans_table= TRUE;
|
||||||
|
if (likely(error == 0))
|
||||||
|
{
|
||||||
|
error= thd->killed_errno();
|
||||||
|
if (error && !thd->is_error())
|
||||||
|
my_error(error, MYF(0));
|
||||||
|
}
|
||||||
} // row processing loop
|
} // row processing loop
|
||||||
while (error == 0 && (m_curr_row != m_rows_end));
|
while (error == 0 && (m_curr_row != m_rows_end));
|
||||||
|
|
||||||
@@ -6189,11 +6202,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
|
free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thd->reset_query_timer();
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
restore_empty_query_table_list(thd->lex);
|
restore_empty_query_table_list(thd->lex);
|
||||||
rgi->slave_close_thread_tables(thd);
|
rgi->slave_close_thread_tables(thd);
|
||||||
|
thd->reset_query_timer();
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -461,6 +461,8 @@ ulonglong binlog_cache_size=0;
|
|||||||
ulonglong binlog_file_cache_size=0;
|
ulonglong binlog_file_cache_size=0;
|
||||||
ulonglong max_binlog_cache_size=0;
|
ulonglong max_binlog_cache_size=0;
|
||||||
ulong slave_max_allowed_packet= 0;
|
ulong slave_max_allowed_packet= 0;
|
||||||
|
double slave_max_statement_time_double;
|
||||||
|
ulonglong slave_max_statement_time;
|
||||||
ulonglong binlog_stmt_cache_size=0;
|
ulonglong binlog_stmt_cache_size=0;
|
||||||
ulonglong max_binlog_stmt_cache_size=0;
|
ulonglong max_binlog_stmt_cache_size=0;
|
||||||
ulonglong test_flags;
|
ulonglong test_flags;
|
||||||
@@ -8718,6 +8720,8 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
|
|||||||
max_relay_log_size_var->option.def_value=
|
max_relay_log_size_var->option.def_value=
|
||||||
max_binlog_size_var->option.def_value;
|
max_binlog_size_var->option.def_value;
|
||||||
}
|
}
|
||||||
|
slave_max_statement_time=
|
||||||
|
double2ulonglong(slave_max_statement_time_double * 1e6);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -244,6 +244,8 @@ extern ulonglong binlog_cache_size, binlog_stmt_cache_size, binlog_file_cache_si
|
|||||||
extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
|
extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
|
||||||
extern ulong max_binlog_size;
|
extern ulong max_binlog_size;
|
||||||
extern ulong slave_max_allowed_packet;
|
extern ulong slave_max_allowed_packet;
|
||||||
|
extern ulonglong slave_max_statement_time;
|
||||||
|
extern double slave_max_statement_time_double;
|
||||||
extern ulong opt_binlog_rows_event_max_size;
|
extern ulong opt_binlog_rows_event_max_size;
|
||||||
extern ulong binlog_row_metadata;
|
extern ulong binlog_row_metadata;
|
||||||
extern ulong thread_cache_size;
|
extern ulong thread_cache_size;
|
||||||
|
@@ -570,6 +570,8 @@ constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_EXEC_MODE=
|
|||||||
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
||||||
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_ALLOWED_PACKET=
|
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_ALLOWED_PACKET=
|
||||||
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
||||||
|
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_STATEMENT_TIME=
|
||||||
|
REPL_SLAVE_ADMIN_ACL;
|
||||||
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT=
|
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT=
|
||||||
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
|
||||||
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MAX_QUEUED=
|
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MAX_QUEUED=
|
||||||
|
@@ -10078,3 +10078,5 @@ WARN_OPTION_CHANGING
|
|||||||
eng "%s is implicitly changing the value of '%s' from '%s' to '%s'"
|
eng "%s is implicitly changing the value of '%s' from '%s' to '%s'"
|
||||||
ER_CM_OPTION_MISSING_REQUIREMENT
|
ER_CM_OPTION_MISSING_REQUIREMENT
|
||||||
eng "CHANGE MASTER TO option '%s=%s' is missing requirement %s"
|
eng "CHANGE MASTER TO option '%s=%s' is missing requirement %s"
|
||||||
|
ER_SLAVE_STATEMENT_TIMEOUT 70100
|
||||||
|
eng "Slave log event execution was interrupted (slave_max_statement_time exceeded)"
|
||||||
|
@@ -2095,7 +2095,8 @@ int THD::killed_errno()
|
|||||||
DBUG_RETURN(ER_QUERY_INTERRUPTED);
|
DBUG_RETURN(ER_QUERY_INTERRUPTED);
|
||||||
case KILL_TIMEOUT:
|
case KILL_TIMEOUT:
|
||||||
case KILL_TIMEOUT_HARD:
|
case KILL_TIMEOUT_HARD:
|
||||||
DBUG_RETURN(ER_STATEMENT_TIMEOUT);
|
DBUG_RETURN(slave_thread ?
|
||||||
|
ER_SLAVE_STATEMENT_TIMEOUT : ER_STATEMENT_TIMEOUT);
|
||||||
case KILL_SERVER:
|
case KILL_SERVER:
|
||||||
case KILL_SERVER_HARD:
|
case KILL_SERVER_HARD:
|
||||||
DBUG_RETURN(ER_SERVER_SHUTDOWN);
|
DBUG_RETURN(ER_SERVER_SHUTDOWN);
|
||||||
|
@@ -5431,24 +5431,29 @@ public:
|
|||||||
void set_query_timer()
|
void set_query_timer()
|
||||||
{
|
{
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
|
/*
|
||||||
|
Slave vs user threads have timeouts configured via different variables,
|
||||||
|
so pick the appropriate one to use.
|
||||||
|
*/
|
||||||
|
ulonglong timeout_val=
|
||||||
|
slave_thread ? slave_max_statement_time : variables.max_statement_time;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Don't start a query timer if
|
Don't start a query timer if
|
||||||
- If timeouts are not set
|
- If timeouts are not set
|
||||||
- if we are in a stored procedure or sub statement
|
- if we are in a stored procedure or sub statement
|
||||||
- If this is a slave thread
|
|
||||||
- If we already have set a timeout (happens when running prepared
|
- If we already have set a timeout (happens when running prepared
|
||||||
statements that calls mysql_execute_command())
|
statements that calls mysql_execute_command())
|
||||||
*/
|
*/
|
||||||
if (!variables.max_statement_time || spcont || in_sub_stmt ||
|
if (!timeout_val || spcont || in_sub_stmt || query_timer.expired == 0)
|
||||||
slave_thread || query_timer.expired == 0)
|
|
||||||
return;
|
return;
|
||||||
thr_timer_settime(&query_timer, variables.max_statement_time);
|
thr_timer_settime(&query_timer, timeout_val);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void reset_query_timer()
|
void reset_query_timer()
|
||||||
{
|
{
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
if (spcont || in_sub_stmt || slave_thread)
|
if (spcont || in_sub_stmt)
|
||||||
return;
|
return;
|
||||||
if (!query_timer.expired)
|
if (!query_timer.expired)
|
||||||
thr_timer_end(&query_timer);
|
thr_timer_end(&query_timer);
|
||||||
|
@@ -2455,6 +2455,27 @@ Sys_gtid_ignore_duplicates(
|
|||||||
DEFAULT(FALSE), NO_MUTEX_GUARD,
|
DEFAULT(FALSE), NO_MUTEX_GUARD,
|
||||||
NOT_IN_BINLOG, ON_CHECK(check_gtid_ignore_duplicates),
|
NOT_IN_BINLOG, ON_CHECK(check_gtid_ignore_duplicates),
|
||||||
ON_UPDATE(fix_gtid_ignore_duplicates));
|
ON_UPDATE(fix_gtid_ignore_duplicates));
|
||||||
|
|
||||||
|
static bool
|
||||||
|
update_slave_max_statement_time(sys_var *self, THD *thd, enum_var_type type)
|
||||||
|
{
|
||||||
|
slave_max_statement_time=
|
||||||
|
double2ulonglong(slave_max_statement_time_double * 1e6);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Sys_var_on_access_global<
|
||||||
|
Sys_var_double, PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_STATEMENT_TIME>
|
||||||
|
Sys_slave_max_statement_time(
|
||||||
|
"slave_max_statement_time",
|
||||||
|
"A query that has taken more than slave_max_statement_time seconds to "
|
||||||
|
"run on the slave will be aborted. The argument will be treated as a "
|
||||||
|
"decimal value with microsecond precision. A value of 0 (default) "
|
||||||
|
"means no timeout",
|
||||||
|
GLOBAL_VAR(slave_max_statement_time_double), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(0, LONG_TIMEOUT), DEFAULT(0), NO_MUTEX_GUARD,
|
||||||
|
NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(update_slave_max_statement_time));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user