mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-24035 Failing assertion: UT_LIST_GET_LEN(lock.trx_locks) == 0 causing disruption and replication failure
Under unknown circumstances, the SQL layer may wrongly disregard an invocation of thd_mark_transaction_to_rollback() when an InnoDB transaction had been aborted (rolled back) due to one of the following errors: * HA_ERR_LOCK_DEADLOCK * HA_ERR_RECORD_CHANGED (if innodb_snapshot_isolation=ON) * HA_ERR_LOCK_WAIT_TIMEOUT (if innodb_rollback_on_timeout=ON) Such an error used to cause a crash of InnoDB during transaction commit. These changes aim to catch and report the error earlier, so that not only this crash can be avoided but also the original root cause be found and fixed more easily later. The idea of this fix is from Michael 'Monty' Widenius. HA_ERR_ROLLBACK: A new error code that will be translated into ER_ROLLBACK_ONLY, signalling that the current transaction has been aborted and the only allowed action is ROLLBACK. trx_t::state: Add TRX_STATE_ABORTED that is like TRX_STATE_NOT_STARTED, but noting that the transaction had been rolled back and aborted. trx_t::is_started(): Replaces trx_is_started(). ha_innobase: Check the transaction state in various places. Simplify the logic around SAVEPOINT. ha_innobase::is_valid_trx(): Replaces ha_innobase::is_read_only(). The InnoDB logic around transaction savepoints, commit, and rollback was unnecessarily complex and might have contributed to this inconsistency. So, we are simplifying that logic as well. trx_savept_t: Replace with const undo_no_t*. When we rollback to a savepoint, all we need to know is the number of undo log records that must survive. trx_named_savept_t, DB_NO_SAVEPOINT: Remove. We can store undo_no_t directly in the space allocated at innobase_hton->savepoint_offset. fts_trx_create(): Do not copy previous savepoints. fts_savepoint_rollback(): If a savepoint was not found, roll back everything after the default savepoint of fts_trx_create(). The test innodb_fts.savepoint is extended to cover this code. Reviewed by: Vladislav Lesin Tested by: Matthias Leich
This commit is contained in:
parent
9aa84cf57f
commit
ddd7d5d8e3
70 changed files with 880 additions and 1163 deletions
|
@ -78,5 +78,7 @@
|
|||
{ "HA_ERR_ABORTED_BY_USER", HA_ERR_ABORTED_BY_USER, "" },
|
||||
{ "HA_ERR_DISK_FULL", HA_ERR_DISK_FULL, "" },
|
||||
{ "HA_ERR_INCOMPATIBLE_DEFINITION", HA_ERR_INCOMPATIBLE_DEFINITION, "" },
|
||||
{ "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, "" },
|
||||
{ "HA_ERR_COMMIT_ERROR", HA_ERR_COMMIT_ERROR, "" },
|
||||
{ "HA_ERR_PARTITION_LIST", HA_ERR_PARTITION_LIST, ""},
|
||||
{ "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, ""},
|
||||
{ "HA_ERR_ROLLBACK", HA_ERR_ROLLBACK, "" },
|
||||
|
|
|
@ -535,7 +535,8 @@ enum ha_base_keytype {
|
|||
#define HA_ERR_COMMIT_ERROR 197
|
||||
#define HA_ERR_PARTITION_LIST 198
|
||||
#define HA_ERR_NO_ENCRYPTION 199
|
||||
#define HA_ERR_LAST 199 /* Copy of last error nr * */
|
||||
#define HA_ERR_ROLLBACK 200 /* Automatic rollback done */
|
||||
#define HA_ERR_LAST 200 /* Copy of last error nr * */
|
||||
|
||||
/* Number of different errors */
|
||||
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
|
||||
|
|
|
@ -110,7 +110,8 @@ static const char *handler_error_messages[]=
|
|||
"Sequence values are conflicting",
|
||||
"Error during commit",
|
||||
"Cannot select partitions",
|
||||
"Cannot initialize encryption. Check that all encryption parameters have been set"
|
||||
"Cannot initialize encryption. Check that all encryption parameters have been set",
|
||||
"Transaction was aborted",
|
||||
};
|
||||
|
||||
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
# Bug #24200: Provide backwards compatibility mode for 4.x "rollback on
|
||||
# transaction timeout"
|
||||
#
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
-- source include/have_innodb.inc
|
||||
-- source include/not_binlog_format_row.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees
|
||||
--echo #
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
--source include/have_metadata_lock_info.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
# Save the initial number of concurrent sessions.
|
||||
--source include/count_sessions.inc
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
--source include/have_partition.inc
|
||||
--source include/have_sequence.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-18707 Server crash in my_hash_sort_bin, ASAN heap-use-after-free in Field::is_null, server hang, corrupted double-linked list
|
||||
--echo #
|
||||
|
|
|
@ -5,6 +5,9 @@ let $MYSQLD_DATADIR= `SELECT @@datadir`;
|
|||
|
||||
call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*");
|
||||
call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB,
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
--source include/have_sequence.inc
|
||||
--source include/innodb_stable_estimates.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
SET SESSION DEFAULT_STORAGE_ENGINE='InnoDB';
|
||||
|
||||
SET @save_stats_persistent=@@GLOBAL.innodb_stats_persistent;
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
# WL#1756
|
||||
#
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
--source include/not_embedded.inc
|
||||
|
||||
# Save the initial number of concurrent sessions
|
||||
--source include/count_sessions.inc
|
||||
|
||||
call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
CREATE TABLE t1(a int not null primary key auto_increment,b int) engine=InnoDB;
|
||||
insert into t1 values (NULL,1);
|
||||
connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
|
||||
connection node_2a;
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
begin;
|
||||
update t1 set a = 5;
|
||||
connection node_2;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
call mtr.add_suppression("WSREP: Trying to continue unpaused monitor");
|
||||
connection node_1;
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
call mtr.add_suppression("WSREP: Trying to continue unpaused monitor");
|
||||
CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2;
|
||||
ALTER TABLE t1 add primary key(a);
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#
|
||||
|
||||
--connection node_2
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
CREATE TABLE t1(a int not null primary key auto_increment,b int) engine=InnoDB;
|
||||
insert into t1 values (NULL,1);
|
||||
|
||||
--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
|
||||
--connection node_2a
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
begin;
|
||||
update t1 set a = 5;
|
||||
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
--source include/big_test.inc
|
||||
|
||||
--connection node_2
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
call mtr.add_suppression("WSREP: Trying to continue unpaused monitor");
|
||||
|
||||
--connection node_1
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
call mtr.add_suppression("WSREP: Trying to continue unpaused monitor");
|
||||
|
||||
CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2;
|
||||
|
|
|
@ -456,7 +456,7 @@ restore: t1 .ibd and .cfg files
|
|||
SET SESSION debug_dbug=@saved_debug_dbug;
|
||||
SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure";
|
||||
ALTER TABLE t1 IMPORT TABLESPACE;
|
||||
ERROR HY000: Got error 42 'Tablespace not found' from ./test/t1.ibd
|
||||
ERROR HY000: Got error 41 'Tablespace not found' from ./test/t1.ibd
|
||||
SET SESSION debug_dbug=@saved_debug_dbug;
|
||||
restore: t1 .ibd and .cfg files
|
||||
SET SESSION debug_dbug="+d,ib_import_check_bitmap_failure";
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/not_embedded.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
# Two parallel connection with autoinc column after restart.
|
||||
|
||||
CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB;
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
--source include/have_innodb.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
let $have_deadlock=`select @@GLOBAL.innodb_deadlock_detect`;
|
||||
|
||||
connection default;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
--source include/have_innodb.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
CREATE TABLE t1 (
|
||||
pkey int NOT NULL PRIMARY KEY,
|
||||
c int
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connect(cancel_purge,localhost,root,,)
|
||||
# Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx
|
||||
# ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
# Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx
|
||||
# ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point
|
||||
# lock_trx_handle_wait_enter, waiting for upd_cont signal, which must be
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
# Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx
|
||||
# ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point
|
||||
# lock_trx_handle_wait_enter, waiting for upd_cont signal, which must be
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
--source include/count_sessions.inc
|
||||
--source include/default_charset.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
SET GLOBAL innodb_stats_persistent = 0;
|
||||
|
||||
--echo #
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
--source include/have_innodb.inc
|
||||
--source include/have_partition.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
#
|
||||
# Check and select innodb lock type
|
||||
#
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
# Bug#42419 Server crash with "Pure virtual method called" on two concurrent connections
|
||||
#
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--source include/not_embedded.inc
|
||||
|
||||
let $innodb_lock_wait_timeout= query_get_value(SHOW VARIABLES LIKE 'innodb_lock_wait_timeout%', Value, 1);
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
--source include/have_innodb.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
#
|
||||
# Bug #41453: Assertion `m_status == DA_ERROR' failed in
|
||||
# Diagnostics_area::sql_errno
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
# be heavier than ones that had not.
|
||||
#
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
SET default_storage_engine=InnoDB;
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/count_sessions.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connect (pause_purge,localhost,root)
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
--source include/have_debug.inc
|
||||
--source include/have_debug_sync.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t VALUES (3);
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
--source include/have_innodb.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-26642 Weird SELECT view when a record is
|
||||
--echo # modified to the same value by two transactions
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
--echo #
|
||||
|
||||
call mtr.add_suppression("\\[Warning\\] InnoDB: Over 67 percent of the buffer pool");
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
CREATE TABLE t1 (col1 INT) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
--source include/innodb_stable_estimates.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
CREATE TABLE t1 (
|
||||
pk INT,
|
||||
f1 VARCHAR(10) NOT NULL,
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
# concurrent CREATE OR REPLACE and transactional UPDATE
|
||||
#
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--source include/have_innodb.inc
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
source include/have_innodb.inc;
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
#
|
||||
# MDEV-20354 All but last insert ignored in InnoDB tables when table locked
|
||||
#
|
||||
|
|
|
@ -249,9 +249,33 @@ id title
|
|||
7 mysql
|
||||
TRUNCATE TABLE articles;
|
||||
INSERT INTO articles(id, title) VALUES(1, 'mysql');
|
||||
CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
INSERT INTO t SET a=1;
|
||||
SAVEPOINT t;
|
||||
INSERT INTO articles(id, title) VALUES(2, 'mysql');
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
id title
|
||||
1 mysql
|
||||
ROLLBACK TO SAVEPOINT t;
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
id title
|
||||
1 mysql
|
||||
SELECT * FROM t;
|
||||
a
|
||||
1
|
||||
COMMIT;
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
id title
|
||||
1 mysql
|
||||
BEGIN;
|
||||
INSERT INTO t SET a=2;
|
||||
INSERT INTO articles(id, title) VALUES(2, 'mysql');
|
||||
ROLLBACK;
|
||||
SELECT * FROM t;
|
||||
a
|
||||
1
|
||||
DROP TABLE t;
|
||||
INSERT INTO articles(id, title) VALUES(3, 'mysql');
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
id title
|
||||
|
|
|
@ -366,12 +366,28 @@ TRUNCATE TABLE articles;
|
|||
|
||||
INSERT INTO articles(id, title) VALUES(1, 'mysql');
|
||||
|
||||
CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
INSERT INTO t SET a=1;
|
||||
SAVEPOINT t;
|
||||
INSERT INTO articles(id, title) VALUES(2, 'mysql');
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
ROLLBACK TO SAVEPOINT t;
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
SELECT * FROM t;
|
||||
COMMIT;
|
||||
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t SET a=2;
|
||||
INSERT INTO articles(id, title) VALUES(2, 'mysql');
|
||||
|
||||
ROLLBACK;
|
||||
|
||||
SELECT * FROM t;
|
||||
DROP TABLE t;
|
||||
|
||||
INSERT INTO articles(id, title) VALUES(3, 'mysql');
|
||||
|
||||
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql');
|
||||
|
|
|
@ -91,7 +91,7 @@ restore: t1 .ibd and .cfg files
|
|||
SET SESSION debug_dbug=@saved_debug_dbug;
|
||||
SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure";
|
||||
ALTER TABLE t1 IMPORT TABLESPACE;
|
||||
ERROR HY000: Got error 42 'Tablespace not found' from ./test/t1.ibd
|
||||
ERROR HY000: Got error 41 'Tablespace not found' from ./test/t1.ibd
|
||||
SET SESSION debug_dbug=@saved_debug_dbug;
|
||||
restore: t1 .ibd and .cfg files
|
||||
SET SESSION debug_dbug="+d,ib_import_check_bitmap_failure";
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
--source include/have_innodb.inc
|
||||
--source include/have_debug.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo *** Test all-to-all replication with --gtid-ignore-duplicates ***
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@ Table Op Msg_type Msg_text
|
|||
test.t1 analyze status Engine-independent statistics collected
|
||||
test.t1 analyze status OK
|
||||
FLUSH LOGS;
|
||||
FOUND 1 /GTID 0-1-8 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-9 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-10 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-11 ddl/ in mysqlbinlog.out
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
|
@ -63,9 +63,9 @@ ALTER TABLE t1 REPAIR PARTITION p0;
|
|||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
FLUSH LOGS;
|
||||
FOUND 1 /GTID 0-1-14 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-15 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-16 ddl/ in mysqlbinlog.out
|
||||
FOUND 1 /GTID 0-1-17 ddl/ in mysqlbinlog.out
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
--let $rpl_topology=1->2
|
||||
--source include/rpl_init.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connection server_1
|
||||
FLUSH TABLES;
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
--source include/have_debug.inc
|
||||
--source include/master-slave.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo MDEV-31655: Parallel replication deadlock victim preference code erroneously removed
|
||||
# The problem was that InnoDB would choose the wrong deadlock victim.
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
--source include/have_debug.inc
|
||||
--source include/have_binlog_format_statement.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connection master
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1(a INT) ENGINE=INNODB;
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
--source include/have_debug_sync.inc
|
||||
--source include/master-slave.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connection server_2
|
||||
SET sql_log_bin=0;
|
||||
CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends");
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
|
||||
call mtr.add_suppression("Can't find record in 't1'");
|
||||
call mtr.add_suppression("Can't find record in 't2'");
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connection server_1
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
--let $rpl_topology=1->2
|
||||
--source include/rpl_init.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--connection server_1
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
--source include/have_perfschema.inc
|
||||
--source include/master-slave.inc
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--let $xid_num = 19
|
||||
--let $repeat = 17
|
||||
--let $workers = 7
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
--source include/master-slave.inc
|
||||
|
||||
call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
--echo *** Provoke a deadlock on the slave, check that transaction retry succeeds. ***
|
||||
--connection master
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
source suite/versioning/engines.inc;
|
||||
source suite/versioning/common.inc;
|
||||
|
||||
--disable_query_log
|
||||
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
|
||||
--enable_query_log
|
||||
|
||||
replace_result $sys_datatype_expl SYS_DATATYPE;
|
||||
eval create table t1(
|
||||
x int unsigned,
|
||||
|
|
|
@ -4676,6 +4676,12 @@ void handler::print_error(int error, myf errflag)
|
|||
case HA_ERR_PARTITION_LIST:
|
||||
my_error(ER_VERS_NOT_ALLOWED, errflag, table->s->db.str, table->s->table_name.str);
|
||||
DBUG_VOID_RETURN;
|
||||
case HA_ERR_ROLLBACK:
|
||||
/* Crash if we run with --debug-assert-on-error */
|
||||
DBUG_ASSERT(!debug_assert_if_crashed_table);
|
||||
SET_FATAL_ERROR;
|
||||
textno= ER_ROLLBACK_ONLY;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/* The error was "unknown" to this function.
|
||||
|
|
|
@ -1541,7 +1541,7 @@ struct find_interesting_trx
|
|||
{
|
||||
void operator()(const trx_t &trx)
|
||||
{
|
||||
if (trx.state == TRX_STATE_NOT_STARTED)
|
||||
if (!trx.is_started())
|
||||
return;
|
||||
if (trx.mysql_thd == nullptr)
|
||||
return;
|
||||
|
@ -1550,12 +1550,12 @@ struct find_interesting_trx
|
|||
|
||||
if (!found)
|
||||
{
|
||||
ib::warn() << "The following trx might hold "
|
||||
sql_print_warning("InnoDB: The following trx might hold "
|
||||
"the blocks in buffer pool to "
|
||||
"be withdrawn. Buffer pool "
|
||||
"resizing can complete only "
|
||||
"after all the transactions "
|
||||
"below release the blocks.";
|
||||
"below release the blocks.");
|
||||
found= true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2211,7 +2211,7 @@ fts_savepoint_t*
|
|||
fts_savepoint_create(
|
||||
/*=================*/
|
||||
ib_vector_t* savepoints, /*!< out: InnoDB transaction */
|
||||
const char* name, /*!< in: savepoint name */
|
||||
const void* name, /*!< in: savepoint */
|
||||
mem_heap_t* heap) /*!< in: heap */
|
||||
{
|
||||
fts_savepoint_t* savepoint;
|
||||
|
@ -2220,11 +2220,7 @@ fts_savepoint_create(
|
|||
ib_vector_push(savepoints, NULL));
|
||||
|
||||
memset(savepoint, 0x0, sizeof(*savepoint));
|
||||
|
||||
if (name) {
|
||||
savepoint->name = mem_heap_strdup(heap, name);
|
||||
}
|
||||
|
||||
savepoint->name = name;
|
||||
static_assert(!offsetof(fts_trx_table_t, table), "ABI");
|
||||
savepoint->tables = rbt_create(sizeof(fts_trx_table_t*), fts_ptr2_cmp);
|
||||
|
||||
|
@ -2243,7 +2239,6 @@ fts_trx_create(
|
|||
fts_trx_t* ftt;
|
||||
ib_alloc_t* heap_alloc;
|
||||
mem_heap_t* heap = mem_heap_create(1024);
|
||||
trx_named_savept_t* savep;
|
||||
|
||||
ut_a(trx->fts_trx == NULL);
|
||||
|
||||
|
@ -2263,14 +2258,6 @@ fts_trx_create(
|
|||
fts_savepoint_create(ftt->savepoints, NULL, NULL);
|
||||
fts_savepoint_create(ftt->last_stmt, NULL, NULL);
|
||||
|
||||
/* Copy savepoints that already set before. */
|
||||
for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
|
||||
savep != NULL;
|
||||
savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) {
|
||||
|
||||
fts_savepoint_take(ftt, savep->name);
|
||||
}
|
||||
|
||||
return(ftt);
|
||||
}
|
||||
|
||||
|
@ -5410,7 +5397,7 @@ void
|
|||
fts_savepoint_take(
|
||||
/*===============*/
|
||||
fts_trx_t* fts_trx, /*!< in: fts transaction */
|
||||
const char* name) /*!< in: savepoint name */
|
||||
const void* name) /*!< in: savepoint */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
fts_savepoint_t* savepoint;
|
||||
|
@ -5433,31 +5420,21 @@ fts_savepoint_take(
|
|||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Lookup a savepoint instance by name.
|
||||
@return ULINT_UNDEFINED if not found */
|
||||
UNIV_INLINE
|
||||
Lookup a savepoint instance.
|
||||
@return 0 if not found */
|
||||
static
|
||||
ulint
|
||||
fts_savepoint_lookup(
|
||||
/*==================*/
|
||||
ib_vector_t* savepoints, /*!< in: savepoints */
|
||||
const char* name) /*!< in: savepoint name */
|
||||
const void* name) /*!< in: savepoint */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
ut_a(ib_vector_size(savepoints) > 0);
|
||||
|
||||
for (i = 1; i < ib_vector_size(savepoints); ++i) {
|
||||
fts_savepoint_t* savepoint;
|
||||
|
||||
savepoint = static_cast<fts_savepoint_t*>(
|
||||
ib_vector_get(savepoints, i));
|
||||
|
||||
if (strcmp(name, savepoint->name) == 0) {
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
return(ULINT_UNDEFINED);
|
||||
for (ulint i= 1; i < ib_vector_size(savepoints); ++i)
|
||||
if (name == static_cast<const fts_savepoint_t*>
|
||||
(ib_vector_get(savepoints, i))->name)
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
@ -5468,7 +5445,7 @@ void
|
|||
fts_savepoint_release(
|
||||
/*==================*/
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* name) /*!< in: savepoint name */
|
||||
const void* name) /*!< in: savepoint name */
|
||||
{
|
||||
ut_a(name != NULL);
|
||||
|
||||
|
@ -5476,10 +5453,7 @@ fts_savepoint_release(
|
|||
|
||||
ut_a(ib_vector_size(savepoints) > 0);
|
||||
|
||||
ulint i = fts_savepoint_lookup(savepoints, name);
|
||||
if (i != ULINT_UNDEFINED) {
|
||||
ut_a(i >= 1);
|
||||
|
||||
if (ulint i = fts_savepoint_lookup(savepoints, name)) {
|
||||
fts_savepoint_t* savepoint;
|
||||
savepoint = static_cast<fts_savepoint_t*>(
|
||||
ib_vector_get(savepoints, i));
|
||||
|
@ -5634,9 +5608,8 @@ void
|
|||
fts_savepoint_rollback(
|
||||
/*===================*/
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* name) /*!< in: savepoint name */
|
||||
const void* name) /*!< in: savepoint */
|
||||
{
|
||||
ulint i;
|
||||
ib_vector_t* savepoints;
|
||||
|
||||
ut_a(name != NULL);
|
||||
|
@ -5645,16 +5618,19 @@ fts_savepoint_rollback(
|
|||
|
||||
/* We pop all savepoints from the the top of the stack up to
|
||||
and including the instance that was found. */
|
||||
i = fts_savepoint_lookup(savepoints, name);
|
||||
ulint i = fts_savepoint_lookup(savepoints, name);
|
||||
|
||||
if (i != ULINT_UNDEFINED) {
|
||||
if (i == 0) {
|
||||
/* fts_trx_create() must have been invoked after
|
||||
this savepoint had been created, and we must roll back
|
||||
everything. */
|
||||
i = 1;
|
||||
}
|
||||
|
||||
{
|
||||
fts_savepoint_t* savepoint;
|
||||
|
||||
ut_a(i > 0);
|
||||
|
||||
while (ib_vector_size(savepoints) > i) {
|
||||
fts_savepoint_t* savepoint;
|
||||
|
||||
savepoint = static_cast<fts_savepoint_t*>(
|
||||
ib_vector_pop(savepoints));
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -465,8 +465,13 @@ protected:
|
|||
@see build_template() */
|
||||
void reset_template();
|
||||
|
||||
/** @return whether the table is read-only */
|
||||
bool is_read_only(bool altering_to_supported= false) const;
|
||||
/** Check the transaction is valid.
|
||||
@param altering_to_supported whether an ALTER TABLE is being run
|
||||
to something else than ROW_FORMAT=COMPRESSED
|
||||
@retval 0 if the transaction is valid for the current operation
|
||||
@retval HA_ERR_TABLE_READONLY if the table is read-only
|
||||
@retval HA_ERR_ROLLBACK if the transaction has been aborted */
|
||||
int is_valid_trx(bool altering_to_supported= false) const noexcept;
|
||||
|
||||
inline void update_thd(THD* thd);
|
||||
void update_thd();
|
||||
|
@ -937,12 +942,3 @@ ib_push_frm_error(
|
|||
@return true if index column length exceeds limit */
|
||||
MY_ATTRIBUTE((warn_unused_result))
|
||||
bool too_big_key_part_length(size_t max_field_len, const KEY& key);
|
||||
|
||||
/** This function is used to rollback one X/Open XA distributed transaction
|
||||
which is in the prepared state
|
||||
|
||||
@param[in] hton InnoDB handlerton
|
||||
@param[in] xid X/Open XA transaction identification
|
||||
|
||||
@return 0 or error number */
|
||||
int innobase_rollback_by_xid(handlerton* hton, XID* xid);
|
||||
|
|
|
@ -2249,7 +2249,7 @@ ha_innobase::check_if_supported_inplace_alter(
|
|||
table->s->table_name.str);
|
||||
}
|
||||
|
||||
if (is_read_only(!high_level_read_only
|
||||
if (is_valid_trx(!high_level_read_only
|
||||
&& (ha_alter_info->handler_flags & ALTER_OPTIONS)
|
||||
&& ha_alter_info->create_info->key_block_size == 0
|
||||
&& ha_alter_info->create_info->row_type
|
||||
|
@ -9154,7 +9154,7 @@ inline bool rollback_inplace_alter_table(Alter_inplace_info *ha_alter_info,
|
|||
/* If we have not started a transaction yet,
|
||||
(almost) nothing has been or needs to be done. */
|
||||
dict_sys.lock(SRW_LOCK_CALL);
|
||||
else if (ctx->trx->state == TRX_STATE_NOT_STARTED)
|
||||
else if (!ctx->trx->is_started())
|
||||
goto free_and_exit;
|
||||
else if (ctx->new_table)
|
||||
{
|
||||
|
@ -11382,7 +11382,7 @@ lock_fail:
|
|||
to remove the newly created table or
|
||||
index from data dictionary and table cache
|
||||
in rollback_inplace_alter_table() */
|
||||
if (trx->state == TRX_STATE_NOT_STARTED) {
|
||||
if (!trx->is_started()) {
|
||||
trx_start_for_ddl(trx);
|
||||
}
|
||||
|
||||
|
@ -11549,7 +11549,7 @@ err_index:
|
|||
purge_sys.resume_FTS();
|
||||
}
|
||||
|
||||
if (trx->state == TRX_STATE_NOT_STARTED) {
|
||||
if (!trx->is_started()) {
|
||||
/* Transaction may have been rolled back
|
||||
due to a lock wait timeout, deadlock,
|
||||
or a KILL statement. So restart the
|
||||
|
|
|
@ -68,8 +68,6 @@ enum dberr_t {
|
|||
noticed */
|
||||
DB_CANNOT_DROP_CONSTRAINT, /*!< dropping a foreign key constraint
|
||||
from a table failed */
|
||||
DB_NO_SAVEPOINT, /*!< no savepoint exists with the given
|
||||
name */
|
||||
DB_TABLESPACE_EXISTS, /*!< we cannot create a new single-table
|
||||
tablespace because a file of the same
|
||||
name already exists */
|
||||
|
|
|
@ -201,9 +201,9 @@ struct fts_trx_t {
|
|||
|
||||
/** Information required for transaction savepoint handling. */
|
||||
struct fts_savepoint_t {
|
||||
char* name; /*!< First entry is always NULL, the
|
||||
default instance. Otherwise the name
|
||||
of the savepoint */
|
||||
const void* name; /*!< First entry is always NULL, the
|
||||
default instance. Otherwise the
|
||||
savepoint */
|
||||
|
||||
ib_rbt_t* tables; /*!< Modified FTS tables */
|
||||
};
|
||||
|
@ -666,7 +666,7 @@ void
|
|||
fts_savepoint_take(
|
||||
/*===============*/
|
||||
fts_trx_t* fts_trx, /*!< in: fts transaction */
|
||||
const char* name); /*!< in: savepoint name */
|
||||
const void* name); /*!< in: savepoint */
|
||||
|
||||
/**********************************************************************//**
|
||||
Refresh last statement savepoint. */
|
||||
|
@ -681,7 +681,7 @@ void
|
|||
fts_savepoint_release(
|
||||
/*==================*/
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* name); /*!< in: savepoint name */
|
||||
const void* name); /*!< in: savepoint */
|
||||
|
||||
/** Clear cache.
|
||||
@param[in,out] cache fts cache */
|
||||
|
@ -702,7 +702,7 @@ void
|
|||
fts_savepoint_rollback(
|
||||
/*===================*/
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* name); /*!< in: savepoint name */
|
||||
const void* name); /*!< in: savepoint */
|
||||
|
||||
/*********************************************************************//**
|
||||
Rollback to and including savepoint indentified by name. */
|
||||
|
|
|
@ -172,7 +172,7 @@ row_mysql_handle_errors(
|
|||
during the function entry */
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
que_thr_t* thr, /*!< in: query thread, or NULL */
|
||||
trx_savept_t* savept) /*!< in: savepoint, or NULL */
|
||||
const undo_no_t*savept) /*!< in: pointer to savepoint, or nullptr */
|
||||
MY_ATTRIBUTE((nonnull(1,2)));
|
||||
/********************************************************************//**
|
||||
Create a prebuilt struct for a MySQL table handle.
|
||||
|
|
|
@ -74,62 +74,6 @@ trx_rollback_for_mysql(
|
|||
/*===================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
/*******************************************************************//**
|
||||
Rollback the latest SQL statement for MySQL.
|
||||
@return error code or DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_rollback_last_sql_stat_for_mysql(
|
||||
/*=================================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
/*******************************************************************//**
|
||||
Rolls back a transaction back to a named savepoint. Modifications after the
|
||||
savepoint are undone but InnoDB does NOT release the corresponding locks
|
||||
which are stored in memory. If a lock is 'implicit', that is, a new inserted
|
||||
row holds a lock where the lock information is carried by the trx id stored in
|
||||
the row, these locks are naturally released in the rollback. Savepoints which
|
||||
were set after this savepoint are deleted.
|
||||
@return if no savepoint of the name found then DB_NO_SAVEPOINT,
|
||||
otherwise DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_rollback_to_savepoint_for_mysql(
|
||||
/*================================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name, /*!< in: savepoint name */
|
||||
int64_t* mysql_binlog_cache_pos) /*!< out: the MySQL binlog cache
|
||||
position corresponding to this
|
||||
savepoint; MySQL needs this
|
||||
information to remove the
|
||||
binlog entries of the queries
|
||||
executed after the savepoint */
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
/*******************************************************************//**
|
||||
Creates a named savepoint. If the transaction is not yet started, starts it.
|
||||
If there is already a savepoint of the same name, this call erases that old
|
||||
savepoint and replaces it with a new. Savepoints are deleted in a transaction
|
||||
commit or rollback.
|
||||
@return always DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_savepoint_for_mysql(
|
||||
/*====================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name, /*!< in: savepoint name */
|
||||
int64_t binlog_cache_pos) /*!< in: MySQL binlog cache
|
||||
position corresponding to this
|
||||
connection at the time of the
|
||||
savepoint */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
/*******************************************************************//**
|
||||
Releases a named savepoint. Savepoints which
|
||||
were set after this savepoint are deleted.
|
||||
@return if no savepoint of the name found then DB_NO_SAVEPOINT,
|
||||
otherwise DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_release_savepoint_for_mysql(
|
||||
/*============================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name) /*!< in: savepoint name */
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/** Rollback node states */
|
||||
enum roll_node_state {
|
||||
|
@ -144,25 +88,9 @@ enum roll_node_state {
|
|||
struct roll_node_t{
|
||||
que_common_t common; /*!< node type: QUE_NODE_ROLLBACK */
|
||||
enum roll_node_state state; /*!< node execution state */
|
||||
const trx_savept_t* savept; /*!< savepoint to which to
|
||||
roll back, in the case of a
|
||||
partial rollback */
|
||||
undo_no_t savept; /*!< savepoint to which to
|
||||
roll back; 0=entire transaction */
|
||||
que_thr_t* undo_thr;/*!< undo query graph */
|
||||
};
|
||||
|
||||
/** A savepoint set with SQL's "SAVEPOINT savepoint_id" command */
|
||||
struct trx_named_savept_t{
|
||||
char* name; /*!< savepoint name */
|
||||
trx_savept_t savept; /*!< the undo number corresponding to
|
||||
the savepoint */
|
||||
int64_t mysql_binlog_cache_pos;
|
||||
/*!< the MySQL binlog cache position
|
||||
corresponding to this savepoint, not
|
||||
defined if the MySQL binlogging is not
|
||||
enabled */
|
||||
UT_LIST_NODE_T(trx_named_savept_t)
|
||||
trx_savepoints; /*!< the list of savepoints of a
|
||||
transaction */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -495,19 +495,7 @@ class rw_trx_hash_t
|
|||
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
static void validate_element(trx_t *trx)
|
||||
{
|
||||
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
|
||||
ut_ad(!trx->is_autocommit_non_locking());
|
||||
/* trx->state can be anything except TRX_STATE_NOT_STARTED */
|
||||
ut_d(bool acquire_trx_mutex = !trx->mutex_is_owner());
|
||||
ut_d(if (acquire_trx_mutex) trx->mutex_lock());
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
|
||||
trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED));
|
||||
ut_d(if (acquire_trx_mutex) trx->mutex_unlock());
|
||||
}
|
||||
static void validate_element(trx_t *trx);
|
||||
|
||||
|
||||
struct debug_iterator_arg
|
||||
|
|
|
@ -149,19 +149,15 @@ void trx_start_for_ddl_low(trx_t *trx);
|
|||
ut_ad((t)->start_file == 0); \
|
||||
(t)->start_line = __LINE__; \
|
||||
(t)->start_file = __FILE__; \
|
||||
t->state= TRX_STATE_NOT_STARTED; \
|
||||
trx_start_for_ddl_low(t); \
|
||||
} while (0)
|
||||
#else
|
||||
# define trx_start_for_ddl(t) trx_start_for_ddl_low(t)
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/**********************************************************************//**
|
||||
Does the transaction commit for MySQL.
|
||||
@return DB_SUCCESS or error number */
|
||||
dberr_t
|
||||
trx_commit_for_mysql(
|
||||
/*=================*/
|
||||
trx_t* trx); /*!< in/out: transaction */
|
||||
/** Commit a transaction */
|
||||
void trx_commit_for_mysql(trx_t *trx) noexcept;
|
||||
/** XA PREPARE a transaction.
|
||||
@param[in,out] trx transaction to prepare */
|
||||
void trx_prepare_for_mysql(trx_t* trx);
|
||||
|
@ -184,12 +180,6 @@ trx_t* trx_get_trx_by_xid(const XID* xid);
|
|||
/** Durably write log until trx->commit_lsn
|
||||
(if trx_t::commit_in_memory() was invoked with flush_log_later=true). */
|
||||
void trx_commit_complete_for_mysql(trx_t *trx);
|
||||
/**********************************************************************//**
|
||||
Marks the latest SQL statement ended. */
|
||||
void
|
||||
trx_mark_sql_stat_end(
|
||||
/*==================*/
|
||||
trx_t* trx); /*!< in: trx handle */
|
||||
/****************************************************************//**
|
||||
Prepares a transaction for commit/rollback. */
|
||||
void
|
||||
|
@ -663,6 +653,7 @@ public:
|
|||
Possible states:
|
||||
|
||||
TRX_STATE_NOT_STARTED
|
||||
TRX_STATE_ABORTED
|
||||
TRX_STATE_ACTIVE
|
||||
TRX_STATE_PREPARED
|
||||
TRX_STATE_PREPARED_RECOVERED (special case of TRX_STATE_PREPARED)
|
||||
|
@ -672,6 +663,8 @@ public:
|
|||
|
||||
Regular transactions:
|
||||
* NOT_STARTED -> ACTIVE -> COMMITTED -> NOT_STARTED
|
||||
* NOT_STARTED -> ABORTED (when thd_mark_transaction_to_rollback() is called)
|
||||
* ABORTED -> NOT_STARTED (acknowledging the rollback of a transaction)
|
||||
|
||||
Auto-commit non-locking read-only:
|
||||
* NOT_STARTED -> ACTIVE -> NOT_STARTED
|
||||
|
@ -708,16 +701,18 @@ public:
|
|||
do we remove it from the read-only list and put it on the read-write
|
||||
list. During this switch we assign it a rollback segment.
|
||||
|
||||
When a transaction is NOT_STARTED, it can be in trx_list. It cannot be
|
||||
in rw_trx_hash.
|
||||
When a transaction is NOT_STARTED or ABORTED, it can be in trx_list.
|
||||
It cannot be in rw_trx_hash.
|
||||
|
||||
ACTIVE->PREPARED->COMMITTED is only possible when trx is in rw_trx_hash.
|
||||
The transition ACTIVE->PREPARED is protected by trx->mutex.
|
||||
ACTIVE->PREPARED->COMMITTED and ACTIVE->COMMITTED is only possible when
|
||||
trx is in rw_trx_hash. These transitions are protected by trx_t::mutex.
|
||||
|
||||
ACTIVE->COMMITTED is possible when the transaction is in
|
||||
rw_trx_hash.
|
||||
COMMITTED->NOT_STARTED is possible when trx_t::mutex is being held.
|
||||
The transaction would already have been removed from rw_trx_hash by
|
||||
trx_sys_t::deregister_rw() on the transition to COMMITTED.
|
||||
|
||||
Transitions to COMMITTED are protected by trx_t::mutex. */
|
||||
Transitions between NOT_STARTED and ABORTED can be performed at any time by
|
||||
the thread that is associated with the transaction. */
|
||||
Atomic_relaxed<trx_state_t> state;
|
||||
|
||||
/** The locks of the transaction. Protected by lock_sys.latch
|
||||
|
@ -733,6 +728,14 @@ public:
|
|||
bool is_wsrep() const { return false; }
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
/** @return whether the transaction has been started */
|
||||
bool is_started() const noexcept
|
||||
{
|
||||
static_assert(TRX_STATE_NOT_STARTED == 0, "");
|
||||
static_assert(TRX_STATE_ABORTED == 1, "");
|
||||
return state > TRX_STATE_ABORTED;
|
||||
}
|
||||
|
||||
/** Consistent read view of the transaction */
|
||||
ReadView read_view;
|
||||
|
||||
|
@ -839,10 +842,6 @@ public:
|
|||
it is a stored procedure with a COMMIT
|
||||
WORK statement, for instance */
|
||||
/*------------------------------*/
|
||||
UT_LIST_BASE_NODE_T(trx_named_savept_t)
|
||||
trx_savepoints; /*!< savepoints set with SAVEPOINT ...,
|
||||
oldest first */
|
||||
/*------------------------------*/
|
||||
undo_no_t undo_no; /*!< next undo log record number to
|
||||
assign; since the undo log is
|
||||
private for a transaction, this
|
||||
|
@ -850,7 +849,7 @@ public:
|
|||
with no gaps; thus it represents
|
||||
the number of modified/inserted
|
||||
rows in a transaction */
|
||||
trx_savept_t last_sql_stat_start;
|
||||
undo_no_t last_stmt_start;
|
||||
/*!< undo_no when the last sql statement
|
||||
was started: in case of an error, trx
|
||||
is rolled back down to this number */
|
||||
|
@ -949,16 +948,17 @@ public:
|
|||
void evict_table(table_id_t table_id, bool reset_only= false);
|
||||
|
||||
/** Initiate rollback.
|
||||
@param savept savepoint to which to roll back
|
||||
@param savept pointer to savepoint; nullptr=entire transaction
|
||||
@return error code or DB_SUCCESS */
|
||||
dberr_t rollback(trx_savept_t *savept= nullptr);
|
||||
dberr_t rollback(const undo_no_t *savept= nullptr) noexcept;
|
||||
/** Roll back an active transaction.
|
||||
@param savept savepoint to which to roll back */
|
||||
inline void rollback_low(trx_savept_t *savept= nullptr);
|
||||
@param savept pointer to savepoint; nullptr=entire transaction
|
||||
@return error code or DB_SUCCESS */
|
||||
dberr_t rollback_low(const undo_no_t *savept= nullptr) noexcept;
|
||||
/** Finish rollback.
|
||||
@return whether the rollback was completed normally
|
||||
@retval false if the rollback was aborted by shutdown */
|
||||
inline bool rollback_finish();
|
||||
bool rollback_finish() noexcept;
|
||||
private:
|
||||
/** Apply any changes to tables for which online DDL is in progress. */
|
||||
ATTRIBUTE_COLD void apply_log();
|
||||
|
@ -968,9 +968,10 @@ private:
|
|||
@param mtr mini-transaction (if there are any persistent modifications) */
|
||||
inline void commit_in_memory(const mtr_t *mtr);
|
||||
/** Write log for committing the transaction. */
|
||||
void commit_persist();
|
||||
/** Clean up the transaction after commit_in_memory() */
|
||||
void commit_cleanup();
|
||||
void commit_persist() noexcept;
|
||||
/** Clean up the transaction after commit_in_memory()
|
||||
@return false (always) */
|
||||
bool commit_cleanup() noexcept;
|
||||
/** Commit the transaction in a mini-transaction.
|
||||
@param mtr mini-transaction (if there are any persistent modifications) */
|
||||
void commit_low(mtr_t *mtr= nullptr);
|
||||
|
@ -985,7 +986,7 @@ private:
|
|||
inline void write_serialisation_history(mtr_t *mtr);
|
||||
public:
|
||||
/** Commit the transaction. */
|
||||
void commit();
|
||||
void commit() noexcept;
|
||||
|
||||
/** Try to drop a persistent table.
|
||||
@param table persistent table
|
||||
|
@ -1005,16 +1006,6 @@ public:
|
|||
void commit(std::vector<pfs_os_file_t> &deleted);
|
||||
|
||||
|
||||
/** Discard all savepoints */
|
||||
void savepoints_discard()
|
||||
{ savepoints_discard(UT_LIST_GET_FIRST(trx_savepoints)); }
|
||||
|
||||
|
||||
/** Discard all savepoints starting from a particular savepoint.
|
||||
@param savept first savepoint to discard */
|
||||
void savepoints_discard(trx_named_savept_t *savept);
|
||||
|
||||
|
||||
bool is_referenced() const
|
||||
{
|
||||
return (skip_lock_inheritance_and_n_ref & ~(1U << 31)) > 0;
|
||||
|
@ -1128,15 +1119,6 @@ private:
|
|||
trx_rseg_t *assign_temp_rseg();
|
||||
};
|
||||
|
||||
/**
|
||||
Check if transaction is started.
|
||||
@param[in] trx Transaction whose state we need to check
|
||||
@reutrn true if transaction is in state started */
|
||||
inline bool trx_is_started(const trx_t* trx)
|
||||
{
|
||||
return trx->state != TRX_STATE_NOT_STARTED;
|
||||
}
|
||||
|
||||
/* Transaction isolation levels (trx->isolation_level) */
|
||||
#define TRX_ISO_READ_UNCOMMITTED 0 /* dirty read: non-locking
|
||||
SELECTs are performed so that
|
||||
|
|
|
@ -67,6 +67,8 @@ trx_state_eq(
|
|||
&& thd_get_error_number(trx->mysql_thd)));
|
||||
|
||||
return(true);
|
||||
case TRX_STATE_ABORTED:
|
||||
break;
|
||||
}
|
||||
ut_error;
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
|
|
@ -52,6 +52,8 @@ constexpr uint innodb_purge_batch_size_MAX= 5000;
|
|||
/** Transaction states (trx_t::state) */
|
||||
enum trx_state_t {
|
||||
TRX_STATE_NOT_STARTED,
|
||||
/** The transaction was aborted (rolled back) due to an error */
|
||||
TRX_STATE_ABORTED,
|
||||
|
||||
TRX_STATE_ACTIVE,
|
||||
/** XA PREPARE has been executed; only XA COMMIT or XA ROLLBACK
|
||||
|
@ -59,6 +61,7 @@ enum trx_state_t {
|
|||
TRX_STATE_PREPARED,
|
||||
/** XA PREPARE transaction that was returned to ha_recover() */
|
||||
TRX_STATE_PREPARED_RECOVERED,
|
||||
/** The transaction has been committed (or completely rolled back) */
|
||||
TRX_STATE_COMMITTED_IN_MEMORY
|
||||
};
|
||||
|
||||
|
@ -76,8 +79,6 @@ struct trx_undo_t;
|
|||
struct roll_node_t;
|
||||
/** Commit command node in a query graph */
|
||||
struct commit_node_t;
|
||||
/** SAVEPOINT command node in a query graph */
|
||||
struct trx_named_savept_t;
|
||||
/* @} */
|
||||
|
||||
/** Row identifier (DB_ROW_ID, DATA_ROW_ID) */
|
||||
|
@ -89,11 +90,6 @@ typedef ib_id_t roll_ptr_t;
|
|||
/** Undo number */
|
||||
typedef ib_id_t undo_no_t;
|
||||
|
||||
/** Transaction savepoint */
|
||||
struct trx_savept_t{
|
||||
undo_no_t least_undo_no; /*!< least undo number to undo */
|
||||
};
|
||||
|
||||
/** File objects */
|
||||
/* @{ */
|
||||
/** Undo segment header */
|
||||
|
|
|
@ -6692,23 +6692,19 @@ lock_unlock_table_autoinc(
|
|||
/*======================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
{
|
||||
/* This function is invoked for a running transaction by the thread
|
||||
that is serving the transaction. Therefore it is not necessary to
|
||||
hold trx->mutex here. */
|
||||
|
||||
lock_sys.assert_unlocked();
|
||||
ut_ad(!trx->mutex_is_owner());
|
||||
ut_ad(!trx->lock.wait_lock);
|
||||
ut_d(trx_state_t trx_state{trx->state});
|
||||
ut_ad(trx_state == TRX_STATE_ACTIVE || trx_state == TRX_STATE_PREPARED ||
|
||||
trx_state == TRX_STATE_NOT_STARTED);
|
||||
|
||||
/* This can be invoked on NOT_STARTED, ACTIVE, PREPARED,
|
||||
but not COMMITTED transactions. */
|
||||
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED)
|
||||
|| !trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
|
||||
|
||||
/* This function is invoked for a running transaction by the
|
||||
thread that is serving the transaction. Therefore it is not
|
||||
necessary to hold trx->mutex here. */
|
||||
|
||||
if (lock_trx_holds_autoinc_locks(trx)) {
|
||||
if (lock_trx_holds_autoinc_locks(trx))
|
||||
lock_release_autoinc_locks(trx);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle a pending lock wait (DB_LOCK_WAIT) in a semi-consistent read
|
||||
|
|
|
@ -514,8 +514,7 @@ que_thr_step(
|
|||
for_step(thr);
|
||||
} else if (type == QUE_NODE_PROC) {
|
||||
if (thr->prev_node == que_node_get_parent(node)) {
|
||||
trx->last_sql_stat_start.least_undo_no
|
||||
= trx->undo_no;
|
||||
trx->last_stmt_start = trx->undo_no;
|
||||
}
|
||||
|
||||
proc_step(thr);
|
||||
|
|
|
@ -625,7 +625,7 @@ row_mysql_handle_errors(
|
|||
function */
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
que_thr_t* thr, /*!< in: query thread, or NULL */
|
||||
trx_savept_t* savept) /*!< in: savepoint, or NULL */
|
||||
const undo_no_t*savept) /*!< in: pointer to savepoint, or nullptr */
|
||||
{
|
||||
dberr_t err;
|
||||
|
||||
|
@ -681,8 +681,7 @@ handle_new_error:
|
|||
}
|
||||
/* MariaDB will roll back the entire transaction. */
|
||||
trx->bulk_insert = false;
|
||||
trx->last_sql_stat_start.least_undo_no = 0;
|
||||
trx->savepoints_discard();
|
||||
trx->last_stmt_start = 0;
|
||||
break;
|
||||
case DB_LOCK_WAIT:
|
||||
err = lock_wait(thr);
|
||||
|
@ -700,7 +699,6 @@ handle_new_error:
|
|||
rollback:
|
||||
/* Roll back the whole transaction; this resolution was added
|
||||
to version 3.23.43 */
|
||||
|
||||
trx->rollback();
|
||||
break;
|
||||
|
||||
|
@ -1137,7 +1135,7 @@ row_lock_table_autoinc_for_mysql(
|
|||
|
||||
trx->error_state = err;
|
||||
} while (err != DB_SUCCESS
|
||||
&& row_mysql_handle_errors(&err, trx, thr, NULL));
|
||||
&& row_mysql_handle_errors(&err, trx, thr, nullptr));
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
|
@ -1179,7 +1177,7 @@ row_lock_table(row_prebuilt_t* prebuilt)
|
|||
prebuilt->select_lock_type), thr);
|
||||
trx->error_state = err;
|
||||
} while (err != DB_SUCCESS
|
||||
&& row_mysql_handle_errors(&err, trx, thr, NULL));
|
||||
&& row_mysql_handle_errors(&err, trx, thr, nullptr));
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
|
@ -1218,7 +1216,6 @@ row_insert_for_mysql(
|
|||
row_prebuilt_t* prebuilt,
|
||||
ins_mode_t ins_mode)
|
||||
{
|
||||
trx_savept_t savept;
|
||||
que_thr_t* thr;
|
||||
dberr_t err;
|
||||
ibool was_lock_wait;
|
||||
|
@ -1272,7 +1269,7 @@ row_insert_for_mysql(
|
|||
roll back to the start of the transaction. For correctness, it
|
||||
would suffice to roll back to the start of the first insert
|
||||
into this empty table, but we will keep it simple and efficient. */
|
||||
savept.least_undo_no = trx->bulk_insert ? 0 : trx->undo_no;
|
||||
const undo_no_t savept{trx->bulk_insert ? 0 : trx->undo_no};
|
||||
|
||||
thr = que_fork_get_first_thr(prebuilt->ins_graph);
|
||||
|
||||
|
@ -1586,7 +1583,6 @@ init_fts_doc_id_for_ref(
|
|||
dberr_t
|
||||
row_update_for_mysql(row_prebuilt_t* prebuilt)
|
||||
{
|
||||
trx_savept_t savept;
|
||||
dberr_t err;
|
||||
que_thr_t* thr;
|
||||
dict_index_t* clust_index;
|
||||
|
@ -1643,7 +1639,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
|
|||
generated for the table: MySQL does not know anything about
|
||||
the row id used as the clustered index key */
|
||||
|
||||
savept.least_undo_no = trx->undo_no;
|
||||
undo_no_t savept = trx->undo_no;
|
||||
|
||||
thr = que_fork_get_first_thr(prebuilt->upd_graph);
|
||||
|
||||
|
|
|
@ -1208,8 +1208,7 @@ re_scan:
|
|||
mtr->commit();
|
||||
trx->error_state = err;
|
||||
thr->lock_state = QUE_THR_LOCK_ROW;
|
||||
if (row_mysql_handle_errors(
|
||||
&err, trx, thr, NULL)) {
|
||||
if (row_mysql_handle_errors(&err, trx, thr, 0)) {
|
||||
thr->lock_state = QUE_THR_LOCK_NOLOCK;
|
||||
mtr->start();
|
||||
|
||||
|
@ -5873,7 +5872,7 @@ lock_table_wait:
|
|||
trx->error_state = err;
|
||||
thr->lock_state = QUE_THR_LOCK_ROW;
|
||||
|
||||
if (row_mysql_handle_errors(&err, trx, thr, NULL)) {
|
||||
if (row_mysql_handle_errors(&err, trx, thr, nullptr)) {
|
||||
/* It was a lock wait, and it ended */
|
||||
|
||||
thr->lock_state = QUE_THR_LOCK_NOLOCK;
|
||||
|
|
|
@ -1054,7 +1054,7 @@ static void fetch_data_into_cache(trx_i_s_cache_t *cache)
|
|||
&trx != (purge_sys.query ? purge_sys.query->trx : nullptr))
|
||||
{
|
||||
trx.mutex_lock();
|
||||
if (trx.state != TRX_STATE_NOT_STARTED)
|
||||
if (trx.is_started())
|
||||
fetch_data_into_cache_low(cache, &trx);
|
||||
trx.mutex_unlock();
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ Created 3/26/1996 Heikki Tuuri
|
|||
#include "trx0sys.h"
|
||||
#include "trx0trx.h"
|
||||
#include "trx0undo.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef UNIV_PFS_THREAD
|
||||
mysql_pfs_key_t trx_rollback_clean_thread_key;
|
||||
|
@ -54,10 +55,7 @@ bool trx_rollback_is_active;
|
|||
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
|
||||
const trx_t* trx_roll_crash_recv_trx;
|
||||
|
||||
/** Finish transaction rollback.
|
||||
@return whether the rollback was completed normally
|
||||
@retval false if the rollback was aborted by shutdown */
|
||||
inline bool trx_t::rollback_finish()
|
||||
bool trx_t::rollback_finish() noexcept
|
||||
{
|
||||
mod_tables.clear();
|
||||
apply_online_log= false;
|
||||
|
@ -85,34 +83,28 @@ inline bool trx_t::rollback_finish()
|
|||
undo= nullptr;
|
||||
}
|
||||
commit_low();
|
||||
commit_cleanup();
|
||||
return false;
|
||||
return commit_cleanup();
|
||||
}
|
||||
|
||||
/** Roll back an active transaction. */
|
||||
inline void trx_t::rollback_low(trx_savept_t *savept)
|
||||
dberr_t trx_t::rollback_low(const undo_no_t *savept) noexcept
|
||||
{
|
||||
op_info= "rollback";
|
||||
mem_heap_t *heap= mem_heap_create(512);
|
||||
roll_node_t *roll_node= roll_node_create(heap);
|
||||
roll_node->savept= savept;
|
||||
|
||||
roll_node->savept= savept ? *savept : 0;
|
||||
|
||||
ut_ad(!in_rollback);
|
||||
#ifdef UNIV_DEBUG
|
||||
{
|
||||
const auto s= state;
|
||||
ut_ad(s == TRX_STATE_ACTIVE ||
|
||||
s == TRX_STATE_PREPARED ||
|
||||
s == TRX_STATE_PREPARED_RECOVERED);
|
||||
if (savept)
|
||||
{
|
||||
ut_ad(s == TRX_STATE_ACTIVE);
|
||||
ut_ad(state == TRX_STATE_ACTIVE);
|
||||
ut_ad(mysql_thd);
|
||||
ut_ad(!is_recovered);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
error_state = DB_SUCCESS;
|
||||
error_state= DB_SUCCESS;
|
||||
|
||||
if (has_logged())
|
||||
{
|
||||
|
@ -139,7 +131,7 @@ inline void trx_t::rollback_low(trx_savept_t *savept)
|
|||
victim. Galera transaction abort can be invoked during partial rollback. */
|
||||
ut_ad(!(lock.was_chosen_as_deadlock_victim & 1));
|
||||
ut_a(error_state == DB_SUCCESS);
|
||||
const undo_no_t limit= savept->least_undo_no;
|
||||
const undo_no_t limit{*savept};
|
||||
apply_online_log= false;
|
||||
for (trx_mod_tables_t::iterator i= mod_tables.begin();
|
||||
i != mod_tables.end(); )
|
||||
|
@ -155,49 +147,34 @@ inline void trx_t::rollback_low(trx_savept_t *savept)
|
|||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
op_info= "";
|
||||
return error_state;
|
||||
}
|
||||
|
||||
/** Initiate rollback.
|
||||
@param savept savepoint
|
||||
@return error code or DB_SUCCESS */
|
||||
dberr_t trx_t::rollback(trx_savept_t *savept)
|
||||
dberr_t trx_t::rollback(const undo_no_t *savept) noexcept
|
||||
{
|
||||
ut_ad(!mutex_is_owner());
|
||||
if (state == TRX_STATE_NOT_STARTED)
|
||||
{
|
||||
switch (state) {
|
||||
case TRX_STATE_ABORTED:
|
||||
ut_ad(!savept);
|
||||
state= TRX_STATE_NOT_STARTED;
|
||||
/* fall through */
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
error_state= DB_SUCCESS;
|
||||
return DB_SUCCESS;
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
ut_ad("invalid state" == 0);
|
||||
/* fall through */
|
||||
case TRX_STATE_ACTIVE:
|
||||
break;
|
||||
}
|
||||
ut_ad(state == TRX_STATE_ACTIVE);
|
||||
#ifdef WITH_WSREP
|
||||
if (!savept && is_wsrep() && wsrep_thd_is_SR(mysql_thd))
|
||||
wsrep_handle_SR_rollback(nullptr, mysql_thd);
|
||||
#endif /* WITH_WSREP */
|
||||
rollback_low(savept);
|
||||
return error_state;
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Rollback a transaction used in MySQL.
|
||||
@return error code or DB_SUCCESS */
|
||||
static
|
||||
dberr_t
|
||||
trx_rollback_for_mysql_low(
|
||||
/*=======================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
{
|
||||
trx->op_info = "rollback";
|
||||
|
||||
/* If we are doing the XA recovery of prepared transactions,
|
||||
then the transaction object does not have an InnoDB session
|
||||
object, and we set a dummy session that we use for all MySQL
|
||||
transactions. */
|
||||
|
||||
trx->rollback_low();
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return(trx->error_state);
|
||||
return rollback_low(savept);
|
||||
}
|
||||
|
||||
/** Rollback a transaction used in MySQL
|
||||
|
@ -211,6 +188,9 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
|
|||
that is associated with the current thread. */
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_ABORTED:
|
||||
trx->state = TRX_STATE_NOT_STARTED;
|
||||
/* fall through */
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
trx->will_lock = false;
|
||||
ut_ad(trx->mysql_thd);
|
||||
|
@ -222,13 +202,13 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
|
|||
ut_ad(!trx->is_wsrep());
|
||||
trx->lock.was_chosen_as_deadlock_victim= false;
|
||||
#endif
|
||||
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
||||
return(DB_SUCCESS);
|
||||
|
||||
case TRX_STATE_ACTIVE:
|
||||
ut_ad(trx->mysql_thd);
|
||||
ut_ad(!trx->is_recovered);
|
||||
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
|
||||
return(trx_rollback_for_mysql_low(trx));
|
||||
return trx->rollback_low();
|
||||
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
|
@ -266,7 +246,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
|
|||
mtr.commit();
|
||||
ut_ad(mtr.commit_lsn() > 0);
|
||||
}
|
||||
return(trx_rollback_for_mysql_low(trx));
|
||||
return trx->rollback_low();
|
||||
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
ut_ad(!trx->is_autocommit_non_locking());
|
||||
|
@ -277,296 +257,6 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
|
|||
return(DB_CORRUPTION);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Rollback the latest SQL statement for MySQL.
|
||||
@return error code or DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_rollback_last_sql_stat_for_mysql(
|
||||
/*=================================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
{
|
||||
dberr_t err;
|
||||
|
||||
/* We are reading trx->state without holding trx->mutex
|
||||
here, because the statement rollback should be invoked for a
|
||||
running active MySQL transaction that is associated with the
|
||||
current thread. */
|
||||
ut_ad(trx->mysql_thd);
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
return(DB_SUCCESS);
|
||||
|
||||
case TRX_STATE_ACTIVE:
|
||||
ut_ad(trx->mysql_thd);
|
||||
ut_ad(!trx->is_recovered);
|
||||
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
|
||||
|
||||
trx->op_info = "rollback of SQL statement";
|
||||
|
||||
err = trx->rollback(&trx->last_sql_stat_start);
|
||||
|
||||
if (trx->fts_trx != NULL) {
|
||||
fts_savepoint_rollback_last_stmt(trx);
|
||||
fts_savepoint_laststmt_refresh(trx);
|
||||
}
|
||||
|
||||
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
|
||||
trx->end_bulk_insert();
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return(err);
|
||||
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
/* The statement rollback is only allowed on an ACTIVE
|
||||
transaction, not a PREPARED or COMMITTED one. */
|
||||
break;
|
||||
}
|
||||
|
||||
ut_error;
|
||||
return(DB_CORRUPTION);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Search for a savepoint using name.
|
||||
@return savepoint if found else NULL */
|
||||
static
|
||||
trx_named_savept_t*
|
||||
trx_savepoint_find(
|
||||
/*===============*/
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* name) /*!< in: savepoint name */
|
||||
{
|
||||
trx_named_savept_t* savep;
|
||||
|
||||
for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
|
||||
savep != NULL;
|
||||
savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) {
|
||||
if (!strcmp(savep->name, name)) {
|
||||
return(savep);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Frees a single savepoint struct. */
|
||||
static
|
||||
void
|
||||
trx_roll_savepoint_free(
|
||||
/*=====================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
trx_named_savept_t* savep) /*!< in: savepoint to free */
|
||||
{
|
||||
UT_LIST_REMOVE(trx->trx_savepoints, savep);
|
||||
|
||||
ut_free(savep->name);
|
||||
ut_free(savep);
|
||||
}
|
||||
|
||||
/** Discard all savepoints starting from a particular savepoint.
|
||||
@param savept first savepoint to discard */
|
||||
void trx_t::savepoints_discard(trx_named_savept_t *savept)
|
||||
{
|
||||
while (savept)
|
||||
{
|
||||
auto next= UT_LIST_GET_NEXT(trx_savepoints, savept);
|
||||
trx_roll_savepoint_free(this, savept);
|
||||
savept= next;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Rolls back a transaction back to a named savepoint. Modifications after the
|
||||
savepoint are undone but InnoDB does NOT release the corresponding locks
|
||||
which are stored in memory. If a lock is 'implicit', that is, a new inserted
|
||||
row holds a lock where the lock information is carried by the trx id stored in
|
||||
the row, these locks are naturally released in the rollback. Savepoints which
|
||||
were set after this savepoint are deleted.
|
||||
@return if no savepoint of the name found then DB_NO_SAVEPOINT,
|
||||
otherwise DB_SUCCESS */
|
||||
static MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||
dberr_t
|
||||
trx_rollback_to_savepoint_for_mysql_low(
|
||||
/*====================================*/
|
||||
trx_t* trx, /*!< in/out: transaction */
|
||||
trx_named_savept_t* savep, /*!< in/out: savepoint */
|
||||
int64_t* mysql_binlog_cache_pos)
|
||||
/*!< out: the MySQL binlog
|
||||
cache position corresponding
|
||||
to this savepoint; MySQL needs
|
||||
this information to remove the
|
||||
binlog entries of the queries
|
||||
executed after the savepoint */
|
||||
{
|
||||
dberr_t err;
|
||||
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
|
||||
ut_ad(trx->mysql_thd);
|
||||
|
||||
/* Free all savepoints strictly later than savep. */
|
||||
|
||||
trx->savepoints_discard(UT_LIST_GET_NEXT(trx_savepoints, savep));
|
||||
|
||||
*mysql_binlog_cache_pos = savep->mysql_binlog_cache_pos;
|
||||
|
||||
trx->op_info = "rollback to a savepoint";
|
||||
|
||||
err = trx->rollback(&savep->savept);
|
||||
|
||||
/* Store the current undo_no of the transaction so that
|
||||
we know where to roll back if we have to roll back the
|
||||
next SQL statement: */
|
||||
|
||||
trx_mark_sql_stat_end(trx);
|
||||
|
||||
trx->op_info = "";
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Rolls back a transaction back to a named savepoint. Modifications after the
|
||||
savepoint are undone but InnoDB does NOT release the corresponding locks
|
||||
which are stored in memory. If a lock is 'implicit', that is, a new inserted
|
||||
row holds a lock where the lock information is carried by the trx id stored in
|
||||
the row, these locks are naturally released in the rollback. Savepoints which
|
||||
were set after this savepoint are deleted.
|
||||
@return if no savepoint of the name found then DB_NO_SAVEPOINT,
|
||||
otherwise DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_rollback_to_savepoint_for_mysql(
|
||||
/*================================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name, /*!< in: savepoint name */
|
||||
int64_t* mysql_binlog_cache_pos) /*!< out: the MySQL binlog cache
|
||||
position corresponding to this
|
||||
savepoint; MySQL needs this
|
||||
information to remove the
|
||||
binlog entries of the queries
|
||||
executed after the savepoint */
|
||||
{
|
||||
trx_named_savept_t* savep;
|
||||
|
||||
/* We are reading trx->state without holding trx->mutex
|
||||
here, because the savepoint rollback should be invoked for a
|
||||
running active MySQL transaction that is associated with the
|
||||
current thread. */
|
||||
ut_ad(trx->mysql_thd);
|
||||
|
||||
savep = trx_savepoint_find(trx, savepoint_name);
|
||||
|
||||
if (savep == NULL) {
|
||||
return(DB_NO_SAVEPOINT);
|
||||
}
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
ib::error() << "Transaction has a savepoint "
|
||||
<< savep->name
|
||||
<< " though it is not started";
|
||||
return(DB_ERROR);
|
||||
|
||||
case TRX_STATE_ACTIVE:
|
||||
|
||||
return(trx_rollback_to_savepoint_for_mysql_low(
|
||||
trx, savep, mysql_binlog_cache_pos));
|
||||
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
/* The savepoint rollback is only allowed on an ACTIVE
|
||||
transaction, not a PREPARED or COMMITTED one. */
|
||||
break;
|
||||
}
|
||||
|
||||
ut_error;
|
||||
return(DB_CORRUPTION);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Creates a named savepoint. If the transaction is not yet started, starts it.
|
||||
If there is already a savepoint of the same name, this call erases that old
|
||||
savepoint and replaces it with a new. Savepoints are deleted in a transaction
|
||||
commit or rollback.
|
||||
@return always DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_savepoint_for_mysql(
|
||||
/*====================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name, /*!< in: savepoint name */
|
||||
int64_t binlog_cache_pos) /*!< in: MySQL binlog cache
|
||||
position corresponding to this
|
||||
connection at the time of the
|
||||
savepoint */
|
||||
{
|
||||
trx_named_savept_t* savep;
|
||||
|
||||
trx_start_if_not_started_xa(trx, false);
|
||||
|
||||
savep = trx_savepoint_find(trx, savepoint_name);
|
||||
|
||||
if (savep) {
|
||||
/* There is a savepoint with the same name: free that */
|
||||
|
||||
UT_LIST_REMOVE(trx->trx_savepoints, savep);
|
||||
|
||||
ut_free(savep->name);
|
||||
ut_free(savep);
|
||||
}
|
||||
|
||||
/* Create a new savepoint and add it as the last in the list */
|
||||
|
||||
savep = static_cast<trx_named_savept_t*>(
|
||||
ut_malloc_nokey(sizeof(*savep)));
|
||||
|
||||
savep->name = mem_strdup(savepoint_name);
|
||||
|
||||
savep->savept.least_undo_no = trx->undo_no;
|
||||
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
|
||||
|
||||
savep->mysql_binlog_cache_pos = binlog_cache_pos;
|
||||
|
||||
UT_LIST_ADD_LAST(trx->trx_savepoints, savep);
|
||||
|
||||
trx->end_bulk_insert();
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Releases only the named savepoint. Savepoints which were set after this
|
||||
savepoint are left as is.
|
||||
@return if no savepoint of the name found then DB_NO_SAVEPOINT,
|
||||
otherwise DB_SUCCESS */
|
||||
dberr_t
|
||||
trx_release_savepoint_for_mysql(
|
||||
/*============================*/
|
||||
trx_t* trx, /*!< in: transaction handle */
|
||||
const char* savepoint_name) /*!< in: savepoint name */
|
||||
{
|
||||
trx_named_savept_t* savep;
|
||||
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE, true)
|
||||
|| trx_state_eq(trx, TRX_STATE_PREPARED, true));
|
||||
ut_ad(trx->mysql_thd);
|
||||
|
||||
savep = trx_savepoint_find(trx, savepoint_name);
|
||||
|
||||
if (savep != NULL) {
|
||||
trx_roll_savepoint_free(trx, savep);
|
||||
return DB_SUCCESS;
|
||||
} else if (trx->last_sql_stat_start.least_undo_no == 0) {
|
||||
/* Bulk insert could have discarded savepoints */
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
return DB_NO_SAVEPOINT;
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Roll back an active transaction. */
|
||||
static
|
||||
|
@ -618,7 +308,9 @@ trx_rollback_active(
|
|||
if (UNIV_UNLIKELY(!trx->rollback_finish())) {
|
||||
ut_ad(!dictionary_locked);
|
||||
} else {
|
||||
ib::info() << "Rolled back recovered transaction " << trx_id;
|
||||
sql_print_information(
|
||||
"InnoDB: Rolled back recovered transaction "
|
||||
TRX_ID_FMT, trx_id);
|
||||
}
|
||||
|
||||
if (dictionary_locked) {
|
||||
|
@ -904,7 +596,6 @@ trx_rollback_step(
|
|||
|
||||
if (node->state == ROLL_NODE_SEND) {
|
||||
trx_t* trx;
|
||||
ib_id_t roll_limit;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
|
@ -912,13 +603,11 @@ trx_rollback_step(
|
|||
|
||||
ut_a(node->undo_thr == NULL);
|
||||
|
||||
roll_limit = node->savept ? node->savept->least_undo_no : 0;
|
||||
|
||||
trx->mutex_lock();
|
||||
|
||||
trx_commit_or_rollback_prepare(trx);
|
||||
|
||||
node->undo_thr = trx_rollback_start(trx, roll_limit);
|
||||
node->undo_thr = trx_rollback_start(trx, node->savept);
|
||||
|
||||
trx->mutex_unlock();
|
||||
} else {
|
||||
|
|
|
@ -47,6 +47,31 @@ trx_sys_t trx_sys;
|
|||
#ifdef UNIV_DEBUG
|
||||
/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
|
||||
uint trx_rseg_n_slots_debug = 0;
|
||||
|
||||
void rw_trx_hash_t::validate_element(trx_t *trx)
|
||||
{
|
||||
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
|
||||
ut_ad(!trx->is_autocommit_non_locking());
|
||||
ut_d(bool acquire_trx_mutex= !trx->mutex_is_owner());
|
||||
ut_d(if (acquire_trx_mutex) trx->mutex_lock());
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
case TRX_STATE_ABORTED:
|
||||
ut_error;
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
ut_ad(!trx->is_autocommit_non_locking());
|
||||
break;
|
||||
case TRX_STATE_ACTIVE:
|
||||
if (!trx->is_autocommit_non_locking())
|
||||
break;
|
||||
ut_ad(!trx->is_recovered);
|
||||
ut_ad(trx->read_only);
|
||||
ut_ad(trx->mysql_thd);
|
||||
}
|
||||
ut_d(if (acquire_trx_mutex) trx->mutex_unlock());
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Display the MySQL binlog offset info if it is present in the trx
|
||||
|
@ -364,6 +389,7 @@ size_t trx_sys_t::any_active_transactions(size_t *prepared)
|
|||
trx_sys.trx_list.for_each([&](const trx_t &trx) {
|
||||
switch (trx.state) {
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
case TRX_STATE_ABORTED:
|
||||
break;
|
||||
case TRX_STATE_ACTIVE:
|
||||
if (!trx.id)
|
||||
|
|
|
@ -144,7 +144,7 @@ trx_init(
|
|||
|
||||
trx->magic_n = TRX_MAGIC_N;
|
||||
|
||||
trx->last_sql_stat_start.least_undo_no = 0;
|
||||
trx->last_stmt_start = 0;
|
||||
|
||||
ut_ad(!trx->read_view.is_open());
|
||||
|
||||
|
@ -192,10 +192,6 @@ struct TrxFactory {
|
|||
UT_LIST_INIT(trx->lock.evicted_tables,
|
||||
&dict_table_t::table_LRU);
|
||||
|
||||
UT_LIST_INIT(
|
||||
trx->trx_savepoints,
|
||||
&trx_named_savept_t::trx_savepoints);
|
||||
|
||||
trx->mutex_init();
|
||||
}
|
||||
|
||||
|
@ -437,9 +433,8 @@ void trx_t::free()
|
|||
MEM_NOACCESS(&error_info, sizeof error_info);
|
||||
MEM_NOACCESS(&error_key_num, sizeof error_key_num);
|
||||
MEM_NOACCESS(&graph, sizeof graph);
|
||||
MEM_NOACCESS(&trx_savepoints, sizeof trx_savepoints);
|
||||
MEM_NOACCESS(&undo_no, sizeof undo_no);
|
||||
MEM_NOACCESS(&last_sql_stat_start, sizeof last_sql_stat_start);
|
||||
MEM_NOACCESS(&last_stmt_start, sizeof last_stmt_start);
|
||||
MEM_NOACCESS(&rsegs, sizeof rsegs);
|
||||
MEM_NOACCESS(&roll_limit, sizeof roll_limit);
|
||||
MEM_NOACCESS(&in_rollback, sizeof in_rollback);
|
||||
|
@ -467,9 +462,10 @@ void trx_t::free()
|
|||
/** Transition to committed state, to release implicit locks. */
|
||||
TRANSACTIONAL_INLINE inline void trx_t::commit_state()
|
||||
{
|
||||
ut_ad(state == TRX_STATE_PREPARED
|
||||
|| state == TRX_STATE_PREPARED_RECOVERED
|
||||
|| state == TRX_STATE_ACTIVE);
|
||||
ut_d(auto trx_state{state});
|
||||
ut_ad(trx_state == TRX_STATE_PREPARED ||
|
||||
trx_state == TRX_STATE_PREPARED_RECOVERED ||
|
||||
trx_state == TRX_STATE_ACTIVE);
|
||||
/* This makes the transaction committed in memory and makes its
|
||||
changes to data visible to other transactions. NOTE that there is a
|
||||
small discrepancy from the strict formal visibility rules here: a
|
||||
|
@ -1490,8 +1486,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
|
|||
}
|
||||
}
|
||||
|
||||
savepoints_discard();
|
||||
|
||||
if (fts_trx)
|
||||
trx_finalize_for_fts(this, undo_no != 0);
|
||||
|
||||
|
@ -1510,7 +1504,7 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
|
|||
lock.was_chosen_as_deadlock_victim= false;
|
||||
}
|
||||
|
||||
void trx_t::commit_cleanup()
|
||||
bool trx_t::commit_cleanup() noexcept
|
||||
{
|
||||
ut_ad(!dict_operation);
|
||||
ut_ad(!was_dict_operation);
|
||||
|
@ -1527,6 +1521,7 @@ void trx_t::commit_cleanup()
|
|||
mutex.wr_unlock();
|
||||
|
||||
ut_a(error_state == DB_SUCCESS);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Commit the transaction in a mini-transaction.
|
||||
|
@ -1591,7 +1586,7 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr)
|
|||
}
|
||||
|
||||
|
||||
void trx_t::commit_persist()
|
||||
void trx_t::commit_persist() noexcept
|
||||
{
|
||||
mtr_t *mtr= nullptr;
|
||||
mtr_t local_mtr;
|
||||
|
@ -1605,7 +1600,7 @@ void trx_t::commit_persist()
|
|||
}
|
||||
|
||||
|
||||
void trx_t::commit()
|
||||
void trx_t::commit() noexcept
|
||||
{
|
||||
ut_ad(!was_dict_operation);
|
||||
ut_d(was_dict_operation= dict_operation);
|
||||
|
@ -1641,6 +1636,7 @@ trx_commit_or_rollback_prepare(
|
|||
return;
|
||||
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
case TRX_STATE_ABORTED:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1708,33 +1704,26 @@ trx_commit_step(
|
|||
return(thr);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Does the transaction commit for MySQL.
|
||||
@return DB_SUCCESS or error number */
|
||||
dberr_t
|
||||
trx_commit_for_mysql(
|
||||
/*=================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
void trx_commit_for_mysql(trx_t *trx) noexcept
|
||||
{
|
||||
/* Because we do not do the commit by sending an Innobase
|
||||
sig to the transaction, we must here make sure that trx has been
|
||||
started. */
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_ABORTED:
|
||||
trx->state= TRX_STATE_NOT_STARTED;
|
||||
/* fall through */
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
return DB_SUCCESS;
|
||||
trx->will_lock= false;
|
||||
break;
|
||||
case TRX_STATE_ACTIVE:
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
trx->op_info = "committing";
|
||||
trx->op_info= "committing";
|
||||
trx->commit();
|
||||
trx->op_info = "";
|
||||
return(DB_SUCCESS);
|
||||
trx->op_info= "";
|
||||
break;
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
ut_error;
|
||||
break;
|
||||
}
|
||||
ut_error;
|
||||
return(DB_CORRUPTION);
|
||||
}
|
||||
|
||||
/** Durably write log until trx->commit_lsn
|
||||
|
@ -1754,42 +1743,6 @@ void trx_commit_complete_for_mysql(trx_t *trx)
|
|||
trx_flush_log_if_needed(lsn, trx);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Marks the latest SQL statement ended. */
|
||||
void
|
||||
trx_mark_sql_stat_end(
|
||||
/*==================*/
|
||||
trx_t* trx) /*!< in: trx handle */
|
||||
{
|
||||
ut_a(trx);
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
break;
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
trx->undo_no = 0;
|
||||
/* fall through */
|
||||
case TRX_STATE_ACTIVE:
|
||||
if (trx->fts_trx != NULL) {
|
||||
fts_savepoint_laststmt_refresh(trx);
|
||||
}
|
||||
|
||||
if (trx->is_bulk_insert()) {
|
||||
/* Allow a subsequent INSERT into an empty table
|
||||
if !unique_checks && !foreign_key_checks. */
|
||||
return;
|
||||
}
|
||||
|
||||
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
|
||||
trx->end_bulk_insert();
|
||||
return;
|
||||
}
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Prints info about a transaction. */
|
||||
void
|
||||
|
@ -1815,9 +1768,16 @@ trx_print_low(
|
|||
fprintf(f, "TRANSACTION (%p)", trx);
|
||||
}
|
||||
|
||||
THD* thd = trx->mysql_thd;
|
||||
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
fputs(", not started", f);
|
||||
thd = nullptr;
|
||||
goto state_ok;
|
||||
case TRX_STATE_ABORTED:
|
||||
fputs(", forced rollback done", f);
|
||||
thd = nullptr;
|
||||
goto state_ok;
|
||||
case TRX_STATE_ACTIVE:
|
||||
fprintf(f, ", ACTIVE %lu sec",
|
||||
|
@ -1883,9 +1843,8 @@ state_ok:
|
|||
putc('\n', f);
|
||||
}
|
||||
|
||||
if (trx->state != TRX_STATE_NOT_STARTED && trx->mysql_thd != NULL) {
|
||||
innobase_mysql_print_thd(
|
||||
f, trx->mysql_thd, static_cast<uint>(max_query_len));
|
||||
if (thd) {
|
||||
innobase_mysql_print_thd(f, thd, uint(max_query_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2201,6 +2160,7 @@ trx_start_if_not_started_xa_low(
|
|||
bool read_write) /*!< in: true if read write transaction */
|
||||
{
|
||||
switch (trx->state) {
|
||||
case TRX_STATE_ABORTED:
|
||||
case TRX_STATE_NOT_STARTED:
|
||||
trx_start_low(trx, read_write);
|
||||
return;
|
||||
|
@ -2244,6 +2204,7 @@ trx_start_if_not_started_low(
|
|||
}
|
||||
return;
|
||||
|
||||
case TRX_STATE_ABORTED:
|
||||
case TRX_STATE_PREPARED:
|
||||
case TRX_STATE_PREPARED_RECOVERED:
|
||||
case TRX_STATE_COMMITTED_IN_MEMORY:
|
||||
|
|
|
@ -340,8 +340,6 @@ ut_strerr(
|
|||
return("Data structure corruption");
|
||||
case DB_CANNOT_DROP_CONSTRAINT:
|
||||
return("Cannot drop constraint");
|
||||
case DB_NO_SAVEPOINT:
|
||||
return("No such savepoint");
|
||||
case DB_TABLESPACE_EXISTS:
|
||||
return("Tablespace already exists");
|
||||
case DB_TABLESPACE_DELETED:
|
||||
|
|
Loading…
Reference in a new issue