From f37d380f309368178b546c6b71f473c580ec55ad Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Thu, 23 Oct 2025 13:59:43 +0300 Subject: [PATCH 1/4] MDEV-34124: Improve sequences replication with Galera - use shared key for sequence update certification - employ native replication's code to apply changes for sequences which handles all corner cases properly - fix the tests to allow more transactions using sequences to be accepted That way the sequence is always updated to the maximum value independent of the order of updates, and shared certification keys allow to improve acceptance ratio of concurrent transactions that use sequences. It's reflected in the test changes. --- .../suite/galera/r/galera_sequences.result | 2 +- .../r/galera_sequences_transaction.result | 28 +++++++++++++++---- mysql-test/suite/galera/r/mdev-22063.result | 2 +- .../suite/galera/t/galera_sequences.test | 11 ++------ .../t/galera_sequences_transaction.test | 2 -- sql/log_event_server.cc | 20 ++++++++----- storage/innobase/handler/ha_innodb.cc | 19 ++++++++----- storage/innobase/include/ha_prototypes.h | 6 ++-- storage/innobase/row/row0ins.cc | 2 +- 9 files changed, 57 insertions(+), 35 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_sequences.result b/mysql-test/suite/galera/r/galera_sequences.result index 7cdeffff1e30d..bacd0f07c9709 100644 --- a/mysql-test/suite/galera/r/galera_sequences.result +++ b/mysql-test/suite/galera/r/galera_sequences.result @@ -206,7 +206,7 @@ t CREATE TABLE `t` ( ) ENGINE=InnoDB SEQUENCE=1 connection node_1; DROP SEQUENCE t; -CREATE SEQUENCE t INCREMENT BY 1 NOCACHE ENGINE=INNODB; +CREATE SEQUENCE t INCREMENT BY 0 CACHE 1 ENGINE=INNODB; CREATE TABLE t1(a int not null primary key default nextval(t), b int) engine=innodb; connection node_2; # Wait DDL to replicate diff --git a/mysql-test/suite/galera/r/galera_sequences_transaction.result b/mysql-test/suite/galera/r/galera_sequences_transaction.result index c1cfdc4aa2092..80bfe44093e47 100644 --- a/mysql-test/suite/galera/r/galera_sequences_transaction.result +++ b/mysql-test/suite/galera/r/galera_sequences_transaction.result @@ -72,7 +72,7 @@ LASTVAL(s) connection node_1a; SELECT LASTVAL(s); LASTVAL(s) -79 +81 connection node_1; SELECT * FROM t1; f1 f2 @@ -106,7 +106,6 @@ f1 f2 56 1 58 1 60 1 -61 1 63 1 65 1 67 1 @@ -116,6 +115,7 @@ f1 f2 75 1 77 1 79 1 +81 1 connection node_2; SELECT * FROM t1; f1 f2 @@ -149,7 +149,6 @@ f1 f2 56 1 58 1 60 1 -61 1 63 1 65 1 67 1 @@ -159,6 +158,7 @@ f1 f2 75 1 77 1 79 1 +81 1 connection node_1; DROP TABLE t1; DROP SEQUENCE s; @@ -299,10 +299,8 @@ connection node_1a; ROLLBACK; connection node_2; COMMIT; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction connection node_2a; ROLLBACK; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction connection node_2; SELECT LASTVAL(s); LASTVAL(s) @@ -332,6 +330,16 @@ f1 f2 15 1 17 1 19 1 +22 1 +24 1 +26 1 +28 1 +30 1 +32 1 +34 1 +36 1 +38 1 +40 1 connection node_2; SELECT * FROM t1; f1 f2 @@ -345,6 +353,16 @@ f1 f2 15 1 17 1 19 1 +22 1 +24 1 +26 1 +28 1 +30 1 +32 1 +34 1 +36 1 +38 1 +40 1 connection node_1; DROP TABLE t1; DROP SEQUENCE s; diff --git a/mysql-test/suite/galera/r/mdev-22063.result b/mysql-test/suite/galera/r/mdev-22063.result index 228f63d6688bc..886a84b05e305 100644 --- a/mysql-test/suite/galera/r/mdev-22063.result +++ b/mysql-test/suite/galera/r/mdev-22063.result @@ -22,7 +22,7 @@ SELECT * FROM t1; a SELECT * FROM s; next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count -1 1 9223372036854775806 1 1 1000 0 0 +1 1 9223372036854775806 1 1 0 0 0 connection node_1; SET GLOBAL WSREP_MODE='REPLICATE_ARIA,REPLICATE_MYISAM'; DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_sequences.test b/mysql-test/suite/galera/t/galera_sequences.test index 9e18353893b2d..c9ab8db237aab 100644 --- a/mysql-test/suite/galera/t/galera_sequences.test +++ b/mysql-test/suite/galera/t/galera_sequences.test @@ -163,7 +163,8 @@ SHOW CREATE TABLE t; --connection node_1 DROP SEQUENCE t; -CREATE SEQUENCE t INCREMENT BY 1 NOCACHE ENGINE=INNODB; +# Don't use NOCACHE as it may produce duplicate entries from multiple nodes +CREATE SEQUENCE t INCREMENT BY 0 CACHE 1 ENGINE=INNODB; CREATE TABLE t1(a int not null primary key default nextval(t), b int) engine=innodb; --connection node_2 @@ -193,15 +194,11 @@ SET SESSION wsrep_sync_wait=0; while ($count) { --connection node_1 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (1); --connection node_2 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (2); ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (2); --connection node_1 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (1); --dec $count } @@ -251,15 +248,11 @@ SET SESSION wsrep_sync_wait=0; while ($count) { --connection node_1 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (1),(2),(3),(4),(5),(6),(7),(8),(9); --connection node_2 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (21),(22),(23),(24),(25),(26),(27),(28),(29); ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (21),(22),(23),(24),(25),(26),(27),(28),(29); --connection node_1 ---error 0,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK INSERT INTO t1(b) values (1),(2),(3),(4),(5),(6),(7),(8),(9); --dec $count } diff --git a/mysql-test/suite/galera/t/galera_sequences_transaction.test b/mysql-test/suite/galera/t/galera_sequences_transaction.test index f3dc7d51285a8..facf65a02fef5 100644 --- a/mysql-test/suite/galera/t/galera_sequences_transaction.test +++ b/mysql-test/suite/galera/t/galera_sequences_transaction.test @@ -230,10 +230,8 @@ COMMIT; --connection node_1a ROLLBACK; --connection node_2 ---error ER_LOCK_DEADLOCK COMMIT; --connection node_2a ---error ER_LOCK_DEADLOCK ROLLBACK; --connection node_2 diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index c93aea23ad0df..9ad2c5ebb1e28 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -7928,15 +7928,21 @@ int Rows_log_event::update_sequence() bool old_master= false; int err= 0; - if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO) || - ( -#if defined(WITH_WSREP) - ! WSREP(thd) && + rpl_group_info *table_rgi= +#ifdef WITH_WSREP + WSREP(thd) ? thd->wsrep_rgi : #endif - table->in_use->rgi_slave && - !(table->in_use->rgi_slave->gtid_ev_flags2 & Gtid_log_event::FL_DDL) && + table->in_use->rgi_slave; + rpl_group_info *thd_rgi= +#ifdef WITH_WSREP + WSREP(thd) ? thd->wsrep_rgi : +#endif + thd->rgi_slave; + if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO) || + (table_rgi && + !(table_rgi->gtid_ev_flags2 & Gtid_log_event::FL_DDL) && !(old_master= - rpl_master_has_bug(thd->rgi_slave->rli, + rpl_master_has_bug(thd_rgi->rli, 29621, FALSE, FALSE, FALSE, TRUE)))) { /* This event come from a setval function executed on the master. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ada50c1b409d7..0523d6f9449c0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8473,12 +8473,15 @@ wsrep_calc_row_hash( return(0); } -/** Append table-level exclusive key. +/** Append table-level exclusive/shared key. @param thd MySQL thread handle @param table table +@param exclusive Exclusive not shared certification key. @retval false on success @retval true on failure */ -ATTRIBUTE_COLD bool wsrep_append_table_key(MYSQL_THD thd, const dict_table_t &table) +ATTRIBUTE_COLD bool wsrep_append_table_key(MYSQL_THD thd, + const dict_table_t &table, + bool exclusive) { char db_buf[NAME_LEN + 1]; char tbl_buf[NAME_LEN + 1]; @@ -8491,9 +8494,11 @@ ATTRIBUTE_COLD bool wsrep_append_table_key(MYSQL_THD thd, const dict_table_t &ta return true; } - /* Append table-level exclusive key */ - const int rcode = wsrep_thd_append_table_key(thd, db_buf, - tbl_buf, WSREP_SERVICE_KEY_EXCLUSIVE); + /* Append table-level key */ + const enum Wsrep_service_key_type key_type = exclusive + ? WSREP_SERVICE_KEY_EXCLUSIVE + : WSREP_SERVICE_KEY_SHARED; + const int rcode = wsrep_thd_append_table_key(thd, db_buf, tbl_buf, key_type); if (rcode) { WSREP_ERROR("Appending table key failed: %s, %d", @@ -8656,10 +8661,10 @@ ha_innobase::update_row( && (thd_sql_command(m_user_thd) != SQLCOM_LOAD || thd_binlog_format(m_user_thd) == BINLOG_FORMAT_ROW)) { - /* We use table-level exclusive key for SEQUENCES + /* We use table-level shared key for SEQUENCES and normal key append for others. */ if (table->s->table_type == TABLE_TYPE_SEQUENCE) { - if (wsrep_append_table_key(m_user_thd, *m_prebuilt->table)) + if (wsrep_append_table_key(m_user_thd, *m_prebuilt->table, false)) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } else if (wsrep_append_keys(m_user_thd, wsrep_protocol_version >= 4 diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 35a93f32ea3d2..cfc067ba45c88 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -406,13 +406,15 @@ char *dict_table_lookup(LEX_CSTRING db, LEX_CSTRING name, dict_table_t **table, mem_heap_t *heap) noexcept; #ifdef WITH_WSREP -/** Append table-level exclusive key. +/** Append table-level exclusive/shared key. @param thd MySQL thread handle @param table table +@param exclusive Exclusive not shared certification key. @retval false on success @retval true on failure */ struct dict_table_t; -bool wsrep_append_table_key(MYSQL_THD thd, const dict_table_t &table); +bool wsrep_append_table_key(MYSQL_THD thd, const dict_table_t &table, + bool exclusive); #endif /* WITH_WSREP */ #endif /* !UNIV_INNOCHECKSUM */ diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index e57f6fa727590..9ece5dd156789 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2798,7 +2798,7 @@ row_ins_clust_index_entry_low( } #ifdef WITH_WSREP if (trx->is_wsrep() && - wsrep_append_table_key(trx->mysql_thd, *index->table)) + wsrep_append_table_key(trx->mysql_thd, *index->table, true)) { trx->error_state = DB_ROLLBACK; goto err_exit; From 85cd0c7ca3b5c94dff823b4566630d629f85de5e Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Fri, 24 Oct 2025 16:23:28 +0300 Subject: [PATCH 2/4] MDEV-34124: Test sequences recovery after crash in Galera cluster --- .../galera/r/galera_sequences_recovery.result | 132 ++++++++++++++++++ .../galera/t/galera_sequences_recovery.cnf | 9 ++ .../t/galera_sequences_recovery.combinations | 5 + .../galera/t/galera_sequences_recovery.test | 123 ++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 mysql-test/suite/galera/r/galera_sequences_recovery.result create mode 100644 mysql-test/suite/galera/t/galera_sequences_recovery.cnf create mode 100644 mysql-test/suite/galera/t/galera_sequences_recovery.combinations create mode 100644 mysql-test/suite/galera/t/galera_sequences_recovery.test diff --git a/mysql-test/suite/galera/r/galera_sequences_recovery.result b/mysql-test/suite/galera/r/galera_sequences_recovery.result new file mode 100644 index 0000000000000..1125f3faf8117 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sequences_recovery.result @@ -0,0 +1,132 @@ +connection node_2; +connection node_1; +connection node_1; +CREATE SEQUENCE s INCREMENT=0 CACHE=5 ENGINE=InnoDB; +CREATE TABLE t1 (f1 INT PRIMARY KEY DEFAULT NEXTVAL(s), f2 INT) ENGINE=InnoDB; +connection node_1; +BEGIN; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +connection node_2; +BEGIN; +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +Killing server ... +SELECT NEXTVAL(s); +NEXTVAL(s) +12 +connection node_1; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +COMMIT; +SELECT LASTVAL(s); +LASTVAL(s) +29 +SELECT * FROM t1; +f1 f2 +1 1 +3 1 +5 1 +7 1 +9 1 +21 1 +23 1 +25 1 +27 1 +29 1 +connection node_2; +SELECT LASTVAL(s); +LASTVAL(s) +12 +SELECT NEXTVAL(s); +NEXTVAL(s) +32 +SELECT * FROM t1; +f1 f2 +1 1 +3 1 +5 1 +7 1 +9 1 +21 1 +23 1 +25 1 +27 1 +29 1 +connection node_1; +DROP TABLE t1; +DROP SEQUENCE s; +connection node_1; +CREATE SEQUENCE s INCREMENT=0 CACHE=5 ENGINE=InnoDB; +CREATE TABLE t1 (f1 INT PRIMARY KEY DEFAULT NEXTVAL(s), f2 INT) ENGINE=InnoDB; +connection node_1; +BEGIN; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +connection node_2; +BEGIN; +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +Killing server ... +connection node_1; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +COMMIT; +SELECT LASTVAL(s); +LASTVAL(s) +19 +SELECT * FROM t1; +f1 f2 +1 1 +3 1 +5 1 +7 1 +9 1 +11 1 +13 1 +15 1 +17 1 +19 1 +connection node_2; +SELECT NEXTVAL(s); +NEXTVAL(s) +22 +SELECT * FROM t1; +f1 f2 +1 1 +3 1 +5 1 +7 1 +9 1 +11 1 +13 1 +15 1 +17 1 +19 1 +connection node_1; +SELECT LASTVAL(s); +LASTVAL(s) +19 +SELECT NEXTVAL(s); +NEXTVAL(s) +33 +connection node_1; +DROP TABLE t1; +DROP SEQUENCE s; diff --git a/mysql-test/suite/galera/t/galera_sequences_recovery.cnf b/mysql-test/suite/galera/t/galera_sequences_recovery.cnf new file mode 100644 index 0000000000000..8701e86db5f0e --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sequences_recovery.cnf @@ -0,0 +1,9 @@ +!include ../galera_2nodes.cnf + +[mysqld.1] +auto-increment-increment=2 +auto-increment-offset=1 + +[mysqld.2] +auto-increment-increment=2 +auto-increment-offset=2 diff --git a/mysql-test/suite/galera/t/galera_sequences_recovery.combinations b/mysql-test/suite/galera/t/galera_sequences_recovery.combinations new file mode 100644 index 0000000000000..cef98e75213f7 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sequences_recovery.combinations @@ -0,0 +1,5 @@ +[binlogon] +log-bin +log-slave-updates + +[binlogoff] diff --git a/mysql-test/suite/galera/t/galera_sequences_recovery.test b/mysql-test/suite/galera/t/galera_sequences_recovery.test new file mode 100644 index 0000000000000..4b59d0ad1afed --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sequences_recovery.test @@ -0,0 +1,123 @@ +# +# Test sequences crash recovery. +# + +--source include/galera_cluster.inc +--source include/have_sequence.inc +--source include/big_test.inc + +--disable_ps2_protocol + +# +# Case 1: Crash a node during a transaction, bring the +# sequence in sync by receiving higher current value +# +--connection node_1 +CREATE SEQUENCE s INCREMENT=0 CACHE=5 ENGINE=InnoDB; +CREATE TABLE t1 (f1 INT PRIMARY KEY DEFAULT NEXTVAL(s), f2 INT) ENGINE=InnoDB; + +--connection node_1 +BEGIN; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); + +--connection node_2 +BEGIN; +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); + +# Crash and restart the node, losing the transaciton +--source include/kill_galera.inc +--let $start_mysqld_params = +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--source include/start_mysqld.inc + +# Check and update the last written sequence value +SELECT NEXTVAL(s); + +--connection node_1 +# Update the sequence value further +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); + +COMMIT; +SELECT LASTVAL(s); +SELECT * FROM t1; + +--connection node_2 +# The next value should be in sync now, but the last +# value is still the same +SELECT LASTVAL(s); +SELECT NEXTVAL(s); +SELECT * FROM t1; + +--connection node_1 +DROP TABLE t1; +DROP SEQUENCE s; + +# +# Case 2: Crash a node during a transaction, bring the +# sequence in sync by sending higher current value +# +--connection node_1 +CREATE SEQUENCE s INCREMENT=0 CACHE=5 ENGINE=InnoDB; +CREATE TABLE t1 (f1 INT PRIMARY KEY DEFAULT NEXTVAL(s), f2 INT) ENGINE=InnoDB; + +--connection node_1 +BEGIN; +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); + +--connection node_2 +# Exhaust the cached values once, but no replication happens even +# though the sequnce table is updated +BEGIN; +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); +INSERT INTO t1(f2) values (2); + +# Crash and restart the node, losing the transaciton +--source include/kill_galera.inc +--let $start_mysqld_params = +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--source include/start_mysqld.inc + +--connection node_1 +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); +INSERT INTO t1(f2) values (1); + +COMMIT; +SELECT LASTVAL(s); +SELECT * FROM t1; + +--connection node_2 +# Check and update the last written sequence value, it's still +# higher than the one from the other node +SELECT NEXTVAL(s); +SELECT * FROM t1; + +--connection node_1 +# The next value should be in sync now, but the last +# value is still the same +SELECT LASTVAL(s); +SELECT NEXTVAL(s); + +--connection node_1 +DROP TABLE t1; +DROP SEQUENCE s; From 24fbb014de935efe2c8fc5f48de58ef9606d68c6 Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Wed, 22 Oct 2025 15:10:04 +0300 Subject: [PATCH 3/4] MDEV-34124: Fix streaming replication offset for binlog stmt cache As the binlog statement cache is only replicated with the last fragment, it's safe to pass zero offset instead of the stored log position, which is used only for the binlog transaction cache. --- sql/wsrep_binlog.cc | 8 +++++--- sql/wsrep_binlog.h | 2 ++ sql/wsrep_client_service.cc | 10 ++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc index 84392facba326..c680ba416ef11 100644 --- a/sql/wsrep_binlog.cc +++ b/sql/wsrep_binlog.cc @@ -118,12 +118,13 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len) */ static int wsrep_write_cache_inc(THD* const thd, IO_CACHE* const cache, + size_t const log_position, size_t* const len) { DBUG_ENTER("wsrep_write_cache_inc"); my_off_t const saved_pos(my_b_tell(cache)); - if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().log_position(), 0, 0)) + if (reinit_io_cache(cache, READ_CACHE, log_position, 0, 0)) { WSREP_ERROR("failed to initialize io-cache"); DBUG_RETURN(1);; @@ -157,7 +158,7 @@ static int wsrep_write_cache_inc(THD* const thd, } while ((cache->file >= 0) && (length= my_b_fill(cache))); if (ret == 0) { - assert(total_length + thd->wsrep_sr().log_position() == saved_pos); + assert(total_length + log_position == saved_pos); } } @@ -178,9 +179,10 @@ static int wsrep_write_cache_inc(THD* const thd, */ int wsrep_write_cache(THD* const thd, IO_CACHE* const cache, + size_t const log_position, size_t* const len) { - return wsrep_write_cache_inc(thd, cache, len); + return wsrep_write_cache_inc(thd, cache, log_position, len); } void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len) diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h index 252fbe602d24f..44985c8a5fbff 100644 --- a/sql/wsrep_binlog.h +++ b/sql/wsrep_binlog.h @@ -36,11 +36,13 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len); This function quite the same as MYSQL_BIN_LOG::write_cache(), with the exception that here we write in buffer instead of log file. + @param log_position position to start writing the cache from @param len total amount of data written @return wsrep error status */ int wsrep_write_cache(THD* thd, IO_CACHE* cache, + size_t log_position, size_t* len); /* Dump replication buffer to disk */ diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc index 268ad0e432dbe..d6448dddee62b 100644 --- a/sql/wsrep_client_service.cc +++ b/sql/wsrep_client_service.cc @@ -95,9 +95,11 @@ int Wsrep_client_service::prepare_data_for_replication() size_t transactional_data_len= 0; size_t stmt_data_len= 0; - // Write transactional cache + // Write transactional cache from the last remembered position if (transactional_cache && - wsrep_write_cache(m_thd, transactional_cache, &transactional_data_len)) + wsrep_write_cache(m_thd, transactional_cache, + m_thd->wsrep_sr().log_position(), + &transactional_data_len)) { WSREP_ERROR("rbr write fail, data_len: %zu", data_len); @@ -105,8 +107,8 @@ int Wsrep_client_service::prepare_data_for_replication() DBUG_RETURN(1); } - // Write stmt cache - if (stmt_cache && wsrep_write_cache(m_thd, stmt_cache, &stmt_data_len)) + // Write stmt cache fully as it's only written upon transaction commit + if (stmt_cache && wsrep_write_cache(m_thd, stmt_cache, 0u, &stmt_data_len)) { WSREP_ERROR("rbr write fail, data_len: %zu", data_len); From 7258e724b1df386fc9e06df08b8e661113ec0ed2 Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Wed, 22 Oct 2025 15:10:25 +0300 Subject: [PATCH 4/4] MDEV-34124: Make sequences work with streaming replication - extend galera_sequences_transaction test with streaming replication combinations (it demonstrates the exact results compared to the regular Wsrep replication) - remove MDEV-28971 test as it's not applicable after fixing the binlog statement cache replication with Wsrep --- .../t/galera_sequences_recovery.combinations | 8 +++++++ .../galera_sequences_transaction.combinations | 8 +++++++ .../suite/galera_sr/r/MDEV-28971.result | 17 --------------- mysql-test/suite/galera_sr/t/MDEV-28971.test | 21 ------------------- sql/ha_sequence.cc | 8 ------- 5 files changed, 16 insertions(+), 46 deletions(-) delete mode 100644 mysql-test/suite/galera_sr/r/MDEV-28971.result delete mode 100644 mysql-test/suite/galera_sr/t/MDEV-28971.test diff --git a/mysql-test/suite/galera/t/galera_sequences_recovery.combinations b/mysql-test/suite/galera/t/galera_sequences_recovery.combinations index cef98e75213f7..fe14ec5e06361 100644 --- a/mysql-test/suite/galera/t/galera_sequences_recovery.combinations +++ b/mysql-test/suite/galera/t/galera_sequences_recovery.combinations @@ -3,3 +3,11 @@ log-bin log-slave-updates [binlogoff] + +[binlogon-sr] +log-bin +log-slave-updates +wsrep-trx-fragment-size=1 + +[binlogoff-sr] +wsrep-trx-fragment-size=1 diff --git a/mysql-test/suite/galera/t/galera_sequences_transaction.combinations b/mysql-test/suite/galera/t/galera_sequences_transaction.combinations index cef98e75213f7..fe14ec5e06361 100644 --- a/mysql-test/suite/galera/t/galera_sequences_transaction.combinations +++ b/mysql-test/suite/galera/t/galera_sequences_transaction.combinations @@ -3,3 +3,11 @@ log-bin log-slave-updates [binlogoff] + +[binlogon-sr] +log-bin +log-slave-updates +wsrep-trx-fragment-size=1 + +[binlogoff-sr] +wsrep-trx-fragment-size=1 diff --git a/mysql-test/suite/galera_sr/r/MDEV-28971.result b/mysql-test/suite/galera_sr/r/MDEV-28971.result deleted file mode 100644 index 0826f5e6b66b6..0000000000000 --- a/mysql-test/suite/galera_sr/r/MDEV-28971.result +++ /dev/null @@ -1,17 +0,0 @@ -connection node_2; -connection node_1; -CREATE SEQUENCE SEQ NOCACHE ENGINE=InnoDB; -SET SESSION wsrep_trx_fragment_size=1; -SET collation_connection=utf16_thai_520_w2; -SET autocommit=0; -CREATE TABLE t1 (a BLOB UNIQUE); -INSERT INTO t1 VALUES ('AAF'); -SELECT SETVAL (SEQ, 100); -ERROR 42000: This version of MariaDB doesn't yet support 'SEQUENCEs with streaming replication in Galera cluster' -ALTER TABLE t1 ADD CONSTRAINT constraint_1 UNIQUE (a); -Warnings: -Note 1831 Duplicate index `constraint_1`. This is deprecated and will be disallowed in a future release -INSERT INTO t1 VALUES(); -ALTER TABLE t1 ADD KEY(b (50)); -ERROR 42000: Key column 'b' doesn't exist in table -DROP TABLE t1,SEQ; diff --git a/mysql-test/suite/galera_sr/t/MDEV-28971.test b/mysql-test/suite/galera_sr/t/MDEV-28971.test deleted file mode 100644 index 2f924e3bec83e..0000000000000 --- a/mysql-test/suite/galera_sr/t/MDEV-28971.test +++ /dev/null @@ -1,21 +0,0 @@ -# -# MDEV-28971 - Assertion `total_length + thd->wsrep_sr().log_position() == saved_pos' -# failed in int wsrep_write_cache_inc(THD*, IO_CACHE*, size_t*) -# - ---source include/galera_cluster.inc ---source include/have_sequence.inc - -CREATE SEQUENCE SEQ NOCACHE ENGINE=InnoDB; -SET SESSION wsrep_trx_fragment_size=1; -SET collation_connection=utf16_thai_520_w2; -SET autocommit=0; -CREATE TABLE t1 (a BLOB UNIQUE); -INSERT INTO t1 VALUES ('AAF'); ---error ER_NOT_SUPPORTED_YET -SELECT SETVAL (SEQ, 100); -ALTER TABLE t1 ADD CONSTRAINT constraint_1 UNIQUE (a); -INSERT INTO t1 VALUES(); ---error ER_KEY_COLUMN_DOES_NOT_EXIST -ALTER TABLE t1 ADD KEY(b (50)); -DROP TABLE t1,SEQ; diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 1e0e253a61897..1dd0e4a363717 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -273,14 +273,6 @@ int ha_sequence::write_row(const uchar *buf) #ifdef WITH_WSREP if (WSREP_ON && WSREP(thd) && wsrep_thd_is_local(thd)) { - if (sequence_locked && - (wsrep_thd_is_SR(thd) || wsrep_streaming_enabled(thd))) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "SEQUENCEs with streaming replication in Galera cluster"); - DBUG_RETURN(HA_ERR_UNSUPPORTED); - } - /* We need to start Galera transaction for select NEXT VALUE FOR sequence if it is not yet started. Note that ALTER is handled