476 lines
16 KiB
Plaintext
476 lines
16 KiB
Plaintext
# ==== Requirements ====
|
|
#
|
|
# R1. If the intersection of slave's MASTER_COMPRESSION_ALGORITHMS with
|
|
# master's @@global.protocol_compression_algorithms is nonempty, then
|
|
# the connection in START SLAVE shall succeed and use zlib if
|
|
# possible; otherwise zstd; otherwise uncompressed.
|
|
#
|
|
# R2. If the intersection of slave's MASTER_COMPRESSION_ALGORITHMS with
|
|
# master's @@global.protocol_compression_algorithms is empty, then
|
|
# connection shall fail with an error.
|
|
#
|
|
# R3. If slave connects with MASTER_COMPRESSION_ALGORITHMS = 'zlib' or
|
|
# 'zstd', the connection should be compressed.
|
|
#
|
|
# R4. If slave connects with MASTER_COMPRESSION_ALGORITHMS = NULL, the
|
|
# connection should be uncompressed.
|
|
#
|
|
# R5. When using the zstd algorithm, MASTER_ZSTD_COMPRESSION_LEVEL=N
|
|
# shall provide better compression ratio than M, if N > M.
|
|
#
|
|
# ==== References ====
|
|
#
|
|
# WL#12475 - Protocol Changes to specify compression configuration for
|
|
# connections
|
|
#
|
|
|
|
# Test does not depend on binlog_format, so should only run once.
|
|
--source include/have_binlog_format_row.inc
|
|
--let $rpl_skip_start_slave = 1
|
|
--source include/master-slave.inc
|
|
|
|
|
|
--echo #### Initialize ####
|
|
|
|
# Don't replicate the auxiliary tables.
|
|
SET sql_log_bin = 0;
|
|
|
|
# List of possible values for MASTER_COMPRESSION_ALGORITHMS
|
|
CREATE TABLE algorithms (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
name TEXT NOT NULL);
|
|
INSERT INTO algorithms(name) VALUES
|
|
('default'),
|
|
('zlib'),
|
|
('zstd'),
|
|
('uncompressed'),
|
|
('zlib,zstd'),
|
|
('zlib,uncompressed'),
|
|
('zstd,uncompressed'),
|
|
('zlib,zstd,uncompressed');
|
|
|
|
# The options above includes all real possibilities. The options
|
|
# below are only variants of the syntax, where algorithms appear in
|
|
# different orders. This test is a bit slow, so we skip the options
|
|
# below, to save time.
|
|
|
|
#('zstd,zlib'),
|
|
#('uncompressed,zlib'),
|
|
#('uncompressed,zstd'),
|
|
#('zlib,uncompressed,zstd'),
|
|
#('zstd,zlib,uncompressed'),
|
|
#('zstd,uncompressed,zlib'),
|
|
#('uncompressed,zlib,zstd'),
|
|
#('uncompressed,zstd,zlib');
|
|
|
|
--let $algorithm_count = `SELECT COUNT(*) FROM algorithms`
|
|
|
|
# List of tested values for MASTER_ZSTD_COMPRESSION_LEVEL
|
|
CREATE TABLE levels (
|
|
id INT AUTO_INCREMENT PRIMARY KEY COMMENT 'order in which to set option',
|
|
level TEXT NOT NULL COMMENT 'compression level',
|
|
position INT NOT NULL COMMENT 'expected ordinal position of achieved compression'
|
|
);
|
|
|
|
# Exclude some levels, to make the test faster.
|
|
# Intermediate compression levels are not making much difference, test default and max.
|
|
INSERT INTO levels(level, position) VALUES
|
|
# ('1', 1),
|
|
#('2', 2),
|
|
('default', 3),
|
|
#('3', 3),
|
|
#('13', 4),
|
|
('22', 5);
|
|
--let $level_count = `SELECT COUNT(*) FROM levels`
|
|
|
|
--delimiter |
|
|
|
|
# Given two comma-separated lists of strings, returns a
|
|
# comma-separated list of those strings that appear in both, with
|
|
# duplicates removed, in the order of set1.
|
|
CREATE FUNCTION set_intersection(set1 TEXT, set2 TEXT) RETURNS TEXT BEGIN
|
|
DECLARE ret TEXT DEFAULT '';
|
|
DECLARE elem TEXT;
|
|
WHILE set1 != '' DO
|
|
SET elem = SUBSTRING_INDEX(set1, ',', 1);
|
|
IF FIND_IN_SET(elem, set2) THEN
|
|
SET ret = sys.list_add(ret, elem);
|
|
SET set2 = sys.list_drop(set2, elem);
|
|
END IF;
|
|
SET set1 = sys.list_drop(set1, elem);
|
|
END WHILE;
|
|
RETURN ret;
|
|
END|
|
|
--delimiter ;
|
|
|
|
SET sql_log_bin = 1;
|
|
|
|
# Statement to reset replication
|
|
--let $change_master_base = CHANGE MASTER TO MASTER_HOST = '127.0.0.1', MASTER_PORT = $SERVER_MYPORT_1, MASTER_USER = 'root', MASTER_RETRY_COUNT=3, MASTER_CONNECT_RETRY=1;
|
|
|
|
--let $script_dir = $MYSQLTEST_VARDIR
|
|
|
|
# ---- Purpose ----
|
|
#
|
|
# Auxiliary script to set configuration options on slave.
|
|
#
|
|
# ---- Usage ----
|
|
#
|
|
# --let $change_master_base = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_algorithm = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_level = <CHANGE MASTER STATEMENT>
|
|
# --let $slave_compressed_protocol = [0|1]
|
|
# --source $script_dir/configure_slave.inc
|
|
#
|
|
# Parameters:
|
|
#
|
|
# $change_master_base
|
|
# CHANGE MASTER statement that sets non-compression attributes to
|
|
# do the base configuration of the channel; for instance
|
|
# MASTER_HOST, MASTER_USER, etc.
|
|
#
|
|
# $change_master_algorithm
|
|
# CHANGE MASTER statement that sets MASTER_COMPRESSION_ALGORITHMS.
|
|
#
|
|
# $change_master_level
|
|
# CHANGE MASTER statement that sets MASTER_ZSTD_COMPRESSION_LEVEL.
|
|
#
|
|
# $slave_compressed_protocol
|
|
# Set @@global.slave_compressed_protocol to this value.
|
|
#
|
|
--write_file $script_dir/configure_slave.inc
|
|
# Make the 'source ...' files less noisy
|
|
--let $rpl_connection_silent = 1
|
|
--let $include_silent = 1
|
|
|
|
--source include/rpl_connection_slave.inc
|
|
--disable_warnings
|
|
--disable_query_log
|
|
eval $change_master_base;
|
|
--enable_query_log
|
|
if ($change_master_algorithm != '') {
|
|
eval $change_master_algorithm;
|
|
}
|
|
if ($change_master_level != '') {
|
|
eval $change_master_level;
|
|
}
|
|
--enable_warnings
|
|
eval SET @@global.slave_compressed_protocol = $slave_compressed_protocol;
|
|
EOF
|
|
|
|
|
|
# ---- Purpose ----
|
|
#
|
|
# Test one configuration that is expected to succeed, and verify
|
|
# requirements R1, R3, and R4.
|
|
#
|
|
# ---- Usage ----
|
|
#
|
|
# --let $change_master_base = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_algorithm = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_level = <CHANGE MASTER STATEMENT>
|
|
# --let $slave_compressed_protocol = [0|1]
|
|
# --let $data_size = size of data in event
|
|
# --let $expected_algorithm = [zlib|zstd|uncompressed]
|
|
# --source $script_dir/test_master_slave_compression.inc
|
|
#
|
|
# Parameters:
|
|
#
|
|
# $change_master_base, $change_master_algorithm, $change_master_level,
|
|
# $slave_compressed_protocol
|
|
# See configure_slave.inc
|
|
#
|
|
# $data_size
|
|
# The size of the data that was inserted on master.
|
|
# We will expect that it sends more than this if the connection is
|
|
# uncompressed, and less than this if the connection is compressed.
|
|
#
|
|
# $expected_algorithm
|
|
# The algorithm that should be used in the protocol.
|
|
#
|
|
# ---- Implementation ----
|
|
#
|
|
# - Configure slave using CHANGE MASTER
|
|
# - Start replication threads
|
|
# - Measure the number of bytes sent on the connection before and after
|
|
# - If the expected algorithm is uncompressed, assert that it sent
|
|
# more than $data_size bytes (data plus overhead)
|
|
# - If the expected algorithm is compressed, assert that it sent less
|
|
# than $data_size bytes (we assume that compression saves more than
|
|
# the overhead).
|
|
--write_file $script_dir/test_master_slave_compression.inc
|
|
|
|
--source $script_dir/configure_slave.inc
|
|
|
|
# Get initial value for number of bytes sent.
|
|
--source include/rpl_connection_master.inc
|
|
--source include/save_master_pos.inc
|
|
|
|
--let $bytes_before = `SELECT SUM_NUMBER_OF_BYTES_WRITE FROM performance_schema.socket_summary_by_event_name WHERE EVENT_NAME = 'wait/io/socket/sql/client_connection'`
|
|
|
|
--echo START SLAVE IO_THREAD
|
|
# Verify that slave can connect
|
|
--source include/rpl_connection_slave.inc
|
|
--source include/start_slave_io.inc
|
|
|
|
# Replicate
|
|
--source include/sync_slave_io.inc
|
|
--source include/stop_slave_io.inc
|
|
|
|
# Get final value for total number of bytes sent.
|
|
--source include/rpl_connection_master.inc
|
|
|
|
--let $bytes_after = `SELECT SUM_NUMBER_OF_BYTES_WRITE FROM performance_schema.socket_summary_by_event_name WHERE EVENT_NAME = 'wait/io/socket/sql/client_connection'`
|
|
--let $bytes_sent = `SELECT $bytes_after - $bytes_before`
|
|
|
|
# Verify that data was compressed / uncompressed according to option
|
|
if ($expected_algorithm == uncompressed) {
|
|
--let $assert_cond = $bytes_sent > $data_size
|
|
--let $assert_text = More than $data_size bytes should be sent uncompressed
|
|
}
|
|
if ($expected_algorithm != uncompressed) {
|
|
--let $assert_cond = $bytes_sent < $data_size
|
|
--let $assert_text = Less than $data_size bytes should be sent compressed
|
|
}
|
|
--let $include_silent = 0
|
|
--source include/assert.inc
|
|
|
|
--source include/rpl_connection_slave.inc
|
|
--disable_query_log
|
|
RESET MASTER;
|
|
RESET SLAVE ALL;
|
|
--enable_query_log
|
|
EOF
|
|
|
|
|
|
# ---- Purpose ----
|
|
#
|
|
# Do the same as $script_dir/test_master_slave_compression.inc, and
|
|
# in addition verify requirement R5.
|
|
#
|
|
# ---- Usage ----
|
|
#
|
|
# --let $change_master_base = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_algorithm = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_level = <CHANGE MASTER STATEMENT>
|
|
# --let $slave_compressed_protocol = [0|1]
|
|
# --let $data_size = size of data in event
|
|
# --let $expected_algorithm = [zlib|zstd|uncompressed]
|
|
# --let $level_it = NUMBER
|
|
# --source $script_dir/test_master_slave_compression_with_level
|
|
#
|
|
# Parameters:
|
|
#
|
|
# $change_master_base, $change_master_algorithm, $change_master_level,
|
|
# $slave_compressed_protocol, $data_size, $expected_algorithm
|
|
# See test_master_slave_compression.inc, above.
|
|
#
|
|
# $level_it
|
|
# Row number in the 'levels' table which contains the compression
|
|
# level to test.
|
|
#
|
|
# ---- Implementation ----
|
|
#
|
|
# - Fetch the compression level from the levels table.
|
|
# - Add MASTER_ZSTD_COMPRESSION_LEVEL to the CHANGE MASTER statement text
|
|
# - Source test_master_slave_compression
|
|
# - If level_it != 1 (it's not the first level we try for the
|
|
# algorithm), compare the compression ratio with the compression
|
|
# ratio of the last run. If the 'position' column of the 'levels'
|
|
# table has the same value as the 'position' column for the previous
|
|
# row in the 'levels' table, then we expect the compression ratios
|
|
# to be the same. Otherwise (i.e. the 'position' column is greater
|
|
# than that of the previous row), then we expect the compression
|
|
# ratio of the current test to be better than that of the last test.
|
|
--write_file $script_dir/test_master_slave_compression_with_level.inc
|
|
--source include/rpl_connection_master.inc
|
|
|
|
--source $script_dir/test_master_slave_compression.inc
|
|
|
|
--source include/rpl_connection_master.inc
|
|
|
|
# If this is not the first run with this algorithm, compare with previous
|
|
# run. If the 'position' value for this row in the 'levels' table equals
|
|
# the 'position' value for the previous row, then the levels are
|
|
# the same and we should expect equal compression. Otherwise, this level
|
|
# is higher than the previous level and we should expect the compression
|
|
# to be better than the previous run.
|
|
if ($level_it != 1) {
|
|
--let $better_than_last = `SELECT position > $last_position FROM levels WHERE id = $level_it`
|
|
if ($better_than_last) {
|
|
--let $assert_cond = $bytes_sent < $last_bytes_sent
|
|
--let $assert_text = Compression ratio should be better than previous algorithm
|
|
}
|
|
if (!$better_than_last) {
|
|
--let $assert_cond = $bytes_sent == $last_bytes_sent
|
|
--let $assert_text = Compression ratio should be equal to previous algorithm
|
|
}
|
|
--source include/assert.inc
|
|
}
|
|
|
|
--let $last_bytes_sent = $bytes_sent
|
|
|
|
--let $last_position = `SELECT position FROM levels WHERE id = $level_it`
|
|
EOF
|
|
|
|
|
|
# ---- Purpose ----
|
|
#
|
|
# Verify that there is an error when master and slave do not have any
|
|
# compression algorithm in common.
|
|
#
|
|
# ---- Usage ----
|
|
#
|
|
# --let $change_master_base = <CHANGE MASTER STATEMENT>
|
|
# --let $change_master_algorithm = <CHANGE MASTER STATEMENT>
|
|
# --source $script_dir/test_master_slave_compression_error.inc
|
|
#
|
|
# Parameters: See test_master_slave_compression.inc.
|
|
#
|
|
# ---- Implementation ----
|
|
#
|
|
# - Execute the CHANGE MASTER statement
|
|
# - Execute START SLAVE IO_THREAD
|
|
# - Wait until error happens.
|
|
--write_file $script_dir/test_master_slave_compression_error.inc
|
|
|
|
--source $script_dir/configure_slave.inc
|
|
|
|
START SLAVE IO_THREAD;
|
|
--let $slave_io_errno = 3922, 2066
|
|
# 3922 = ER_WRONG_COMPRESSION_ALGORITHM_CLIENT
|
|
# 2066 = CR_COMPRESSION_WRONGLY_CONFIGURED
|
|
--source include/wait_for_slave_io_error.inc
|
|
--echo got error
|
|
RESET SLAVE ALL;
|
|
EOF
|
|
|
|
|
|
# Generate some binlog data. This will be more than 10000 bytes
|
|
# uncompressed, and less than 10000 bytes compressed.
|
|
--let $data_size = 10000
|
|
CREATE TABLE t (a LONGTEXT);
|
|
eval INSERT INTO t VALUES (REPEAT('a', $data_size));
|
|
|
|
--let $saved_protocol_compression_algorithms = `SELECT @@global.protocol_compression_algorithms`
|
|
|
|
--echo #### Test ####
|
|
|
|
# Iterate over all the algorithms on master
|
|
--let $master_algorithm_it = 1
|
|
while ($master_algorithm_it <= $algorithm_count) {
|
|
--source include/rpl_connection_master.inc
|
|
--let $master_algorithm_text = `SELECT name FROM algorithms WHERE id = $master_algorithm_it`
|
|
--let $master_algorithm = $master_algorithm_text
|
|
if ($master_algorithm == default) {
|
|
--let $master_algorithm = zlib,zstd,uncompressed
|
|
}
|
|
|
|
--echo ==== master:$master_algorithm_text ====
|
|
|
|
--source include/rpl_connection_master.inc
|
|
if ($master_algorithm_text == default) {
|
|
eval SET @@global.protocol_compression_algorithms = DEFAULT;
|
|
}
|
|
if ($master_algorithm != default) {
|
|
eval SET @@global.protocol_compression_algorithms = '$master_algorithm';
|
|
}
|
|
SELECT @@global.protocol_compression_algorithms;
|
|
|
|
# Iterate over all algorithms on slave
|
|
--let $slave_algorithm_it = 1
|
|
while ($slave_algorithm_it <= $algorithm_count) {
|
|
--source include/rpl_connection_master.inc
|
|
--let $slave_algorithm_text = `SELECT name FROM algorithms WHERE id = $slave_algorithm_it`
|
|
--let $slave_algorithm = $slave_algorithm_text
|
|
--let $change_master_algorithm = CHANGE MASTER TO MASTER_COMPRESSION_ALGORITHMS = '$slave_algorithm'
|
|
if ($slave_algorithm == default) {
|
|
--let $slave_algorithm = uncompressed
|
|
--let $change_master_algorithm =
|
|
}
|
|
|
|
--let $slave_compressed_protocol = 0
|
|
--let $slave_compressed_protocol_iterations = 1
|
|
if ($slave_algorithm == uncompressed) {
|
|
--let $slave_compressed_protocol_iterations = 2
|
|
}
|
|
|
|
while ($slave_compressed_protocol < $slave_compressed_protocol_iterations) {
|
|
--source include/rpl_connection_slave.inc
|
|
if ($slave_compressed_protocol) {
|
|
--let $slave_algorithm = zlib
|
|
}
|
|
|
|
--source include/rpl_connection_master.inc
|
|
--let $intersection = `SELECT set_intersection('$master_algorithm', '$slave_algorithm')`
|
|
|
|
if ($intersection != '') {
|
|
let $expected_algorithm = `
|
|
SELECT IF(FIND_IN_SET('zlib', '$intersection'), 'zlib',
|
|
IF(FIND_IN_SET('zstd', '$intersection'), 'zstd',
|
|
'uncompressed'))`;
|
|
|
|
if ($expected_algorithm == zstd) {
|
|
# Iterate over levels.
|
|
--let $level_it = 1
|
|
while ($level_it <= $level_count) {
|
|
# Get the compression level from the table.
|
|
--let $level = `SELECT level FROM levels WHERE id = $level_it`
|
|
|
|
# If $level != 'default', set MASTER_ZSTD_COMPRESSION_LEVEL.
|
|
# Otherwise don't.
|
|
--let $change_master_level =
|
|
if ($level != 'default') {
|
|
--let $change_master_level = CHANGE MASTER TO MASTER_ZSTD_COMPRESSION_LEVEL = $level
|
|
}
|
|
|
|
--echo ---- master:$master_algorithm slave:$slave_algorithm slave_option:$slave_compressed_protocol expect:$expected_algorithm level:$level ----
|
|
|
|
--source $script_dir/test_master_slave_compression_with_level.inc
|
|
|
|
--inc $level_it
|
|
}
|
|
}
|
|
if ($expected_algorithm != zstd) {
|
|
--echo ---- master:$master_algorithm slave:$slave_algorithm_text slave_option:$slave_compressed_protocol expected:$expected_algorithm ----
|
|
--source $script_dir/test_master_slave_compression.inc
|
|
}
|
|
}
|
|
|
|
if ($intersection == '') {
|
|
--echo ---- master:$master_algorithm slave:$slave_algorithm_text slave_option:$slave_compressed_protocol expect:error ----
|
|
--source $script_dir/test_master_slave_compression_error.inc
|
|
}
|
|
--inc $slave_compressed_protocol
|
|
}
|
|
--inc $slave_algorithm_it
|
|
}
|
|
--inc $master_algorithm_it
|
|
}
|
|
|
|
--echo #### Clean up ####
|
|
|
|
--source include/rpl_connection_master.inc
|
|
--eval SET @@global.protocol_compression_algorithms = "$saved_protocol_compression_algorithms";
|
|
|
|
SET sql_log_bin = 0;
|
|
DROP TABLE algorithms;
|
|
DROP TABLE levels;
|
|
DROP TABLE t;
|
|
DROP FUNCTION set_intersection;
|
|
SET sql_log_bin = 1;
|
|
|
|
--remove_file $script_dir/configure_slave.inc
|
|
--remove_file $script_dir/test_master_slave_compression.inc
|
|
--remove_file $script_dir/test_master_slave_compression_with_level.inc
|
|
--remove_file $script_dir/test_master_slave_compression_error.inc
|
|
|
|
--source include/rpl_connection_slave.inc
|
|
--disable_query_log
|
|
eval CHANGE MASTER TO MASTER_HOST = '127.0.0.1', MASTER_PORT = $SERVER_MYPORT_1, MASTER_USER = 'root';
|
|
--enable_query_log
|
|
|
|
# Tell rpl_end to not try to sync
|
|
--let $rpl_skip_sync = 1
|
|
--source include/rpl_end.inc
|