mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 17:54:16 +01:00
MDEV-28487: sequences not respect value of binlog_row_image with select nextval(seq_gen)
Problem: ======== When using sequences, the function sequence_definition::write(TABLE *table, bool all_fields) is used to save DML/DDL updates to sequence tables (e.g. nextval, setval, and alter). Prior to this patch, the value all_fields was always false when invoked via nextval and setval, which forced the bitmap to only include changed columns. Solution: ======== Change all_fields when invoked via nextval and setval to be reliant on binlog_row_image, such that it is false when binlog_row_image is MINIMAL, and true otherwise. Reviewed By: =========== Andrei Elkin <andrei.elkin@mariadb.com>
This commit is contained in:
parent
96be3fe841
commit
02e85aeafd
6 changed files with 2546 additions and 2 deletions
72
mysql-test/include/ensure_binlog_row_event_columns.inc
Normal file
72
mysql-test/include/ensure_binlog_row_event_columns.inc
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# Helper file to ensure that a binary log file properly writes the expected
|
||||
# fields based on the binlog_row_image value.
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# --let $expected_columns= (COLUMN_IDS)
|
||||
# --let $binlog_filename= FILENAME
|
||||
# --source include/count_binlog_row_event_columns.inc
|
||||
#
|
||||
# Parameters:
|
||||
# expected_columns (list<uint>, in) : A list of positive integers which
|
||||
# correspond to the column numbers that should be output in a binary
|
||||
# log's write_rows event
|
||||
# binlog_filename (string, in) : Name of the binary log file to analyze
|
||||
#
|
||||
|
||||
if (!$expected_columns)
|
||||
{
|
||||
--die expected_columns parameter is required but was not set
|
||||
}
|
||||
|
||||
if (!$binlog_filename)
|
||||
{
|
||||
--die binlog_filename parameter is required but was not set
|
||||
}
|
||||
|
||||
--let $include_filename= ensure_binlog_row_event_columns.inc [$expected_columns]
|
||||
--source include/begin_include_file.inc
|
||||
|
||||
--let $assert_file=$MYSQLTEST_VARDIR/tmp/binlog_decoded.out
|
||||
--let mysqld_datadir=`select @@datadir`
|
||||
|
||||
--echo # MYSQL_BINLOG mysqld_datadir/binlog_filename -vv > assert_file
|
||||
--exec $MYSQL_BINLOG $mysqld_datadir/$binlog_filename -vv > $assert_file
|
||||
|
||||
--echo # Verifying all expected column ids appear in binlog event output..
|
||||
--let num_cols_found=0
|
||||
--let last_expected_col= `SELECT GREATEST $expected_columns`
|
||||
--let i= 1
|
||||
while($i <= $last_expected_col)
|
||||
{
|
||||
# By default, assume the column is not expected to be in the binary log.
|
||||
# If the column id is set in expected_columns, then override assertion
|
||||
# parameters.
|
||||
--let assert_count= 0
|
||||
--let assert_text= Column @$i should not be in binary log
|
||||
|
||||
if (`SELECT $i IN $expected_columns`)
|
||||
{
|
||||
--let assert_count= 1
|
||||
--let assert_text= Column @$i should be in binary log
|
||||
|
||||
--inc $num_cols_found
|
||||
}
|
||||
|
||||
--let assert_select= @$i
|
||||
--source include/assert_grep.inc
|
||||
|
||||
--inc $i
|
||||
}
|
||||
--echo # ..success
|
||||
|
||||
--echo # Verifying only expected column ids appear in binlog event output..
|
||||
--let assert_count= $num_cols_found
|
||||
--let assert_text= The binlog event should only have $num_cols_found columns
|
||||
--let assert_select= @[\d]+
|
||||
--source include/assert_grep.inc
|
||||
--echo # ..success
|
||||
|
||||
--let $include_filename= ensure_binlog_row_event_columns.inc [$expected_columns]
|
||||
--source include/end_include_file.inc
|
90
mysql-test/suite/rpl/include/rpl_row_img_sequence.inc
Normal file
90
mysql-test/suite/rpl/include/rpl_row_img_sequence.inc
Normal file
|
@ -0,0 +1,90 @@
|
|||
#
|
||||
# This include file validates that sequence events are properly binlogged
|
||||
# and replicated.
|
||||
#
|
||||
# Parameters:
|
||||
# expected_columns (list<uint>, in) : A list of positive integers which
|
||||
# correspond to the column numbers that should be output in a binary
|
||||
# log's write_rows event
|
||||
#
|
||||
|
||||
--echo # Create sequences with specific engines per server
|
||||
--connection server_1
|
||||
--eval SET STATEMENT sql_log_bin=0 FOR create sequence s1 cache=0 engine=$server_1_engine
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
--eval SET STATEMENT sql_log_bin=0 FOR create sequence s1 cache=0 engine=$server_2_engine
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
--connection server_3
|
||||
--eval SET STATEMENT sql_log_bin=0 FOR create sequence s1 cache=0 engine=$server_3_engine
|
||||
--source include/sync_with_master_gtid.inc
|
||||
|
||||
|
||||
--echo # Pt.1 Ensure SETVAL replicates and binlogs correctly
|
||||
--connection server_1
|
||||
SELECT SETVAL(s1, 10);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--echo # Validate SETVAL replicated correctly to other servers
|
||||
--connection server_3
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--let $diff_tables= server_1:test.s1,server_2:test.s1,server_3:test.s1
|
||||
--source include/diff_tables.inc
|
||||
|
||||
--echo # Validate server_1 binlogged SETVAL with the correct columns
|
||||
--connection server_1
|
||||
--let binlog_filenamE= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
--echo # Validate server_2 binlogged SETVAL with the correct columns
|
||||
--connection server_2
|
||||
--let binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
--echo # Validate server_3 binlogged SETVAL with the correct columns
|
||||
--connection server_3
|
||||
--let binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
|
||||
--echo # Pt.2 Ensure NEXTVAL replicates and binlogs correctly
|
||||
--connection server_1
|
||||
SELECT NEXTVAL(s1);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--echo # Validate NEXTVAL replicated correctly to other servers
|
||||
--connection server_3
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--let $diff_tables= server_1:test.s1,server_2:test.s1,server_3:test.s1
|
||||
--source include/diff_tables.inc
|
||||
|
||||
--echo # Validate server_1 binlogged NEXTVAL with the correct columns
|
||||
--connection server_1
|
||||
--let binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
--echo # Validate server_2 binlogged NEXTVAL with the correct columns
|
||||
--connection server_2
|
||||
--let binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
--echo # Validate server_3 binlogged NEXTVAL with the correct columns
|
||||
--connection server_3
|
||||
--let binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||
FLUSH LOGS;
|
||||
--source include/ensure_binlog_row_event_columns.inc
|
||||
|
||||
|
||||
--echo # Cleanup
|
||||
--connection server_1
|
||||
DROP TABLE s1;
|
||||
--source include/save_master_gtid.inc
|
||||
--connection server_3
|
||||
--source include/sync_with_master_gtid.inc
|
2290
mysql-test/suite/rpl/r/rpl_row_img_sequence.result
Normal file
2290
mysql-test/suite/rpl/r/rpl_row_img_sequence.result
Normal file
File diff suppressed because it is too large
Load diff
21
mysql-test/suite/rpl/t/rpl_row_img_sequence.cnf
Normal file
21
mysql-test/suite/rpl/t/rpl_row_img_sequence.cnf
Normal file
|
@ -0,0 +1,21 @@
|
|||
!include include/default_mysqld.cnf
|
||||
|
||||
[mysqld.1]
|
||||
log-slave-updates
|
||||
innodb
|
||||
gtid_domain_id=0
|
||||
|
||||
[mysqld.2]
|
||||
log-slave-updates
|
||||
innodb
|
||||
gtid_domain_id=1
|
||||
|
||||
[mysqld.3]
|
||||
log-slave-updates
|
||||
innodb
|
||||
gtid_domain_id=2
|
||||
|
||||
[ENV]
|
||||
SERVER_MYPORT_1= @mysqld.1.port
|
||||
SERVER_MYPORT_2= @mysqld.2.port
|
||||
SERVER_MYPORT_3= @mysqld.3.port
|
65
mysql-test/suite/rpl/t/rpl_row_img_sequence.test
Normal file
65
mysql-test/suite/rpl/t/rpl_row_img_sequence.test
Normal file
|
@ -0,0 +1,65 @@
|
|||
#
|
||||
# Purpose:
|
||||
# This test verifies that sequence DML updates, i.e. NEXTVAL and SETVAL,
|
||||
# respect the binlog_row_image variable value when written into the binary log.
|
||||
# In particular, it ensures that only changed columns are written with MINIMAL
|
||||
# image mode, and all columns are written otherwise.
|
||||
#
|
||||
# Methodology
|
||||
# After issuing a sequence update, ensure that both 1) it was replicated
|
||||
# correctly, and 2) it was binlogged respective to the binlog_row_image value.
|
||||
# The sequence table does not use caching to ensure each update is immediately
|
||||
# binlogged. Each command is binlogged into its own unique log file, and the
|
||||
# entirety of the file is analyzed for correctness of its sequence event.
|
||||
# Specifically, mysqlbinlog is used in verbose mode so it outputs the columns
|
||||
# which belong to the event, and the columns are analyzed to ensure the correct
|
||||
# ones were logged. rpl_row_img_general_loop.inc is used to test with multiple
|
||||
# chained replicas, varying engines between InnoDB and MyISAM.
|
||||
#
|
||||
# References:
|
||||
# MDEV-28487: sequences not respect value of binlog_row_image with select
|
||||
# nextval(seq_gen)
|
||||
#
|
||||
|
||||
--let $rpl_topology= 1->2->3
|
||||
--source include/rpl_init.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
|
||||
--connection server_1
|
||||
--source include/have_innodb.inc
|
||||
--connection server_2
|
||||
--source include/have_innodb.inc
|
||||
--connection server_3
|
||||
--source include/have_innodb.inc
|
||||
--connection server_1
|
||||
|
||||
--echo #
|
||||
--echo # Test Case 1) binlog_row_image=MINIMAL should write only columns
|
||||
--echo # 1 and 8 to the binary log
|
||||
--echo #
|
||||
--let $row_img_set=server_1:MINIMAL:N,server_2:MINIMAL:Y,server_3:MINIMAL:Y
|
||||
--source include/rpl_row_img_set.inc
|
||||
--let $expected_columns=(1,8)
|
||||
--let row_img_test_script= include/rpl_row_img_sequence.inc
|
||||
--source include/rpl_row_img_general_loop.inc
|
||||
|
||||
--echo #
|
||||
--echo # Test Case 2) binlog_row_image=NOBLOB should write all columns to the
|
||||
--echo # binary log
|
||||
--echo #
|
||||
--let $row_img_set=server_1:NOBLOB:N,server_2:NOBLOB:Y,server_3:NOBLOB:Y
|
||||
--source include/rpl_row_img_set.inc
|
||||
--let $expected_columns=(1,2,3,4,5,6,7,8)
|
||||
--source include/rpl_row_img_general_loop.inc
|
||||
|
||||
--echo #
|
||||
--echo # Test Case 3) binlog_row_image=NOBLOB should write all columns to the
|
||||
--echo # binary log
|
||||
--echo #
|
||||
--let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y
|
||||
--source include/rpl_row_img_set.inc
|
||||
--let $expected_columns=(1,2,3,4,5,6,7,8)
|
||||
--source include/rpl_row_img_general_loop.inc
|
||||
|
||||
--source include/rpl_end.inc
|
||||
--echo # End of tests
|
|
@ -704,7 +704,9 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
|
|||
{
|
||||
longlong res_value, org_reserved_until, add_to;
|
||||
bool out_of_values;
|
||||
THD *thd= table->in_use;
|
||||
DBUG_ENTER("SEQUENCE::next_value");
|
||||
DBUG_ASSERT(thd);
|
||||
|
||||
*error= 0;
|
||||
if (!second_round)
|
||||
|
@ -769,7 +771,8 @@ longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
|
|||
DBUG_RETURN(next_value(table, 1, error));
|
||||
}
|
||||
|
||||
if (unlikely((*error= write(table, 0))))
|
||||
if (unlikely((*error= write(table, thd->variables.binlog_row_image !=
|
||||
BINLOG_ROW_IMAGE_MINIMAL))))
|
||||
{
|
||||
reserved_until= org_reserved_until;
|
||||
next_free_value= res_value;
|
||||
|
@ -836,7 +839,9 @@ int SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round,
|
|||
longlong org_reserved_until= reserved_until;
|
||||
longlong org_next_free_value= next_free_value;
|
||||
ulonglong org_round= round;
|
||||
THD *thd= table->in_use;
|
||||
DBUG_ENTER("SEQUENCE::set_value");
|
||||
DBUG_ASSERT(thd);
|
||||
|
||||
write_lock(table);
|
||||
if (is_used)
|
||||
|
@ -875,7 +880,8 @@ int SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round,
|
|||
needs_to_be_stored)
|
||||
{
|
||||
reserved_until= next_free_value;
|
||||
if (write(table, 0))
|
||||
if (write(table,
|
||||
thd->variables.binlog_row_image != BINLOG_ROW_IMAGE_MINIMAL))
|
||||
{
|
||||
reserved_until= org_reserved_until;
|
||||
next_free_value= org_next_free_value;
|
||||
|
|
Loading…
Add table
Reference in a new issue