21 Nov '18
revision-id: 8324e5e84dc786b2d4a07d7798f26ddea239159e (mariadb-10.1.37-22-g8324e5e84dc)
parent(s): 41fa9a598655a15b423a7453eba5acaf5bd5d324
author: Jan Lindström
committer: Jan Lindström
timestamp: 2018-11-21 09:05:47 +0200
message:
MDEV-17771: Add Galera ist and sst tests using mariabackup
Add test case for encrypted and page compressed tables.
---
.../include/innodb_encrypt_tables.combinations | 14 +
mysql-test/include/innodb_encrypt_tables.inc | 4 +
.../r/galera_sst_mariabackup_table_options.result | 985 +++++++++++++++++++++
.../t/galera_sst_mariabackup_table_options.cnf | 16 +
.../t/galera_sst_mariabackup_table_options.opt | 2 +
.../t/galera_sst_mariabackup_table_options.test | 218 +++++
6 files changed, 1239 insertions(+)
diff --git a/mysql-test/include/innodb_encrypt_tables.combinations b/mysql-test/include/innodb_encrypt_tables.combinations
new file mode 100644
index 00000000000..cb32fea998a
--- /dev/null
+++ b/mysql-test/include/innodb_encrypt_tables.combinations
@@ -0,0 +1,14 @@
+[crypt]
+innodb_encrypt_tables=ON
+plugin-load-add=$FILE_KEY_MANAGEMENT_SO
+loose-file-key-management
+loose-file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys.txt
+file-key-management-encryption-algorithm=aes_ctr
+
+[clear]
+innodb_encrypt_tables=OFF
+plugin-load-add=$FILE_KEY_MANAGEMENT_SO
+loose-file-key-management
+loose-file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys.txt
+file-key-management-encryption-algorithm=aes_ctr
+
diff --git a/mysql-test/include/innodb_encrypt_tables.inc b/mysql-test/include/innodb_encrypt_tables.inc
new file mode 100644
index 00000000000..31ab7999aef
--- /dev/null
+++ b/mysql-test/include/innodb_encrypt_tables.inc
@@ -0,0 +1,4 @@
+# The goal of including this file is to enable innodb_encrypt_tables combinations
+# (see include/innodb_encrypt_tables.combinations)
+
+--source include/have_innodb.inc
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result
new file mode 100644
index 00000000000..f55a926d4de
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result
@@ -0,0 +1,985 @@
+Performing State Transfer on a server that starts from a clean var directory
+This is accomplished by shutting down node #2 and removing its var directory before restarting it
+CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1;
+CREATE TABLE t3 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=NO;
+CREATE TABLE t4 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=YES;
+CREATE TABLE t5 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
+CREATE TABLE t6 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED ENCRYPTED=NO;
+CREATE TABLE t7 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED ENCRYPTED=YES;
+CREATE TABLE t8 (f1 CHAR(255)) ENGINE=InnoDB ENCRYPTED=NO;
+CREATE TABLE t9 (f1 CHAR(255)) ENGINE=InnoDB ENCRYPTED=YES;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+insert into t9 values ('node1_committed_before');
+insert into t9 values ('node1_committed_before');
+insert into t9 values ('node1_committed_before');
+insert into t9 values ('node1_committed_before');
+insert into t9 values ('node1_committed_before');
+insert into t8 values ('node1_committed_before');
+insert into t8 values ('node1_committed_before');
+insert into t8 values ('node1_committed_before');
+insert into t8 values ('node1_committed_before');
+insert into t8 values ('node1_committed_before');
+insert into t7 values ('node1_committed_before');
+insert into t7 values ('node1_committed_before');
+insert into t7 values ('node1_committed_before');
+insert into t7 values ('node1_committed_before');
+insert into t7 values ('node1_committed_before');
+insert into t6 values ('node1_committed_before');
+insert into t6 values ('node1_committed_before');
+insert into t6 values ('node1_committed_before');
+insert into t6 values ('node1_committed_before');
+insert into t6 values ('node1_committed_before');
+insert into t5 values ('node1_committed_before');
+insert into t5 values ('node1_committed_before');
+insert into t5 values ('node1_committed_before');
+insert into t5 values ('node1_committed_before');
+insert into t5 values ('node1_committed_before');
+insert into t4 values ('node1_committed_before');
+insert into t4 values ('node1_committed_before');
+insert into t4 values ('node1_committed_before');
+insert into t4 values ('node1_committed_before');
+insert into t4 values ('node1_committed_before');
+insert into t3 values ('node1_committed_before');
+insert into t3 values ('node1_committed_before');
+insert into t3 values ('node1_committed_before');
+insert into t3 values ('node1_committed_before');
+insert into t3 values ('node1_committed_before');
+insert into t2 values ('node1_committed_before');
+insert into t2 values ('node1_committed_before');
+insert into t2 values ('node1_committed_before');
+insert into t2 values ('node1_committed_before');
+insert into t2 values ('node1_committed_before');
+insert into t1 values ('node1_committed_before');
+insert into t1 values ('node1_committed_before');
+insert into t1 values ('node1_committed_before');
+insert into t1 values ('node1_committed_before');
+insert into t1 values ('node1_committed_before');
+COMMIT;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+insert into t9 values ('node2_committed_before');
+insert into t9 values ('node2_committed_before');
+insert into t9 values ('node2_committed_before');
+insert into t9 values ('node2_committed_before');
+insert into t9 values ('node2_committed_before');
+insert into t8 values ('node2_committed_before');
+insert into t8 values ('node2_committed_before');
+insert into t8 values ('node2_committed_before');
+insert into t8 values ('node2_committed_before');
+insert into t8 values ('node2_committed_before');
+insert into t7 values ('node2_committed_before');
+insert into t7 values ('node2_committed_before');
+insert into t7 values ('node2_committed_before');
+insert into t7 values ('node2_committed_before');
+insert into t7 values ('node2_committed_before');
+insert into t6 values ('node2_committed_before');
+insert into t6 values ('node2_committed_before');
+insert into t6 values ('node2_committed_before');
+insert into t6 values ('node2_committed_before');
+insert into t6 values ('node2_committed_before');
+insert into t5 values ('node2_committed_before');
+insert into t5 values ('node2_committed_before');
+insert into t5 values ('node2_committed_before');
+insert into t5 values ('node2_committed_before');
+insert into t5 values ('node2_committed_before');
+insert into t4 values ('node2_committed_before');
+insert into t4 values ('node2_committed_before');
+insert into t4 values ('node2_committed_before');
+insert into t4 values ('node2_committed_before');
+insert into t4 values ('node2_committed_before');
+insert into t3 values ('node2_committed_before');
+insert into t3 values ('node2_committed_before');
+insert into t3 values ('node2_committed_before');
+insert into t3 values ('node2_committed_before');
+insert into t3 values ('node2_committed_before');
+insert into t2 values ('node2_committed_before');
+insert into t2 values ('node2_committed_before');
+insert into t2 values ('node2_committed_before');
+insert into t2 values ('node2_committed_before');
+insert into t2 values ('node2_committed_before');
+insert into t1 values ('node2_committed_before');
+insert into t1 values ('node2_committed_before');
+insert into t1 values ('node2_committed_before');
+insert into t1 values ('node2_committed_before');
+insert into t1 values ('node2_committed_before');
+COMMIT;
+Shutting down server ...
+Cleaning var directory ...
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+insert into t9 values ('node1_committed_during');
+insert into t9 values ('node1_committed_during');
+insert into t9 values ('node1_committed_during');
+insert into t9 values ('node1_committed_during');
+insert into t9 values ('node1_committed_during');
+insert into t8 values ('node1_committed_during');
+insert into t8 values ('node1_committed_during');
+insert into t8 values ('node1_committed_during');
+insert into t8 values ('node1_committed_during');
+insert into t8 values ('node1_committed_during');
+insert into t7 values ('node1_committed_during');
+insert into t7 values ('node1_committed_during');
+insert into t7 values ('node1_committed_during');
+insert into t7 values ('node1_committed_during');
+insert into t7 values ('node1_committed_during');
+insert into t6 values ('node1_committed_during');
+insert into t6 values ('node1_committed_during');
+insert into t6 values ('node1_committed_during');
+insert into t6 values ('node1_committed_during');
+insert into t6 values ('node1_committed_during');
+insert into t5 values ('node1_committed_during');
+insert into t5 values ('node1_committed_during');
+insert into t5 values ('node1_committed_during');
+insert into t5 values ('node1_committed_during');
+insert into t5 values ('node1_committed_during');
+insert into t4 values ('node1_committed_during');
+insert into t4 values ('node1_committed_during');
+insert into t4 values ('node1_committed_during');
+insert into t4 values ('node1_committed_during');
+insert into t4 values ('node1_committed_during');
+insert into t3 values ('node1_committed_during');
+insert into t3 values ('node1_committed_during');
+insert into t3 values ('node1_committed_during');
+insert into t3 values ('node1_committed_during');
+insert into t3 values ('node1_committed_during');
+insert into t2 values ('node1_committed_during');
+insert into t2 values ('node1_committed_during');
+insert into t2 values ('node1_committed_during');
+insert into t2 values ('node1_committed_during');
+insert into t2 values ('node1_committed_during');
+insert into t1 values ('node1_committed_during');
+insert into t1 values ('node1_committed_during');
+insert into t1 values ('node1_committed_during');
+insert into t1 values ('node1_committed_during');
+insert into t1 values ('node1_committed_during');
+COMMIT;
+START TRANSACTION;
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+insert into t9 values ('node1_to_be_rollbacked_after');
+insert into t9 values ('node1_to_be_rollbacked_after');
+insert into t9 values ('node1_to_be_rollbacked_after');
+insert into t9 values ('node1_to_be_rollbacked_after');
+insert into t9 values ('node1_to_be_rollbacked_after');
+insert into t8 values ('node1_to_be_rollbacked_after');
+insert into t8 values ('node1_to_be_rollbacked_after');
+insert into t8 values ('node1_to_be_rollbacked_after');
+insert into t8 values ('node1_to_be_rollbacked_after');
+insert into t8 values ('node1_to_be_rollbacked_after');
+insert into t7 values ('node1_to_be_rollbacked_after');
+insert into t7 values ('node1_to_be_rollbacked_after');
+insert into t7 values ('node1_to_be_rollbacked_after');
+insert into t7 values ('node1_to_be_rollbacked_after');
+insert into t7 values ('node1_to_be_rollbacked_after');
+insert into t6 values ('node1_to_be_rollbacked_after');
+insert into t6 values ('node1_to_be_rollbacked_after');
+insert into t6 values ('node1_to_be_rollbacked_after');
+insert into t6 values ('node1_to_be_rollbacked_after');
+insert into t6 values ('node1_to_be_rollbacked_after');
+insert into t5 values ('node1_to_be_rollbacked_after');
+insert into t5 values ('node1_to_be_rollbacked_after');
+insert into t5 values ('node1_to_be_rollbacked_after');
+insert into t5 values ('node1_to_be_rollbacked_after');
+insert into t5 values ('node1_to_be_rollbacked_after');
+insert into t4 values ('node1_to_be_rollbacked_after');
+insert into t4 values ('node1_to_be_rollbacked_after');
+insert into t4 values ('node1_to_be_rollbacked_after');
+insert into t4 values ('node1_to_be_rollbacked_after');
+insert into t4 values ('node1_to_be_rollbacked_after');
+insert into t3 values ('node1_to_be_rollbacked_after');
+insert into t3 values ('node1_to_be_rollbacked_after');
+insert into t3 values ('node1_to_be_rollbacked_after');
+insert into t3 values ('node1_to_be_rollbacked_after');
+insert into t3 values ('node1_to_be_rollbacked_after');
+insert into t2 values ('node1_to_be_rollbacked_after');
+insert into t2 values ('node1_to_be_rollbacked_after');
+insert into t2 values ('node1_to_be_rollbacked_after');
+insert into t2 values ('node1_to_be_rollbacked_after');
+insert into t2 values ('node1_to_be_rollbacked_after');
+insert into t1 values ('node1_to_be_rollbacked_after');
+insert into t1 values ('node1_to_be_rollbacked_after');
+insert into t1 values ('node1_to_be_rollbacked_after');
+insert into t1 values ('node1_to_be_rollbacked_after');
+insert into t1 values ('node1_to_be_rollbacked_after');
+Starting server ...
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+COMMIT;
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t9 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t8 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t7 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t6 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t5 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t4 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t3 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t2 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+insert into t1 values ('node1_to_be_committed_after');
+COMMIT;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+insert into t9 values ('node1_committed_after');
+insert into t9 values ('node1_committed_after');
+insert into t9 values ('node1_committed_after');
+insert into t9 values ('node1_committed_after');
+insert into t9 values ('node1_committed_after');
+insert into t8 values ('node1_committed_after');
+insert into t8 values ('node1_committed_after');
+insert into t8 values ('node1_committed_after');
+insert into t8 values ('node1_committed_after');
+insert into t8 values ('node1_committed_after');
+insert into t7 values ('node1_committed_after');
+insert into t7 values ('node1_committed_after');
+insert into t7 values ('node1_committed_after');
+insert into t7 values ('node1_committed_after');
+insert into t7 values ('node1_committed_after');
+insert into t6 values ('node1_committed_after');
+insert into t6 values ('node1_committed_after');
+insert into t6 values ('node1_committed_after');
+insert into t6 values ('node1_committed_after');
+insert into t6 values ('node1_committed_after');
+insert into t5 values ('node1_committed_after');
+insert into t5 values ('node1_committed_after');
+insert into t5 values ('node1_committed_after');
+insert into t5 values ('node1_committed_after');
+insert into t5 values ('node1_committed_after');
+insert into t4 values ('node1_committed_after');
+insert into t4 values ('node1_committed_after');
+insert into t4 values ('node1_committed_after');
+insert into t4 values ('node1_committed_after');
+insert into t4 values ('node1_committed_after');
+insert into t3 values ('node1_committed_after');
+insert into t3 values ('node1_committed_after');
+insert into t3 values ('node1_committed_after');
+insert into t3 values ('node1_committed_after');
+insert into t3 values ('node1_committed_after');
+insert into t2 values ('node1_committed_after');
+insert into t2 values ('node1_committed_after');
+insert into t2 values ('node1_committed_after');
+insert into t2 values ('node1_committed_after');
+insert into t2 values ('node1_committed_after');
+insert into t1 values ('node1_committed_after');
+insert into t1 values ('node1_committed_after');
+insert into t1 values ('node1_committed_after');
+insert into t1 values ('node1_committed_after');
+insert into t1 values ('node1_committed_after');
+COMMIT;
+ROLLBACK;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t3;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t4;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t5;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t6;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t7;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t8;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t9;
+COUNT(*)
+30
+SELECT * FROM t1;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t2;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t3;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t4;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t5;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t6;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t7;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t8;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t9;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+COMMIT;
+SET AUTOCOMMIT=ON;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t3;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t4;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t5;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t6;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t7;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t8;
+COUNT(*)
+30
+SELECT COUNT(*) FROM t9;
+COUNT(*)
+30
+SELECT * FROM t1;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t2;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t3;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t4;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t5;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t6;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t7;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t8;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+SELECT * FROM t9;
+f1
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node1_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node2_committed_before
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_committed_during
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_to_be_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+node1_committed_after
+COMMIT;
+DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9;
+COMMIT;
+SET AUTOCOMMIT=ON;
diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf
new file mode 100644
index 00000000000..336296e9bfe
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf
@@ -0,0 +1,16 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=mariabackup
+wsrep_sst_auth="root:"
+wsrep_debug=ON
+
+[mysqld.1]
+wsrep_provider_options='base_port=(a)mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
+
+[mysqld.2]
+wsrep_provider_options='base_port=(a)mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
+
+[sst]
+transferfmt=(a)ENV.MTR_GALERA_TFMT
+streamfmt=xbstream
diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.opt b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.opt
new file mode 100644
index 00000000000..ae3fb580433
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.opt
@@ -0,0 +1,2 @@
+--innodb-file-format='Barracuda'
+--innodb-file-per-table=ON
diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test
new file mode 100644
index 00000000000..61cef44135b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.test
@@ -0,0 +1,218 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/innodb_encrypt_tables.inc
+--source include/have_mariabackup.inc
+
+--echo Performing State Transfer on a server that starts from a clean var directory
+--echo This is accomplished by shutting down node #2 and removing its var directory before restarting it
+
+--connection node_1
+CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1;
+CREATE TABLE t3 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=NO;
+CREATE TABLE t4 (f1 CHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=YES;
+CREATE TABLE t5 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
+CREATE TABLE t6 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED ENCRYPTED=NO;
+CREATE TABLE t7 (f1 CHAR(255)) ENGINE=InnoDB ROW_FORMAT=COMPRESSED ENCRYPTED=YES;
+CREATE TABLE t8 (f1 CHAR(255)) ENGINE=InnoDB ENCRYPTED=NO;
+CREATE TABLE t9 (f1 CHAR(255)) ENGINE=InnoDB ENCRYPTED=YES;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_committed_before');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t7;
+--source include/wait_condition.inc
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node2_committed_before');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--echo Cleaning var directory ...
+--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mtr
+--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/performance_schema
+--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/test
+--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mysql
+--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_committed_during');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_to_be_committed_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+
+--connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_to_be_rollbacked_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+
+--connection node_2
+--echo Starting server ...
+--source include/start_mysqld.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node2_committed_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+--connection node_1
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_to_be_committed_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+let $tables = 9;
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_committed_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+COMMIT;
+
+--connection node_1a_galera_st_clean_slave
+while ($tables)
+{
+ let $rows = 5;
+ while($rows)
+ {
+ eval insert into t$tables values ('node1_to_be_rollbacked_after');
+ dec $rows;
+ }
+ dec $tables;
+}
+ROLLBACK;
+
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+SELECT COUNT(*) FROM t3;
+SELECT COUNT(*) FROM t4;
+SELECT COUNT(*) FROM t5;
+SELECT COUNT(*) FROM t6;
+SELECT COUNT(*) FROM t7;
+SELECT COUNT(*) FROM t8;
+SELECT COUNT(*) FROM t9;
+SELECT * FROM t1;
+SELECT * FROM t2;
+SELECT * FROM t3;
+SELECT * FROM t4;
+SELECT * FROM t5;
+SELECT * FROM t6;
+SELECT * FROM t7;
+SELECT * FROM t8;
+SELECT * FROM t9;
+COMMIT;
+SET AUTOCOMMIT=ON;
+
+--connection node_1
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+SELECT COUNT(*) FROM t3;
+SELECT COUNT(*) FROM t4;
+SELECT COUNT(*) FROM t5;
+SELECT COUNT(*) FROM t6;
+SELECT COUNT(*) FROM t7;
+SELECT COUNT(*) FROM t8;
+SELECT COUNT(*) FROM t9;
+SELECT * FROM t1;
+SELECT * FROM t2;
+SELECT * FROM t3;
+SELECT * FROM t4;
+SELECT * FROM t5;
+SELECT * FROM t6;
+SELECT * FROM t7;
+SELECT * FROM t8;
+SELECT * FROM t9;
+COMMIT;
+
+DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9;
+COMMIT;
+SET AUTOCOMMIT=ON;
1
0
[Commits] d07a6e33dd8: Check that default() do not see invisible field.
by Oleksandr Byelkin 20 Nov '18
by Oleksandr Byelkin 20 Nov '18
20 Nov '18
revision-id: d07a6e33dd8738d7521e376ca55d5ae3062eb3cf (mariadb-10.3.10-88-gd07a6e33dd8)
parent(s): 02b70702d9df049433c4d4d276a9c15d0aaf5427
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-11-20 17:31:07 +0100
message:
Check that default() do not see invisible field.
---
mysql-test/main/invisible_field_debug.result | 2 ++
mysql-test/main/invisible_field_debug.test | 2 ++
2 files changed, 4 insertions(+)
diff --git a/mysql-test/main/invisible_field_debug.result b/mysql-test/main/invisible_field_debug.result
index b3c84d18333..0ea8ab12de8 100644
--- a/mysql-test/main/invisible_field_debug.result
+++ b/mysql-test/main/invisible_field_debug.result
@@ -17,6 +17,8 @@ a invisible
1 9
insert into t1(a, invisible) values(99,99);
ERROR 42S22: Unknown column 'invisible' in 'field list'
+select default(invisible) from t1;
+ERROR 42S22: Unknown column 'invisible' in 'field list'
insert into t1(invisible) values(99);
ERROR 42S22: Unknown column 'invisible' in 'field list'
insert into t_tmp select a, invisible from t1;
diff --git a/mysql-test/main/invisible_field_debug.test b/mysql-test/main/invisible_field_debug.test
index c1d6899d16e..86252512386 100644
--- a/mysql-test/main/invisible_field_debug.test
+++ b/mysql-test/main/invisible_field_debug.test
@@ -13,6 +13,8 @@ select a , invisible from t1;
--error ER_BAD_FIELD_ERROR
insert into t1(a, invisible) values(99,99);
--error ER_BAD_FIELD_ERROR
+select default(invisible) from t1;
+--error ER_BAD_FIELD_ERROR
insert into t1(invisible) values(99);
insert into t_tmp select a, invisible from t1;
--error ER_WRONG_VALUE_COUNT_ON_ROW
1
0
[Commits] be8828fa10f: MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes
by Varun 20 Nov '18
by Varun 20 Nov '18
20 Nov '18
revision-id: be8828fa10fe52682c85f0ab2b3fba6842fd5bfd (mariadb-10.0.36-81-gbe8828fa10f)
parent(s): f0db071ffeb1a6f3b8e048932c305f2c3e4a28bd
author: Varun Gupta
committer: Varun Gupta
timestamp: 2018-11-20 18:27:31 +0530
message:
MDEV-17734: AddressSanitizer: use-after-poison in create_key_parts_for_pseudo_indexes
In this case we were trying to access memory for key_parts which we did not assign
for a fields because it did not any EITS statistics.
The check if EITS statistics for a column is avaialable or not was missing.
---
sql/opt_range.cc | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3bcaa72e32f..a3943cbe3ff 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3350,7 +3350,9 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
if (bitmap_is_set(used_fields, (*field_ptr)->field_index))
{
Field *field= *field_ptr;
- if (field->type() == MYSQL_TYPE_GEOMETRY)
+ Column_statistics* col_stats= field->read_stats;
+ if (field->type() == MYSQL_TYPE_GEOMETRY ||
+ !col_stats || col_stats->no_stat_values_provided())
continue;
uint16 store_length;
1
0
[Commits] 13c1b6faf23: MDEV-17778: Alter table leads to a truncation warning with ANALYZE command
by Varun 20 Nov '18
by Varun 20 Nov '18
20 Nov '18
revision-id: 13c1b6faf23ecf645b4e47868feb24ac22921bf4 (mariadb-10.3.10-82-g13c1b6faf23)
parent(s): efc235d84d0df8a9895a5ae71c829303bbd39c8f
author: Varun Gupta
committer: Varun Gupta
timestamp: 2018-11-20 17:36:37 +0530
message:
MDEV-17778: Alter table leads to a truncation warning with ANALYZE command
Alter statement changed the THD structure by setting the value to FIELD_CHECK_WARN
and then not resetting it back. This led ANALYZE to throw a warning which previously
it didn't.
---
mysql-test/main/alter_table.result | 21 +++++++++++++++++++++
mysql-test/main/alter_table.test | 19 +++++++++++++++++++
sql/sql_table.cc | 12 +++++++-----
3 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/mysql-test/main/alter_table.result b/mysql-test/main/alter_table.result
index 49c42479516..8e54e882979 100644
--- a/mysql-test/main/alter_table.result
+++ b/mysql-test/main/alter_table.result
@@ -2469,3 +2469,24 @@ DROP TABLE t1;
#
# End of 10.2 tests
#
+#
+# MDEV-17778: Alter table leads to a truncation warning with ANALYZE command
+#
+set @save_use_stat_tables= @@use_stat_tables;
+set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
+set @@optimizer_use_condition_selectivity=4;
+set @@use_stat_tables=PREFERABLY;
+create table t1 (a int)engine=InnoDB;
+insert into t1 values (1),(1),(2),(3);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+alter table t1 change a b int;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+set @@use_stat_tables= @save_use_stat_tables;
+set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
+drop table t1;
diff --git a/mysql-test/main/alter_table.test b/mysql-test/main/alter_table.test
index dfa8e2e148b..829f4013cb3 100644
--- a/mysql-test/main/alter_table.test
+++ b/mysql-test/main/alter_table.test
@@ -2021,3 +2021,22 @@ DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #
+
+--echo #
+--echo # MDEV-17778: Alter table leads to a truncation warning with ANALYZE command
+--echo #
+
+set @save_use_stat_tables= @@use_stat_tables;
+set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
+set @@optimizer_use_condition_selectivity=4;
+set @@use_stat_tables=PREFERABLY;
+
+create table t1 (a int)engine=InnoDB;
+insert into t1 values (1),(1),(2),(3);
+
+analyze table t1;
+alter table t1 change a b int;
+analyze table t1;
+set @@use_stat_tables= @save_use_stat_tables;
+set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
+drop table t1;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index b9fc431feb1..ba91b208d03 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -7401,11 +7401,6 @@ static bool mysql_inplace_alter_table(THD *thd,
bool reopen_tables= false;
bool res;
- /*
- Set the truncated column values of thd as warning
- for alter table.
- */
- thd->count_cuted_fields = CHECK_FIELD_WARN;
DBUG_ENTER("mysql_inplace_alter_table");
/*
@@ -9694,9 +9689,16 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
if (use_inplace)
{
table->s->frm_image= &frm;
+ enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
+ /*
+ Set the truncated column values of thd as warning
+ for alter table.
+ */
+ thd->count_cuted_fields = CHECK_FIELD_WARN;
int res= mysql_inplace_alter_table(thd, table_list, table, altered_table,
&ha_alter_info, inplace_supported,
&target_mdl_request, &alter_ctx);
+ thd->count_cuted_fields= save_count_cuted_fields;
my_free(const_cast<uchar*>(frm.str));
if (res)
1
0
[Commits] 41fa9a59865: Add missing .rdiff file to test galera_sst_xtrabackup-v2_data_dir
by jan 20 Nov '18
by jan 20 Nov '18
20 Nov '18
revision-id: 41fa9a598655a15b423a7453eba5acaf5bd5d324 (mariadb-10.1.37-21-g41fa9a59865)
parent(s): 6fad15d02a82f4cc8dbbb0a3cc03f4abd56d4898
author: Jan Lindström
committer: Jan Lindström
timestamp: 2018-11-20 07:49:46 +0200
message:
Add missing .rdiff file to test galera_sst_xtrabackup-v2_data_dir
for debug build.
---
.../galera_sst_xtrabackup-v2_data_dir,debug.rdiff | 103 +++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_data_dir,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_data_dir,debug.rdiff
new file mode 100644
index 00000000000..ac232020037
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_data_dir,debug.rdiff
@@ -0,0 +1,103 @@
+--- r/galera_sst_xtrabackup-v2_data_dir.result 2018-11-19 12:27:24.795221479 +0200
++++ r/galera_sst_xtrabackup-v2_data_dir.reject 2018-11-19 19:15:38.774008404 +0200
+@@ -260,3 +260,100 @@
+ DROP TABLE t1;
+ COMMIT;
+ SET AUTOCOMMIT=ON;
++Performing State Transfer on a server that has been killed and restarted
++while a DDL was in progress on it
++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++INSERT INTO t1 VALUES ('node1_committed_before');
++START TRANSACTION;
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++INSERT INTO t1 VALUES ('node2_committed_before');
++COMMIT;
++SET GLOBAL debug_dbug = 'd,sync.alter_opened_table';
++ALTER TABLE t1 ADD COLUMN f2 INTEGER;
++SET wsrep_sync_wait = 0;
++Killing server ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++INSERT INTO t1 (f1) VALUES ('node1_committed_during');
++COMMIT;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++Performing --wsrep-recover ...
++Starting server ...
++Using --wsrep-start-position when starting mysqld ...
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++INSERT INTO t1 (f1) VALUES ('node2_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after');
++COMMIT;
++SET AUTOCOMMIT=OFF;
++START TRANSACTION;
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++INSERT INTO t1 (f1) VALUES ('node1_committed_after');
++COMMIT;
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after');
++ROLLBACK;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++COMMIT;
++SET AUTOCOMMIT=ON;
++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
++COUNT(*) = 2
++1
++SELECT COUNT(*) = 35 FROM t1;
++COUNT(*) = 35
++1
++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1;
++COUNT(*) = 0
++1
++DROP TABLE t1;
++COMMIT;
++SET AUTOCOMMIT=ON;
++SET GLOBAL debug_dbug = $debug_orig;
1
0
revision-id: dd23963099ad840bc86fd24cee0913647a8e93b3 (mariadb-10.3.6-137-gdd23963)
parent(s): 81ba90b59e9ed57fdc525a631d3b6643d3669a7c
committer: Alexey Botchkov
timestamp: 2018-11-20 02:12:54 +0400
message:
MDEV-7974 XA transactions.
First part of the patch - binlogging of the XA transactions.
---
sql/handler.cc | 20 ++-
sql/handler.h | 10 ++
sql/log.cc | 86 +++++++++++-
sql/log_event.cc | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++--
sql/log_event.h | 77 +++++++++++
sql/sql_class.cc | 18 +--
sql/sql_class.h | 20 ++-
sql/sql_connect.cc | 1 +
sql/transaction.cc | 69 ++++++++-
sql/transaction.h | 1 +
10 files changed, 675 insertions(+), 26 deletions(-)
diff --git a/sql/handler.cc b/sql/handler.cc
index 943722a..61bd7d4 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1185,9 +1185,12 @@ static int prepare_or_error(handlerton *ht, THD *thd, bool all)
*/
int ha_prepare(THD *thd)
{
- int error=0, all=1;
+ int error=0, all=1, cookie;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list;
+ bool need_prepare_ordered= FALSE;
+ bool need_commit_ordered= FALSE;
+
DBUG_ENTER("ha_prepare");
if (ha_info)
@@ -1212,9 +1215,24 @@ int ha_prepare(THD *thd)
ha_resolve_storage_engine_name(ht));
}
+ need_prepare_ordered|= (ht->prepare_ordered != NULL);
+ need_commit_ordered|= (ht->commit_ordered != NULL);
+ }
+ cookie= tc_log->log_and_order(thd, 0, all, need_prepare_ordered,
+ need_commit_ordered);
+ if (!cookie)
+ {
+ error= 1;
+ goto end;
+ }
+ if (tc_log->unlog(cookie, 0))
+ {
+ error= 1;
+ goto end;
}
}
+end:
DBUG_RETURN(error);
}
diff --git a/sql/handler.h b/sql/handler.h
index 68a54cc..52165a6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -787,6 +787,16 @@ struct xid_t {
long gtrid_length;
long bqual_length;
char data[XIDDATASIZE]; // not \0-terminated !
+ /*
+ The size of the string containing serialized Xid representation
+ is computed as a sum of
+ eight as the number of formatting symbols (X'',X'',)
+ plus 2 x XIDDATASIZE (2 due to hex format),
+ plus space for decimal digits of XID::formatID,
+ plus one for 0x0.
+ */
+ static const uint ser_buf_size=
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(long) + 1;
xid_t() {} /* Remove gcc warning */
bool eq(struct xid_t *xid)
diff --git a/sql/log.cc b/sql/log.cc
index 86137ad..d0dbd25 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -87,6 +87,9 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_xa_recover(handlerton *hton, XID *xid_list, uint len);
+static int binlog_commit_by_xid(handlerton *hton, XID *xid);
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid);
static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
static const LEX_CSTRING write_error_msg=
@@ -1688,6 +1691,10 @@ int binlog_init(void *p)
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
binlog_hton->prepare= binlog_prepare;
+ binlog_hton->recover= binlog_xa_recover;
+ binlog_hton->commit_by_xid = binlog_commit_by_xid;
+ binlog_hton->rollback_by_xid = binlog_rollback_by_xid;
+
binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
@@ -1883,12 +1890,23 @@ static inline int
binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
bool all, my_xid xid)
{
+ /* Mask XA COMMIT ... ONE PHASE as plain BEGIN ... COMMIT */
+ if (!xid && thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt == XA_ONE_PHASE)
+ xid= thd->query_id;
+
if (xid)
{
Xid_log_event end_evt(thd, xid, TRUE);
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
}
- else
+ else if (thd->transaction.xid_state.xa_state == XA_IDLE)
+ {
+ /* XA PREPARE */
+ XID *xid= &thd->transaction.xid_state.xid;
+ XA_prepare_log_event end_evt(thd, xid, TRUE);
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
+ }
{
/*
Empty xid occurs in XA COMMIT ... ONE PHASE.
@@ -1966,6 +1984,72 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
return 0;
}
+
+static int serialize_xid(XID *xid, char *buf)
+{
+ size_t size;
+ buf[0]= '\'';
+ memcpy(buf+1, xid->data, xid->gtrid_length);
+ size= xid->gtrid_length + 2;
+ buf[size-1]= '\'';
+ if (xid->bqual_length == 0 && xid->formatID == 1)
+ return size;
+
+ memcpy(buf+size, ", '", 3);
+ memcpy(buf+size+3, xid->data+xid->gtrid_length, xid->bqual_length);
+ size+= 3 + xid->bqual_length;
+ buf[size]= '\'';
+ size++;
+ if (xid->formatID != 1)
+ size+= sprintf(buf+size, ", %ld", xid->formatID);
+ return size;
+}
+
+
+static int binlog_xa_recover(handlerton *hton __attribute__((unused)),
+ XID *xid_list __attribute__((unused)),
+ uint len __attribute__((unused)))
+{
+ /* Does nothing. */
+ return 0;
+}
+
+
+static int binlog_commit_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xc_len= sizeof("XA COMMIT ") - 1; // do not count trailing 0
+ char buf[xc_len + xid_t::ser_buf_size];
+ size_t buflen;
+ binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data();
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT);
+
+ if (!cache_mngr)
+ return 1;
+
+ memcpy(buf, "XA COMMIT ", xc_len);
+ buflen= xc_len + serialize_xid(xid, buf+xc_len);
+ Query_log_event qe(thd, buf, buflen, TRUE, FALSE, FALSE, 0);
+ return binlog_flush_cache(thd, cache_mngr, &qe, TRUE, TRUE, TRUE);
+}
+
+
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xr_len= sizeof("XA ROLLBACK ") - 1; // do not count trailing 0
+ char buf[xr_len + xid_t::ser_buf_size];
+ size_t buflen;
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
+ memcpy(buf, "XA ROLLBACK ", xr_len);
+ buflen= xr_len + serialize_xid(xid, buf+xr_len);
+ Query_log_event qe(thd, buf, buflen, FALSE, TRUE, TRUE, 0);
+ return mysql_bin_log.write_event(&qe);
+}
+
+
/*
We flush the cache wrapped in a beging/rollback if:
. aborting a single or multi-statement transaction and;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 13690a8..ed91111 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2124,6 +2124,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case XID_EVENT:
ev = new Xid_log_event(buf, fdle);
break;
+ case XA_PREPARE_LOG_EVENT:
+ ev = new XA_prepare_log_event(buf, fdle);
+ break;
case RAND_EVENT:
ev = new Rand_log_event(buf, fdle);
break;
@@ -2175,7 +2178,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case PREVIOUS_GTIDS_LOG_EVENT:
case TRANSACTION_CONTEXT_EVENT:
case VIEW_CHANGE_EVENT:
- case XA_PREPARE_LOG_EVENT:
ev= new Ignorable_log_event(buf, fdle,
get_type_str((Log_event_type) event_type));
break;
@@ -6185,6 +6187,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[USER_VAR_EVENT-1]= USER_VAR_HEADER_LEN;
post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
post_header_len[XID_EVENT-1]= XID_HEADER_LEN;
+ post_header_len[XA_PREPARE_LOG_EVENT-1]= XA_PREPARE_HEADER_LEN;
post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= BEGIN_LOAD_QUERY_HEADER_LEN;
post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
/*
@@ -7840,7 +7843,7 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
buf+= 8;
domain_id= uint4korr(buf);
buf+= 4;
- flags2= *buf;
+ flags2= *(buf++);
if (flags2 & FL_GROUP_COMMIT_ID)
{
if (event_len < (uint)header_size + GTID_HEADER_LEN + 2)
@@ -7848,8 +7851,22 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
seq_no= 0; // So is_valid() returns false
return;
}
- ++buf;
commit_id= uint8korr(buf);
+ buf+= 8;
+ }
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ xid.formatID= (long) buf[0];
+ xid.gtrid_length= (long) buf[1];
+ xid.bqual_length= (long) buf[2];
+
+ buf+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(xid.data, buf, data_length);
+ buf+= data_length;
+ }
}
}
@@ -7880,6 +7897,12 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
/* Preserve any DDL or WAITED flag in the slave's binlog. */
if (thd_arg->rgi_slave)
flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt != XA_ONE_PHASE)
+ {
+ flags2|= FL_XA_TRANSACTION;
+ xid= thd->transaction.xid_state.xid;
+ }
}
@@ -7922,7 +7945,7 @@ Gtid_log_event::peek(const char *event_start, size_t event_len,
bool
Gtid_log_event::write()
{
- uchar buf[GTID_HEADER_LEN+2];
+ uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
size_t write_len;
int8store(buf, seq_no);
@@ -7934,8 +7957,25 @@ Gtid_log_event::write()
write_len= GTID_HEADER_LEN + 2;
}
else
+ write_len= 13;
+
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ buf[write_len]= (uchar) ((char) xid.formatID);
+ buf[write_len+1]= (uchar) xid.gtrid_length;
+ buf[write_len+2]= (uchar) xid.bqual_length;
+ write_len+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(buf+write_len, xid.data, data_length);
+ write_len+= data_length;
+ }
+ }
+
+ if (write_len < GTID_HEADER_LEN)
{
- bzero(buf+13, GTID_HEADER_LEN-13);
+ bzero(buf+write_len, GTID_HEADER_LEN-write_len);
write_len= GTID_HEADER_LEN;
}
return write_header(write_len) ||
@@ -7978,7 +8018,7 @@ Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
void
Gtid_log_event::pack_info(Protocol *protocol)
{
- char buf[6+5+10+1+10+1+20+1+4+20+1];
+ char buf[6+5+10+1+10+1+20+1+4+20+1+5+128];
char *p;
p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
p= longlong10_to_str(domain_id, p, 10);
@@ -7992,6 +8032,12 @@ Gtid_log_event::pack_info(Protocol *protocol)
p= longlong10_to_str(commit_id, p, 10);
}
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ p= strmov(p, " XID :");
+ p= strnmov(p, xid.data, xid.bqual_length + xid.gtrid_length);
+ }
+
protocol->store(buf, p-buf, &my_charset_bin);
}
@@ -8048,11 +8094,25 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi)
thd->lex->sql_command= SQLCOM_BEGIN;
thd->is_slave_error= 0;
status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
- if (trans_begin(thd, 0))
+ if (flags2 & FL_XA_TRANSACTION)
{
- DBUG_PRINT("error", ("trans_begin() failed"));
- thd->is_slave_error= 1;
+ thd->lex->xid= &xid;
+ thd->lex->xa_opt= XA_NONE;
+ if (trans_xa_start(thd))
+ {
+ DBUG_PRINT("error", ("trans_xa_start() failed"));
+ thd->is_slave_error= 1;
+ }
+ }
+ else
+ {
+ if (trans_begin(thd, 0))
+ {
+ DBUG_PRINT("error", ("trans_begin() failed"));
+ thd->is_slave_error= 1;
+ }
}
+
thd->update_stats();
if (likely(!thd->is_slave_error))
@@ -8171,9 +8231,29 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
buf, print_event_info->delimiter))
goto err;
}
- if (!(flags2 & FL_STANDALONE))
- if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+ if ((flags2 & FL_XA_TRANSACTION) && !is_flashback)
+ {
+ my_b_write_string(&cache, "XA START '");
+ my_b_write(&cache, (uchar *) xid.data, xid.gtrid_length);
+ my_b_write_string(&cache, "'");
+ if (xid.bqual_length > 0 || xid.formatID != 1)
+ {
+ my_b_write_string(&cache, ", '");
+ my_b_write(&cache, (uchar *) xid.data+xid.gtrid_length, xid.bqual_length);
+ my_b_write_string(&cache, "'");
+ if (xid.formatID != 1)
+ if (my_b_printf(&cache, ", %d", xid.formatID))
+ goto err;
+ }
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else if (!(flags2 & FL_STANDALONE))
+ {
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n",
+ print_event_info->delimiter))
goto err;
+ }
return cache.flush_data();
err:
@@ -8972,6 +9052,302 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi)
#endif /* !MYSQL_CLIENT */
+/**
+ Function serializes XID which is characterized by by four last arguments
+ of the function.
+ Serialized XID is presented in valid hex format and is returned to
+ the caller in a buffer pointed by the first argument.
+ The buffer size provived by the caller must be not less than
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(XID::formatID) + 1, see
+ XID::serialize_xid() that is a caller and plugin.h for XID declaration.
+
+ @param buf pointer to a buffer allocated for storing serialized data
+
+ @return the value of the buffer pointer
+*/
+
+char *XA_prepare_log_event::event_xid_t::serialize(char *buf) const
+{
+ int i;
+ char *c= buf;
+ /*
+ Build a string like following pattern:
+ X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
+ and store it into buf.
+ Here hex1i and hex2k are hexadecimals representing XID's internal
+ raw bytes (1 <= i <= m, 1 <= k <= n), and `m' and `n' even numbers
+ half of which corresponding to the lengths of XID's components.
+ */
+ c[0]= 'X';
+ c[1]= '\'';
+ c+= 2;
+ for (i= 0; i < gtrid_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ c[1]= ',';
+ c[2]= 'X';
+ c[3]= '\'';
+ c+= 4;
+
+ for (; i < gtrid_length + bqual_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ sprintf(c+1, ",%lu", formatID);
+
+ return buf;
+}
+
+
+/**************************************************************************
+ XA_prepare_log_event methods
+**************************************************************************/
+/**
+ @note
+ It's ok not to use int8store here,
+ as long as xid_t::set(ulonglong) and
+ xid_t::get_n_xid doesn't do it either.
+ We don't care about actual values of xids as long as
+ identical numbers compare identically
+*/
+
+XA_prepare_log_event::
+XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Log_event(buf, description_event)
+{
+ uint32 temp= 0;
+ uint8 temp_byte;
+
+ buf+= description_event->common_header_len +
+ description_event->post_header_len[XA_PREPARE_LOG_EVENT-1];
+ memcpy(&temp_byte, buf, 1);
+ one_phase= (bool) temp_byte;
+ buf += sizeof(temp_byte);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.formatID= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.gtrid_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.bqual_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(m_xid.data, buf, m_xid.gtrid_length + m_xid.bqual_length);
+
+ xid= NULL;
+}
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void XA_prepare_log_event::pack_info(Protocol *protocol)
+{
+ char buf[ser_buf_size];
+ char query[sizeof("XA COMMIT ONE PHASE") + 1 + sizeof(buf)];
+
+ /* RHS of the following assert is unknown to client sources */
+ compile_time_assert(ser_buf_size == XID::ser_buf_size);
+ m_xid.serialize(buf);
+ sprintf(query,
+ (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+ buf);
+
+ protocol->store(query, strlen(query), &my_charset_bin);
+}
+#endif
+
+
+#ifndef MYSQL_CLIENT
+bool XA_prepare_log_event::write()
+{
+ uchar data[1 + 4 + 4 + 4];
+ uint8 one_phase_byte= one_phase;
+
+ data[0]= one_phase;
+ int4store(data+1, static_cast<XID*>(xid)->formatID);
+ int4store(data+(1+4), static_cast<XID*>(xid)->gtrid_length);
+ int4store(data+(1+4+4), static_cast<XID*>(xid)->bqual_length);
+
+ DBUG_ASSERT(xid_bufs_size == sizeof(data) - 1);
+
+ return write_header(sizeof(one_phase_byte) + xid_bufs_size +
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_data(data, sizeof(data)) ||
+ write_data((uchar*) static_cast<XID*>(xid)->data,
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_footer();
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ char buf[ser_buf_size];
+
+ m_xid.serialize(buf);
+
+ if (!print_event_info->short_form)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ if (my_b_printf(&cache, "\tXID = %s\n", buf))
+ goto error;
+ }
+
+ if (my_b_printf(&cache, "XA END %s\n%s\n",
+ buf, print_event_info->delimiter) ||
+ my_b_printf(&cache, "XA PREPARE %s\n%s\n",
+ buf, print_event_info->delimiter))
+ goto error;
+
+ return cache.flush_data();
+error:
+ return TRUE;
+}
+#endif /* MYSQL_CLIENT */
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int XA_prepare_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ bool res;
+ int err;
+ rpl_gtid gtid;
+ uint64 sub_id= 0;
+ Relay_log_info const *rli= rgi->rli;
+ xid_t xid;
+ void *hton= NULL;
+
+ /*
+ XID_EVENT works like a COMMIT statement. And it also updates the
+ mysql.gtid_slave_pos table with the GTID of the current transaction.
+
+ Therefore, it acts much like a normal SQL statement, so we need to do
+ THD::reset_for_next_command() as if starting a new statement.
+ */
+ thd->reset_for_next_command();
+ /*
+ Record any GTID in the same transaction, so slave state is transactionally
+ consistent.
+ */
+#ifdef WITH_WSREP
+ thd->wsrep_affected_rows= 0;
+#endif
+
+ if (rgi->gtid_pending)
+ {
+ xa_states c_state= thd->transaction.xid_state.xa_state;
+ sub_id= rgi->gtid_sub_id;
+ rgi->gtid_pending= false;
+
+ gtid= rgi->current_gtid;
+
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true,
+ false, &hton);
+ thd->transaction.xid_state.xa_state= c_state;
+ if (err)
+ {
+ int ec= thd->get_stmt_da()->sql_errno();
+ /*
+ Do not report an error if this is really a kill due to a deadlock.
+ In this case, the transaction will be re-tried instead.
+ */
+ if (!is_parallel_retry_error(rgi, ec))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
+ "Error during XID COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str, ec,
+ thd->get_stmt_da()->message());
+ thd->is_slave_error= 1;
+ return err;
+ }
+
+ DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
+ { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
+ thd->is_slave_error= 1;
+ return 1;
+ });
+ }
+ /* For a slave XA_prepare_log_event is COMMIT */
+ general_log_print(thd, COM_QUERY,
+ "COMMIT /* implicit, from Xid_log_event */");
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+
+ xid.set(m_xid.formatID,
+ m_xid.data, m_xid.gtrid_length,
+ m_xid.data + m_xid.gtrid_length, m_xid.bqual_length);
+
+ thd->lex->xid= &xid;
+ if (trans_xa_end(thd))
+ return 1;
+
+ if (!one_phase)
+ {
+ res= trans_xa_prepare(thd);
+ }
+ else
+ {
+ res= trans_xa_commit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
+
+ if (!res && sub_id)
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi);
+
+ /*
+ Increment the global status commit count variable
+ */
+ status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+
+ return res;
+}
+
+
+Log_event::enum_skip_reason
+XA_prepare_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Xid_log_event::do_shall_skip");
+ if (rgi->rli->slave_skip_counter > 0)
+ {
+ DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON &&
+ opt_slave_domain_parallel_threads == 0)
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+#endif /* !MYSQL_CLIENT */
+
+
+
+
/**************************************************************************
User_var_log_event methods
**************************************************************************/
@@ -14753,7 +15129,6 @@ bool event_that_should_be_ignored(const char *buf)
event_type == PREVIOUS_GTIDS_LOG_EVENT ||
event_type == TRANSACTION_CONTEXT_EVENT ||
event_type == VIEW_CHANGE_EVENT ||
- event_type == XA_PREPARE_LOG_EVENT ||
(uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
return 1;
return 0;
diff --git a/sql/log_event.h b/sql/log_event.h
index 8402555..8d7ad39 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -217,6 +217,7 @@ class String;
#define GTID_HEADER_LEN 19
#define GTID_LIST_HEADER_LEN 4
#define START_ENCRYPTION_HEADER_LEN 0
+#define XA_PREPARE_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
@@ -3033,6 +3034,75 @@ class Xid_log_event: public Log_event
#endif
};
+
+/**
+ @class XA_prepare_log_event
+
+ Similar to Xid_log_event except that
+ - it is specific to XA transaction
+ - it carries out the prepare logics rather than the final committing
+ when @c one_phase member is off.
+ From the groupping perspective the event finalizes the current "prepare" group
+ started with XA START Query-log-event.
+ When @c one_phase is false Commit of Rollback for XA transaction are
+ logged separately to the prepare-group events so being a groups of
+ their own.
+*/
+
+class XA_prepare_log_event: public Log_event
+{
+protected:
+ /* The event_xid_t members were copied from handler.h */
+ struct event_xid_t
+ {
+ long formatID;
+ long gtrid_length;
+ long bqual_length;
+ char data[MYSQL_XIDDATASIZE]; // not \0-terminated !
+ char *serialize(char *buf) const;
+ };
+
+ /* size of serialization buffer is explained in $MYSQL/sql/xa.h. */
+ static const uint ser_buf_size=
+ 8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
+
+ /* Total size of buffers to hold serialized members of XID struct */
+ static const int xid_bufs_size= 12;
+ event_xid_t m_xid;
+ void *xid;
+ bool one_phase;
+
+public:
+#ifdef MYSQL_SERVER
+ XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
+ Log_event(thd_arg, 0, TRUE), xid(xid_arg), one_phase(one_phase_arg) {}
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
+#else
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+#endif
+ XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event);
+ ~XA_prepare_log_event() {}
+ Log_event_type get_type_code() { return XA_PREPARE_LOG_EVENT; }
+ int get_data_size()
+ {
+ return xid_bufs_size + m_xid.gtrid_length + m_xid.bqual_length;
+ }
+
+#ifdef MYSQL_SERVER
+ bool write();
+#endif
+ bool is_valid() const { return 1; }
+
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(rpl_group_info *rgi);
+ enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+#endif
+};
+
/**
@class User_var_log_event
@@ -3345,6 +3415,11 @@ class Gtid_log_event: public Log_event
uint64 seq_no;
uint64 commit_id;
uint32 domain_id;
+#ifdef MYSQL_SERVER
+ XID xid;
+#else
+ struct st_mysql_xid xid;
+#endif
uchar flags2;
/* Flags2. */
@@ -3373,6 +3448,8 @@ class Gtid_log_event: public Log_event
static const uchar FL_WAITED= 16;
/* FL_DDL is set for event group containing DDL. */
static const uchar FL_DDL= 32;
+ /* FL_XA_TRANSACTION is set for XA transaction. */
+ static const uchar FL_XA_TRANSACTION= 64;
#ifdef MYSQL_SERVER
Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0bbfdba..47d1fc2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1455,12 +1455,19 @@ void THD::cleanup(void)
DBUG_ASSERT(cleanup_done == 0);
set_killed(KILL_CONNECTION);
-#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
-#error xid_state in the cache should be replaced by the allocated value
+ trans_detach(this);
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ }
+ else
+ {
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ trans_rollback(this);
+ xid_cache_delete(this, &transaction.xid_state);
}
-#endif
mysql_ha_cleanup(this);
locked_tables_list.unlock_locked_tables(this);
@@ -1468,11 +1475,6 @@ void THD::cleanup(void)
delete_dynamic(&user_var_events);
close_temporary_tables();
- transaction.xid_state.xa_state= XA_NOTR;
- transaction.xid_state.rm_error= 0;
- trans_rollback(this);
- xid_cache_delete(this, &transaction.xid_state);
-
DBUG_ASSERT(open_tables == NULL);
/*
If the thread was in the middle of an ongoing transaction (rolled
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 30622fd..cdd5b6e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1249,6 +1249,18 @@ typedef struct st_xid_state {
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error;
XID_cache_element *xid_cache_element;
+ /*
+ Binary logging status.
+ It is set to TRUE at XA PREPARE if the transaction was written
+ to the binlog.
+ Naturally FALSE means the transaction was not written to
+ the binlog. Happens if the trnasaction did not modify anything
+ or binlogging was turned off. In that case we shouldn't binlog
+ the consequent XA COMMIT/ROLLBACK.
+ The recovered transaction after server restart sets it to TRUE always.
+ That can cause inconsistencies (shoud be fixed?).
+ */
+ bool is_binlogged;
/**
Check that XA transaction has an uncommitted work. Report an error
@@ -1272,6 +1284,12 @@ typedef struct st_xid_state {
}
return false;
}
+
+ void reset()
+ {
+ xid.null();
+ is_binlogged= FALSE;
+ }
} XID_STATE;
void xid_cache_init(void);
@@ -2616,7 +2634,7 @@ class THD :public Statement,
then.
*/
if (!xid_state.rm_error)
- xid_state.xid.null();
+ xid_state.reset();
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b48070b..3e4a067 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1414,6 +1414,7 @@ void do_handle_one_connection(CONNECT *connect)
#endif
end_thread:
close_connection(thd);
+ thd->get_stmt_da()->reset_diagnostics_area();
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 1c28202..a44b4da 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -790,6 +790,44 @@ bool trans_release_savepoint(THD *thd, LEX_CSTRING name)
/**
+ Detach the current XA transaction;
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_detach(THD *thd)
+{
+ XID_STATE *xid_s= &thd->transaction.xid_state;
+ Ha_trx_info *ha_info, *ha_info_next;
+
+ DBUG_ENTER("trans_detach");
+
+// DBUG_ASSERT(xid_s->xa_state == XA_PREPARED &&
+// xid_cache_search(thd, &xid_s->xid));
+
+ xid_cache_delete(thd, xid_s);
+ if (xid_cache_insert(&xid_s->xid, XA_PREPARED))
+ DBUG_RETURN(TRUE);
+
+ for (ha_info= thd->transaction.all.ha_list;
+ ha_info;
+ ha_info= ha_info_next)
+ {
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
+ }
+
+ thd->transaction.all.ha_list= 0;
+ thd->transaction.all.no_2pc= 0;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Starts an XA transaction with the given xid value.
@param thd Current thread
@@ -928,6 +966,12 @@ bool trans_xa_commit(THD *thd)
res= !xs;
if (res)
my_error(ER_XAER_NOTA, MYF(0));
+ else if (thd->in_multi_stmt_transaction_mode())
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ res= TRUE;
+ }
else
{
res= xa_trans_rolled_back(xs);
@@ -978,8 +1022,16 @@ bool trans_xa_commit(THD *thd)
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- res= MY_TEST(ha_commit_one_phase(thd, 1));
- if (res)
+ if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ TRUE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ if (res || (res= MY_TEST(ha_commit_one_phase(thd, 1))))
my_error(ER_XAER_RMERR, MYF(0));
}
}
@@ -1044,7 +1096,18 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(TRUE);
}
- res= xa_trans_force_rollback(thd);
+ if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ TRUE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ res= res || xa_trans_force_rollback(thd);
+ if (res || (res= MY_TEST(xa_trans_force_rollback(thd))))
+ my_error(ER_XAER_RMERR, MYF(0));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
diff --git a/sql/transaction.h b/sql/transaction.h
index 7e34693..f228cc6 100644
--- a/sql/transaction.h
+++ b/sql/transaction.h
@@ -29,6 +29,7 @@ bool trans_commit(THD *thd);
bool trans_commit_implicit(THD *thd);
bool trans_rollback(THD *thd);
bool trans_rollback_implicit(THD *thd);
+bool trans_detach(THD *thd);
bool trans_commit_stmt(THD *thd);
bool trans_rollback_stmt(THD *thd);
1
0
revision-id: dd23963099ad840bc86fd24cee0913647a8e93b3 (mariadb-10.3.6-137-gdd23963)
parent(s): 81ba90b59e9ed57fdc525a631d3b6643d3669a7c
committer: Alexey Botchkov
timestamp: 2018-11-20 02:12:54 +0400
message:
MDEV-7974 XA transactions.
First part of the patch - binlogging of the XA transactions.
---
sql/handler.cc | 20 ++-
sql/handler.h | 10 ++
sql/log.cc | 86 +++++++++++-
sql/log_event.cc | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++--
sql/log_event.h | 77 +++++++++++
sql/sql_class.cc | 18 +--
sql/sql_class.h | 20 ++-
sql/sql_connect.cc | 1 +
sql/transaction.cc | 69 ++++++++-
sql/transaction.h | 1 +
10 files changed, 675 insertions(+), 26 deletions(-)
diff --git a/sql/handler.cc b/sql/handler.cc
index 943722a..61bd7d4 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1185,9 +1185,12 @@ static int prepare_or_error(handlerton *ht, THD *thd, bool all)
*/
int ha_prepare(THD *thd)
{
- int error=0, all=1;
+ int error=0, all=1, cookie;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list;
+ bool need_prepare_ordered= FALSE;
+ bool need_commit_ordered= FALSE;
+
DBUG_ENTER("ha_prepare");
if (ha_info)
@@ -1212,9 +1215,24 @@ int ha_prepare(THD *thd)
ha_resolve_storage_engine_name(ht));
}
+ need_prepare_ordered|= (ht->prepare_ordered != NULL);
+ need_commit_ordered|= (ht->commit_ordered != NULL);
+ }
+ cookie= tc_log->log_and_order(thd, 0, all, need_prepare_ordered,
+ need_commit_ordered);
+ if (!cookie)
+ {
+ error= 1;
+ goto end;
+ }
+ if (tc_log->unlog(cookie, 0))
+ {
+ error= 1;
+ goto end;
}
}
+end:
DBUG_RETURN(error);
}
diff --git a/sql/handler.h b/sql/handler.h
index 68a54cc..52165a6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -787,6 +787,16 @@ struct xid_t {
long gtrid_length;
long bqual_length;
char data[XIDDATASIZE]; // not \0-terminated !
+ /*
+ The size of the string containing serialized Xid representation
+ is computed as a sum of
+ eight as the number of formatting symbols (X'',X'',)
+ plus 2 x XIDDATASIZE (2 due to hex format),
+ plus space for decimal digits of XID::formatID,
+ plus one for 0x0.
+ */
+ static const uint ser_buf_size=
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(long) + 1;
xid_t() {} /* Remove gcc warning */
bool eq(struct xid_t *xid)
diff --git a/sql/log.cc b/sql/log.cc
index 86137ad..d0dbd25 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -87,6 +87,9 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_xa_recover(handlerton *hton, XID *xid_list, uint len);
+static int binlog_commit_by_xid(handlerton *hton, XID *xid);
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid);
static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
static const LEX_CSTRING write_error_msg=
@@ -1688,6 +1691,10 @@ int binlog_init(void *p)
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
binlog_hton->prepare= binlog_prepare;
+ binlog_hton->recover= binlog_xa_recover;
+ binlog_hton->commit_by_xid = binlog_commit_by_xid;
+ binlog_hton->rollback_by_xid = binlog_rollback_by_xid;
+
binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
@@ -1883,12 +1890,23 @@ static inline int
binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
bool all, my_xid xid)
{
+ /* Mask XA COMMIT ... ONE PHASE as plain BEGIN ... COMMIT */
+ if (!xid && thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt == XA_ONE_PHASE)
+ xid= thd->query_id;
+
if (xid)
{
Xid_log_event end_evt(thd, xid, TRUE);
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
}
- else
+ else if (thd->transaction.xid_state.xa_state == XA_IDLE)
+ {
+ /* XA PREPARE */
+ XID *xid= &thd->transaction.xid_state.xid;
+ XA_prepare_log_event end_evt(thd, xid, TRUE);
+ return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
+ }
{
/*
Empty xid occurs in XA COMMIT ... ONE PHASE.
@@ -1966,6 +1984,72 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
return 0;
}
+
+static int serialize_xid(XID *xid, char *buf)
+{
+ size_t size;
+ buf[0]= '\'';
+ memcpy(buf+1, xid->data, xid->gtrid_length);
+ size= xid->gtrid_length + 2;
+ buf[size-1]= '\'';
+ if (xid->bqual_length == 0 && xid->formatID == 1)
+ return size;
+
+ memcpy(buf+size, ", '", 3);
+ memcpy(buf+size+3, xid->data+xid->gtrid_length, xid->bqual_length);
+ size+= 3 + xid->bqual_length;
+ buf[size]= '\'';
+ size++;
+ if (xid->formatID != 1)
+ size+= sprintf(buf+size, ", %ld", xid->formatID);
+ return size;
+}
+
+
+static int binlog_xa_recover(handlerton *hton __attribute__((unused)),
+ XID *xid_list __attribute__((unused)),
+ uint len __attribute__((unused)))
+{
+ /* Does nothing. */
+ return 0;
+}
+
+
+static int binlog_commit_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xc_len= sizeof("XA COMMIT ") - 1; // do not count trailing 0
+ char buf[xc_len + xid_t::ser_buf_size];
+ size_t buflen;
+ binlog_cache_mngr *const cache_mngr= thd->binlog_setup_trx_data();
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT);
+
+ if (!cache_mngr)
+ return 1;
+
+ memcpy(buf, "XA COMMIT ", xc_len);
+ buflen= xc_len + serialize_xid(xid, buf+xc_len);
+ Query_log_event qe(thd, buf, buflen, TRUE, FALSE, FALSE, 0);
+ return binlog_flush_cache(thd, cache_mngr, &qe, TRUE, TRUE, TRUE);
+}
+
+
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid)
+{
+ THD *thd= current_thd;
+ const size_t xr_len= sizeof("XA ROLLBACK ") - 1; // do not count trailing 0
+ char buf[xr_len + xid_t::ser_buf_size];
+ size_t buflen;
+
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
+ memcpy(buf, "XA ROLLBACK ", xr_len);
+ buflen= xr_len + serialize_xid(xid, buf+xr_len);
+ Query_log_event qe(thd, buf, buflen, FALSE, TRUE, TRUE, 0);
+ return mysql_bin_log.write_event(&qe);
+}
+
+
/*
We flush the cache wrapped in a beging/rollback if:
. aborting a single or multi-statement transaction and;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 13690a8..ed91111 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2124,6 +2124,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case XID_EVENT:
ev = new Xid_log_event(buf, fdle);
break;
+ case XA_PREPARE_LOG_EVENT:
+ ev = new XA_prepare_log_event(buf, fdle);
+ break;
case RAND_EVENT:
ev = new Rand_log_event(buf, fdle);
break;
@@ -2175,7 +2178,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case PREVIOUS_GTIDS_LOG_EVENT:
case TRANSACTION_CONTEXT_EVENT:
case VIEW_CHANGE_EVENT:
- case XA_PREPARE_LOG_EVENT:
ev= new Ignorable_log_event(buf, fdle,
get_type_str((Log_event_type) event_type));
break;
@@ -6185,6 +6187,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[USER_VAR_EVENT-1]= USER_VAR_HEADER_LEN;
post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
post_header_len[XID_EVENT-1]= XID_HEADER_LEN;
+ post_header_len[XA_PREPARE_LOG_EVENT-1]= XA_PREPARE_HEADER_LEN;
post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= BEGIN_LOAD_QUERY_HEADER_LEN;
post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
/*
@@ -7840,7 +7843,7 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
buf+= 8;
domain_id= uint4korr(buf);
buf+= 4;
- flags2= *buf;
+ flags2= *(buf++);
if (flags2 & FL_GROUP_COMMIT_ID)
{
if (event_len < (uint)header_size + GTID_HEADER_LEN + 2)
@@ -7848,8 +7851,22 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
seq_no= 0; // So is_valid() returns false
return;
}
- ++buf;
commit_id= uint8korr(buf);
+ buf+= 8;
+ }
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ xid.formatID= (long) buf[0];
+ xid.gtrid_length= (long) buf[1];
+ xid.bqual_length= (long) buf[2];
+
+ buf+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(xid.data, buf, data_length);
+ buf+= data_length;
+ }
}
}
@@ -7880,6 +7897,12 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
/* Preserve any DDL or WAITED flag in the slave's binlog. */
if (thd_arg->rgi_slave)
flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+ if (thd->transaction.xid_state.xa_state == XA_IDLE &&
+ thd->lex->xa_opt != XA_ONE_PHASE)
+ {
+ flags2|= FL_XA_TRANSACTION;
+ xid= thd->transaction.xid_state.xid;
+ }
}
@@ -7922,7 +7945,7 @@ Gtid_log_event::peek(const char *event_start, size_t event_len,
bool
Gtid_log_event::write()
{
- uchar buf[GTID_HEADER_LEN+2];
+ uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
size_t write_len;
int8store(buf, seq_no);
@@ -7934,8 +7957,25 @@ Gtid_log_event::write()
write_len= GTID_HEADER_LEN + 2;
}
else
+ write_len= 13;
+
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ buf[write_len]= (uchar) ((char) xid.formatID);
+ buf[write_len+1]= (uchar) xid.gtrid_length;
+ buf[write_len+2]= (uchar) xid.bqual_length;
+ write_len+= 3;
+ if (xid.formatID >= 0)
+ {
+ long data_length= xid.bqual_length + xid.gtrid_length;
+ memcpy(buf+write_len, xid.data, data_length);
+ write_len+= data_length;
+ }
+ }
+
+ if (write_len < GTID_HEADER_LEN)
{
- bzero(buf+13, GTID_HEADER_LEN-13);
+ bzero(buf+write_len, GTID_HEADER_LEN-write_len);
write_len= GTID_HEADER_LEN;
}
return write_header(write_len) ||
@@ -7978,7 +8018,7 @@ Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
void
Gtid_log_event::pack_info(Protocol *protocol)
{
- char buf[6+5+10+1+10+1+20+1+4+20+1];
+ char buf[6+5+10+1+10+1+20+1+4+20+1+5+128];
char *p;
p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
p= longlong10_to_str(domain_id, p, 10);
@@ -7992,6 +8032,12 @@ Gtid_log_event::pack_info(Protocol *protocol)
p= longlong10_to_str(commit_id, p, 10);
}
+ if (flags2 & FL_XA_TRANSACTION)
+ {
+ p= strmov(p, " XID :");
+ p= strnmov(p, xid.data, xid.bqual_length + xid.gtrid_length);
+ }
+
protocol->store(buf, p-buf, &my_charset_bin);
}
@@ -8048,11 +8094,25 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi)
thd->lex->sql_command= SQLCOM_BEGIN;
thd->is_slave_error= 0;
status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
- if (trans_begin(thd, 0))
+ if (flags2 & FL_XA_TRANSACTION)
{
- DBUG_PRINT("error", ("trans_begin() failed"));
- thd->is_slave_error= 1;
+ thd->lex->xid= &xid;
+ thd->lex->xa_opt= XA_NONE;
+ if (trans_xa_start(thd))
+ {
+ DBUG_PRINT("error", ("trans_xa_start() failed"));
+ thd->is_slave_error= 1;
+ }
+ }
+ else
+ {
+ if (trans_begin(thd, 0))
+ {
+ DBUG_PRINT("error", ("trans_begin() failed"));
+ thd->is_slave_error= 1;
+ }
}
+
thd->update_stats();
if (likely(!thd->is_slave_error))
@@ -8171,9 +8231,29 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
buf, print_event_info->delimiter))
goto err;
}
- if (!(flags2 & FL_STANDALONE))
- if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+ if ((flags2 & FL_XA_TRANSACTION) && !is_flashback)
+ {
+ my_b_write_string(&cache, "XA START '");
+ my_b_write(&cache, (uchar *) xid.data, xid.gtrid_length);
+ my_b_write_string(&cache, "'");
+ if (xid.bqual_length > 0 || xid.formatID != 1)
+ {
+ my_b_write_string(&cache, ", '");
+ my_b_write(&cache, (uchar *) xid.data+xid.gtrid_length, xid.bqual_length);
+ my_b_write_string(&cache, "'");
+ if (xid.formatID != 1)
+ if (my_b_printf(&cache, ", %d", xid.formatID))
+ goto err;
+ }
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else if (!(flags2 & FL_STANDALONE))
+ {
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n",
+ print_event_info->delimiter))
goto err;
+ }
return cache.flush_data();
err:
@@ -8972,6 +9052,302 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi)
#endif /* !MYSQL_CLIENT */
+/**
+ Function serializes XID which is characterized by by four last arguments
+ of the function.
+ Serialized XID is presented in valid hex format and is returned to
+ the caller in a buffer pointed by the first argument.
+ The buffer size provived by the caller must be not less than
+ 8 + 2 * XIDDATASIZE + 4 * sizeof(XID::formatID) + 1, see
+ XID::serialize_xid() that is a caller and plugin.h for XID declaration.
+
+ @param buf pointer to a buffer allocated for storing serialized data
+
+ @return the value of the buffer pointer
+*/
+
+char *XA_prepare_log_event::event_xid_t::serialize(char *buf) const
+{
+ int i;
+ char *c= buf;
+ /*
+ Build a string like following pattern:
+ X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
+ and store it into buf.
+ Here hex1i and hex2k are hexadecimals representing XID's internal
+ raw bytes (1 <= i <= m, 1 <= k <= n), and `m' and `n' even numbers
+ half of which corresponding to the lengths of XID's components.
+ */
+ c[0]= 'X';
+ c[1]= '\'';
+ c+= 2;
+ for (i= 0; i < gtrid_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ c[1]= ',';
+ c[2]= 'X';
+ c[3]= '\'';
+ c+= 4;
+
+ for (; i < gtrid_length + bqual_length; i++)
+ {
+ c[0]=_dig_vec_lower[((uchar*) data)[i] >> 4];
+ c[1]=_dig_vec_lower[((uchar*) data)[i] & 0x0f];
+ c+= 2;
+ }
+ c[0]= '\'';
+ sprintf(c+1, ",%lu", formatID);
+
+ return buf;
+}
+
+
+/**************************************************************************
+ XA_prepare_log_event methods
+**************************************************************************/
+/**
+ @note
+ It's ok not to use int8store here,
+ as long as xid_t::set(ulonglong) and
+ xid_t::get_n_xid doesn't do it either.
+ We don't care about actual values of xids as long as
+ identical numbers compare identically
+*/
+
+XA_prepare_log_event::
+XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Log_event(buf, description_event)
+{
+ uint32 temp= 0;
+ uint8 temp_byte;
+
+ buf+= description_event->common_header_len +
+ description_event->post_header_len[XA_PREPARE_LOG_EVENT-1];
+ memcpy(&temp_byte, buf, 1);
+ one_phase= (bool) temp_byte;
+ buf += sizeof(temp_byte);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.formatID= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.gtrid_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(&temp, buf, sizeof(temp));
+ m_xid.bqual_length= le32toh(temp);
+ buf += sizeof(temp);
+ memcpy(m_xid.data, buf, m_xid.gtrid_length + m_xid.bqual_length);
+
+ xid= NULL;
+}
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void XA_prepare_log_event::pack_info(Protocol *protocol)
+{
+ char buf[ser_buf_size];
+ char query[sizeof("XA COMMIT ONE PHASE") + 1 + sizeof(buf)];
+
+ /* RHS of the following assert is unknown to client sources */
+ compile_time_assert(ser_buf_size == XID::ser_buf_size);
+ m_xid.serialize(buf);
+ sprintf(query,
+ (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+ buf);
+
+ protocol->store(query, strlen(query), &my_charset_bin);
+}
+#endif
+
+
+#ifndef MYSQL_CLIENT
+bool XA_prepare_log_event::write()
+{
+ uchar data[1 + 4 + 4 + 4];
+ uint8 one_phase_byte= one_phase;
+
+ data[0]= one_phase;
+ int4store(data+1, static_cast<XID*>(xid)->formatID);
+ int4store(data+(1+4), static_cast<XID*>(xid)->gtrid_length);
+ int4store(data+(1+4+4), static_cast<XID*>(xid)->bqual_length);
+
+ DBUG_ASSERT(xid_bufs_size == sizeof(data) - 1);
+
+ return write_header(sizeof(one_phase_byte) + xid_bufs_size +
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_data(data, sizeof(data)) ||
+ write_data((uchar*) static_cast<XID*>(xid)->data,
+ static_cast<XID*>(xid)->gtrid_length +
+ static_cast<XID*>(xid)->bqual_length) ||
+ write_footer();
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ char buf[ser_buf_size];
+
+ m_xid.serialize(buf);
+
+ if (!print_event_info->short_form)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ if (my_b_printf(&cache, "\tXID = %s\n", buf))
+ goto error;
+ }
+
+ if (my_b_printf(&cache, "XA END %s\n%s\n",
+ buf, print_event_info->delimiter) ||
+ my_b_printf(&cache, "XA PREPARE %s\n%s\n",
+ buf, print_event_info->delimiter))
+ goto error;
+
+ return cache.flush_data();
+error:
+ return TRUE;
+}
+#endif /* MYSQL_CLIENT */
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int XA_prepare_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ bool res;
+ int err;
+ rpl_gtid gtid;
+ uint64 sub_id= 0;
+ Relay_log_info const *rli= rgi->rli;
+ xid_t xid;
+ void *hton= NULL;
+
+ /*
+ XID_EVENT works like a COMMIT statement. And it also updates the
+ mysql.gtid_slave_pos table with the GTID of the current transaction.
+
+ Therefore, it acts much like a normal SQL statement, so we need to do
+ THD::reset_for_next_command() as if starting a new statement.
+ */
+ thd->reset_for_next_command();
+ /*
+ Record any GTID in the same transaction, so slave state is transactionally
+ consistent.
+ */
+#ifdef WITH_WSREP
+ thd->wsrep_affected_rows= 0;
+#endif
+
+ if (rgi->gtid_pending)
+ {
+ xa_states c_state= thd->transaction.xid_state.xa_state;
+ sub_id= rgi->gtid_sub_id;
+ rgi->gtid_pending= false;
+
+ gtid= rgi->current_gtid;
+
+ thd->transaction.xid_state.xa_state= XA_ACTIVE;
+ err= rpl_global_gtid_slave_state->record_gtid(thd, >id, sub_id, true,
+ false, &hton);
+ thd->transaction.xid_state.xa_state= c_state;
+ if (err)
+ {
+ int ec= thd->get_stmt_da()->sql_errno();
+ /*
+ Do not report an error if this is really a kill due to a deadlock.
+ In this case, the transaction will be re-tried instead.
+ */
+ if (!is_parallel_retry_error(rgi, ec))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
+ "Error during XID COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str, ec,
+ thd->get_stmt_da()->message());
+ thd->is_slave_error= 1;
+ return err;
+ }
+
+ DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
+ { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
+ thd->is_slave_error= 1;
+ return 1;
+ });
+ }
+ /* For a slave XA_prepare_log_event is COMMIT */
+ general_log_print(thd, COM_QUERY,
+ "COMMIT /* implicit, from Xid_log_event */");
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+
+ xid.set(m_xid.formatID,
+ m_xid.data, m_xid.gtrid_length,
+ m_xid.data + m_xid.gtrid_length, m_xid.bqual_length);
+
+ thd->lex->xid= &xid;
+ if (trans_xa_end(thd))
+ return 1;
+
+ if (!one_phase)
+ {
+ res= trans_xa_prepare(thd);
+ }
+ else
+ {
+ res= trans_xa_commit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
+
+ if (!res && sub_id)
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, >id, hton, rgi);
+
+ /*
+ Increment the global status commit count variable
+ */
+ status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+
+ return res;
+}
+
+
+Log_event::enum_skip_reason
+XA_prepare_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Xid_log_event::do_shall_skip");
+ if (rgi->rli->slave_skip_counter > 0)
+ {
+ DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON &&
+ opt_slave_domain_parallel_threads == 0)
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+#endif /* !MYSQL_CLIENT */
+
+
+
+
/**************************************************************************
User_var_log_event methods
**************************************************************************/
@@ -14753,7 +15129,6 @@ bool event_that_should_be_ignored(const char *buf)
event_type == PREVIOUS_GTIDS_LOG_EVENT ||
event_type == TRANSACTION_CONTEXT_EVENT ||
event_type == VIEW_CHANGE_EVENT ||
- event_type == XA_PREPARE_LOG_EVENT ||
(uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
return 1;
return 0;
diff --git a/sql/log_event.h b/sql/log_event.h
index 8402555..8d7ad39 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -217,6 +217,7 @@ class String;
#define GTID_HEADER_LEN 19
#define GTID_LIST_HEADER_LEN 4
#define START_ENCRYPTION_HEADER_LEN 0
+#define XA_PREPARE_HEADER_LEN 0
/*
Max number of possible extra bytes in a replication event compared to a
@@ -3033,6 +3034,75 @@ class Xid_log_event: public Log_event
#endif
};
+
+/**
+ @class XA_prepare_log_event
+
+ Similar to Xid_log_event except that
+ - it is specific to XA transaction
+ - it carries out the prepare logics rather than the final committing
+ when @c one_phase member is off.
+ From the groupping perspective the event finalizes the current "prepare" group
+ started with XA START Query-log-event.
+ When @c one_phase is false Commit of Rollback for XA transaction are
+ logged separately to the prepare-group events so being a groups of
+ their own.
+*/
+
+class XA_prepare_log_event: public Log_event
+{
+protected:
+ /* The event_xid_t members were copied from handler.h */
+ struct event_xid_t
+ {
+ long formatID;
+ long gtrid_length;
+ long bqual_length;
+ char data[MYSQL_XIDDATASIZE]; // not \0-terminated !
+ char *serialize(char *buf) const;
+ };
+
+ /* size of serialization buffer is explained in $MYSQL/sql/xa.h. */
+ static const uint ser_buf_size=
+ 8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
+
+ /* Total size of buffers to hold serialized members of XID struct */
+ static const int xid_bufs_size= 12;
+ event_xid_t m_xid;
+ void *xid;
+ bool one_phase;
+
+public:
+#ifdef MYSQL_SERVER
+ XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
+ Log_event(thd_arg, 0, TRUE), xid(xid_arg), one_phase(one_phase_arg) {}
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
+#else
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+#endif
+ XA_prepare_log_event(const char* buf,
+ const Format_description_log_event *description_event);
+ ~XA_prepare_log_event() {}
+ Log_event_type get_type_code() { return XA_PREPARE_LOG_EVENT; }
+ int get_data_size()
+ {
+ return xid_bufs_size + m_xid.gtrid_length + m_xid.bqual_length;
+ }
+
+#ifdef MYSQL_SERVER
+ bool write();
+#endif
+ bool is_valid() const { return 1; }
+
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(rpl_group_info *rgi);
+ enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+#endif
+};
+
/**
@class User_var_log_event
@@ -3345,6 +3415,11 @@ class Gtid_log_event: public Log_event
uint64 seq_no;
uint64 commit_id;
uint32 domain_id;
+#ifdef MYSQL_SERVER
+ XID xid;
+#else
+ struct st_mysql_xid xid;
+#endif
uchar flags2;
/* Flags2. */
@@ -3373,6 +3448,8 @@ class Gtid_log_event: public Log_event
static const uchar FL_WAITED= 16;
/* FL_DDL is set for event group containing DDL. */
static const uchar FL_DDL= 32;
+ /* FL_XA_TRANSACTION is set for XA transaction. */
+ static const uchar FL_XA_TRANSACTION= 64;
#ifdef MYSQL_SERVER
Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0bbfdba..47d1fc2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1455,12 +1455,19 @@ void THD::cleanup(void)
DBUG_ASSERT(cleanup_done == 0);
set_killed(KILL_CONNECTION);
-#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
-#error xid_state in the cache should be replaced by the allocated value
+ trans_detach(this);
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ }
+ else
+ {
+ transaction.xid_state.xa_state= XA_NOTR;
+ transaction.xid_state.rm_error= 0;
+ trans_rollback(this);
+ xid_cache_delete(this, &transaction.xid_state);
}
-#endif
mysql_ha_cleanup(this);
locked_tables_list.unlock_locked_tables(this);
@@ -1468,11 +1475,6 @@ void THD::cleanup(void)
delete_dynamic(&user_var_events);
close_temporary_tables();
- transaction.xid_state.xa_state= XA_NOTR;
- transaction.xid_state.rm_error= 0;
- trans_rollback(this);
- xid_cache_delete(this, &transaction.xid_state);
-
DBUG_ASSERT(open_tables == NULL);
/*
If the thread was in the middle of an ongoing transaction (rolled
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 30622fd..cdd5b6e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1249,6 +1249,18 @@ typedef struct st_xid_state {
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error;
XID_cache_element *xid_cache_element;
+ /*
+ Binary logging status.
+ It is set to TRUE at XA PREPARE if the transaction was written
+ to the binlog.
+ Naturally FALSE means the transaction was not written to
+ the binlog. Happens if the trnasaction did not modify anything
+ or binlogging was turned off. In that case we shouldn't binlog
+ the consequent XA COMMIT/ROLLBACK.
+ The recovered transaction after server restart sets it to TRUE always.
+ That can cause inconsistencies (shoud be fixed?).
+ */
+ bool is_binlogged;
/**
Check that XA transaction has an uncommitted work. Report an error
@@ -1272,6 +1284,12 @@ typedef struct st_xid_state {
}
return false;
}
+
+ void reset()
+ {
+ xid.null();
+ is_binlogged= FALSE;
+ }
} XID_STATE;
void xid_cache_init(void);
@@ -2616,7 +2634,7 @@ class THD :public Statement,
then.
*/
if (!xid_state.rm_error)
- xid_state.xid.null();
+ xid_state.reset();
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b48070b..3e4a067 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1414,6 +1414,7 @@ void do_handle_one_connection(CONNECT *connect)
#endif
end_thread:
close_connection(thd);
+ thd->get_stmt_da()->reset_diagnostics_area();
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 1c28202..a44b4da 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -790,6 +790,44 @@ bool trans_release_savepoint(THD *thd, LEX_CSTRING name)
/**
+ Detach the current XA transaction;
+
+ @param thd Current thread
+
+ @retval FALSE Success
+ @retval TRUE Failure
+*/
+
+bool trans_detach(THD *thd)
+{
+ XID_STATE *xid_s= &thd->transaction.xid_state;
+ Ha_trx_info *ha_info, *ha_info_next;
+
+ DBUG_ENTER("trans_detach");
+
+// DBUG_ASSERT(xid_s->xa_state == XA_PREPARED &&
+// xid_cache_search(thd, &xid_s->xid));
+
+ xid_cache_delete(thd, xid_s);
+ if (xid_cache_insert(&xid_s->xid, XA_PREPARED))
+ DBUG_RETURN(TRUE);
+
+ for (ha_info= thd->transaction.all.ha_list;
+ ha_info;
+ ha_info= ha_info_next)
+ {
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
+ }
+
+ thd->transaction.all.ha_list= 0;
+ thd->transaction.all.no_2pc= 0;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Starts an XA transaction with the given xid value.
@param thd Current thread
@@ -928,6 +966,12 @@ bool trans_xa_commit(THD *thd)
res= !xs;
if (res)
my_error(ER_XAER_NOTA, MYF(0));
+ else if (thd->in_multi_stmt_transaction_mode())
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xid_state.xa_state]);
+ res= TRUE;
+ }
else
{
res= xa_trans_rolled_back(xs);
@@ -978,8 +1022,16 @@ bool trans_xa_commit(THD *thd)
{
DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
- res= MY_TEST(ha_commit_one_phase(thd, 1));
- if (res)
+ if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ TRUE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ if (res || (res= MY_TEST(ha_commit_one_phase(thd, 1))))
my_error(ER_XAER_RMERR, MYF(0));
}
}
@@ -1044,7 +1096,18 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(TRUE);
}
- res= xa_trans_force_rollback(thd);
+ if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+ {
+ res= thd->binlog_query(THD::THD::STMT_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ TRUE, FALSE, FALSE, 0);
+ }
+ else
+ res= 0;
+
+ res= res || xa_trans_force_rollback(thd);
+ if (res || (res= MY_TEST(xa_trans_force_rollback(thd))))
+ my_error(ER_XAER_RMERR, MYF(0));
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
diff --git a/sql/transaction.h b/sql/transaction.h
index 7e34693..f228cc6 100644
--- a/sql/transaction.h
+++ b/sql/transaction.h
@@ -29,6 +29,7 @@ bool trans_commit(THD *thd);
bool trans_commit_implicit(THD *thd);
bool trans_rollback(THD *thd);
bool trans_rollback_implicit(THD *thd);
+bool trans_detach(THD *thd);
bool trans_commit_stmt(THD *thd);
bool trans_rollback_stmt(THD *thd);
1
0
revision-id: 01688fb01660a363d8ee3f594d9d97455db8c5ae (fb-prod201801-166-g01688fb0166)
parent(s): 36f310f32dff0d34cb21a66afbcaec955d0642bc
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2018-11-20 00:42:50 +0300
message:
Range Locking test coverage
Add rocksdb_use_range_locking=1 into 'combinations' so all tests are
also run with Range Locking by default.
Some tests still fail.
Disable rocksdb.rocksdb in Range Locking mode as an example.
---
mysql-test/suite/rocksdb/combinations | 3 +++
mysql-test/suite/rocksdb/include/not_range_locking.inc | 5 +++++
mysql-test/suite/rocksdb/t/rocksdb.test | 3 +++
3 files changed, 11 insertions(+)
diff --git a/mysql-test/suite/rocksdb/combinations b/mysql-test/suite/rocksdb/combinations
index b7316c71485..c9a4494607a 100644
--- a/mysql-test/suite/rocksdb/combinations
+++ b/mysql-test/suite/rocksdb/combinations
@@ -3,3 +3,6 @@ rocksdb_write_policy=write_committed
[write_prepared]
rocksdb_write_policy=write_prepared
+
+[range_locking]
+rocksdb_use_range_locking=1
diff --git a/mysql-test/suite/rocksdb/include/not_range_locking.inc b/mysql-test/suite/rocksdb/include/not_range_locking.inc
new file mode 100644
index 00000000000..62c26b134bc
--- /dev/null
+++ b/mysql-test/suite/rocksdb/include/not_range_locking.inc
@@ -0,0 +1,5 @@
+--let $_use_range_locking= `select @@rocksdb_use_range_locking`
+if ($_use_range_locking == 1)
+{
+ --skip Test doesn't support range locking
+}
diff --git a/mysql-test/suite/rocksdb/t/rocksdb.test b/mysql-test/suite/rocksdb/t/rocksdb.test
index cf8fb29e20f..09004b1bf57 100644
--- a/mysql-test/suite/rocksdb/t/rocksdb.test
+++ b/mysql-test/suite/rocksdb/t/rocksdb.test
@@ -1,6 +1,9 @@
--source include/have_rocksdb.inc
--source suite/rocksdb/include/have_write_committed.inc
+# Does SHOW WARNINGS and SHOW STATUS which change in Range Locking mode
+--source suite/rocksdb/include/not_range_locking.inc
+
#
# RocksDB Storage Engine tests
#
1
0
revision-id: 52eb05359d8e8ab2b3f425a5299fbfc2ff510946 (fb-prod201801-166-g52eb05359d8)
parent(s): 36f310f32dff0d34cb21a66afbcaec955d0642bc
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2018-11-20 00:41:09 +0300
message:
Range Locking test coverage
Add rocksdb_use_range_locking=1 into 'combinations' so all tests are
also run with Range Locking by default.
Some tests still fail.
Disable rocksdb.rocksdb in Range Locking mode as an example.
---
mysql-test/suite/rocksdb/combinations | 3 +++
mysql-test/suite/rocksdb/include/not_range_locking.inc | 5 +++++
mysql-test/suite/rocksdb/t/rocksdb.test | 3 +++
3 files changed, 11 insertions(+)
diff --git a/mysql-test/suite/rocksdb/combinations b/mysql-test/suite/rocksdb/combinations
index b7316c71485..c9a4494607a 100644
--- a/mysql-test/suite/rocksdb/combinations
+++ b/mysql-test/suite/rocksdb/combinations
@@ -3,3 +3,6 @@ rocksdb_write_policy=write_committed
[write_prepared]
rocksdb_write_policy=write_prepared
+
+[range_locking]
+rocksdb_use_range_locking=1
diff --git a/mysql-test/suite/rocksdb/include/not_range_locking.inc b/mysql-test/suite/rocksdb/include/not_range_locking.inc
new file mode 100644
index 00000000000..62c26b134bc
--- /dev/null
+++ b/mysql-test/suite/rocksdb/include/not_range_locking.inc
@@ -0,0 +1,5 @@
+--let $_use_range_locking= `select @@rocksdb_use_range_locking`
+if ($_use_range_locking == 1)
+{
+ --skip Test doesn't support range locking
+}
diff --git a/mysql-test/suite/rocksdb/t/rocksdb.test b/mysql-test/suite/rocksdb/t/rocksdb.test
index cf8fb29e20f..09004b1bf57 100644
--- a/mysql-test/suite/rocksdb/t/rocksdb.test
+++ b/mysql-test/suite/rocksdb/t/rocksdb.test
@@ -1,6 +1,9 @@
--source include/have_rocksdb.inc
--source suite/rocksdb/include/have_write_committed.inc
+# Does SHOW WARNINGS and SHOW STATUS which change in Range Locking mode
+--source suite/rocksdb/include/not_range_locking.inc
+
#
# RocksDB Storage Engine tests
#
1
0
19 Nov '18
revision-id: 36f310f32dff0d34cb21a66afbcaec955d0642bc (fb-prod201801-165-g36f310f32df)
parent(s): a953b2edbca118a1689497882f4cfe21f5e1f207
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2018-11-19 23:09:44 +0300
message:
Make rocksdb_kill_connection() thread-safe
This was observable as a failure of rocksdb.ddl_high_priority test
---
storage/rocksdb/ha_rocksdb.cc | 42 +++++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc
index 72f422ce1ce..da75885cd36 100644
--- a/storage/rocksdb/ha_rocksdb.cc
+++ b/storage/rocksdb/ha_rocksdb.cc
@@ -2032,6 +2032,9 @@ protected:
bool m_is_delayed_snapshot = false;
bool m_is_two_phase = false;
+ // Last known TransactionID of the underlying transaction, or UINT_MAX
+ // for write batches. See kill_lock_wait_by_thd.
+ uint64_t m_last_trx_id;
private:
/*
Number of write operations this transaction had when we took the last
@@ -2690,6 +2693,8 @@ public:
s_tx_list.erase(this);
RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
}
+
+ static void kill_lock_wait_by_thd(THD *thd);
};
/*
@@ -2975,6 +2980,8 @@ public:
rdb->BeginTransaction(write_opts, tx_opts, m_rocksdb_reuse_tx);
m_rocksdb_reuse_tx = nullptr;
+ m_last_trx_id = m_rocksdb_tx->GetID();
+
m_read_opts = rocksdb::ReadOptions();
set_initial_savepoint();
@@ -3246,6 +3253,7 @@ public:
: Rdb_transaction(thd), m_batch(nullptr) {
m_batch = new rocksdb::WriteBatchWithIndex(rocksdb::BytewiseComparator(), 0,
true);
+ m_last_trx_id= UINT64_MAX;
}
virtual ~Rdb_writebatch_impl() {
@@ -4319,24 +4327,32 @@ static int rocksdb_start_tx_and_assign_read_view(
}
-static void
-rocksdb_kill_connection(handlerton* hton,
- THD* thd)
+void rocksdb_kill_connection(handlerton* hton, THD* thd)
{
- //TODO: db_env->kill_waiter(db_env, thd);
- // locktree_manager::kill_waiter(void *extra)
+ Rdb_transaction::kill_lock_wait_by_thd(thd);
+}
+
+
+void Rdb_transaction::kill_lock_wait_by_thd(THD *thd)
+{
+ /*
+ Piggy-back on s_tx_list_mutex to avoid the situtation where the transaction
+ that we are trying to kill finishes after we got it from get_tx_from_thd()
+ but before we get its m_last_trx_id.
+
+ The lock wait may be gone, and tx->m_rocksdb_tx may change while we are
+ running the code lines below. This is why we use m_last_trx_id. We may
+ end up with an identifier of a transaction that is already gone, but this
+ won't be a problem.
+ */
+ RDB_MUTEX_LOCK_CHECK(Rdb_transaction::s_tx_list_mutex);
Rdb_transaction *const tx = get_tx_from_thd(thd);
- // tx can be zero if that thread doesn't have a RocksDB transaction
- // TODO: how do we know if things that are done in this function are
- // thread-safe? e.g. the transaction doesn't disappear while execution
- // is right on this line?
- if (tx && !tx->is_writebatch_trx())
+ if (tx && tx->m_last_trx_id != UINT64_MAX)
{
- Rdb_transaction_impl *tx_impl= (Rdb_transaction_impl*) tx;
- const rocksdb::Transaction *rdb_trx = tx_impl->get_rdb_trx();
- rdb->KillLockWait((void*)rdb_trx->GetID());
+ rdb->KillLockWait((void*)tx->m_last_trx_id);
}
+ RDB_MUTEX_UNLOCK_CHECK(Rdb_transaction::s_tx_list_mutex);
}
1
0