From d762e9d943aa444695ebe845a7376fd9cbb0e3dc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 5 Sep 2023 16:58:55 +0200 Subject: [PATCH] MDEV-32093 long uniques break old->new replication recalculate long unique hash in Write_rows_log_event and Update_rows_log_event. normally generated columns (stored and indexed virtual) are deterministic and their values don't need to be recalculated on the slave as they're already present in the row image. but the long unique hash function was changed in MDEV-27653, so a row event from the old master will have the old hash, but a table created on the new slave will need a new hash. --- .../main/long_unique_bugs_replication.result | 19 ++++++++++- .../main/long_unique_bugs_replication.test | 33 ++++++++++++++++--- sql/log_event.cc | 16 ++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/long_unique_bugs_replication.result b/mysql-test/main/long_unique_bugs_replication.result index af583d00cea..39b0ebe26d2 100644 --- a/mysql-test/main/long_unique_bugs_replication.result +++ b/mysql-test/main/long_unique_bugs_replication.result @@ -1,3 +1,6 @@ +# +# MDEV-22722 Assertion "inited==NONE" failed in handler::ha_index_init on the slave during UPDATE +# include/master-slave.inc [connection master] create table t1 (i1 int, a1 text, unique key i1 (a1)) engine=myisam; @@ -6,7 +9,21 @@ insert into t1 values (2,2); update t1 set a1 = 'd' limit 1; update t1 set a1 = 'd2' where i1= 2; connection slave; -connection slave; connection master; drop table t1; +# +# MDEV-32093 long uniques break old->new replication +# +connection slave; +create table t1 (id int not null, b1 varchar(255) not null, b2 varchar(2550) not null, unique (id), unique key (b1,b2) using hash) default charset utf8mb3; +set global slave_exec_mode=idempotent; +binlog 'aRf2ZA8BAAAA/AAAAAABAAAAAAQAMTAuNS4xNS1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpF/ZkEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEwQADQgICAoKCgFRmTlk'; +binlog 'bBf2ZBMBAAAANAAAAJgHAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AeqMD4A==bBf2ZBcBAAAANAAAAMwHAAAAAHEAAAAAAAEABP/wj6QAAAEAYgEAZa6/VU0JAAAANteqUw=='; +binlog 'bBf2ZBMBAAAANAAAAJgHAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AeqMD4A==bBf2ZBcBAAAANAAAAMwHAAAAAHEAAAAAAAEABP/wj6QAAAEAYgEAZa6/VU0JAAAANteqUw=='; +binlog 'bBf2ZBMBAAAANAAAAHUkAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AaTGFIg==bBf2ZBgBAAAASAAAAL0kAAAAAHEAAAAAAAEABP//8I+kAAABAGIBAGWuv1VNCQAAAPBuWwAAAQBiAQBlrr9VTQkAAADxS9Lu'; +drop table t1; +set global slave_exec_mode=default; +# +# End of 10.4 tests +# include/rpl_end.inc diff --git a/mysql-test/main/long_unique_bugs_replication.test b/mysql-test/main/long_unique_bugs_replication.test index 1cacd088bee..9c44d13e6a5 100644 --- a/mysql-test/main/long_unique_bugs_replication.test +++ b/mysql-test/main/long_unique_bugs_replication.test @@ -2,9 +2,9 @@ # Long unique bugs related to master slave replication # -# -# MDEV-22722 Assertion "inited==NONE" failed in handler::ha_index_init on the slave during UPDATE -# +--echo # +--echo # MDEV-22722 Assertion "inited==NONE" failed in handler::ha_index_init on the slave during UPDATE +--echo # --source include/have_binlog_format_row.inc --source include/master-slave.inc @@ -16,9 +16,34 @@ update t1 set a1 = 'd' limit 1; update t1 set a1 = 'd2' where i1= 2; sync_slave_with_master; -connection slave; connection master; drop table t1; +--echo # +--echo # MDEV-32093 long uniques break old->new replication +--echo # + +# this is techically a bug in replication, but it needs an old master +# so we'll run it as a non-replicated test with BINLOG command +sync_slave_with_master; +create table t1 (id int not null, b1 varchar(255) not null, b2 varchar(2550) not null, unique (id), unique key (b1,b2) using hash) default charset utf8mb3; +set global slave_exec_mode=idempotent; + +# Format_description_log_event, MariaDB-10.5.15 +binlog 'aRf2ZA8BAAAA/AAAAAABAAAAAAQAMTAuNS4xNS1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpF/ZkEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEwQADQgICAoKCgFRmTlk'; + +### INSERT t1 VALUES (42127, 'b', 'e', 39952170926) +binlog 'bBf2ZBMBAAAANAAAAJgHAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AeqMD4A==bBf2ZBcBAAAANAAAAMwHAAAAAHEAAAAAAAEABP/wj6QAAAEAYgEAZa6/VU0JAAAANteqUw=='; +binlog 'bBf2ZBMBAAAANAAAAJgHAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AeqMD4A==bBf2ZBcBAAAANAAAAMwHAAAAAHEAAAAAAAEABP/wj6QAAAEAYgEAZa6/VU0JAAAANteqUw=='; + +### UPDATE t1 WHERE (42127, 'b', 'e', 39952170926) SET (23406, 'b', 'e', 39952170926) +binlog 'bBf2ZBMBAAAANAAAAHUkAAAAAHEAAAAAAAEABHRlc3QAAnQxAAQDDw8IBP0C4h0AaTGFIg==bBf2ZBgBAAAASAAAAL0kAAAAAHEAAAAAAAEABP//8I+kAAABAGIBAGWuv1VNCQAAAPBuWwAAAQBiAQBlrr9VTQkAAADxS9Lu'; + +drop table t1; +set global slave_exec_mode=default; + +--echo # +--echo # End of 10.4 tests +--echo # --source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 002bf3f29b7..014968e31d4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -13563,6 +13563,9 @@ Rows_log_event::write_row(rpl_group_info *rgi, DBUG_PRINT_BITSET("debug", "rpl_write_set: %s", table->rpl_write_set); DBUG_PRINT_BITSET("debug", "read_set: %s", table->read_set); + if (table->s->long_unique_table) + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE); + if (invoke_triggers && unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE))) { @@ -13674,7 +13677,14 @@ Rows_log_event::write_row(rpl_group_info *rgi, Now, record[1] should contain the offending row. That will enable us to update it or, alternatively, delete it (so that we can insert the new row afterwards). - */ + */ + if (table->s->long_unique_table) + { + /* same as for REPLACE/ODKU */ + table->move_fields(table->field, table->record[1], table->record[0]); + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); + table->move_fields(table->field, table->record[0], table->record[1]); + } /* If row is incomplete we will use the record found to fill @@ -13684,6 +13694,8 @@ Rows_log_event::write_row(rpl_group_info *rgi, { restore_record(table,record[1]); error= unpack_current_row(rgi); + if (table->s->long_unique_table) + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE); } DBUG_PRINT("debug",("preparing for update: before and after image")); @@ -14791,6 +14803,8 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) thd_proc_info(thd, message); if (unlikely((error= unpack_current_row(rgi, &m_cols_ai)))) goto err; + if (m_table->s->long_unique_table) + m_table->update_virtual_fields(m_table->file, VCOL_UPDATE_FOR_WRITE); /* Now we have the right row to update. The old row (the one we're