mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
MDEV-515 Reduce InnoDB undo logging for insert into empty table
We implement an idea that was suggested by Michael 'Monty' Widenius in October 2017: When InnoDB is inserting into an empty table or partition, we can write a single undo log record TRX_UNDO_EMPTY, which will cause ROLLBACK to clear the table. For this to work, the insert into an empty table or partition must be covered by an exclusive table lock that will be held until the transaction has been committed or rolled back, or the INSERT operation has been rolled back (and the table is empty again), in lock_table_x_unlock(). Clustered index records that are covered by the TRX_UNDO_EMPTY record will carry DB_TRX_ID=0 and DB_ROLL_PTR=1<<55, and thus they cannot be distinguished from what MDEV-12288 leaves behind after purging the history of row-logged operations. Concurrent non-locking reads must be adjusted: If the read view was created before the INSERT into an empty table, then we must continue to imagine that the table is empty, and not try to read any records. If the read view was created after the INSERT was committed, then all records must be visible normally. To implement this, we introduce the field dict_table_t::bulk_trx_id. This special handling only applies to the very first INSERT statement of a transaction for the empty table or partition. If a subsequent statement in the transaction is modifying the initially empty table again, we must enable row-level undo logging, so that we will be able to roll back to the start of the statement in case of an error (such as duplicate key). INSERT IGNORE will continue to use row-level logging and locking, because implementing it would require the ability to roll back the latest row. Since the undo log that we write only allows us to roll back the entire statement, we cannot support INSERT IGNORE. We will introduce a handler::extra() parameter HA_EXTRA_IGNORE_INSERT to indicate to storage engines that INSERT IGNORE is being executed. In many test cases, we add an extra record to the table, so that during the 'interesting' part of the test, row-level locking and logging will be used. Replicas will continue to use row-level logging and locking until MDEV-24622 has been addressed. Likewise, this optimization will be disabled in Galera cluster until MDEV-24623 enables it. dict_table_t::bulk_trx_id: The latest active or committed transaction that initiated an insert into an empty table or partition. Protected by exclusive table lock and a clustered index leaf page latch. ins_node_t::bulk_insert: Whether bulk insert was initiated. trx_t::mod_tables: Use C++11 style accessors (emplace instead of insert). Unlike earlier, this collection will cover also temporary tables. trx_mod_table_time_t: Add start_bulk_insert(), end_bulk_insert(), is_bulk_insert(), was_bulk_insert(). trx_undo_report_row_operation(): Before accessing any undo log pages, invoke trx->mod_tables.emplace() in order to determine whether undo logging was disabled, or whether this is the first INSERT and we are supposed to write a TRX_UNDO_EMPTY record. row_ins_clust_index_entry_low(): If we are inserting into an empty clustered index leaf page, set the ins_node_t::bulk_insert flag for the subsequent trx_undo_report_row_operation() call. lock_rec_insert_check_and_lock(), lock_prdt_insert_check_and_lock(): Remove the redundant parameter 'flags' that can be checked in the caller. btr_cur_ins_lock_and_undo(): Simplify the logic. Correctly write DB_TRX_ID,DB_ROLL_PTR after invoking trx_undo_report_row_operation(). trx_mark_sql_stat_end(), ha_innobase::extra(HA_EXTRA_IGNORE_INSERT), ha_innobase::external_lock(): Invoke trx_t::end_bulk_insert() so that the next statement will not be covered by table-level undo logging. ReadView::changes_visible(trx_id_t) const: New accessor for the case where the trx_id_t is not read from a potentially corrupted index page but directly from the memory. In this case, we can skip a sanity check. row_sel(), row_sel_try_search_shortcut(), row_search_mvcc(): row_sel_try_search_shortcut_for_mysql(), row_merge_read_clustered_index(): Check dict_table_t::bulk_trx_id. row_sel_clust_sees(): Replaces lock_clust_rec_cons_read_sees(). lock_sec_rec_cons_read_sees(): Replaced with lower-level code. btr_root_page_init(): Refactored from btr_create(). dict_index_t::clear(), dict_table_t::clear(): Empty an index or table, for the ROLLBACK of an INSERT operation. ROW_T_EMPTY, ROW_OP_EMPTY: Note a concurrent ROLLBACK of an INSERT into an empty table. This is joint work with Thirunarayanan Balathandayuthapani, who created a working prototype. Thanks to Matthias Leich for extensive testing.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
|
||||
Copyright (c) 1995, 2018, MariaDB Corporation.
|
||||
Copyright (c) 1995, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -219,7 +219,9 @@ enum ha_extra_function {
|
||||
/** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */
|
||||
HA_EXTRA_END_ALTER_COPY,
|
||||
/** Fake the start of a statement after wsrep_load_data_splitting hack */
|
||||
HA_EXTRA_FAKE_START_STMT
|
||||
HA_EXTRA_FAKE_START_STMT,
|
||||
/** IGNORE is being used for the insert statement */
|
||||
HA_EXTRA_IGNORE_INSERT
|
||||
};
|
||||
|
||||
/* Compatible option, to be deleted in 6.0 */
|
||||
|
||||
@@ -247,11 +247,13 @@ COMMIT;
|
||||
SET @@completion_type=1;
|
||||
COMMIT AND NO CHAIN;
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
START TRANSACTION;
|
||||
TRUNCATE TABLE t1;
|
||||
INSERT INTO t1 VALUES(100);
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1000);
|
||||
SELECT * FROM t1;
|
||||
s1
|
||||
100
|
||||
1000
|
||||
Should read '1000'
|
||||
connection con1;
|
||||
@@ -260,6 +262,7 @@ COMMIT;
|
||||
connection default;
|
||||
SELECT * FROM t1;
|
||||
s1
|
||||
100
|
||||
1000
|
||||
Should only read the '1000' as this transaction is now in REP READ
|
||||
COMMIT AND NO CHAIN;
|
||||
|
||||
@@ -284,8 +284,11 @@ COMMIT;
|
||||
SET @@completion_type=1;
|
||||
COMMIT AND NO CHAIN;
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
START TRANSACTION;
|
||||
TRUNCATE TABLE t1;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100);
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1000);
|
||||
SELECT * FROM t1;
|
||||
--echo Should read '1000'
|
||||
|
||||
@@ -1372,6 +1372,7 @@ unlock tables;
|
||||
connection default;
|
||||
# Reap XA COMMIT.
|
||||
delete from t3_trans;
|
||||
INSERT INTO t3_trans VALUES(100);
|
||||
#
|
||||
# Check that XA COMMIT / ROLLBACK for prepared transaction from a
|
||||
# disconnected session is blocked by active FTWRL in another connection.
|
||||
|
||||
@@ -1679,6 +1679,9 @@ connection default;
|
||||
--echo # Reap XA COMMIT.
|
||||
--reap
|
||||
delete from t3_trans;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t3_trans VALUES(100);
|
||||
--echo #
|
||||
--echo # Check that XA COMMIT / ROLLBACK for prepared transaction from a
|
||||
--echo # disconnected session is blocked by active FTWRL in another connection.
|
||||
|
||||
@@ -12,6 +12,8 @@ connect con3,localhost,root,,;
|
||||
connection con1;
|
||||
set @@autocommit=0;
|
||||
CREATE TABLE t1(s1 INT UNIQUE) ENGINE=innodb;
|
||||
INSERT INTO t1 VALUES (100);
|
||||
COMMIT;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
connection con2;
|
||||
set @@autocommit=0;
|
||||
|
||||
@@ -25,6 +25,11 @@ connect (con3,localhost,root,,);
|
||||
connection con1;
|
||||
set @@autocommit=0;
|
||||
CREATE TABLE t1(s1 INT UNIQUE) ENGINE=innodb;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent DML won't happen on the table
|
||||
INSERT INTO t1 VALUES (100);
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO t1 VALUES (1);
|
||||
|
||||
connection con2;
|
||||
|
||||
@@ -3,6 +3,7 @@ connection default;
|
||||
CREATE VIEW v_processlist as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
|
||||
call mtr.add_suppression("Found 10 prepared XA transactions");
|
||||
CREATE TABLE t (a INT) ENGINE=innodb;
|
||||
INSERT INTO t VALUES(100);
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
SET @@sql_log_bin = OFF;
|
||||
CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
|
||||
@@ -48,18 +49,21 @@ connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx1ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx1ro';
|
||||
XA PREPARE 'trx1ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx2ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx2ro';
|
||||
XA PREPARE 'trx2ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx3ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx3ro';
|
||||
XA PREPARE 'trx3ro';
|
||||
connection default;
|
||||
@@ -402,6 +406,7 @@ ERROR XAE08: XAER_DUPID: The XID already exists
|
||||
XA ROLLBACK 'trx_19';
|
||||
SELECT * FROM t;
|
||||
a
|
||||
100
|
||||
5
|
||||
6
|
||||
7
|
||||
@@ -533,6 +538,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx1ro';
|
||||
XA PREPARE 'trx1ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
@@ -559,6 +565,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx2ro';
|
||||
XA PREPARE 'trx2ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
@@ -585,6 +592,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx3ro';
|
||||
XA PREPARE 'trx3ro';
|
||||
connection default;
|
||||
@@ -927,6 +935,7 @@ ERROR XAE08: XAER_DUPID: The XID already exists
|
||||
XA ROLLBACK 'trx_19';
|
||||
SELECT * FROM t;
|
||||
a
|
||||
100
|
||||
5
|
||||
6
|
||||
7
|
||||
@@ -1036,7 +1045,7 @@ XA END 'one_phase_trx_4';
|
||||
XA COMMIT 'one_phase_trx_4' ONE PHASE;
|
||||
SELECT SUM(a) FROM t;
|
||||
SUM(a)
|
||||
290
|
||||
390
|
||||
DROP TABLE t;
|
||||
DROP VIEW v_processlist;
|
||||
All transactions must be completed, to empty-list the following:
|
||||
|
||||
@@ -2,6 +2,7 @@ SET GLOBAL max_binlog_size= 4096;
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit= 1;
|
||||
RESET MASTER;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
|
||||
INSERT INTO t1 VALUES(100, "MDEV-515");
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC= "binlog_open_before_update_index SIGNAL con1_ready WAIT_FOR con1_cont";
|
||||
SET SESSION debug_dbug="+d,crash_create_critical_before_update_index";
|
||||
@@ -20,6 +21,7 @@ connection default;
|
||||
SELECT a FROM t1 ORDER BY a;
|
||||
a
|
||||
1
|
||||
100
|
||||
show binary logs;
|
||||
Log_name File_size
|
||||
master-bin.000001 #
|
||||
@@ -32,6 +34,11 @@ master-bin.000001 # Binlog_checkpoint # # master-bin.000001
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Annotate_rows # # INSERT INTO t1 VALUES(100, "MDEV-515")
|
||||
master-bin.000001 # Table_map # # table_id: # (test.t1)
|
||||
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Annotate_rows # # INSERT INTO t1 VALUES (1, REPEAT("x", 4100))
|
||||
master-bin.000001 # Table_map # # table_id: # (test.t1)
|
||||
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
|
||||
|
||||
@@ -3,6 +3,7 @@ RESET MASTER;
|
||||
CREATE VIEW v_processlist as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
|
||||
call mtr.add_suppression("Found 10 prepared XA transactions");
|
||||
CREATE TABLE t (a INT) ENGINE=innodb;
|
||||
INSERT INTO t VALUES(100);
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
SET @@sql_log_bin = OFF;
|
||||
CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
|
||||
@@ -48,18 +49,21 @@ connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx1ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx1ro';
|
||||
XA PREPARE 'trx1ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx2ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx2ro';
|
||||
XA PREPARE 'trx2ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
XA START 'trx3ro';
|
||||
SELECT * from t ORDER BY a;
|
||||
a
|
||||
100
|
||||
XA END 'trx3ro';
|
||||
XA PREPARE 'trx3ro';
|
||||
connection default;
|
||||
@@ -402,6 +406,7 @@ ERROR XAE08: XAER_DUPID: The XID already exists
|
||||
XA ROLLBACK 'trx_19';
|
||||
SELECT * FROM t;
|
||||
a
|
||||
100
|
||||
5
|
||||
6
|
||||
7
|
||||
@@ -533,6 +538,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx1ro';
|
||||
XA PREPARE 'trx1ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
@@ -559,6 +565,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx2ro';
|
||||
XA PREPARE 'trx2ro';
|
||||
connect conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
@@ -585,6 +592,7 @@ a
|
||||
12
|
||||
13
|
||||
14
|
||||
100
|
||||
XA END 'trx3ro';
|
||||
XA PREPARE 'trx3ro';
|
||||
connection default;
|
||||
@@ -927,6 +935,7 @@ ERROR XAE08: XAER_DUPID: The XID already exists
|
||||
XA ROLLBACK 'trx_19';
|
||||
SELECT * FROM t;
|
||||
a
|
||||
100
|
||||
5
|
||||
6
|
||||
7
|
||||
@@ -1036,7 +1045,7 @@ XA END 'one_phase_trx_4';
|
||||
XA COMMIT 'one_phase_trx_4' ONE PHASE;
|
||||
SELECT SUM(a) FROM t;
|
||||
SUM(a)
|
||||
290
|
||||
390
|
||||
DROP TABLE t;
|
||||
DROP VIEW v_processlist;
|
||||
include/show_binlog_events.inc
|
||||
@@ -1048,6 +1057,9 @@ master-bin.000001 # Query # # use `mtr`; INSERT INTO test_suppressions (pattern)
|
||||
master-bin.000001 # Query # # COMMIT
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t (a INT) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES(100)
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # XA START X'7472785f30',X'',1 GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t SET a=0
|
||||
master-bin.000001 # Query # # XA END X'7472785f30',X'',1
|
||||
|
||||
@@ -11,7 +11,9 @@ SET GLOBAL innodb_flush_log_at_trx_commit= 1;
|
||||
RESET MASTER;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert
|
||||
# In that case, Concurrent DML will get blocked
|
||||
INSERT INTO t1 VALUES(100, "MDEV-515");
|
||||
# One connection does an insert that causes a binlog rotate.
|
||||
# The rotate is paused after writing new file but before updating index.
|
||||
connect(con1,localhost,root,,);
|
||||
|
||||
@@ -54,6 +54,10 @@ CREATE VIEW v_processlist as SELECT * FROM performance_schema.threads where typ
|
||||
|
||||
CREATE TABLE t (a INT) ENGINE=innodb;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t VALUES(100);
|
||||
|
||||
# Counter is incremented at the end of post restart to
|
||||
# reflect number of loops done in correctness computation.
|
||||
--let $restart_number = 0
|
||||
|
||||
@@ -20,6 +20,7 @@ connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
connection server_1;
|
||||
SET sql_log_bin=0;
|
||||
@@ -136,6 +137,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now SIGNAL d0_cont';
|
||||
@@ -161,6 +163,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -190,6 +193,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -225,6 +229,7 @@ SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
|
||||
a b
|
||||
80 0
|
||||
81 10000
|
||||
100 100
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR wait_queue_ready';
|
||||
KILL THD_ID;
|
||||
@@ -244,6 +249,7 @@ a b
|
||||
80 0
|
||||
81 10000
|
||||
82 0
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||
|
||||
@@ -13,6 +13,7 @@ include/start_slave.inc
|
||||
connection server_1;
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
include/save_master_gtid.inc
|
||||
connection server_2;
|
||||
include/sync_with_master_gtid.inc
|
||||
|
||||
@@ -17,6 +17,8 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
connection server_1;
|
||||
SET sql_log_bin=0;
|
||||
@@ -80,6 +82,7 @@ a b
|
||||
32 32
|
||||
33 33
|
||||
34 34
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET sql_log_bin=0;
|
||||
@@ -98,6 +101,7 @@ STOP SLAVE IO_THREAD;
|
||||
SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
|
||||
a b
|
||||
31 31
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -121,6 +125,7 @@ a b
|
||||
33 33
|
||||
34 34
|
||||
39 0
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -179,6 +184,7 @@ a b
|
||||
42 42
|
||||
43 43
|
||||
44 44
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR t2_query';
|
||||
@@ -211,6 +217,7 @@ a b
|
||||
43 43
|
||||
44 44
|
||||
49 0
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -274,6 +281,7 @@ a b
|
||||
52 52
|
||||
53 53
|
||||
54 54
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR t2_query';
|
||||
@@ -286,6 +294,7 @@ include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
|
||||
SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
|
||||
a b
|
||||
51 51
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -309,6 +318,7 @@ a b
|
||||
53 53
|
||||
54 54
|
||||
59 0
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||
|
||||
@@ -16,6 +16,8 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
connection server_1;
|
||||
@@ -55,9 +57,11 @@ SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
20
|
||||
21
|
||||
100
|
||||
SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
|
||||
a b
|
||||
20 20
|
||||
100 100
|
||||
include/start_slave.inc
|
||||
SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
@@ -66,11 +70,13 @@ SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
20
|
||||
21
|
||||
100
|
||||
SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
|
||||
a b
|
||||
20 20
|
||||
21 21
|
||||
22 22
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||
|
||||
@@ -66,6 +66,7 @@ test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
SET SQL_MODE= strict_trans_tables;
|
||||
CREATE TABLE t1(a INT UNIQUE) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(3);
|
||||
SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done';
|
||||
ALTER TABLE t1 MODIFY COLUMN a INT NOT NULL;
|
||||
connection con1;
|
||||
|
||||
@@ -5,6 +5,7 @@ connect con3,localhost,root,,;
|
||||
connect con4,localhost,root,,;
|
||||
connection default;
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
|
||||
INSERT INTO t1 VALUES(9, "");
|
||||
SHOW MASTER STATUS;
|
||||
File Position Binlog_Do_DB Binlog_Ignore_DB
|
||||
master-bin.000001 <pos>
|
||||
@@ -39,6 +40,7 @@ connection default;
|
||||
SELECT * FROM t1 ORDER BY a,b;
|
||||
a b
|
||||
0
|
||||
9
|
||||
SHOW STATUS LIKE 'binlog_snapshot_%';
|
||||
Variable_name Value
|
||||
Binlog_snapshot_file master-bin.000001
|
||||
@@ -61,6 +63,7 @@ connection default;
|
||||
SELECT * FROM t1 ORDER BY a,b;
|
||||
a b
|
||||
0
|
||||
9
|
||||
SHOW STATUS LIKE 'binlog_snapshot_%';
|
||||
Variable_name Value
|
||||
Binlog_snapshot_file master-bin.000001
|
||||
@@ -80,6 +83,9 @@ include/show_binlog_events.inc
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(9, "")
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CREATE TABLE t0 (pk INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t0 VALUES(100);
|
||||
connect con1,localhost,root,,test;
|
||||
BEGIN;
|
||||
INSERT INTO t0 SET pk=1;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=innodb;
|
||||
INSERT INTO t1 VALUES(100);
|
||||
SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
SELECT variable_value INTO @group_commits FROM information_schema.global_status
|
||||
@@ -32,11 +33,13 @@ SET DEBUG_SYNC= "now WAIT_FOR group2_con4";
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
100
|
||||
SET DEBUG_SYNC= "now SIGNAL group2_queued";
|
||||
connection con1;
|
||||
connection default;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
100
|
||||
con1
|
||||
connection con5;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
@@ -51,11 +54,13 @@ connection default;
|
||||
SET DEBUG_SYNC= "now WAIT_FOR group3_con5";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
100
|
||||
con1
|
||||
SET DEBUG_SYNC= "now SIGNAL group3_committed";
|
||||
SET DEBUG_SYNC= "now WAIT_FOR group2_visible";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
100
|
||||
con1
|
||||
con2
|
||||
con3
|
||||
@@ -69,6 +74,7 @@ connection con6;
|
||||
connection default;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
100
|
||||
con1
|
||||
con2
|
||||
con3
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=innodb;
|
||||
INSERT INTO t1 VALUES("default");
|
||||
SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
SELECT variable_value INTO @group_commits FROM information_schema.global_status
|
||||
@@ -32,12 +33,14 @@ SET DEBUG_SYNC= "now WAIT_FOR group2_con4";
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
default
|
||||
SET DEBUG_SYNC= "now SIGNAL group2_queued";
|
||||
connection con1;
|
||||
connection default;
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
con1
|
||||
default
|
||||
connection con5;
|
||||
SET DEBUG_SYNC= "commit_before_get_LOCK_after_binlog_sync SIGNAL group3_con5";
|
||||
SET DEBUG_SYNC= "commit_after_get_LOCK_log SIGNAL con5_leader WAIT_FOR con6_queued";
|
||||
@@ -52,6 +55,7 @@ SET DEBUG_SYNC= "now WAIT_FOR group3_con5";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
a
|
||||
con1
|
||||
default
|
||||
SET DEBUG_SYNC= "now SIGNAL group3_committed";
|
||||
SET DEBUG_SYNC= "now WAIT_FOR group2_visible";
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
@@ -60,6 +64,7 @@ con1
|
||||
con2
|
||||
con3
|
||||
con4
|
||||
default
|
||||
SET DEBUG_SYNC= "now SIGNAL group2_checked";
|
||||
connection con2;
|
||||
connection con3;
|
||||
@@ -75,6 +80,7 @@ con3
|
||||
con4
|
||||
con5
|
||||
con6
|
||||
default
|
||||
SELECT variable_value - @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
variable_value - @commits
|
||||
|
||||
@@ -147,6 +147,8 @@ DROP TABLE t1, t2;
|
||||
#
|
||||
CREATE TABLE t1 (pk INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB
|
||||
PARTITION BY key (pk) PARTITIONS 2;
|
||||
INSERT INTO t1 VALUES(100);
|
||||
INSERT INTO t1 VALUES(101);
|
||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
|
||||
CREATE TABLE t3 (b INT) ENGINE=InnoDB;
|
||||
|
||||
@@ -18,15 +18,12 @@ ddl_log_file_alter_table 0
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
SET DEBUG_SYNC = 'write_row_noreplace SIGNAL have_handle WAIT_FOR go_ahead';
|
||||
INSERT INTO t1 VALUES(1,2,3);
|
||||
# Establish session con1 (user=root)
|
||||
connect con1,localhost,root,,;
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR have_handle';
|
||||
SET lock_wait_timeout = 1;
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
SET DEBUG_SYNC = 'now SIGNAL go_ahead';
|
||||
# session default
|
||||
connection default;
|
||||
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -37,7 +34,6 @@ ddl_online_create_index 0
|
||||
ddl_pending_alter_table 0
|
||||
ddl_sort_file_alter_table 0
|
||||
ddl_log_file_alter_table 0
|
||||
# session con1
|
||||
connection con1;
|
||||
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
||||
SET DEBUG_DBUG = '+d,innodb_OOM_prepare_inplace_alter';
|
||||
@@ -55,7 +51,6 @@ SET SESSION DEBUG = @saved_debug_dbug;
|
||||
Warnings:
|
||||
Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE;
|
||||
# session default
|
||||
connection default;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
@@ -67,22 +62,17 @@ t1 CREATE TABLE `t1` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(7,4,2);
|
||||
# session con1
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL scanned WAIT_FOR insert_done';
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2);
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
# session default
|
||||
connection default;
|
||||
COMMIT;
|
||||
# session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2);
|
||||
ERROR 23000: Duplicate entry '4' for key 'c2'
|
||||
# session default
|
||||
connection default;
|
||||
DELETE FROM t1 WHERE c1 = 7;
|
||||
# session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2), ROW_FORMAT=COMPACT,
|
||||
LOCK = SHARED, ALGORITHM = INPLACE;
|
||||
@@ -100,7 +90,6 @@ t1 CREATE TABLE `t1` (
|
||||
UNIQUE KEY `c2_2` (`c2`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
|
||||
ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1);
|
||||
# session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR scanned';
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -114,13 +103,10 @@ ddl_log_file_alter_table 0
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(4,7,2);
|
||||
SET DEBUG_SYNC = 'now SIGNAL insert_done';
|
||||
# session con1
|
||||
connection con1;
|
||||
ERROR 23000: Duplicate entry '4' for key 'PRIMARY'
|
||||
# session default
|
||||
connection default;
|
||||
ROLLBACK;
|
||||
# session con1
|
||||
connection con1;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
@@ -142,7 +128,6 @@ ddl_online_create_index 0
|
||||
ddl_pending_alter_table 0
|
||||
ddl_sort_file_alter_table 0
|
||||
ddl_log_file_alter_table 0
|
||||
# session default
|
||||
connection default;
|
||||
INSERT INTO t1 VALUES(6,3,1);
|
||||
ERROR 23000: Duplicate entry '3' for key 'c2_2'
|
||||
@@ -152,14 +137,12 @@ DROP INDEX c2_2 ON t1;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(7,4,2);
|
||||
ROLLBACK;
|
||||
# session con1
|
||||
connection con1;
|
||||
KILL QUERY @id;
|
||||
ERROR 70100: Query execution was interrupted
|
||||
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL rebuilt WAIT_FOR dml_done';
|
||||
SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL applied WAIT_FOR kill_done';
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
# session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rebuilt';
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -176,7 +159,6 @@ ROLLBACK;
|
||||
SET DEBUG_SYNC = 'now SIGNAL dml_done WAIT_FOR applied';
|
||||
KILL QUERY @id;
|
||||
SET DEBUG_SYNC = 'now SIGNAL kill_done';
|
||||
# session con1
|
||||
connection con1;
|
||||
ERROR 70100: Query execution was interrupted
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -187,7 +169,6 @@ ddl_online_create_index 0
|
||||
ddl_pending_alter_table 0
|
||||
ddl_sort_file_alter_table 0
|
||||
ddl_log_file_alter_table 0
|
||||
# session default
|
||||
connection default;
|
||||
CHECK TABLE t1;
|
||||
Table Op Msg_type Msg_text
|
||||
@@ -212,7 +193,6 @@ WHERE variable_name = 'innodb_encryption_n_merge_blocks_decrypted');
|
||||
SET @rowlog_encrypt_0=
|
||||
(SELECT variable_value FROM information_schema.global_status
|
||||
WHERE variable_name = 'innodb_encryption_n_rowlog_blocks_encrypted');
|
||||
# session con1
|
||||
connection con1;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
@@ -227,7 +207,6 @@ SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL rebuilt2 WAIT_FOR dml2_done
|
||||
SET lock_wait_timeout = 10;
|
||||
ALTER TABLE t1 ROW_FORMAT=COMPACT
|
||||
PAGE_COMPRESSED = YES PAGE_COMPRESSION_LEVEL = 1, ALGORITHM = INPLACE;
|
||||
# session default
|
||||
connection default;
|
||||
INSERT INTO t1 SELECT 80 + c1, c2, c3 FROM t1;
|
||||
INSERT INTO t1 SELECT 160 + c1, c2, c3 FROM t1;
|
||||
@@ -290,7 +269,6 @@ SELECT
|
||||
sort_balance @merge_encrypt_1>@merge_encrypt_0 @merge_decrypt_1>@merge_decrypt_0 @rowlog_encrypt_1>@rowlog_encrypt_0
|
||||
0 0 0 0
|
||||
SET DEBUG_SYNC = 'now SIGNAL dml2_done';
|
||||
# session con1
|
||||
connection con1;
|
||||
ERROR HY000: Creating index 'PRIMARY' required more than 'innodb_online_alter_log_max_size' bytes of modification log. Please try again
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -321,7 +299,6 @@ ERROR 23000: Duplicate entry '5' for key 'PRIMARY'
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(c22f,c1,c4(5)),
|
||||
CHANGE c2 c22f INT, CHANGE c3 c3 CHAR(255) NULL, CHANGE c1 c1 INT AFTER c22f,
|
||||
ADD COLUMN c4 VARCHAR(6) DEFAULT 'Online', LOCK=NONE;
|
||||
# session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rebuilt3';
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
@@ -349,7 +326,6 @@ ddl_pending_alter_table 1
|
||||
ddl_sort_file_alter_table 2
|
||||
ddl_log_file_alter_table 2
|
||||
SET DEBUG_SYNC = 'now SIGNAL dml3_done';
|
||||
# session con1
|
||||
connection con1;
|
||||
SELECT name, count FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE subsystem = 'ddl';
|
||||
name count
|
||||
@@ -405,20 +381,16 @@ SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL c3p5_created0 WAIT_FOR ins_
|
||||
ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL, DROP COLUMN c22f,
|
||||
DROP PRIMARY KEY, ADD PRIMARY KEY(c1,c4(5)),
|
||||
ADD COLUMN c5 CHAR(5) DEFAULT 'tired' FIRST;
|
||||
# session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR c3p5_created0';
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(347,33101,'Pikku kakkosen posti','YLETV2');
|
||||
INSERT INTO t1 VALUES(33101,347,NULL,'');
|
||||
SET DEBUG_SYNC = 'now SIGNAL ins_done0';
|
||||
# session con1
|
||||
connection con1;
|
||||
ERROR 01000: Data truncated for column 'c3' at row 323
|
||||
# session default
|
||||
connection default;
|
||||
ROLLBACK;
|
||||
# session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL;
|
||||
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL c3p5_created WAIT_FOR ins_done';
|
||||
@@ -426,14 +398,12 @@ ALTER TABLE t1 DROP PRIMARY KEY, DROP COLUMN c22f,
|
||||
ADD COLUMN c6 VARCHAR(1000) DEFAULT
|
||||
'I love tracking down hard-to-reproduce bugs.',
|
||||
ADD PRIMARY KEY c3p5(c3(5), c6(2));
|
||||
# session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR c3p5_created';
|
||||
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL ins_done WAIT_FOR ddl_timed_out';
|
||||
INSERT INTO t1 VALUES(347,33101,NULL,'');
|
||||
ERROR 23000: Column 'c3' cannot be null
|
||||
INSERT INTO t1 VALUES(347,33101,'Pikku kakkosen posti','');
|
||||
# session con1
|
||||
connection con1;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
SET DEBUG_SYNC = 'now SIGNAL ddl_timed_out';
|
||||
@@ -445,7 +415,6 @@ ddl_online_create_index 0
|
||||
ddl_pending_alter_table 0
|
||||
ddl_sort_file_alter_table 6
|
||||
ddl_log_file_alter_table 2
|
||||
# session default
|
||||
connection default;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
@@ -463,12 +432,8 @@ c22f c1 c3 c4
|
||||
5 36 36foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo Online
|
||||
5 41 41foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo Online
|
||||
5 46 46foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo Online
|
||||
# session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 DISCARD TABLESPACE;
|
||||
# Disconnect session con1
|
||||
disconnect con1;
|
||||
# session default
|
||||
connection default;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
@@ -479,9 +444,25 @@ t1 CREATE TABLE `t1` (
|
||||
`c4` varchar(6) NOT NULL DEFAULT 'Online',
|
||||
PRIMARY KEY (`c22f`,`c1`,`c4`(5))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
SET GLOBAL innodb_monitor_disable = module_ddl;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL created WAIT_FOR ins';
|
||||
ALTER TABLE t1 FORCE;
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR created';
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
ROLLBACK;
|
||||
SET DEBUG_SYNC = 'now SIGNAL ins';
|
||||
connection con1;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
SET GLOBAL innodb_file_per_table = @global_innodb_file_per_table_orig;
|
||||
SET GLOBAL innodb_monitor_enable = default;
|
||||
SET GLOBAL innodb_monitor_disable = default;
|
||||
|
||||
24
mysql-test/suite/innodb/r/lock_insert_into_empty.result
Normal file
24
mysql-test/suite/innodb/r/lock_insert_into_empty.result
Normal file
@@ -0,0 +1,24 @@
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(0);
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t2 VALUES(1),(1);
|
||||
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
|
||||
connect con1,localhost,root,,;
|
||||
BEGIN;
|
||||
SELECT * FROM t2 LOCK IN SHARE MODE;
|
||||
a
|
||||
connection default;
|
||||
SET innodb_lock_wait_timeout=1;
|
||||
INSERT INTO t2 VALUES(2);
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
disconnect con1;
|
||||
INSERT INTO t2 VALUES(3);
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
SELECT * FROM t2;
|
||||
a
|
||||
3
|
||||
DROP TABLE t1, t2;
|
||||
@@ -42,6 +42,9 @@ DROP TABLE t1;
|
||||
|
||||
SET SQL_MODE= strict_trans_tables;
|
||||
CREATE TABLE t1(a INT UNIQUE) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(3);
|
||||
SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL dml WAIT_FOR dml_done';
|
||||
--send ALTER TABLE t1 MODIFY COLUMN a INT NOT NULL
|
||||
connection con1;
|
||||
|
||||
@@ -410,6 +410,17 @@ INSERT INTO mdev6076a SET b=NULL;
|
||||
SELECT * FROM mdev6076a;
|
||||
INSERT INTO mdev6076b SET b=NULL;
|
||||
SELECT * FROM mdev6076b;
|
||||
# MDEV-515 resets the PAGE_ROOT_AUTOINC field in
|
||||
# root page during rollback.
|
||||
--disable_query_log
|
||||
BEGIN;
|
||||
let $i = 55;
|
||||
WHILE ($i) {
|
||||
eval INSERT INTO mdev6076empty SET b=$i;
|
||||
dec $i;
|
||||
}
|
||||
ROLLBACK;
|
||||
--enable_query_log
|
||||
INSERT INTO mdev6076empty SET b=NULL;
|
||||
SELECT * FROM mdev6076empty;
|
||||
DROP TABLE mdev6076a, mdev6076b, mdev6076empty;
|
||||
|
||||
@@ -16,7 +16,10 @@ connect(con4,localhost,root,,);
|
||||
connection default;
|
||||
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
|
||||
let pos=`select $binlog_start_pos + 254`;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(9, "");
|
||||
let pos=`select $binlog_start_pos + 422`;
|
||||
--replace_result $pos <pos>
|
||||
SHOW MASTER STATUS;
|
||||
--replace_result $pos <pos>
|
||||
@@ -53,10 +56,10 @@ COMMIT;
|
||||
|
||||
connection default;
|
||||
SELECT * FROM t1 ORDER BY a,b;
|
||||
let pos=`select $binlog_start_pos + 788`;
|
||||
let pos=`select $binlog_start_pos + 956`;
|
||||
--replace_result $pos <pos>
|
||||
SHOW STATUS LIKE 'binlog_snapshot_%';
|
||||
let pos=`select $binlog_start_pos + 1164`;
|
||||
let pos=`select $binlog_start_pos + 1332`;
|
||||
--replace_result $pos <pos>
|
||||
SHOW MASTER STATUS;
|
||||
SELECT * FROM t2 ORDER BY a;
|
||||
@@ -74,7 +77,7 @@ FLUSH LOGS;
|
||||
|
||||
connection default;
|
||||
SELECT * FROM t1 ORDER BY a,b;
|
||||
let pos=`select $binlog_start_pos + 788`;
|
||||
let pos=`select $binlog_start_pos + 956`;
|
||||
--replace_result $pos <pos>
|
||||
SHOW STATUS LIKE 'binlog_snapshot_%';
|
||||
let pos=`select $binlog_start_pos + 131`;
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
CREATE TABLE t0 (pk INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t0 VALUES(100);
|
||||
--connect (con1,localhost,root,,test)
|
||||
BEGIN;
|
||||
INSERT INTO t0 SET pk=1;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
# to check some edge case for concurrency control.
|
||||
|
||||
CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=innodb;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100);
|
||||
|
||||
SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
# to check some edge case for concurrency control.
|
||||
|
||||
CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=innodb;
|
||||
# MDEV-515 takes X-LOCK on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES("default");
|
||||
|
||||
SELECT variable_value INTO @commits FROM information_schema.global_status
|
||||
WHERE variable_name = 'binlog_commits';
|
||||
|
||||
@@ -199,6 +199,10 @@ DROP TABLE t1, t2;
|
||||
|
||||
CREATE TABLE t1 (pk INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB
|
||||
PARTITION BY key (pk) PARTITIONS 2;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100);
|
||||
INSERT INTO t1 VALUES(101);
|
||||
|
||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6);
|
||||
|
||||
@@ -30,9 +30,7 @@ SET DEBUG_SYNC = 'write_row_noreplace SIGNAL have_handle WAIT_FOR go_ahead';
|
||||
--send
|
||||
INSERT INTO t1 VALUES(1,2,3);
|
||||
|
||||
--echo # Establish session con1 (user=root)
|
||||
connect (con1,localhost,root,,);
|
||||
connection con1;
|
||||
|
||||
# This should block at the end because of the INSERT in connection default
|
||||
# is holding a metadata lock.
|
||||
@@ -42,13 +40,11 @@ SET lock_wait_timeout = 1;
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
SET DEBUG_SYNC = 'now SIGNAL go_ahead';
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
--error ER_DUP_ENTRY
|
||||
reap;
|
||||
eval $innodb_metrics_select;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
||||
SET DEBUG_DBUG = '+d,innodb_OOM_prepare_inplace_alter';
|
||||
@@ -61,14 +57,12 @@ ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE;
|
||||
SET SESSION DEBUG = @saved_debug_dbug;
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SHOW CREATE TABLE t1;
|
||||
# Insert a duplicate entry (4) for the upcoming UNIQUE INDEX(c2).
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(7,4,2);
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
# This DEBUG_SYNC should not kick in yet, because the duplicate key will be
|
||||
# detected before we get a chance to apply the online log.
|
||||
@@ -78,20 +72,16 @@ SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL scanned WAIT_FOR insert_don
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2);
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
COMMIT;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
--error ER_DUP_ENTRY
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2);
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
DELETE FROM t1 WHERE c1 = 7;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2), ROW_FORMAT=COMPACT,
|
||||
LOCK = SHARED, ALGORITHM = INPLACE;
|
||||
@@ -106,7 +96,6 @@ SHOW CREATE TABLE t1;
|
||||
--send
|
||||
ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1);
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR scanned';
|
||||
eval $innodb_metrics_select;
|
||||
@@ -116,7 +105,6 @@ BEGIN;
|
||||
INSERT INTO t1 VALUES(4,7,2);
|
||||
SET DEBUG_SYNC = 'now SIGNAL insert_done';
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
# Because the modification log will be applied in order and we did
|
||||
# not roll back before the log apply, there will be a duplicate key
|
||||
@@ -124,11 +112,9 @@ connection con1;
|
||||
--error ER_DUP_ENTRY
|
||||
reap;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
ROLLBACK;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
SHOW CREATE TABLE t1;
|
||||
# Now, rebuild the table without any concurrent DML, while no duplicate exists.
|
||||
@@ -137,7 +123,6 @@ ALTER TABLE t1 DROP PRIMARY KEY, ADD UNIQUE INDEX(c2), ALGORITHM = INPLACE;
|
||||
ALTER TABLE t1 DROP INDEX c2, ADD PRIMARY KEY(c1), ALGORITHM = INPLACE;
|
||||
eval $innodb_metrics_select;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
--error ER_DUP_ENTRY
|
||||
INSERT INTO t1 VALUES(6,3,1);
|
||||
@@ -148,7 +133,6 @@ BEGIN;
|
||||
INSERT INTO t1 VALUES(7,4,2);
|
||||
ROLLBACK;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
let $ID= `SELECT @id := CONNECTION_ID()`;
|
||||
--error ER_QUERY_INTERRUPTED
|
||||
@@ -159,7 +143,6 @@ SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL applied WAIT_FOR kill_done'
|
||||
--send
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rebuilt';
|
||||
eval $innodb_metrics_select;
|
||||
@@ -171,13 +154,11 @@ let $ignore= `SELECT @id := $ID`;
|
||||
KILL QUERY @id;
|
||||
SET DEBUG_SYNC = 'now SIGNAL kill_done';
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
--error ER_QUERY_INTERRUPTED
|
||||
reap;
|
||||
eval $innodb_metrics_select;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
CHECK TABLE t1;
|
||||
INSERT INTO t1 SELECT 5 + c1, c2, c3 FROM t1;
|
||||
@@ -199,7 +180,6 @@ SET @rowlog_encrypt_0=
|
||||
(SELECT variable_value FROM information_schema.global_status
|
||||
WHERE variable_name = 'innodb_encryption_n_rowlog_blocks_encrypted');
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
SHOW CREATE TABLE t1;
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
@@ -217,7 +197,6 @@ PAGE_COMPRESSED = YES PAGE_COMPRESSION_LEVEL = 1, ALGORITHM = INPLACE;
|
||||
# Generate some log (delete-mark, delete-unmark, insert etc.)
|
||||
# while the index creation is blocked. Some of this may run
|
||||
# in parallel with the clustered index scan.
|
||||
--echo # session default
|
||||
connection default;
|
||||
INSERT INTO t1 SELECT 80 + c1, c2, c3 FROM t1;
|
||||
INSERT INTO t1 SELECT 160 + c1, c2, c3 FROM t1;
|
||||
@@ -261,7 +240,6 @@ SELECT
|
||||
# Release con1.
|
||||
SET DEBUG_SYNC = 'now SIGNAL dml2_done';
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
# If the following fails with the wrong error, it probably means that
|
||||
# you should rerun with a larger mtr --debug-sync-timeout.
|
||||
@@ -295,7 +273,6 @@ ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(c22f,c1,c4(5)),
|
||||
CHANGE c2 c22f INT, CHANGE c3 c3 CHAR(255) NULL, CHANGE c1 c1 INT AFTER c22f,
|
||||
ADD COLUMN c4 VARCHAR(6) DEFAULT 'Online', LOCK=NONE;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR rebuilt3';
|
||||
# Generate some log (delete-mark, delete-unmark, insert etc.)
|
||||
@@ -312,7 +289,6 @@ eval $innodb_metrics_select;
|
||||
# Release con1.
|
||||
SET DEBUG_SYNC = 'now SIGNAL dml3_done';
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
reap;
|
||||
eval $innodb_metrics_select;
|
||||
@@ -365,7 +341,6 @@ ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL, DROP COLUMN c22f,
|
||||
DROP PRIMARY KEY, ADD PRIMARY KEY(c1,c4(5)),
|
||||
ADD COLUMN c5 CHAR(5) DEFAULT 'tired' FIRST;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR c3p5_created0';
|
||||
@@ -374,16 +349,13 @@ INSERT INTO t1 VALUES(347,33101,'Pikku kakkosen posti','YLETV2');
|
||||
INSERT INTO t1 VALUES(33101,347,NULL,'');
|
||||
SET DEBUG_SYNC = 'now SIGNAL ins_done0';
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
--error WARN_DATA_TRUNCATED
|
||||
reap;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
ROLLBACK;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL;
|
||||
|
||||
@@ -394,7 +366,6 @@ ADD COLUMN c6 VARCHAR(1000) DEFAULT
|
||||
'I love tracking down hard-to-reproduce bugs.',
|
||||
ADD PRIMARY KEY c3p5(c3(5), c6(2));
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR c3p5_created';
|
||||
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL ins_done WAIT_FOR ddl_timed_out';
|
||||
@@ -403,33 +374,48 @@ INSERT INTO t1 VALUES(347,33101,NULL,'');
|
||||
--send
|
||||
INSERT INTO t1 VALUES(347,33101,'Pikku kakkosen posti','');
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
reap;
|
||||
SET DEBUG_SYNC = 'now SIGNAL ddl_timed_out';
|
||||
eval $innodb_metrics_select;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
reap;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
|
||||
SELECT * FROM t1 LIMIT 10;
|
||||
|
||||
--echo # session con1
|
||||
connection con1;
|
||||
ALTER TABLE t1 DISCARD TABLESPACE;
|
||||
--echo # Disconnect session con1
|
||||
disconnect con1;
|
||||
|
||||
--echo # session default
|
||||
connection default;
|
||||
SHOW CREATE TABLE t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
SET GLOBAL innodb_monitor_disable = module_ddl;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
|
||||
connection con1;
|
||||
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL created WAIT_FOR ins';
|
||||
send ALTER TABLE t1 FORCE;
|
||||
|
||||
connection default;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR created';
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
ROLLBACK;
|
||||
SET DEBUG_SYNC = 'now SIGNAL ins';
|
||||
|
||||
connection con1;
|
||||
reap;
|
||||
disconnect con1;
|
||||
|
||||
connection default;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
# Check that all connections opened by test cases in this file are really
|
||||
# gone so execution of other tests won't be affected by their presence.
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
||||
@@ -78,7 +78,7 @@ INSERT INTO t3 SELECT * FROM t3;
|
||||
-- let $con1_extra_sql_present = 1
|
||||
-- let $con2_extra_sql = SELECT * FROM t3 FOR UPDATE
|
||||
-- let $con2_extra_sql_present = 1
|
||||
-- let $con1_should_be_rolledback = 0
|
||||
-- let $con1_should_be_rolledback = 1
|
||||
-- source include/innodb_trx_weight.inc
|
||||
|
||||
# test weight when non-transactional tables are edited
|
||||
|
||||
26
mysql-test/suite/innodb/t/lock_insert_into_empty.test
Normal file
26
mysql-test/suite/innodb/t/lock_insert_into_empty.test
Normal file
@@ -0,0 +1,26 @@
|
||||
--source include/have_innodb.inc
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO t1 VALUES(0);
|
||||
BEGIN;
|
||||
DELETE FROM t1;
|
||||
--error ER_DUP_ENTRY
|
||||
INSERT INTO t2 VALUES(1),(1);
|
||||
|
||||
connect (con1,localhost,root,,);
|
||||
BEGIN;
|
||||
SELECT * FROM t2 LOCK IN SHARE MODE;
|
||||
|
||||
connection default;
|
||||
SET innodb_lock_wait_timeout=1;
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
INSERT INTO t2 VALUES(2);
|
||||
disconnect con1;
|
||||
INSERT INTO t2 VALUES(3);
|
||||
COMMIT;
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t1, t2;
|
||||
@@ -139,25 +139,25 @@ INSERT INTO articles (title, body) VALUES
|
||||
SELECT * FROM articles WHERE
|
||||
MATCH(title, body) AGAINST('MySQL');
|
||||
id title body
|
||||
6 MySQL Tutorial DBMS stands for MySQL DataBase ...
|
||||
7 How To Use MySQL Well After you went through a ...
|
||||
8 Optimizing MySQL In this tutorial we will show ...
|
||||
9 1001 MySQL Tricks How to use full-text search engine
|
||||
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
|
||||
2 How To Use MySQL Well After you went through a ...
|
||||
3 Optimizing MySQL In this tutorial we will show ...
|
||||
4 1001 MySQL Tricks How to use full-text search engine
|
||||
SELECT * FROM articles WHERE
|
||||
MATCH(title, body) AGAINST('tutorial');
|
||||
id title body
|
||||
6 MySQL Tutorial DBMS stands for MySQL DataBase ...
|
||||
8 Optimizing MySQL In this tutorial we will show ...
|
||||
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
|
||||
3 Optimizing MySQL In this tutorial we will show ...
|
||||
SELECT * FROM articles WHERE
|
||||
MATCH(title, body) AGAINST('Tricks');
|
||||
id title body
|
||||
9 1001 MySQL Tricks How to use full-text search engine
|
||||
10 Go MariaDB Tricks How to use full text search engine
|
||||
4 1001 MySQL Tricks How to use full-text search engine
|
||||
5 Go MariaDB Tricks How to use full text search engine
|
||||
SELECT * FROM articles WHERE
|
||||
MATCH(title, body) AGAINST('full text search');
|
||||
id title body
|
||||
10 Go MariaDB Tricks How to use full text search engine
|
||||
9 1001 MySQL Tricks How to use full-text search engine
|
||||
5 Go MariaDB Tricks How to use full text search engine
|
||||
4 1001 MySQL Tricks How to use full-text search engine
|
||||
SELECT COUNT(*) FROM articles;
|
||||
COUNT(*)
|
||||
5
|
||||
|
||||
@@ -328,6 +328,7 @@ connection default;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
create table t1 (c1 int, c2 geometry not null, spatial index (c2))engine=innodb;
|
||||
insert into t1 values(100, point(100, 100));
|
||||
create procedure insert_t1(IN total int)
|
||||
begin
|
||||
declare i int default 1;
|
||||
@@ -348,7 +349,7 @@ rollback;
|
||||
SET DEBUG_SYNC= 'now SIGNAL sigb';
|
||||
connection a;
|
||||
count(*)
|
||||
0
|
||||
1
|
||||
connection default;
|
||||
drop procedure insert_t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
@@ -388,6 +388,7 @@ DROP TABLE t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
||||
|
||||
create table t1 (c1 int, c2 geometry not null, spatial index (c2))engine=innodb;
|
||||
insert into t1 values(100, point(100, 100));
|
||||
|
||||
delimiter |;
|
||||
create procedure insert_t1(IN total int)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
call mtr.add_suppression("InnoDB: New log files created");
|
||||
CREATE TABLE t_aria(i INT) ENGINE ARIA;
|
||||
CREATE TABLE t(i INT PRIMARY KEY) ENGINE INNODB;
|
||||
INSERT INTO t VALUES(100);
|
||||
BEGIN;
|
||||
INSERT INTO t VALUES(2);
|
||||
connect con1,localhost,root,,;
|
||||
@@ -17,6 +18,7 @@ SELECT * FROM t;
|
||||
i
|
||||
1
|
||||
2
|
||||
100
|
||||
# Prepare full backup, apply incremental one
|
||||
# Aria log file was updated during applying incremental backup
|
||||
disconnect con1;
|
||||
@@ -29,5 +31,6 @@ SELECT * FROM t;
|
||||
i
|
||||
1
|
||||
2
|
||||
100
|
||||
DROP TABLE t;
|
||||
DROP TABLE t_aria;
|
||||
|
||||
@@ -13,6 +13,9 @@ let incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1;
|
||||
|
||||
CREATE TABLE t_aria(i INT) ENGINE ARIA;
|
||||
CREATE TABLE t(i INT PRIMARY KEY) ENGINE INNODB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t VALUES(100);
|
||||
BEGIN;
|
||||
INSERT INTO t VALUES(2);
|
||||
connect (con1,localhost,root,,);
|
||||
|
||||
@@ -393,6 +393,12 @@ connect(con1, localhost, root,,);
|
||||
connection default;
|
||||
eval CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
|
||||
ENGINE = $engine;
|
||||
if ($engine == "'InnoDB'")
|
||||
{
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1(c1) VALUES(100);
|
||||
}
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 (c1) VALUES (2);
|
||||
INSERT INTO t1 (c1) VALUES (4);
|
||||
@@ -434,6 +440,13 @@ eval CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
|
||||
ENGINE = $engine
|
||||
PARTITION BY HASH(c1)
|
||||
PARTITIONS 2;
|
||||
IF ($engine == "'InnoDB'")
|
||||
{
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 (c1) VALUES (100);
|
||||
INSERT INTO t1 (c1) VALUES (101);
|
||||
}
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 (c1) VALUES (2);
|
||||
INSERT INTO t1 (c1) VALUES (4);
|
||||
|
||||
@@ -490,6 +490,7 @@ connect con1, localhost, root,,;
|
||||
connection default;
|
||||
CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
|
||||
ENGINE = 'InnoDB';
|
||||
INSERT INTO t1(c1) VALUES(100);
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 (c1) VALUES (2);
|
||||
INSERT INTO t1 (c1) VALUES (4);
|
||||
@@ -510,17 +511,19 @@ connection con1;
|
||||
INSERT INTO t1 (c1) VALUES (NULL);
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
5
|
||||
10
|
||||
22
|
||||
23
|
||||
100
|
||||
101
|
||||
104
|
||||
105
|
||||
COMMIT;
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
5
|
||||
10
|
||||
22
|
||||
23
|
||||
100
|
||||
101
|
||||
104
|
||||
105
|
||||
disconnect con1;
|
||||
connection default;
|
||||
INSERT INTO t1 (c1) VALUES (NULL);
|
||||
@@ -528,31 +531,33 @@ SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
2
|
||||
4
|
||||
5
|
||||
10
|
||||
11
|
||||
12
|
||||
16
|
||||
19
|
||||
21
|
||||
22
|
||||
23
|
||||
24
|
||||
100
|
||||
101
|
||||
102
|
||||
103
|
||||
104
|
||||
105
|
||||
106
|
||||
COMMIT;
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
2
|
||||
4
|
||||
5
|
||||
10
|
||||
11
|
||||
12
|
||||
16
|
||||
19
|
||||
21
|
||||
22
|
||||
23
|
||||
24
|
||||
100
|
||||
101
|
||||
102
|
||||
103
|
||||
104
|
||||
105
|
||||
106
|
||||
DROP TABLE t1;
|
||||
# Test with two threads + start transaction
|
||||
connect con1, localhost, root,,;
|
||||
@@ -561,6 +566,8 @@ CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
|
||||
ENGINE = 'InnoDB'
|
||||
PARTITION BY HASH(c1)
|
||||
PARTITIONS 2;
|
||||
INSERT INTO t1 (c1) VALUES (100);
|
||||
INSERT INTO t1 (c1) VALUES (101);
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 (c1) VALUES (2);
|
||||
INSERT INTO t1 (c1) VALUES (4);
|
||||
@@ -578,17 +585,21 @@ connection con1;
|
||||
INSERT INTO t1 (c1) VALUES (NULL);
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
5
|
||||
10
|
||||
22
|
||||
23
|
||||
100
|
||||
101
|
||||
102
|
||||
105
|
||||
106
|
||||
COMMIT;
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
5
|
||||
10
|
||||
22
|
||||
23
|
||||
100
|
||||
101
|
||||
102
|
||||
105
|
||||
106
|
||||
disconnect con1;
|
||||
connection default;
|
||||
INSERT INTO t1 (c1) VALUES (NULL);
|
||||
@@ -596,31 +607,35 @@ SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
2
|
||||
4
|
||||
5
|
||||
10
|
||||
11
|
||||
12
|
||||
16
|
||||
19
|
||||
21
|
||||
22
|
||||
23
|
||||
24
|
||||
100
|
||||
101
|
||||
102
|
||||
103
|
||||
104
|
||||
105
|
||||
106
|
||||
107
|
||||
COMMIT;
|
||||
SELECT * FROM t1 ORDER BY c1;
|
||||
c1
|
||||
2
|
||||
4
|
||||
5
|
||||
10
|
||||
11
|
||||
12
|
||||
16
|
||||
19
|
||||
21
|
||||
22
|
||||
23
|
||||
24
|
||||
100
|
||||
101
|
||||
102
|
||||
103
|
||||
104
|
||||
105
|
||||
106
|
||||
107
|
||||
DROP TABLE t1;
|
||||
# Test with another column after
|
||||
CREATE TABLE t1 (
|
||||
|
||||
@@ -26,6 +26,10 @@ CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||
--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
|
||||
--save_master_pos
|
||||
|
||||
--connection server_2
|
||||
|
||||
@@ -57,6 +57,9 @@ CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on w
|
||||
--connection server_1
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(1);
|
||||
--source include/save_master_gtid.inc
|
||||
|
||||
--connection server_2
|
||||
|
||||
@@ -25,6 +25,10 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
--save_master_pos
|
||||
|
||||
--connection server_2
|
||||
|
||||
@@ -23,6 +23,10 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
--save_master_pos
|
||||
|
||||
--connection server_2
|
||||
|
||||
@@ -6,6 +6,7 @@ include/master-slave.inc
|
||||
#
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
|
||||
INSERT INTO t1 VALUES(100);
|
||||
connection slave;
|
||||
include/stop_slave.inc
|
||||
SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads;
|
||||
|
||||
@@ -17,6 +17,7 @@ SET auto_increment_offset= 1;
|
||||
connection server_1;
|
||||
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=InnoDB;
|
||||
INSERT INTO t2 (b,c) VALUES('MDEV-515', 100);
|
||||
include/rpl_sync.inc
|
||||
connection server_4;
|
||||
call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group");
|
||||
|
||||
@@ -78,6 +78,7 @@ slave-relay-bin.000007 # Query # # COMMIT
|
||||
*** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 ***
|
||||
connection master;
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(100);
|
||||
connect con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
INSERT INTO t2 VALUES (1);
|
||||
@@ -112,6 +113,7 @@ SELECT * FROM t2 ORDER BY a;
|
||||
a
|
||||
1
|
||||
2
|
||||
100
|
||||
# Test that slave which cannot tolerate holes in binlog stream but
|
||||
# knows the event does not get dummy event
|
||||
include/stop_slave.inc
|
||||
|
||||
@@ -20,6 +20,7 @@ connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
connection server_1;
|
||||
SET sql_log_bin=0;
|
||||
@@ -136,6 +137,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now SIGNAL d0_cont';
|
||||
@@ -161,6 +163,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -190,6 +193,7 @@ a b
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -225,6 +229,7 @@ SELECT * FROM t3 WHERE a >= 80 ORDER BY a;
|
||||
a b
|
||||
80 0
|
||||
81 10000
|
||||
100 100
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR wait_queue_ready';
|
||||
KILL THD_ID;
|
||||
@@ -244,6 +249,7 @@ a b
|
||||
80 0
|
||||
81 10000
|
||||
82 0
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||
|
||||
@@ -13,6 +13,7 @@ include/start_slave.inc
|
||||
connection server_1;
|
||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
include/save_master_gtid.inc
|
||||
connection server_2;
|
||||
include/sync_with_master_gtid.inc
|
||||
|
||||
@@ -35,6 +35,7 @@ SET sql_log_bin=1;
|
||||
connect con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
SET binlog_format=statement;
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
INSERT INTO t3 VALUES (31, foo(31,
|
||||
'ha_commit_one_phase WAIT_FOR t2_waiting',
|
||||
'commit_one_phase_2 SIGNAL t1_ready WAIT_FOR t1_cont'));
|
||||
@@ -43,6 +44,7 @@ SET debug_sync='now WAIT_FOR master_queued1';
|
||||
connect con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
|
||||
SET binlog_format=statement;
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
BEGIN;
|
||||
INSERT INTO t3 VALUES (32, foo(32,
|
||||
'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont',
|
||||
@@ -56,6 +58,7 @@ SET debug_sync='now WAIT_FOR master_queued2';
|
||||
connect con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,;
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
|
||||
SET binlog_format=statement;
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
INSERT INTO t3 VALUES (34, foo(34,
|
||||
'',
|
||||
''));
|
||||
|
||||
@@ -259,6 +259,7 @@ connection server_1;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
|
||||
INSERT INTO t3 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
|
||||
CREATE TABLE t4 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t4 VALUES(100, 100);
|
||||
SET @old_format= @@SESSION.binlog_format;
|
||||
SET binlog_format='statement';
|
||||
connection server_2;
|
||||
@@ -344,6 +345,7 @@ DROP function foo;
|
||||
connection server_2;
|
||||
connection server_1;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(100, 100);
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads;
|
||||
|
||||
@@ -17,6 +17,8 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
connection server_1;
|
||||
SET sql_log_bin=0;
|
||||
@@ -80,6 +82,7 @@ a b
|
||||
32 32
|
||||
33 33
|
||||
34 34
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET sql_log_bin=0;
|
||||
@@ -98,6 +101,7 @@ STOP SLAVE IO_THREAD;
|
||||
SELECT * FROM t3 WHERE a >= 30 ORDER BY a;
|
||||
a b
|
||||
31 31
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -121,6 +125,7 @@ a b
|
||||
33 33
|
||||
34 34
|
||||
39 0
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -179,6 +184,7 @@ a b
|
||||
42 42
|
||||
43 43
|
||||
44 44
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR t2_query';
|
||||
@@ -211,6 +217,7 @@ a b
|
||||
43 43
|
||||
44 44
|
||||
49 0
|
||||
100 100
|
||||
SET sql_log_bin=0;
|
||||
DROP FUNCTION foo;
|
||||
CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500))
|
||||
@@ -274,6 +281,7 @@ a b
|
||||
52 52
|
||||
53 53
|
||||
54 54
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
connection server_2;
|
||||
SET debug_sync='now WAIT_FOR t2_query';
|
||||
@@ -286,6 +294,7 @@ include/wait_for_slave_sql_error.inc [errno=1317,1927,1964]
|
||||
SELECT * FROM t3 WHERE a >= 50 ORDER BY a;
|
||||
a b
|
||||
51 51
|
||||
100 100
|
||||
SET debug_sync='RESET';
|
||||
SET GLOBAL slave_parallel_threads=0;
|
||||
SET GLOBAL slave_parallel_threads=10;
|
||||
@@ -309,6 +318,7 @@ a b
|
||||
53 53
|
||||
54 54
|
||||
59 0
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||
|
||||
@@ -16,6 +16,8 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(100);
|
||||
INSERT INTO t3 VALUES(100, 100);
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
connection server_1;
|
||||
@@ -55,9 +57,11 @@ SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
20
|
||||
21
|
||||
100
|
||||
SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
|
||||
a b
|
||||
20 20
|
||||
100 100
|
||||
include/start_slave.inc
|
||||
SELECT * FROM t1 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
@@ -66,11 +70,13 @@ SELECT * FROM t2 WHERE a >= 20 ORDER BY a;
|
||||
a
|
||||
20
|
||||
21
|
||||
100
|
||||
SELECT * FROM t3 WHERE a >= 20 ORDER BY a;
|
||||
a b
|
||||
20 20
|
||||
21 21
|
||||
22 22
|
||||
100 100
|
||||
connection server_2;
|
||||
include/stop_slave.inc
|
||||
SET GLOBAL slave_parallel_mode=@old_parallel_mode;
|
||||
|
||||
@@ -74,6 +74,7 @@ select * from t1;
|
||||
a
|
||||
1
|
||||
truncate table t1;
|
||||
INSERT INTO t1 VALUES (100);
|
||||
connection slave;
|
||||
connection con1;
|
||||
SET DEBUG_SYNC= 'reset';
|
||||
@@ -107,6 +108,7 @@ SET DEBUG_SYNC= "now WAIT_FOR after_commit_done";
|
||||
connection slave;
|
||||
select * from t1;
|
||||
a
|
||||
100
|
||||
1
|
||||
2
|
||||
3
|
||||
@@ -114,6 +116,7 @@ a
|
||||
connection con2;
|
||||
select * from t1;
|
||||
a
|
||||
100
|
||||
1
|
||||
2
|
||||
3
|
||||
@@ -123,6 +126,7 @@ connection con1;
|
||||
connection con1;
|
||||
select * from t1;
|
||||
a
|
||||
100
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
@@ -7,6 +7,7 @@ CREATE DATABASE d1;
|
||||
CREATE DATABASE d2;
|
||||
CREATE TABLE d1.t (a INT) ENGINE=innodb;
|
||||
CREATE TABLE d2.t (a INT) ENGINE=innodb;
|
||||
INSERT INTO d1.t VALUES(100);
|
||||
connect master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
SET @@session.binlog_format= statement;
|
||||
XA START '1-stmt';
|
||||
@@ -45,6 +46,9 @@ master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE d1.t (a INT) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE d2.t (a INT) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO d1.t VALUES(100)
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # XA START X'312d73746d74',X'',1 GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO d1.t VALUES (1)
|
||||
master-bin.000001 # Query # # XA END X'312d73746d74',X'',1
|
||||
@@ -90,6 +94,7 @@ connection master2;
|
||||
XA START '4';
|
||||
SELECT * FROM d1.t;
|
||||
a
|
||||
100
|
||||
1
|
||||
2
|
||||
XA END '4';
|
||||
|
||||
@@ -7,6 +7,7 @@ CREATE DATABASE d1;
|
||||
CREATE DATABASE d2;
|
||||
CREATE TABLE d1.t (a INT) ENGINE=innodb;
|
||||
CREATE TABLE d2.t (a INT) ENGINE=innodb;
|
||||
INSERT INTO d1.t VALUES(100);
|
||||
connect master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,;
|
||||
SET @@session.binlog_format= statement;
|
||||
XA START '1-stmt';
|
||||
@@ -45,6 +46,9 @@ master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE d1.t (a INT) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; CREATE TABLE d2.t (a INT) ENGINE=innodb
|
||||
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO d1.t VALUES(100)
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Gtid # # XA START X'312d73746d74',X'',1 GTID #-#-#
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO d1.t VALUES (1)
|
||||
master-bin.000001 # Query # # XA END X'312d73746d74',X'',1
|
||||
@@ -90,6 +94,7 @@ connection master2;
|
||||
XA START '4';
|
||||
SELECT * FROM d1.t;
|
||||
a
|
||||
100
|
||||
1
|
||||
2
|
||||
XA END '4';
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
|
||||
--connection master
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100);
|
||||
|
||||
--sync_slave_with_master
|
||||
--source include/stop_slave.inc
|
||||
|
||||
@@ -39,6 +39,9 @@ while ($_rpl_server)
|
||||
--connection server_1
|
||||
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=MyISAM;
|
||||
CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table. So it won't allow
|
||||
# concurrent DML to happen at the same time
|
||||
INSERT INTO t2 (b,c) VALUES('MDEV-515', 100);
|
||||
--source include/rpl_sync.inc
|
||||
--connection server_4
|
||||
call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group");
|
||||
|
||||
@@ -84,6 +84,9 @@ let $binlog_limit=7,5;
|
||||
|
||||
--connection master
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t2 VALUES(100);
|
||||
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
|
||||
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ SET sql_log_bin=1;
|
||||
--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
|
||||
SET binlog_format=statement;
|
||||
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
send INSERT INTO t3 VALUES (31, foo(31,
|
||||
'ha_commit_one_phase WAIT_FOR t2_waiting',
|
||||
'commit_one_phase_2 SIGNAL t1_ready WAIT_FOR t1_cont'));
|
||||
@@ -67,6 +69,7 @@ SET debug_sync='now WAIT_FOR master_queued1';
|
||||
--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
|
||||
SET binlog_format=statement;
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
BEGIN;
|
||||
# This insert is just so we can get T2 to wait while a query is running that we
|
||||
# can see in SHOW PROCESSLIST so we can get its thread_id to kill later.
|
||||
@@ -86,6 +89,7 @@ SET debug_sync='now WAIT_FOR master_queued2';
|
||||
--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,)
|
||||
SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3';
|
||||
SET binlog_format=statement;
|
||||
SET debug_dbug='+d,row_ins_row_level';
|
||||
send INSERT INTO t3 VALUES (34, foo(34,
|
||||
'',
|
||||
''));
|
||||
|
||||
@@ -266,6 +266,9 @@ SELECT * FROM t1 WHERE a >= 100 ORDER BY a;
|
||||
CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB;
|
||||
INSERT INTO t3 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6);
|
||||
CREATE TABLE t4 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t4 VALUES(100, 100);
|
||||
|
||||
# We need statement binlog format to be able to inject debug_sync statements
|
||||
# on the slave with calls to foo().
|
||||
@@ -390,7 +393,9 @@ DROP function foo;
|
||||
|
||||
--connection server_1
|
||||
CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100, 100);
|
||||
|
||||
# Replicate create-t1 and prepare to re-start slave in optimistic mode
|
||||
--sync_slave_with_master server_2
|
||||
|
||||
@@ -81,6 +81,10 @@ connection con1;
|
||||
select * from t1;
|
||||
truncate table t1;
|
||||
|
||||
# MDEV-515 takes X-lock on the table
|
||||
# So concurrent DML won't happen on the table
|
||||
INSERT INTO t1 VALUES (100);
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
# Test more threads in one semisync queue
|
||||
|
||||
@@ -30,6 +30,10 @@ CREATE DATABASE d2;
|
||||
CREATE TABLE d1.t (a INT) ENGINE=innodb;
|
||||
CREATE TABLE d2.t (a INT) ENGINE=innodb;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert.
|
||||
# So concurrent DML won't happen on the table
|
||||
INSERT INTO d1.t VALUES(100);
|
||||
|
||||
connect (master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,);
|
||||
--let $conn_id=`SELECT connection_id()`
|
||||
SET @@session.binlog_format= statement;
|
||||
|
||||
@@ -14,6 +14,8 @@ id INT NOT NULL auto_increment,
|
||||
PRIMARY KEY (id),
|
||||
name VARCHAR(30)
|
||||
) ENGINE = INNODB;
|
||||
INSERT INTO t1 VALUES(100, "MDEV-515");
|
||||
INSERT INTO t2 VALUES(100, "MDEV-515");
|
||||
'#--------------------FN_DYNVARS_035_01-------------------------#'
|
||||
## It should be zero ##
|
||||
SELECT @@identity = 0;
|
||||
@@ -29,40 +31,47 @@ INSERT into t1(name) values('Record_3');
|
||||
## Verifying total values in t1 ##
|
||||
SELECT @@identity from t1;
|
||||
@@identity
|
||||
3
|
||||
3
|
||||
3
|
||||
103
|
||||
103
|
||||
103
|
||||
103
|
||||
## Now inserting some data in table t2 ##
|
||||
INSERT into t2(name) values('Record_1');
|
||||
## Verifying total values in t2 ##
|
||||
SELECT @@identity from t2;
|
||||
@@identity
|
||||
1
|
||||
101
|
||||
101
|
||||
'#--------------------FN_DYNVARS_035_02-------------------------#'
|
||||
connect test_con2, localhost, root,,;
|
||||
connection test_con2;
|
||||
SELECT * from t1;
|
||||
id name
|
||||
100 MDEV-515
|
||||
## Verifying total values in t1 ##
|
||||
SELECT @@identity from t1;
|
||||
@@identity
|
||||
0
|
||||
## Verifying total values in t2 ##
|
||||
SELECT @@identity from t2;
|
||||
@@identity
|
||||
0
|
||||
## Inserting some more records in table t1 ##
|
||||
INSERT into t1(name) values('Record_1_1');
|
||||
INSERT into t1(name) values('Record_1_2');
|
||||
## Verifying total values in t1 ##
|
||||
SELECT @@identity from t1;
|
||||
@@identity
|
||||
5
|
||||
5
|
||||
105
|
||||
105
|
||||
105
|
||||
## Inserting row in table t2 ##
|
||||
INSERT into t2(name) values('Record_1_3');
|
||||
## Verifying total values in t2 ##
|
||||
SELECT @@identity from t2;
|
||||
@@identity
|
||||
2
|
||||
102
|
||||
102
|
||||
'#--------------------FN_DYNVARS_035_03-------------------------#'
|
||||
connection test_con1;
|
||||
## Commiting rows added in test_con1 ##
|
||||
@@ -70,38 +79,43 @@ COMMIT;
|
||||
## Verifying records in both tables ##
|
||||
SELECT * from t1;
|
||||
id name
|
||||
1 Record_1
|
||||
2 Record_2
|
||||
3 Record_3
|
||||
4 Record_1_1
|
||||
5 Record_1_2
|
||||
100 MDEV-515
|
||||
101 Record_1
|
||||
102 Record_2
|
||||
103 Record_3
|
||||
104 Record_1_1
|
||||
105 Record_1_2
|
||||
SELECT * from t2;
|
||||
id name
|
||||
1 Record_1
|
||||
2 Record_1_3
|
||||
100 MDEV-515
|
||||
101 Record_1
|
||||
102 Record_1_3
|
||||
## Verifying total values in t1 after commiting data ##
|
||||
SELECT @@identity from t1;
|
||||
@@identity
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
101
|
||||
101
|
||||
101
|
||||
101
|
||||
101
|
||||
101
|
||||
## Verifying total values in t2 after commiting data ##
|
||||
SELECT @@identity from t2;
|
||||
@@identity
|
||||
1
|
||||
1
|
||||
101
|
||||
101
|
||||
101
|
||||
INSERT into t1(name) values('Record_4');
|
||||
## Now verifying value of variable after inserting 1 row in this connection ##
|
||||
SELECT @@identity from t1;
|
||||
@@identity
|
||||
6
|
||||
6
|
||||
6
|
||||
6
|
||||
6
|
||||
6
|
||||
106
|
||||
106
|
||||
106
|
||||
106
|
||||
106
|
||||
106
|
||||
106
|
||||
## Dropping tables t1 & t2 ##
|
||||
drop table t1, t2;
|
||||
disconnect test_con1;
|
||||
|
||||
@@ -46,6 +46,11 @@ PRIMARY KEY (id),
|
||||
name VARCHAR(30)
|
||||
) ENGINE = INNODB;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert
|
||||
# So concurrent insert won't happen on the table
|
||||
INSERT INTO t1 VALUES(100, "MDEV-515");
|
||||
INSERT INTO t2 VALUES(100, "MDEV-515");
|
||||
|
||||
--echo '#--------------------FN_DYNVARS_035_01-------------------------#'
|
||||
###############################################
|
||||
# Verifying initial value of identity. #
|
||||
|
||||
@@ -89,6 +89,7 @@ sys_start bigint(20) unsigned as row start invisible,
|
||||
sys_end bigint(20) unsigned as row end invisible,
|
||||
period for system_time (sys_start, sys_end)
|
||||
) with system versioning;
|
||||
INSERT INTO t1 VALUES(100);
|
||||
set transaction isolation level read committed;
|
||||
start transaction;
|
||||
insert into t1 values (1);
|
||||
@@ -129,25 +130,31 @@ select @ts1 < @ts2, @ts2 < @ts3;
|
||||
# MVCC is resolved
|
||||
select * from t1 for system_time as of transaction @trx_id1;
|
||||
x
|
||||
100
|
||||
1
|
||||
2
|
||||
3
|
||||
select * from t1 for system_time as of timestamp @ts1;
|
||||
x
|
||||
100
|
||||
3
|
||||
select * from t1 for system_time as of transaction @trx_id2;
|
||||
x
|
||||
100
|
||||
2
|
||||
3
|
||||
select * from t1 for system_time as of timestamp @ts2;
|
||||
x
|
||||
100
|
||||
2
|
||||
3
|
||||
select * from t1 for system_time as of transaction @trx_id3;
|
||||
x
|
||||
100
|
||||
3
|
||||
select * from t1 for system_time as of timestamp @ts3;
|
||||
x
|
||||
100
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
@@ -87,6 +87,10 @@ create or replace table t1 (
|
||||
period for system_time (sys_start, sys_end)
|
||||
) with system versioning;
|
||||
|
||||
# MDEV-515 takes X-lock on the table for the first insert
|
||||
# So concurrent DML won't happen on the table
|
||||
INSERT INTO t1 VALUES(100);
|
||||
|
||||
set transaction isolation level read committed;
|
||||
start transaction;
|
||||
insert into t1 values (1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2005, 2019, Oracle and/or its affiliates.
|
||||
Copyright (c) 2009, 2020, MariaDB
|
||||
Copyright (c) 2009, 2021, MariaDB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -9145,6 +9145,7 @@ int ha_partition::extra(enum ha_extra_function operation)
|
||||
case HA_EXTRA_BEGIN_ALTER_COPY:
|
||||
case HA_EXTRA_END_ALTER_COPY:
|
||||
case HA_EXTRA_FAKE_START_STMT:
|
||||
case HA_EXTRA_IGNORE_INSERT:
|
||||
DBUG_RETURN(loop_partitions(extra_cb, &operation));
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -5062,6 +5062,14 @@ extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd)
|
||||
return thd->get_command();
|
||||
}
|
||||
|
||||
#ifdef HAVE_REPLICATION /* Working around MDEV-24622 */
|
||||
/** @return whether the current thread is for applying binlog in a replica */
|
||||
extern "C" int thd_is_slave(const MYSQL_THD thd)
|
||||
{
|
||||
return thd && thd->slave_thread;
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
||||
/* Returns high resolution timestamp for the start
|
||||
of the current query. */
|
||||
extern "C" unsigned long long thd_start_utime(const MYSQL_THD thd)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
|
||||
Copyright (c) 2010, 2019, MariaDB Corporation
|
||||
Copyright (c) 2010, 2021, MariaDB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -2116,6 +2116,9 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
|
||||
goto after_trg_or_ignored_err;
|
||||
}
|
||||
|
||||
/* Notify the engine about insert ignore operation */
|
||||
if (info->handle_duplicates == DUP_ERROR && info->ignore)
|
||||
table->file->extra(HA_EXTRA_IGNORE_INSERT);
|
||||
after_trg_n_copied_inc:
|
||||
info->copied++;
|
||||
thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
|
||||
@@ -4148,6 +4151,7 @@ bool select_insert::prepare_eof()
|
||||
if (info.ignore || info.handle_duplicates != DUP_ERROR)
|
||||
if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
|
||||
table->file->ha_rnd_end();
|
||||
table->file->extra(HA_EXTRA_END_ALTER_COPY);
|
||||
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
||||
|
||||
@@ -4740,7 +4744,10 @@ select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u)
|
||||
if (info.handle_duplicates == DUP_UPDATE)
|
||||
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
|
||||
if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
|
||||
{
|
||||
table->file->ha_start_bulk_insert((ha_rows) 0);
|
||||
table->file->extra(HA_EXTRA_BEGIN_ALTER_COPY);
|
||||
}
|
||||
thd->abort_on_warning= !info.ignore && thd->is_strict_mode();
|
||||
if (check_that_all_fields_are_given_values(thd, table, table_list))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
|
||||
Copyright (c) 2010, 2020, MariaDB
|
||||
Copyright (c) 2010, 2021, MariaDB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -11533,6 +11533,9 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In case of alter ignore, notify the engine about it. */
|
||||
if (ignore)
|
||||
to->file->extra(HA_EXTRA_IGNORE_INSERT);
|
||||
DEBUG_SYNC(thd, "copy_data_between_tables_before");
|
||||
found_count++;
|
||||
mysql_stage_set_work_completed(thd->m_stage_progress_psi, found_count);
|
||||
|
||||
@@ -977,6 +977,43 @@ btr_free_root_check(
|
||||
return(block);
|
||||
}
|
||||
|
||||
/** Initialize the root page of the b-tree
|
||||
@param[in,out] block root block
|
||||
@param[in] index_id index id
|
||||
@param[in] index index of root page
|
||||
@param[in,out] mtr mini-transaction */
|
||||
static void btr_root_page_init(buf_block_t *block, index_id_t index_id,
|
||||
dict_index_t *index, mtr_t *mtr)
|
||||
{
|
||||
constexpr uint16_t field= PAGE_HEADER + PAGE_INDEX_ID;
|
||||
byte *page_index_id= my_assume_aligned<2>(field + block->frame);
|
||||
|
||||
/* Create a new index page on the allocated segment page */
|
||||
if (UNIV_LIKELY_NULL(block->page.zip.data))
|
||||
{
|
||||
mach_write_to_8(page_index_id, index_id);
|
||||
ut_ad(!page_has_siblings(block->page.zip.data));
|
||||
page_create_zip(block, index, 0, 0, mtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
page_create(block, mtr, index && index->table->not_redundant());
|
||||
if (index && index->is_spatial())
|
||||
{
|
||||
static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) ==
|
||||
FIL_PAGE_RTREE, "compatibility");
|
||||
mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->frame,
|
||||
byte(FIL_PAGE_RTREE));
|
||||
if (mach_read_from_8(block->frame + FIL_RTREE_SPLIT_SEQ_NUM))
|
||||
mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM, 8, 0);
|
||||
}
|
||||
/* Set the level of the new index page */
|
||||
mtr->write<2,mtr_t::MAYBE_NOP>(
|
||||
*block, PAGE_HEADER + PAGE_LEVEL + block->frame, 0U);
|
||||
mtr->write<8,mtr_t::MAYBE_NOP>(*block, page_index_id, index_id);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create the root node for a new index tree.
|
||||
@param[in] type type of the index
|
||||
@param[in] index_id index id
|
||||
@@ -1049,36 +1086,7 @@ btr_create(
|
||||
|
||||
ut_ad(!page_has_siblings(block->frame));
|
||||
|
||||
constexpr uint16_t field = PAGE_HEADER + PAGE_INDEX_ID;
|
||||
|
||||
byte* page_index_id = my_assume_aligned<2>(field + block->frame);
|
||||
|
||||
/* Create a new index page on the allocated segment page */
|
||||
if (UNIV_LIKELY_NULL(block->page.zip.data)) {
|
||||
mach_write_to_8(page_index_id, index_id);
|
||||
ut_ad(!page_has_siblings(block->page.zip.data));
|
||||
page_create_zip(block, index, 0, 0, mtr);
|
||||
} else {
|
||||
page_create(block, mtr,
|
||||
index && index->table->not_redundant());
|
||||
if (index && index->is_spatial()) {
|
||||
static_assert(((FIL_PAGE_INDEX & 0xff00)
|
||||
| byte(FIL_PAGE_RTREE))
|
||||
== FIL_PAGE_RTREE, "compatibility");
|
||||
mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->frame,
|
||||
byte(FIL_PAGE_RTREE));
|
||||
if (mach_read_from_8(block->frame
|
||||
+ FIL_RTREE_SPLIT_SEQ_NUM)) {
|
||||
mtr->memset(block, FIL_RTREE_SPLIT_SEQ_NUM,
|
||||
8, 0);
|
||||
}
|
||||
}
|
||||
/* Set the level of the new index page */
|
||||
mtr->write<2,mtr_t::MAYBE_NOP>(*block, PAGE_HEADER + PAGE_LEVEL
|
||||
+ block->frame, 0U);
|
||||
mtr->write<8,mtr_t::MAYBE_NOP>(*block, page_index_id,
|
||||
index_id);
|
||||
}
|
||||
btr_root_page_init(block, index_id, index, mtr);
|
||||
|
||||
/* We reset the free bits for the page in a separate
|
||||
mini-transaction to allow creation of several trees in the
|
||||
@@ -1167,6 +1175,33 @@ top_loop:
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear the index tree and reinitialize the root page, in the
|
||||
rollback of TRX_UNDO_EMPTY. The BTR_SEG_LEAF is freed and reinitialized.
|
||||
@param thr query thread */
|
||||
void dict_index_t::clear(que_thr_t *thr)
|
||||
{
|
||||
mtr_t mtr;
|
||||
mtr.start();
|
||||
if (table->is_temporary())
|
||||
mtr.set_log_mode(MTR_LOG_NO_REDO);
|
||||
else
|
||||
set_modified(mtr);
|
||||
|
||||
if (buf_block_t *root_block= buf_page_get(page_id_t(table->space->id, page),
|
||||
table->space->zip_size(),
|
||||
RW_X_LATCH, &mtr))
|
||||
{
|
||||
btr_free_but_not_root(root_block, mtr.get_log_mode());
|
||||
mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
|
||||
FSEG_HEADER_SIZE, 0);
|
||||
if (fseg_create(table->space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, &mtr, false,
|
||||
root_block))
|
||||
btr_root_page_init(root_block, id, this, &mtr);
|
||||
}
|
||||
|
||||
mtr.commit();
|
||||
}
|
||||
|
||||
/** Free a persistent index tree if it exists.
|
||||
@param[in] page_id root page id
|
||||
@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2021, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
@@ -67,6 +67,7 @@ Created 10/16/1994 Heikki Tuuri
|
||||
#include "srv0start.h"
|
||||
#include "mysql_com.h"
|
||||
#include "dict0stats.h"
|
||||
#include "row0ins.h"
|
||||
|
||||
/** Buffered B-tree operation types, introduced as part of delete buffering. */
|
||||
enum btr_op_t {
|
||||
@@ -3210,25 +3211,27 @@ btr_cur_ins_lock_and_undo(
|
||||
should inherit LOCK_GAP type locks from the
|
||||
successor record */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
rec_t* rec;
|
||||
roll_ptr_t roll_ptr;
|
||||
if (!(~flags | (BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG))) {
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
/* Check if we have to wait for a lock: enqueue an explicit lock
|
||||
request if yes */
|
||||
|
||||
rec = btr_cur_get_rec(cursor);
|
||||
index = cursor->index;
|
||||
rec_t* rec = btr_cur_get_rec(cursor);
|
||||
dict_index_t* index = cursor->index;
|
||||
|
||||
ut_ad(!dict_index_is_online_ddl(index)
|
||||
|| dict_index_is_clust(index)
|
||||
|| (flags & BTR_CREATE_FLAG));
|
||||
ut_ad((flags & BTR_NO_UNDO_LOG_FLAG)
|
||||
|| !index->table->skip_alter_undo);
|
||||
|
||||
ut_ad(mtr->is_named_space(index->table->space));
|
||||
|
||||
/* Check if there is predicate or GAP lock preventing the insertion */
|
||||
if (!(flags & BTR_NO_LOCKING_FLAG)) {
|
||||
if (dict_index_is_spatial(index)) {
|
||||
if (index->is_spatial()) {
|
||||
lock_prdt_t prdt;
|
||||
rtr_mbr_t mbr;
|
||||
|
||||
@@ -3240,44 +3243,55 @@ btr_cur_ins_lock_and_undo(
|
||||
lock_init_prdt_from_mbr(
|
||||
&prdt, &mbr, 0, NULL);
|
||||
|
||||
err = lock_prdt_insert_check_and_lock(
|
||||
flags, rec, btr_cur_get_block(cursor),
|
||||
index, thr, mtr, &prdt);
|
||||
if (dberr_t err = lock_prdt_insert_check_and_lock(
|
||||
rec, btr_cur_get_block(cursor),
|
||||
index, thr, mtr, &prdt)) {
|
||||
return err;
|
||||
}
|
||||
*inherit = false;
|
||||
} else {
|
||||
err = lock_rec_insert_check_and_lock(
|
||||
flags, rec, btr_cur_get_block(cursor),
|
||||
index, thr, mtr, inherit);
|
||||
ut_ad(!dict_index_is_online_ddl(index)
|
||||
|| index->is_primary()
|
||||
|| (flags & BTR_CREATE_FLAG));
|
||||
if (dberr_t err = lock_rec_insert_check_and_lock(
|
||||
rec, btr_cur_get_block(cursor),
|
||||
index, thr, mtr, inherit)) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS
|
||||
|| !(~flags | (BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG))
|
||||
|| !dict_index_is_clust(index) || dict_index_is_ibuf(index)) {
|
||||
|
||||
return(err);
|
||||
if (!index->is_primary() || !page_is_leaf(page_align(rec))) {
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
if (flags & BTR_NO_UNDO_LOG_FLAG) {
|
||||
roll_ptr = roll_ptr_t(1) << ROLL_PTR_INSERT_FLAG_POS;
|
||||
if (!(flags & BTR_KEEP_SYS_FLAG)) {
|
||||
upd_sys:
|
||||
dfield_t* r = dtuple_get_nth_field(
|
||||
entry, index->db_roll_ptr());
|
||||
ut_ad(r->len == DATA_ROLL_PTR_LEN);
|
||||
trx_write_roll_ptr(static_cast<byte*>(r->data),
|
||||
roll_ptr);
|
||||
constexpr roll_ptr_t dummy_roll_ptr = roll_ptr_t{1}
|
||||
<< ROLL_PTR_INSERT_FLAG_POS;
|
||||
roll_ptr_t roll_ptr = dummy_roll_ptr;
|
||||
|
||||
if (!(flags & BTR_NO_UNDO_LOG_FLAG)) {
|
||||
if (dberr_t err = trx_undo_report_row_operation(
|
||||
thr, index, entry, NULL, 0, NULL, NULL,
|
||||
&roll_ptr)) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
err = trx_undo_report_row_operation(thr, index, entry,
|
||||
NULL, 0, NULL, NULL,
|
||||
&roll_ptr);
|
||||
if (err == DB_SUCCESS) {
|
||||
goto upd_sys;
|
||||
|
||||
if (roll_ptr != dummy_roll_ptr) {
|
||||
dfield_t* r = dtuple_get_nth_field(entry,
|
||||
index->db_trx_id());
|
||||
trx_write_trx_id(static_cast<byte*>(r->data),
|
||||
thr_get_trx(thr)->id);
|
||||
}
|
||||
}
|
||||
|
||||
return(err);
|
||||
if (!(flags & BTR_KEEP_SYS_FLAG)) {
|
||||
dfield_t* r = dtuple_get_nth_field(
|
||||
entry, index->db_roll_ptr());
|
||||
ut_ad(r->len == DATA_ROLL_PTR_LEN);
|
||||
trx_write_roll_ptr(static_cast<byte*>(r->data), roll_ptr);
|
||||
}
|
||||
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3510,7 +3524,9 @@ fail_err:
|
||||
ut_ad(thr->graph->trx->id
|
||||
== trx_read_trx_id(
|
||||
static_cast<const byte*>(
|
||||
trx_id->data)));
|
||||
trx_id->data))
|
||||
|| static_cast<ins_node_t*>(
|
||||
thr->run_node)->bulk_insert);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -5506,6 +5522,7 @@ btr_cur_optimistic_delete_func(
|
||||
/* MDEV-17383: free metadata BLOBs! */
|
||||
index->clear_instant_alter();
|
||||
}
|
||||
|
||||
page_cur_set_after_last(block,
|
||||
btr_cur_get_page_cur(cursor));
|
||||
goto func_exit;
|
||||
@@ -5723,6 +5740,7 @@ btr_cur_pessimistic_delete(
|
||||
/* MDEV-17383: free metadata BLOBs! */
|
||||
index->clear_instant_alter();
|
||||
}
|
||||
|
||||
page_cur_set_after_last(
|
||||
block,
|
||||
btr_cur_get_page_cur(cursor));
|
||||
|
||||
@@ -3141,11 +3141,9 @@ static ulonglong innodb_prepare_commit_versioned(THD* thd, ulonglong *trx_id)
|
||||
if (const trx_t* trx = thd_to_trx(thd)) {
|
||||
*trx_id = trx->id;
|
||||
|
||||
for (trx_mod_tables_t::const_iterator t
|
||||
= trx->mod_tables.begin();
|
||||
t != trx->mod_tables.end(); t++) {
|
||||
if (t->second.is_versioned()) {
|
||||
DBUG_ASSERT(t->first->versioned_by_id());
|
||||
for (const auto& t : trx->mod_tables) {
|
||||
if (t.second.is_versioned()) {
|
||||
DBUG_ASSERT(t.first->versioned_by_id());
|
||||
DBUG_ASSERT(trx->rsegs.m_redo.rseg);
|
||||
|
||||
return trx_sys.get_new_trx_id();
|
||||
@@ -12959,16 +12957,14 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
|
||||
SET AUTOCOMMIT=0;
|
||||
CREATE TABLE t (PRIMARY KEY (a)) ENGINE=INNODB SELECT 1 AS a UNION
|
||||
ALL SELECT 1 AS a; */
|
||||
trx_mod_tables_t::const_iterator iter;
|
||||
|
||||
for (iter = parent_trx->mod_tables.begin();
|
||||
for (auto iter = parent_trx->mod_tables.begin();
|
||||
iter != parent_trx->mod_tables.end();
|
||||
++iter) {
|
||||
|
||||
dict_table_t* table_to_drop = iter->first;
|
||||
|
||||
if (strcmp(norm_name, table_to_drop->name.m_name) == 0) {
|
||||
parent_trx->mod_tables.erase(table_to_drop);
|
||||
parent_trx->mod_tables.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -15113,10 +15109,8 @@ ha_innobase::extra(
|
||||
break;
|
||||
}
|
||||
trx_start_if_not_started(m_prebuilt->trx, true);
|
||||
m_prebuilt->trx->mod_tables.insert(
|
||||
trx_mod_tables_t::value_type(
|
||||
const_cast<dict_table_t*>(m_prebuilt->table),
|
||||
0))
|
||||
m_prebuilt->trx->mod_tables.emplace(
|
||||
const_cast<dict_table_t*>(m_prebuilt->table), 0)
|
||||
.first->second.set_versioned(0);
|
||||
break;
|
||||
case HA_EXTRA_END_ALTER_COPY:
|
||||
@@ -15126,6 +15120,13 @@ ha_innobase::extra(
|
||||
trx_register_for_2pc(m_prebuilt->trx);
|
||||
m_prebuilt->sql_stat_start = true;
|
||||
break;
|
||||
case HA_EXTRA_IGNORE_INSERT:
|
||||
if (ins_node_t* node = m_prebuilt->ins_node) {
|
||||
if (node->bulk_insert) {
|
||||
m_prebuilt->trx->end_bulk_insert(*node->table);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:/* Do nothing */
|
||||
;
|
||||
}
|
||||
@@ -15362,6 +15363,7 @@ ha_innobase::external_lock(
|
||||
m_prebuilt->hint_need_to_fetch_extra_cols = 0;
|
||||
|
||||
reset_template();
|
||||
trx->end_bulk_insert();
|
||||
|
||||
switch (m_prebuilt->table->quiesce) {
|
||||
case QUIESCE_START:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
Copyright (c) 2013, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2013, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -1368,6 +1368,11 @@ public:
|
||||
everything in overflow) size of the longest possible row and index
|
||||
of a field which made index records too big to fit on a page.*/
|
||||
inline record_size_info_t record_size_info() const;
|
||||
|
||||
/** Clear the index tree and reinitialize the root page, in the
|
||||
rollback of TRX_UNDO_EMPTY. The BTR_SEG_LEAF is freed and reinitialized.
|
||||
@param thr query thread */
|
||||
void clear(que_thr_t *thr);
|
||||
};
|
||||
|
||||
/** Detach a virtual column from an index.
|
||||
@@ -1950,6 +1955,9 @@ struct dict_table_t {
|
||||
char (&tbl_name)[NAME_LEN + 1],
|
||||
size_t *db_name_len, size_t *tbl_name_len) const;
|
||||
|
||||
/** Clear the table when rolling back TRX_UNDO_EMPTY */
|
||||
void clear(que_thr_t *thr);
|
||||
|
||||
private:
|
||||
/** Initialize instant->field_map.
|
||||
@param[in] table table definition to copy from */
|
||||
@@ -2127,6 +2135,11 @@ public:
|
||||
loading the definition or CREATE TABLE, or ALTER TABLE (prepare,
|
||||
commit, and rollback phases). */
|
||||
trx_id_t def_trx_id;
|
||||
/** Last transaction that inserted into an empty table.
|
||||
Updated while holding exclusive table lock and an exclusive
|
||||
latch on the clustered index root page (which must also be
|
||||
an empty leaf page), and an ahi_latch (if btr_search_enabled). */
|
||||
Atomic_relaxed<trx_id_t> bulk_trx_id;
|
||||
|
||||
/*!< set of foreign key constraints in the table; these refer to
|
||||
columns in other tables */
|
||||
@@ -2298,7 +2311,6 @@ private:
|
||||
table is NOT allowed until this count gets to zero. MySQL does NOT
|
||||
itself check the number of open handles at DROP. */
|
||||
Atomic_counter<uint32_t> n_ref_count;
|
||||
|
||||
public:
|
||||
/** List of locks on the table. Protected by lock_sys.mutex. */
|
||||
table_lock_list_t locks;
|
||||
|
||||
@@ -250,8 +250,6 @@ for a gap x-lock to the lock queue.
|
||||
dberr_t
|
||||
lock_rec_insert_check_and_lock(
|
||||
/*===========================*/
|
||||
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is
|
||||
set, does nothing */
|
||||
const rec_t* rec, /*!< in: record after which to insert */
|
||||
buf_block_t* block, /*!< in/out: buffer block of rec */
|
||||
dict_index_t* index, /*!< in: index */
|
||||
@@ -386,37 +384,6 @@ lock_clust_rec_read_check_and_lock_alt(
|
||||
que_thr_t* thr) /*!< in: query thread */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
/*********************************************************************//**
|
||||
Checks that a record is seen in a consistent read.
|
||||
@return true if sees, or false if an earlier version of the record
|
||||
should be retrieved */
|
||||
bool
|
||||
lock_clust_rec_cons_read_sees(
|
||||
/*==========================*/
|
||||
const rec_t* rec, /*!< in: user record which should be read or
|
||||
passed over by a read cursor */
|
||||
dict_index_t* index, /*!< in: clustered index */
|
||||
const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */
|
||||
ReadView* view); /*!< in: consistent read view */
|
||||
/*********************************************************************//**
|
||||
Checks that a non-clustered index record is seen in a consistent read.
|
||||
|
||||
NOTE that a non-clustered index page contains so little information on
|
||||
its modifications that also in the case false, the present version of
|
||||
rec may be the right, but we must check this from the clustered index
|
||||
record.
|
||||
|
||||
@return true if certainly sees, or false if an earlier version of the
|
||||
clustered index record might be needed */
|
||||
bool
|
||||
lock_sec_rec_cons_read_sees(
|
||||
/*========================*/
|
||||
const rec_t* rec, /*!< in: user record which
|
||||
should be read or passed over
|
||||
by a read cursor */
|
||||
const dict_index_t* index, /*!< in: index */
|
||||
const ReadView* view) /*!< in: consistent read view */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
/*********************************************************************//**
|
||||
Locks the specified database table in the mode given. If the lock cannot
|
||||
be granted immediately, the query thread is put to wait.
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */
|
||||
@@ -438,6 +405,17 @@ lock_table_ix_resurrect(
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
trx_t* trx); /*!< in/out: transaction */
|
||||
|
||||
/** Create a table X lock object for a resurrected TRX_UNDO_EMPTY transaction.
|
||||
@param table table to be X-locked
|
||||
@param trx transaction */
|
||||
void lock_table_x_resurrect(dict_table_t *table, trx_t *trx);
|
||||
|
||||
/** Release a table X lock after rolling back an insert into an empty table
|
||||
(which was covered by a TRX_UNDO_EMPTY record).
|
||||
@param table table to be X-unlocked
|
||||
@param trx transaction */
|
||||
void lock_table_x_unlock(dict_table_t *table, trx_t *trx);
|
||||
|
||||
/** Sets a lock on a table based on the given mode.
|
||||
@param[in] table table to lock
|
||||
@param[in,out] trx transaction
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -126,8 +126,6 @@ a predicate record.
|
||||
dberr_t
|
||||
lock_prdt_insert_check_and_lock(
|
||||
/*============================*/
|
||||
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is
|
||||
set, does nothing */
|
||||
const rec_t* rec, /*!< in: record after which to insert */
|
||||
buf_block_t* block, /*!< in/out: buffer block of rec */
|
||||
dict_index_t* index, /*!< in: index */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -140,6 +140,20 @@ loop:
|
||||
*/
|
||||
static void check_trx_id_sanity(trx_id_t id, const table_name_t &name);
|
||||
|
||||
/**
|
||||
Check whether the changes by id are visible.
|
||||
@param[in] id transaction id to check against the view
|
||||
@return whether the view sees the modifications of id.
|
||||
*/
|
||||
bool changes_visible(trx_id_t id) const
|
||||
MY_ATTRIBUTE((warn_unused_result))
|
||||
{
|
||||
if (id >= m_low_limit_id)
|
||||
return false;
|
||||
return id < m_up_limit_id ||
|
||||
m_ids.empty() ||
|
||||
!std::binary_search(m_ids.begin(), m_ids.end(), id);
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the changes by id are visible.
|
||||
@@ -266,7 +280,8 @@ public:
|
||||
*/
|
||||
bool changes_visible(trx_id_t id, const table_name_t &name) const
|
||||
{ return id == m_creator_trx_id || ReadViewBase::changes_visible(id, name); }
|
||||
|
||||
bool changes_visible(trx_id_t id) const
|
||||
{ return id == m_creator_trx_id || ReadViewBase::changes_visible(id); }
|
||||
|
||||
/**
|
||||
A wrapper around ReadViewBase::append().
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -207,6 +207,9 @@ struct ins_node_t
|
||||
and buffers for sys fields in row allocated */
|
||||
void vers_update_end(row_prebuilt_t *prebuilt, bool history_row);
|
||||
bool vers_history_row() const; /* true if 'row' is historical */
|
||||
|
||||
/** Bulk insert enabled for this table */
|
||||
bool bulk_insert= false;
|
||||
};
|
||||
|
||||
/** Create an insert object.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -101,10 +101,10 @@ void
|
||||
row_log_online_op(
|
||||
/*==============*/
|
||||
dict_index_t* index, /*!< in/out: index, S or X latched */
|
||||
const dtuple_t* tuple, /*!< in: index tuple */
|
||||
const dtuple_t* tuple, /*!< in: index tuple (NULL=empty the index) */
|
||||
trx_id_t trx_id) /*!< in: transaction ID for insert,
|
||||
or 0 for delete */
|
||||
ATTRIBUTE_COLD __attribute__((nonnull));
|
||||
ATTRIBUTE_COLD;
|
||||
|
||||
/******************************************************//**
|
||||
Gets the error status of the online index rebuild log.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -296,6 +296,13 @@ record */
|
||||
fields of the record can change */
|
||||
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
|
||||
do not change */
|
||||
/** Bulk insert operation. It is written only when the table is
|
||||
under exclusive lock and the clustered index root page latch is being held,
|
||||
and the clustered index is empty. Rollback will empty the table and
|
||||
free the leaf segment of all indexes, re-create the new
|
||||
leaf segment and re-initialize the root page alone. */
|
||||
#define TRX_UNDO_EMPTY 15
|
||||
|
||||
#define TRX_UNDO_CMPL_INFO_MULT 16U /* compilation info is multiplied by
|
||||
this and ORed to the type above */
|
||||
#define TRX_UNDO_UPD_EXTERN 128U /* This bit can be ORed to type_cmpl
|
||||
|
||||
@@ -557,58 +557,73 @@ struct trx_lock_t {
|
||||
/** Logical first modification time of a table in a transaction */
|
||||
class trx_mod_table_time_t
|
||||
{
|
||||
/** First modification of the table */
|
||||
undo_no_t first;
|
||||
/** First modification of a system versioned column */
|
||||
undo_no_t first_versioned;
|
||||
/** Impossible value for trx_t::undo_no */
|
||||
static constexpr undo_no_t NONE= ~undo_no_t{0};
|
||||
/** Theoretical maximum value for trx_t::undo_no.
|
||||
DB_ROLL_PTR is only 7 bytes, so it cannot point to more than
|
||||
this many undo log records. */
|
||||
static constexpr undo_no_t LIMIT= (undo_no_t{1} << (7 * 8)) - 1;
|
||||
|
||||
/** Magic value signifying that a system versioned column of a
|
||||
table was never modified in a transaction. */
|
||||
static const undo_no_t UNVERSIONED = IB_ID_MAX;
|
||||
/** Flag in 'first' to indicate that subsequent operations are
|
||||
covered by a TRX_UNDO_EMPTY record (for the first statement to
|
||||
insert into an empty table) */
|
||||
static constexpr undo_no_t BULK= 1ULL << 63;
|
||||
/** Flag in 'first' to indicate that some operations were
|
||||
covered by a TRX_UNDO_EMPTY record (for the first statement to
|
||||
insert into an empty table) */
|
||||
static constexpr undo_no_t WAS_BULK= 1ULL << 63;
|
||||
|
||||
/** First modification of the table, possibly ORed with BULK */
|
||||
undo_no_t first;
|
||||
/** First modification of a system versioned column (or NONE) */
|
||||
undo_no_t first_versioned= NONE;
|
||||
public:
|
||||
/** Constructor
|
||||
@param[in] rows number of modified rows so far */
|
||||
trx_mod_table_time_t(undo_no_t rows)
|
||||
: first(rows), first_versioned(UNVERSIONED) {}
|
||||
/** Constructor
|
||||
@param rows number of modified rows so far */
|
||||
trx_mod_table_time_t(undo_no_t rows) : first(rows) { ut_ad(rows < LIMIT); }
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/** Validation
|
||||
@param[in] rows number of modified rows so far
|
||||
@return whether the object is valid */
|
||||
bool valid(undo_no_t rows = UNVERSIONED) const
|
||||
{
|
||||
return first <= first_versioned && first <= rows;
|
||||
}
|
||||
/** Validation
|
||||
@param rows number of modified rows so far
|
||||
@return whether the object is valid */
|
||||
bool valid(undo_no_t rows= NONE) const
|
||||
{ auto f= first & LIMIT; return f <= first_versioned && f <= rows; }
|
||||
#endif /* UNIV_DEBUG */
|
||||
/** @return if versioned columns were modified */
|
||||
bool is_versioned() const { return first_versioned != UNVERSIONED; }
|
||||
/** @return if versioned columns were modified */
|
||||
bool is_versioned() const { return first_versioned != NONE; }
|
||||
|
||||
/** After writing an undo log record, set is_versioned() if needed
|
||||
@param[in] rows number of modified rows so far */
|
||||
void set_versioned(undo_no_t rows)
|
||||
{
|
||||
ut_ad(!is_versioned());
|
||||
first_versioned = rows;
|
||||
ut_ad(valid());
|
||||
}
|
||||
/** After writing an undo log record, set is_versioned() if needed
|
||||
@param rows number of modified rows so far */
|
||||
void set_versioned(undo_no_t rows)
|
||||
{
|
||||
ut_ad(!is_versioned());
|
||||
first_versioned= rows;
|
||||
ut_ad(valid(rows));
|
||||
}
|
||||
|
||||
/** Invoked after partial rollback
|
||||
@param[in] limit number of surviving modified rows
|
||||
@return whether this should be erased from trx_t::mod_tables */
|
||||
bool rollback(undo_no_t limit)
|
||||
{
|
||||
ut_ad(valid());
|
||||
if (first >= limit) {
|
||||
return true;
|
||||
}
|
||||
/** Notify the start of a bulk insert operation */
|
||||
void start_bulk_insert() { first|= BULK | WAS_BULK; }
|
||||
|
||||
if (first_versioned < limit && is_versioned()) {
|
||||
first_versioned = UNVERSIONED;
|
||||
}
|
||||
/** Notify the end of a bulk insert operation */
|
||||
void end_bulk_insert() { first&= ~BULK; }
|
||||
|
||||
return false;
|
||||
}
|
||||
/** @return whether an insert is covered by TRX_UNDO_EMPTY record */
|
||||
bool is_bulk_insert() const { return first & BULK; }
|
||||
/** @return whether an insert was covered by TRX_UNDO_EMPTY record */
|
||||
bool was_bulk_insert() const { return first & WAS_BULK; }
|
||||
|
||||
/** Invoked after partial rollback
|
||||
@param limit number of surviving modified rows (trx_t::undo_no)
|
||||
@return whether this should be erased from trx_t::mod_tables */
|
||||
bool rollback(undo_no_t limit)
|
||||
{
|
||||
ut_ad(valid());
|
||||
if ((LIMIT & first) >= limit)
|
||||
return true;
|
||||
if (first_versioned < limit)
|
||||
first_versioned= NONE;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** Collection of persistent tables and their first modification
|
||||
@@ -1086,11 +1101,34 @@ public:
|
||||
ut_ad(dict_operation == TRX_DICT_OP_NONE);
|
||||
}
|
||||
|
||||
/** This has to be invoked on SAVEPOINT or at the end of a statement.
|
||||
Even if a TRX_UNDO_EMPTY record was written for this table to cover an
|
||||
insert into an empty table, subsequent operations will have to be covered
|
||||
by row-level undo log records, so that ROLLBACK TO SAVEPOINT or a
|
||||
rollback to the start of a statement will work.
|
||||
@param table table on which any preceding bulk insert ended */
|
||||
void end_bulk_insert(const dict_table_t &table)
|
||||
{
|
||||
auto it= mod_tables.find(const_cast<dict_table_t*>(&table));
|
||||
if (it != mod_tables.end())
|
||||
it->second.end_bulk_insert();
|
||||
}
|
||||
|
||||
/** This has to be invoked on SAVEPOINT or at the start of a statement.
|
||||
Even if TRX_UNDO_EMPTY records were written for any table to cover an
|
||||
insert into an empty table, subsequent operations will have to be covered
|
||||
by row-level undo log records, so that ROLLBACK TO SAVEPOINT or a
|
||||
rollback to the start of a statement will work. */
|
||||
void end_bulk_insert()
|
||||
{
|
||||
for (auto& t : mod_tables)
|
||||
t.second.end_bulk_insert();
|
||||
}
|
||||
|
||||
private:
|
||||
/** Assign a rollback segment for modifying temporary tables.
|
||||
@return the assigned rollback segment */
|
||||
trx_rseg_t* assign_temp_rseg();
|
||||
/** Assign a rollback segment for modifying temporary tables.
|
||||
@return the assigned rollback segment */
|
||||
trx_rseg_t *assign_temp_rseg();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -360,83 +360,6 @@ lock_check_trx_id_sanity(
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks that a record is seen in a consistent read.
|
||||
@return true if sees, or false if an earlier version of the record
|
||||
should be retrieved */
|
||||
bool
|
||||
lock_clust_rec_cons_read_sees(
|
||||
/*==========================*/
|
||||
const rec_t* rec, /*!< in: user record which should be read or
|
||||
passed over by a read cursor */
|
||||
dict_index_t* index, /*!< in: clustered index */
|
||||
const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */
|
||||
ReadView* view) /*!< in: consistent read view */
|
||||
{
|
||||
ut_ad(dict_index_is_clust(index));
|
||||
ut_ad(page_rec_is_user_rec(rec));
|
||||
ut_ad(rec_offs_validate(rec, index, offsets));
|
||||
ut_ad(!rec_is_metadata(rec, *index));
|
||||
|
||||
/* Temp-tables are not shared across connections and multiple
|
||||
transactions from different connections cannot simultaneously
|
||||
operate on same temp-table and so read of temp-table is
|
||||
always consistent read. */
|
||||
if (index->table->is_temporary()) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
/* NOTE that we call this function while holding the search
|
||||
system latch. */
|
||||
|
||||
trx_id_t trx_id = row_get_rec_trx_id(rec, index, offsets);
|
||||
|
||||
return(view->changes_visible(trx_id, index->table->name));
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks that a non-clustered index record is seen in a consistent read.
|
||||
|
||||
NOTE that a non-clustered index page contains so little information on
|
||||
its modifications that also in the case false, the present version of
|
||||
rec may be the right, but we must check this from the clustered index
|
||||
record.
|
||||
|
||||
@return true if certainly sees, or false if an earlier version of the
|
||||
clustered index record might be needed */
|
||||
bool
|
||||
lock_sec_rec_cons_read_sees(
|
||||
/*========================*/
|
||||
const rec_t* rec, /*!< in: user record which
|
||||
should be read or passed over
|
||||
by a read cursor */
|
||||
const dict_index_t* index, /*!< in: index */
|
||||
const ReadView* view) /*!< in: consistent read view */
|
||||
{
|
||||
ut_ad(page_rec_is_user_rec(rec));
|
||||
ut_ad(!index->is_primary());
|
||||
ut_ad(!rec_is_metadata(rec, *index));
|
||||
|
||||
/* NOTE that we might call this function while holding the search
|
||||
system latch. */
|
||||
|
||||
if (index->table->is_temporary()) {
|
||||
|
||||
/* Temp-tables are not shared across connections and multiple
|
||||
transactions from different connections cannot simultaneously
|
||||
operate on same temp-table and so read of temp-table is
|
||||
always consistent read. */
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
trx_id_t max_trx_id = page_get_max_trx_id(page_align(rec));
|
||||
|
||||
ut_ad(max_trx_id > 0);
|
||||
|
||||
return(view->sees(max_trx_id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Creates the lock system at database start.
|
||||
@@ -2125,7 +2048,9 @@ lock_rec_inherit_to_gap_if_gap_lock(
|
||||
|
||||
if (!lock_rec_get_insert_intention(lock)
|
||||
&& (heap_no == PAGE_HEAP_NO_SUPREMUM
|
||||
|| !lock_rec_get_rec_not_gap(lock))) {
|
||||
|| !lock_rec_get_rec_not_gap(lock))
|
||||
&& !lock_table_has(lock->trx, lock->index->table,
|
||||
LOCK_X)) {
|
||||
|
||||
lock_rec_add_to_queue(
|
||||
LOCK_REC | LOCK_GAP | lock_get_mode(lock),
|
||||
@@ -3598,6 +3523,27 @@ lock_table_ix_resurrect(
|
||||
mutex->wr_unlock();
|
||||
}
|
||||
|
||||
/** Create a table X lock object for a resurrected TRX_UNDO_EMPTY transaction.
|
||||
@param table table to be X-locked
|
||||
@param trx transaction */
|
||||
void lock_table_x_resurrect(dict_table_t *table, trx_t *trx)
|
||||
{
|
||||
ut_ad(trx->is_recovered);
|
||||
if (lock_table_has(trx, table, LOCK_X))
|
||||
return;
|
||||
|
||||
auto mutex= &trx->mutex;
|
||||
lock_sys.mutex_lock();
|
||||
/* We have to check if the new lock is compatible with any locks
|
||||
other transactions have in the table lock queue. */
|
||||
ut_ad(!lock_table_other_has_incompatible(trx, LOCK_WAIT, table, LOCK_X));
|
||||
|
||||
mutex->wr_lock();
|
||||
lock_table_create(table, LOCK_X, trx);
|
||||
lock_sys.mutex_unlock();
|
||||
mutex->wr_unlock();
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks if a waiting table lock request still has to wait in a queue.
|
||||
@return TRUE if still has to wait */
|
||||
@@ -3664,6 +3610,32 @@ lock_table_dequeue(
|
||||
}
|
||||
}
|
||||
|
||||
/** Release a table X lock after rolling back an insert into an empty table
|
||||
(which was covered by a TRX_UNDO_EMPTY record).
|
||||
@param table table to be X-unlocked
|
||||
@param trx transaction */
|
||||
void lock_table_x_unlock(dict_table_t *table, trx_t *trx)
|
||||
{
|
||||
ut_ad(!trx->is_recovered);
|
||||
|
||||
lock_sys.mutex_lock();
|
||||
|
||||
for (lock_t*& lock : trx->lock.table_locks)
|
||||
{
|
||||
if (lock && lock->trx == trx && lock->type_mode == (LOCK_TABLE | LOCK_X))
|
||||
{
|
||||
ut_ad(!lock_get_wait(lock));
|
||||
lock_table_dequeue(lock);
|
||||
lock= nullptr;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
ut_ad("lock not found" == 0);
|
||||
|
||||
func_exit:
|
||||
lock_sys.mutex_unlock();
|
||||
}
|
||||
|
||||
/** Sets a lock on a table based on the given mode.
|
||||
@param[in] table table to lock
|
||||
@param[in,out] trx transaction
|
||||
@@ -4752,8 +4724,6 @@ for a gap x-lock to the lock queue.
|
||||
dberr_t
|
||||
lock_rec_insert_check_and_lock(
|
||||
/*===========================*/
|
||||
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is
|
||||
set, does nothing */
|
||||
const rec_t* rec, /*!< in: record after which to insert */
|
||||
buf_block_t* block, /*!< in/out: buffer block of rec */
|
||||
dict_index_t* index, /*!< in: index */
|
||||
@@ -4765,17 +4735,9 @@ lock_rec_insert_check_and_lock(
|
||||
record */
|
||||
{
|
||||
ut_ad(block->frame == page_align(rec));
|
||||
ut_ad(!dict_index_is_online_ddl(index)
|
||||
|| index->is_primary()
|
||||
|| (flags & BTR_CREATE_FLAG));
|
||||
ut_ad(mtr->is_named_space(index->table->space));
|
||||
ut_ad(page_rec_is_leaf(rec));
|
||||
|
||||
if (flags & BTR_NO_LOCKING_FLAG) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
ut_ad(!index->table->is_temporary());
|
||||
ut_ad(page_is_leaf(block->frame));
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2018, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -509,8 +509,6 @@ a predicate record.
|
||||
dberr_t
|
||||
lock_prdt_insert_check_and_lock(
|
||||
/*============================*/
|
||||
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is
|
||||
set, does nothing */
|
||||
const rec_t* rec, /*!< in: record after which to insert */
|
||||
buf_block_t* block, /*!< in/out: buffer block of rec */
|
||||
dict_index_t* index, /*!< in: index */
|
||||
@@ -520,14 +518,8 @@ lock_prdt_insert_check_and_lock(
|
||||
Rectangle */
|
||||
{
|
||||
ut_ad(block->frame == page_align(rec));
|
||||
|
||||
if (flags & BTR_NO_LOCKING_FLAG) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
ut_ad(!index->table->is_temporary());
|
||||
ut_ad(!dict_index_is_clust(index));
|
||||
ut_ad(index->is_spatial());
|
||||
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ Created 4/20/1996 Heikki Tuuri
|
||||
#include "buf0lru.h"
|
||||
#include "fts0fts.h"
|
||||
#include "fts0types.h"
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
# include "btr0sea.h"
|
||||
#endif
|
||||
#ifdef WITH_WSREP
|
||||
#include "wsrep_mysqld.h"
|
||||
#endif /* WITH_WSREP */
|
||||
@@ -2530,6 +2533,12 @@ row_ins_index_entry_big_rec(
|
||||
return(error);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REPLICATION /* Working around MDEV-24622 */
|
||||
extern "C" int thd_is_slave(const MYSQL_THD thd);
|
||||
#else
|
||||
# define thd_is_slave(thd) 0
|
||||
#endif
|
||||
|
||||
/***************************************************************//**
|
||||
Tries to insert an entry into a clustered index, ignoring foreign key
|
||||
constraints. If a record with the same unique key is found, the other
|
||||
@@ -2564,6 +2573,8 @@ row_ins_clust_index_entry_low(
|
||||
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
rec_offs* offsets = offsets_;
|
||||
rec_offs_init(offsets_);
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
buf_block_t* block;
|
||||
|
||||
DBUG_ENTER("row_ins_clust_index_entry_low");
|
||||
|
||||
@@ -2571,7 +2582,7 @@ row_ins_clust_index_entry_low(
|
||||
ut_ad(!dict_index_is_unique(index)
|
||||
|| n_uniq == dict_index_get_n_unique(index));
|
||||
ut_ad(!n_uniq || n_uniq == dict_index_get_n_unique(index));
|
||||
ut_ad(!thr_get_trx(thr)->in_rollback);
|
||||
ut_ad(!trx->in_rollback);
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
@@ -2625,6 +2636,7 @@ row_ins_clust_index_entry_low(
|
||||
auto_inc, &mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
index->table->file_unreadable = true;
|
||||
commit_exit:
|
||||
mtr.commit();
|
||||
goto func_exit;
|
||||
}
|
||||
@@ -2643,6 +2655,47 @@ row_ins_clust_index_entry_low(
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
block = btr_cur_get_block(cursor);
|
||||
|
||||
DBUG_EXECUTE_IF("row_ins_row_level", goto skip_bulk_insert;);
|
||||
|
||||
if (!(flags & BTR_NO_UNDO_LOG_FLAG)
|
||||
&& page_is_empty(block->frame)
|
||||
&& !entry->is_metadata() && !trx->duplicates
|
||||
&& !trx->ddl && !trx->internal
|
||||
&& block->page.id().page_no() == index->page
|
||||
&& !index->table->skip_alter_undo
|
||||
&& !trx->is_wsrep() /* FIXME: MDEV-24623 */
|
||||
&& !thd_is_slave(trx->mysql_thd) /* FIXME: MDEV-24622 */) {
|
||||
DEBUG_SYNC_C("empty_root_page_insert");
|
||||
|
||||
if (!index->table->is_temporary()) {
|
||||
err = lock_table(0, index->table, LOCK_X, thr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
trx->error_state = err;
|
||||
goto commit_exit;
|
||||
}
|
||||
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
if (btr_search_enabled) {
|
||||
btr_search_x_lock_all();
|
||||
index->table->bulk_trx_id = trx->id;
|
||||
btr_search_x_unlock_all();
|
||||
} else {
|
||||
index->table->bulk_trx_id = trx->id;
|
||||
}
|
||||
#else /* BTR_CUR_HASH_ADAPT */
|
||||
index->table->bulk_trx_id = trx->id;
|
||||
#endif /* BTR_CUR_HASH_ADAPT */
|
||||
}
|
||||
|
||||
static_cast<ins_node_t*>(thr->run_node)->bulk_insert = true;
|
||||
}
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
skip_bulk_insert:
|
||||
#endif
|
||||
if (UNIV_UNLIKELY(entry->info_bits != 0)) {
|
||||
ut_ad(entry->is_metadata());
|
||||
ut_ad(flags == BTR_NO_LOCKING_FLAG);
|
||||
@@ -2653,7 +2706,7 @@ row_ins_clust_index_entry_low(
|
||||
|
||||
if (rec_get_info_bits(rec, page_rec_is_comp(rec))
|
||||
& REC_INFO_MIN_REC_FLAG) {
|
||||
thr_get_trx(thr)->error_info = index;
|
||||
trx->error_info = index;
|
||||
err = DB_DUPLICATE_KEY;
|
||||
goto err_exit;
|
||||
}
|
||||
@@ -2686,7 +2739,7 @@ row_ins_clust_index_entry_low(
|
||||
/* fall through */
|
||||
case DB_SUCCESS_LOCKED_REC:
|
||||
case DB_DUPLICATE_KEY:
|
||||
thr_get_trx(thr)->error_info = cursor->index;
|
||||
trx->error_info = cursor->index;
|
||||
}
|
||||
} else {
|
||||
/* Note that the following may return also
|
||||
@@ -2770,7 +2823,7 @@ do_insert:
|
||||
log_write_up_to(mtr.commit_lsn(), true););
|
||||
err = row_ins_index_entry_big_rec(
|
||||
entry, big_rec, offsets, &offsets_heap, index,
|
||||
thr_get_trx(thr)->mysql_thd);
|
||||
trx->mysql_thd);
|
||||
dtuple_convert_back_big_rec(index, entry, big_rec);
|
||||
} else {
|
||||
if (err == DB_SUCCESS
|
||||
@@ -3734,10 +3787,6 @@ row_ins_step(
|
||||
goto do_insert;
|
||||
}
|
||||
|
||||
if (UNIV_LIKELY(!node->table->skip_alter_undo)) {
|
||||
trx_write_trx_id(&node->sys_buf[DATA_ROW_ID_LEN], trx->id);
|
||||
}
|
||||
|
||||
if (node->state == INS_NODE_SET_IX_LOCK) {
|
||||
|
||||
node->state = INS_NODE_ALLOC_ROW_ID;
|
||||
@@ -3757,7 +3806,7 @@ row_ins_step(
|
||||
err = DB_LOCK_WAIT;);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
node->state = INS_NODE_SET_IX_LOCK;
|
||||
goto error_handling;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -54,7 +54,9 @@ enum row_tab_op {
|
||||
/** Update a record in place */
|
||||
ROW_T_UPDATE,
|
||||
/** Delete (purge) a record */
|
||||
ROW_T_DELETE
|
||||
ROW_T_DELETE,
|
||||
/** Empty the table */
|
||||
ROW_T_EMPTY
|
||||
};
|
||||
|
||||
/** Index record modification operations during online index creation */
|
||||
@@ -62,7 +64,9 @@ enum row_op {
|
||||
/** Insert a record */
|
||||
ROW_OP_INSERT = 0x61,
|
||||
/** Delete a record */
|
||||
ROW_OP_DELETE
|
||||
ROW_OP_DELETE,
|
||||
/** Empy the index */
|
||||
ROW_OP_EMPTY
|
||||
};
|
||||
|
||||
/** Size of the modification log entry header, in bytes */
|
||||
@@ -328,7 +332,7 @@ void
|
||||
row_log_online_op(
|
||||
/*==============*/
|
||||
dict_index_t* index, /*!< in/out: index, S or X latched */
|
||||
const dtuple_t* tuple, /*!< in: index tuple */
|
||||
const dtuple_t* tuple, /*!< in: index tuple (NULL=empty the index) */
|
||||
trx_id_t trx_id) /*!< in: transaction ID for insert,
|
||||
or 0 for delete */
|
||||
{
|
||||
@@ -339,8 +343,8 @@ row_log_online_op(
|
||||
ulint avail_size;
|
||||
row_log_t* log;
|
||||
|
||||
ut_ad(dtuple_validate(tuple));
|
||||
ut_ad(dtuple_get_n_fields(tuple) == dict_index_get_n_fields(index));
|
||||
ut_ad(!tuple || dtuple_validate(tuple));
|
||||
ut_ad(!tuple || dtuple_get_n_fields(tuple) == dict_index_get_n_fields(index));
|
||||
ut_ad(index->lock.have_x() || index->lock.have_s());
|
||||
|
||||
if (index->is_corrupted()) {
|
||||
@@ -353,14 +357,20 @@ row_log_online_op(
|
||||
row_merge_buf_encode(), because here we do not encode
|
||||
extra_size+1 (and reserve 0 as the end-of-chunk marker). */
|
||||
|
||||
size = rec_get_converted_size_temp(
|
||||
index, tuple->fields, tuple->n_fields, &extra_size);
|
||||
ut_ad(size >= extra_size);
|
||||
ut_ad(size <= sizeof log->tail.buf);
|
||||
if (!tuple) {
|
||||
mrec_size = 4;
|
||||
extra_size = 0;
|
||||
size = 2;
|
||||
} else {
|
||||
size = rec_get_converted_size_temp(
|
||||
index, tuple->fields, tuple->n_fields, &extra_size);
|
||||
ut_ad(size >= extra_size);
|
||||
ut_ad(size <= sizeof log->tail.buf);
|
||||
|
||||
mrec_size = ROW_LOG_HEADER_SIZE
|
||||
+ (extra_size >= 0x80) + size
|
||||
+ (trx_id ? DATA_TRX_ID_LEN : 0);
|
||||
mrec_size = ROW_LOG_HEADER_SIZE
|
||||
+ (extra_size >= 0x80) + size
|
||||
+ (trx_id ? DATA_TRX_ID_LEN : 0);
|
||||
}
|
||||
|
||||
log = index->online_log;
|
||||
mysql_mutex_lock(&log->mutex);
|
||||
@@ -389,6 +399,8 @@ row_log_online_op(
|
||||
*b++ = ROW_OP_INSERT;
|
||||
trx_write_trx_id(b, trx_id);
|
||||
b += DATA_TRX_ID_LEN;
|
||||
} else if (!tuple) {
|
||||
*b++ = ROW_OP_EMPTY;
|
||||
} else {
|
||||
*b++ = ROW_OP_DELETE;
|
||||
}
|
||||
@@ -401,8 +413,14 @@ row_log_online_op(
|
||||
*b++ = (byte) extra_size;
|
||||
}
|
||||
|
||||
rec_convert_dtuple_to_temp(
|
||||
b + extra_size, index, tuple->fields, tuple->n_fields);
|
||||
if (tuple) {
|
||||
rec_convert_dtuple_to_temp(
|
||||
b + extra_size, index, tuple->fields,
|
||||
tuple->n_fields);
|
||||
} else {
|
||||
memset(b, 0, 2);
|
||||
}
|
||||
|
||||
b += size;
|
||||
|
||||
if (mrec_size >= avail_size) {
|
||||
@@ -2422,11 +2440,6 @@ row_log_table_apply_op(
|
||||
|
||||
*error = DB_SUCCESS;
|
||||
|
||||
/* 3 = 1 (op type) + 1 (extra_size) + at least 1 byte payload */
|
||||
if (mrec + 3 >= mrec_end) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
const bool is_instant = log->is_instant(dup->index);
|
||||
const mrec_t* const mrec_start = mrec;
|
||||
|
||||
@@ -2657,6 +2670,11 @@ row_log_table_apply_op(
|
||||
thr, new_trx_id_col,
|
||||
mrec, offsets, offsets_heap, heap, dup, old_pk);
|
||||
break;
|
||||
case ROW_T_EMPTY:
|
||||
dup->index->online_log->table->clear(thr);
|
||||
log->head.total += 1;
|
||||
next_mrec = mrec;
|
||||
break;
|
||||
}
|
||||
|
||||
ut_ad(log->head.total <= log->tail.total);
|
||||
@@ -3438,6 +3456,9 @@ row_log_apply_op_low(
|
||||
}
|
||||
|
||||
goto duplicate;
|
||||
case ROW_OP_EMPTY:
|
||||
ut_ad(0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (op) {
|
||||
@@ -3508,6 +3529,9 @@ insert_the_rec:
|
||||
0, NULL, &mtr);
|
||||
ut_ad(!big_rec);
|
||||
break;
|
||||
case ROW_OP_EMPTY:
|
||||
ut_ad(0);
|
||||
break;
|
||||
}
|
||||
mem_heap_empty(offsets_heap);
|
||||
}
|
||||
@@ -3582,6 +3606,16 @@ row_log_apply_op(
|
||||
op = static_cast<enum row_op>(*mrec++);
|
||||
trx_id = 0;
|
||||
break;
|
||||
case ROW_OP_EMPTY:
|
||||
{
|
||||
mem_heap_t* heap = mem_heap_create(512);
|
||||
que_fork_t* fork = que_fork_create(
|
||||
NULL, NULL, QUE_FORK_MYSQL_INTERFACE, heap);
|
||||
que_thr_t* thr = que_thr_create(fork, heap, nullptr);
|
||||
index->clear(thr);
|
||||
mem_heap_free(heap);
|
||||
return mrec + 4;
|
||||
}
|
||||
default:
|
||||
corrupted:
|
||||
ut_ad(0);
|
||||
@@ -4024,3 +4058,54 @@ row_log_apply(
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/** Notify that the table was emptied by concurrent rollback or purge.
|
||||
@param index clustered index */
|
||||
static void row_log_table_empty(dict_index_t *index)
|
||||
{
|
||||
ut_ad(index->lock.have_any());
|
||||
row_log_t* log= index->online_log;
|
||||
ulint avail_size;
|
||||
if (byte *b= row_log_table_open(log, 1, &avail_size))
|
||||
{
|
||||
*b++ = ROW_T_EMPTY;
|
||||
row_log_table_close(index, b, 1, avail_size);
|
||||
}
|
||||
}
|
||||
|
||||
void dict_table_t::clear(que_thr_t *thr)
|
||||
{
|
||||
bool rebuild= false;
|
||||
for (dict_index_t *index= UT_LIST_GET_FIRST(indexes); index;
|
||||
index= UT_LIST_GET_NEXT(indexes, index))
|
||||
{
|
||||
if (index->type & DICT_FTS)
|
||||
continue;
|
||||
|
||||
switch (dict_index_get_online_status(index)) {
|
||||
case ONLINE_INDEX_ABORTED:
|
||||
case ONLINE_INDEX_ABORTED_DROPPED:
|
||||
continue;
|
||||
|
||||
case ONLINE_INDEX_COMPLETE:
|
||||
break;
|
||||
|
||||
case ONLINE_INDEX_CREATION:
|
||||
index->lock.u_lock(SRW_LOCK_CALL);
|
||||
if (dict_index_get_online_status(index) == ONLINE_INDEX_CREATION)
|
||||
{
|
||||
if (index->is_clust())
|
||||
{
|
||||
row_log_table_empty(index);
|
||||
rebuild= true;
|
||||
}
|
||||
else if (!rebuild)
|
||||
row_log_online_op(index, nullptr, 0);
|
||||
}
|
||||
|
||||
index->lock.u_unlock();
|
||||
}
|
||||
|
||||
index->clear(thr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2014, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2014, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -1739,7 +1739,7 @@ row_merge_read_clustered_index(
|
||||
ut_malloc_nokey(n_index * sizeof *merge_buf));
|
||||
|
||||
row_merge_dup_t clust_dup = {index[0], table, col_map, 0};
|
||||
dfield_t* prev_fields;
|
||||
dfield_t* prev_fields = nullptr;
|
||||
const ulint n_uniq = dict_index_get_n_unique(index[0]);
|
||||
|
||||
ut_ad(trx->mysql_thd != NULL);
|
||||
@@ -1838,6 +1838,34 @@ row_merge_read_clustered_index(
|
||||
btr_pcur_move_to_prev_on_page(&pcur);
|
||||
}
|
||||
|
||||
uint64_t n_rows = 0;
|
||||
|
||||
/* Check if the table is supposed to be empty for our read view.
|
||||
|
||||
If we read bulk_trx_id as an older transaction ID, it is not
|
||||
incorrect to check here whether that transaction should be
|
||||
visible to us. If bulk_trx_id is not visible to us, the table
|
||||
must have been empty at an earlier point of time, also in our
|
||||
read view.
|
||||
|
||||
An INSERT would only update bulk_trx_id in
|
||||
row_ins_clust_index_entry_low() if the table really was empty
|
||||
(everything had been purged), when holding a leaf page latch
|
||||
in the clustered index (actually, the root page is the only
|
||||
leaf page in that case).
|
||||
|
||||
We are holding a clustered index leaf page latch here.
|
||||
That will obviously prevent any concurrent INSERT from
|
||||
updating bulk_trx_id while we read it. */
|
||||
if (!online) {
|
||||
} else if (trx_id_t bulk_trx_id = old_table->bulk_trx_id) {
|
||||
ut_ad(trx->read_view.is_open());
|
||||
ut_ad(bulk_trx_id != trx->id);
|
||||
if (!trx->read_view.changes_visible(bulk_trx_id)) {
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_table != new_table) {
|
||||
/* The table is being rebuilt. Identify the columns
|
||||
that were flagged NOT NULL in the new table, so that
|
||||
@@ -1884,13 +1912,10 @@ row_merge_read_clustered_index(
|
||||
prev_fields = static_cast<dfield_t*>(
|
||||
ut_malloc_nokey(n_uniq * sizeof *prev_fields));
|
||||
mtuple_heap = mem_heap_create(sizeof(mrec_buf_t));
|
||||
} else {
|
||||
prev_fields = NULL;
|
||||
}
|
||||
|
||||
mach_write_to_8(new_sys_trx_start, trx->id);
|
||||
mach_write_to_8(new_sys_trx_end, TRX_ID_MAX);
|
||||
uint64_t n_rows = 0;
|
||||
|
||||
/* Scan the clustered index. */
|
||||
for (;;) {
|
||||
@@ -2720,7 +2745,7 @@ all_done:
|
||||
UT_DELETE(clust_btr_bulk);
|
||||
}
|
||||
|
||||
if (prev_fields != NULL) {
|
||||
if (prev_fields) {
|
||||
ut_free(prev_fields);
|
||||
mem_heap_free(mtuple_heap);
|
||||
}
|
||||
|
||||
@@ -1096,6 +1096,12 @@ row_get_prebuilt_insert_row(
|
||||
&& prebuilt->ins_node->entry_list.size()
|
||||
== UT_LIST_GET_LEN(table->indexes)) {
|
||||
|
||||
if (prebuilt->ins_node->bulk_insert
|
||||
&& prebuilt->ins_node->trx_id
|
||||
!= prebuilt->trx->id) {
|
||||
prebuilt->ins_node->bulk_insert= false;
|
||||
}
|
||||
|
||||
return(prebuilt->ins_node->row);
|
||||
}
|
||||
|
||||
@@ -1409,6 +1415,7 @@ row_insert_for_mysql(
|
||||
prebuilt->sql_stat_start = FALSE;
|
||||
} else {
|
||||
node->state = INS_NODE_ALLOC_ROW_ID;
|
||||
node->trx_id = trx->id;
|
||||
}
|
||||
|
||||
thr->start_running();
|
||||
@@ -1437,7 +1444,8 @@ error_exit:
|
||||
|
||||
if (was_lock_wait) {
|
||||
ut_ad(node->state == INS_NODE_INSERT_ENTRIES
|
||||
|| node->state == INS_NODE_ALLOC_ROW_ID);
|
||||
|| node->state == INS_NODE_ALLOC_ROW_ID
|
||||
|| node->state == INS_NODE_SET_IX_LOCK);
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -892,6 +892,7 @@ row_purge_parse_undo_rec(
|
||||
switch (type) {
|
||||
case TRX_UNDO_RENAME_TABLE:
|
||||
return false;
|
||||
case TRX_UNDO_EMPTY:
|
||||
case TRX_UNDO_INSERT_METADATA:
|
||||
case TRX_UNDO_INSERT_REC:
|
||||
/* These records do not store any transaction identifier.
|
||||
@@ -982,6 +983,9 @@ err_exit:
|
||||
if (type == TRX_UNDO_INSERT_METADATA) {
|
||||
node->ref = &trx_undo_metadata;
|
||||
return(true);
|
||||
} else if (type == TRX_UNDO_EMPTY) {
|
||||
node->ref = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
|
||||
@@ -1039,6 +1043,8 @@ row_purge_record_func(
|
||||
ut_ad(!trx_undo_roll_ptr_is_insert(node->roll_ptr));
|
||||
|
||||
switch (node->rec_type) {
|
||||
case TRX_UNDO_EMPTY:
|
||||
break;
|
||||
case TRX_UNDO_DEL_MARK_REC:
|
||||
purged = row_purge_del_mark(node);
|
||||
if (purged) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2015, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2015, 2021, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
@@ -875,6 +875,25 @@ row_sel_test_other_conds(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/** Check that a clustered index record is visible in a consistent read view.
|
||||
@param rec clustered index record (in leaf page, or in memory)
|
||||
@param index clustered index
|
||||
@param offsets rec_get_offsets(rec, index)
|
||||
@param view consistent read view
|
||||
@return whether rec is visible in view */
|
||||
static bool row_sel_clust_sees(const rec_t *rec, const dict_index_t &index,
|
||||
const rec_offs *offsets, const ReadView &view)
|
||||
{
|
||||
ut_ad(index.is_primary());
|
||||
ut_ad(page_rec_is_user_rec(rec));
|
||||
ut_ad(rec_offs_validate(rec, &index, offsets));
|
||||
ut_ad(!rec_is_metadata(rec, index));
|
||||
ut_ad(!index.table->is_temporary());
|
||||
|
||||
return view.changes_visible(row_get_rec_trx_id(rec, &index, offsets),
|
||||
index.table->name);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Retrieves the clustered index record corresponding to a record in a
|
||||
non-clustered index. Does the necessary locking.
|
||||
@@ -977,8 +996,8 @@ row_sel_get_clust_rec(
|
||||
|
||||
old_vers = NULL;
|
||||
|
||||
if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
|
||||
node->read_view)) {
|
||||
if (!row_sel_clust_sees(clust_rec, *index, offsets,
|
||||
*node->read_view)) {
|
||||
|
||||
err = row_sel_build_prev_vers(
|
||||
node->read_view, index, clust_rec,
|
||||
@@ -1450,7 +1469,9 @@ row_sel_try_search_shortcut(
|
||||
{
|
||||
dict_index_t* index = plan->index;
|
||||
|
||||
ut_ad(!index->table->is_temporary());
|
||||
ut_ad(node->read_view);
|
||||
ut_ad(node->read_view->is_open());
|
||||
ut_ad(plan->unique_search);
|
||||
ut_ad(!plan->must_get_clust);
|
||||
|
||||
@@ -1474,6 +1495,13 @@ exhausted:
|
||||
return(SEL_EXHAUSTED);
|
||||
}
|
||||
|
||||
if (trx_id_t bulk_trx_id = index->table->bulk_trx_id) {
|
||||
/* See row_search_mvcc() for a comment on bulk_trx_id */
|
||||
if (!node->read_view->changes_visible(bulk_trx_id)) {
|
||||
goto exhausted;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a non-locking consistent read: if necessary, fetch
|
||||
a previous version of the record */
|
||||
|
||||
@@ -1485,14 +1513,16 @@ exhausted:
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
if (dict_index_is_clust(index)) {
|
||||
if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
|
||||
node->read_view)) {
|
||||
if (!row_sel_clust_sees(rec, *index, offsets,
|
||||
*node->read_view)) {
|
||||
goto retry;
|
||||
}
|
||||
} else if (!srv_read_only_mode) {
|
||||
trx_id_t trx_id = page_get_max_trx_id(page_align(rec));
|
||||
ut_ad(trx_id);
|
||||
if (!node->read_view->sees(trx_id)) {
|
||||
goto retry;
|
||||
}
|
||||
} else if (!srv_read_only_mode
|
||||
&& !lock_sec_rec_cons_read_sees(
|
||||
rec, index, node->read_view)) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec, dict_table_is_comp(plan->table))) {
|
||||
@@ -1541,7 +1571,6 @@ row_sel(
|
||||
rec_t* rec;
|
||||
rec_t* old_vers;
|
||||
rec_t* clust_rec;
|
||||
ibool consistent_read;
|
||||
|
||||
/* The following flag becomes TRUE when we are doing a
|
||||
consistent read from a non-clustered index and we must look
|
||||
@@ -1564,21 +1593,11 @@ row_sel(
|
||||
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
rec_offs* offsets = offsets_;
|
||||
rec_offs_init(offsets_);
|
||||
const trx_t* trx = thr_get_trx(thr);
|
||||
|
||||
ut_ad(thr->run_node == node);
|
||||
|
||||
if (node->read_view) {
|
||||
/* In consistent reads, we try to do with the hash index and
|
||||
not to use the buffer page get. This is to reduce memory bus
|
||||
load resulting from semaphore operations. The search latch
|
||||
will be s-locked when we access an index with a unique search
|
||||
condition, but not locked when we access an index with a
|
||||
less selective search condition. */
|
||||
|
||||
consistent_read = TRUE;
|
||||
} else {
|
||||
consistent_read = FALSE;
|
||||
}
|
||||
ut_ad(!node->read_view || node->read_view == &trx->read_view);
|
||||
ut_ad(!node->read_view || node->read_view->is_open());
|
||||
|
||||
table_loop:
|
||||
/* TABLE LOOP
|
||||
@@ -1613,7 +1632,7 @@ table_loop:
|
||||
mtr.start();
|
||||
|
||||
#ifdef BTR_CUR_HASH_ADAPT
|
||||
if (consistent_read && plan->unique_search && !plan->pcur_is_open
|
||||
if (node->read_view && plan->unique_search && !plan->pcur_is_open
|
||||
&& !plan->must_get_clust) {
|
||||
switch (row_sel_try_search_shortcut(node, plan, &mtr)) {
|
||||
case SEL_FOUND:
|
||||
@@ -1658,6 +1677,15 @@ table_loop:
|
||||
}
|
||||
}
|
||||
|
||||
if (!node->read_view
|
||||
|| trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) {
|
||||
} else if (trx_id_t bulk_trx_id = index->table->bulk_trx_id) {
|
||||
/* See row_search_mvcc() for a comment on bulk_trx_id */
|
||||
if (!trx->read_view.changes_visible(bulk_trx_id)) {
|
||||
goto table_exhausted;
|
||||
}
|
||||
}
|
||||
|
||||
rec_loop:
|
||||
/* RECORD LOOP
|
||||
-----------
|
||||
@@ -1689,12 +1717,9 @@ rec_loop:
|
||||
and it might be that these new records should appear in the
|
||||
search result set, resulting in the phantom problem. */
|
||||
|
||||
if (!consistent_read) {
|
||||
if (!node->read_view) {
|
||||
rec_t* next_rec = page_rec_get_next(rec);
|
||||
unsigned lock_type;
|
||||
trx_t* trx;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
offsets = rec_get_offsets(next_rec, index, offsets,
|
||||
true,
|
||||
@@ -1752,16 +1777,13 @@ skip_lock:
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
if (!consistent_read) {
|
||||
if (!node->read_view) {
|
||||
/* Try to place a lock on the index record */
|
||||
unsigned lock_type;
|
||||
trx_t* trx;
|
||||
|
||||
offsets = rec_get_offsets(rec, index, offsets, true,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
/* At READ UNCOMMITTED or READ COMMITTED isolation level,
|
||||
we lock only the record, i.e., next-key locking is
|
||||
not used. */
|
||||
@@ -1845,15 +1867,14 @@ skip_lock:
|
||||
offsets = rec_get_offsets(rec, index, offsets, true,
|
||||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
if (consistent_read) {
|
||||
if (node->read_view) {
|
||||
/* This is a non-locking consistent read: if necessary, fetch
|
||||
a previous version of the record */
|
||||
|
||||
if (dict_index_is_clust(index)) {
|
||||
|
||||
if (!lock_clust_rec_cons_read_sees(
|
||||
rec, index, offsets, node->read_view)) {
|
||||
|
||||
if (!node->read_view->changes_visible(
|
||||
row_get_rec_trx_id(rec, index, offsets),
|
||||
index->table->name)) {
|
||||
err = row_sel_build_prev_vers(
|
||||
node->read_view, index, rec,
|
||||
&offsets, &heap, &plan->old_vers_heap,
|
||||
@@ -1900,11 +1921,12 @@ skip_lock:
|
||||
|
||||
rec = old_vers;
|
||||
}
|
||||
} else if (!srv_read_only_mode
|
||||
&& !lock_sec_rec_cons_read_sees(
|
||||
rec, index, node->read_view)) {
|
||||
|
||||
cons_read_requires_clust_rec = TRUE;
|
||||
} else if (!srv_read_only_mode) {
|
||||
trx_id_t trx_id = page_get_max_trx_id(page_align(rec));
|
||||
ut_ad(trx_id);
|
||||
if (!node->read_view->sees(trx_id)) {
|
||||
cons_read_requires_clust_rec = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1970,7 +1992,7 @@ skip_lock:
|
||||
|
||||
if (clust_rec == NULL) {
|
||||
/* The record did not exist in the read view */
|
||||
ut_ad(consistent_read);
|
||||
ut_ad(node->read_view);
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
@@ -3403,13 +3425,13 @@ Row_sel_get_clust_rec_for_mysql::operator()(
|
||||
|
||||
old_vers = NULL;
|
||||
|
||||
/* If the isolation level allows reading of uncommitted data,
|
||||
then we never look for an earlier version */
|
||||
|
||||
if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
|
||||
&& !lock_clust_rec_cons_read_sees(
|
||||
clust_rec, clust_index, *offsets,
|
||||
&trx->read_view)) {
|
||||
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED
|
||||
|| clust_index->table->is_temporary()) {
|
||||
/* If the isolation level allows reading of
|
||||
uncommitted data, then we never look for an
|
||||
earlier version */
|
||||
} else if (!row_sel_clust_sees(clust_rec, *clust_index,
|
||||
*offsets, trx->read_view)) {
|
||||
const buf_page_t& bpage = btr_pcur_get_block(
|
||||
prebuilt->clust_pcur)->page;
|
||||
|
||||
@@ -3847,8 +3869,10 @@ row_sel_try_search_shortcut_for_mysql(
|
||||
trx_t* trx = prebuilt->trx;
|
||||
const rec_t* rec;
|
||||
|
||||
ut_ad(dict_index_is_clust(index));
|
||||
ut_ad(index->is_primary());
|
||||
ut_ad(!index->table->is_temporary());
|
||||
ut_ad(!prebuilt->templ_contains_blob);
|
||||
ut_ad(trx->read_view.is_open());
|
||||
|
||||
srw_lock* ahi_latch = btr_search_sys.get_latch(*index);
|
||||
ahi_latch->rd_lock(SRW_LOCK_CALL);
|
||||
@@ -3872,14 +3896,21 @@ exhausted:
|
||||
return(SEL_EXHAUSTED);
|
||||
}
|
||||
|
||||
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) {
|
||||
} else if (trx_id_t bulk_trx_id = index->table->bulk_trx_id) {
|
||||
/* See row_search_mvcc() for a comment on bulk_trx_id */
|
||||
if (!trx->read_view.changes_visible(bulk_trx_id)) {
|
||||
goto exhausted;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a non-locking consistent read: if necessary, fetch
|
||||
a previous version of the record */
|
||||
|
||||
*offsets = rec_get_offsets(rec, index, *offsets, true,
|
||||
ULINT_UNDEFINED, heap);
|
||||
|
||||
if (!lock_clust_rec_cons_read_sees(rec, index, *offsets,
|
||||
&trx->read_view)) {
|
||||
if (!row_sel_clust_sees(rec, *index, *offsets, trx->read_view)) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -4413,6 +4444,7 @@ early_not_found:
|
||||
&& unique_search
|
||||
&& btr_search_enabled
|
||||
&& dict_index_is_clust(index)
|
||||
&& !index->table->is_temporary()
|
||||
&& !prebuilt->templ_contains_blob
|
||||
&& !prebuilt->used_in_HANDLER
|
||||
&& (prebuilt->mysql_row_len < srv_page_size / 8)) {
|
||||
@@ -4709,6 +4741,50 @@ wait_table_again:
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the table is supposed to be empty for our read view.
|
||||
|
||||
If we read bulk_trx_id as an older transaction ID, it is not
|
||||
incorrect to check here whether that transaction should be
|
||||
visible to us. If bulk_trx_id is not visible to us, the table
|
||||
must have been empty at an earlier point of time, also in our
|
||||
read view.
|
||||
|
||||
An INSERT would only update bulk_trx_id in
|
||||
row_ins_clust_index_entry_low() if the table really was empty
|
||||
(everything had been purged), when holding a leaf page latch
|
||||
in the clustered index (actually, the root page is the only
|
||||
leaf page in that case).
|
||||
|
||||
We are already holding a leaf page latch here, either
|
||||
in a secondary index or in a clustered index.
|
||||
|
||||
If we are holding a clustered index page latch, there clearly
|
||||
is no potential for race condition with a concurrent INSERT:
|
||||
such INSERT would be blocked by us.
|
||||
|
||||
If we are holding a secondary index page latch, then we are
|
||||
not directly blocking a concurrent INSERT that might update
|
||||
bulk_trx_id to something that does not exist in our read view.
|
||||
But, in that case, the entire table (all indexes) must have
|
||||
been empty. So, even if our read below missed the update of
|
||||
index->table->bulk_trx_id, we can safely proceed to reading
|
||||
the empty secondary index page. Our latch will prevent the
|
||||
INSERT from proceeding to that page. It will first modify
|
||||
the clustered index. Also, we may only look up something in
|
||||
the clustered index if the secondary index page is not empty
|
||||
to begin with. So, only if the table is corrupted
|
||||
(the clustered index is empty but the secondary index is not)
|
||||
we could return corrupted results. */
|
||||
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED
|
||||
|| !trx->read_view.is_open()) {
|
||||
} else if (trx_id_t bulk_trx_id = index->table->bulk_trx_id) {
|
||||
if (!trx->read_view.changes_visible(bulk_trx_id)) {
|
||||
trx->op_info = "";
|
||||
err = DB_END_OF_INDEX;
|
||||
goto normal_return;
|
||||
}
|
||||
}
|
||||
|
||||
rec_loop:
|
||||
DEBUG_SYNC_C("row_search_rec_loop");
|
||||
if (trx_is_interrupted(trx)) {
|
||||
@@ -5136,6 +5212,7 @@ no_gap_lock:
|
||||
a previous version of the record */
|
||||
|
||||
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED
|
||||
|| prebuilt->table->is_temporary()
|
||||
|| prebuilt->table->no_rollback()) {
|
||||
|
||||
/* Do nothing: we let a non-locking SELECT read the
|
||||
@@ -5148,8 +5225,8 @@ no_gap_lock:
|
||||
high force recovery level set, we try to avoid crashes
|
||||
by skipping this lookup */
|
||||
|
||||
if (!lock_clust_rec_cons_read_sees(
|
||||
rec, index, offsets, &trx->read_view)) {
|
||||
if (!row_sel_clust_sees(rec, *index, offsets,
|
||||
trx->read_view)) {
|
||||
ut_ad(srv_force_recovery
|
||||
< SRV_FORCE_NO_UNDO_LOG_SCAN);
|
||||
rec_t* old_vers;
|
||||
@@ -5184,9 +5261,13 @@ no_gap_lock:
|
||||
|
||||
ut_ad(!dict_index_is_clust(index));
|
||||
|
||||
if (!srv_read_only_mode
|
||||
&& !lock_sec_rec_cons_read_sees(
|
||||
rec, index, &trx->read_view)) {
|
||||
if (!srv_read_only_mode) {
|
||||
trx_id_t trx_id = page_get_max_trx_id(
|
||||
page_align(rec));
|
||||
ut_ad(trx_id);
|
||||
if (trx->read_view.sees(trx_id)) {
|
||||
goto locks_ok;
|
||||
}
|
||||
/* We should look at the clustered index.
|
||||
However, as this is a non-locking read,
|
||||
we can skip the clustered index lookup if
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -384,6 +384,7 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked)
|
||||
goto close_table;
|
||||
case TRX_UNDO_INSERT_METADATA:
|
||||
case TRX_UNDO_INSERT_REC:
|
||||
case TRX_UNDO_EMPTY:
|
||||
break;
|
||||
case TRX_UNDO_RENAME_TABLE:
|
||||
dict_table_t* table = node->table;
|
||||
@@ -420,11 +421,16 @@ close_table:
|
||||
clust_index = dict_table_get_first_index(node->table);
|
||||
|
||||
if (clust_index != NULL) {
|
||||
if (node->rec_type == TRX_UNDO_INSERT_REC) {
|
||||
switch (node->rec_type) {
|
||||
case TRX_UNDO_INSERT_REC:
|
||||
ptr = trx_undo_rec_get_row_ref(
|
||||
ptr, clust_index, &node->ref,
|
||||
node->heap);
|
||||
} else {
|
||||
break;
|
||||
case TRX_UNDO_EMPTY:
|
||||
node->ref = nullptr;
|
||||
return true;
|
||||
default:
|
||||
node->ref = &trx_undo_metadata;
|
||||
if (!row_undo_search_clust_to_pcur(node)) {
|
||||
/* An error probably occurred during
|
||||
@@ -596,6 +602,11 @@ row_undo_ins(
|
||||
log_free_check();
|
||||
ut_ad(!node->table->is_temporary());
|
||||
err = row_undo_ins_remove_clust_rec(node);
|
||||
break;
|
||||
case TRX_UNDO_EMPTY:
|
||||
node->table->clear(thr);
|
||||
err = DB_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
dict_table_close(node->table, dict_locked, FALSE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -362,6 +362,12 @@ static bool row_undo_rec_get(undo_node_t* node)
|
||||
mtr.commit();
|
||||
|
||||
switch (trx_undo_rec_get_type(node->undo_rec)) {
|
||||
case TRX_UNDO_EMPTY:
|
||||
/* This record type was introduced in MDEV-515 bulk insert,
|
||||
which was implemented after MDEV-12288 removed the
|
||||
insert_undo log. */
|
||||
ut_ad(undo == update || undo == temp);
|
||||
goto insert_like;
|
||||
case TRX_UNDO_INSERT_METADATA:
|
||||
/* This record type was introduced in MDEV-11369
|
||||
instant ADD COLUMN, which was implemented after
|
||||
@@ -374,6 +380,7 @@ static bool row_undo_rec_get(undo_node_t* node)
|
||||
ut_ad(undo == insert || undo == update);
|
||||
/* fall through */
|
||||
case TRX_UNDO_INSERT_REC:
|
||||
insert_like:
|
||||
ut_ad(undo == insert || undo == update || undo == temp);
|
||||
node->roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS;
|
||||
node->state = undo == temp
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -38,6 +38,7 @@ Created 3/26/1996 Heikki Tuuri
|
||||
#include "trx0rseg.h"
|
||||
#include "row0row.h"
|
||||
#include "row0mysql.h"
|
||||
#include "row0ins.h"
|
||||
|
||||
/** The search tuple corresponding to TRX_UNDO_INSERT_METADATA. */
|
||||
const dtuple_t trx_undo_metadata = {
|
||||
@@ -371,19 +372,24 @@ trx_undo_report_insert_virtual(
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Reports in the undo log of an insert of a clustered index record.
|
||||
/** Reports in the undo log of an insert of a clustered index record.
|
||||
@param undo_block undo log page
|
||||
@param trx transaction
|
||||
@param index clustered index
|
||||
@param clust_entry index entry which will be inserted to the
|
||||
clustered index
|
||||
@param mtr mini-transaction
|
||||
@param write_empty write empty table undo log record
|
||||
@return offset of the inserted entry on the page if succeed, 0 if fail */
|
||||
static
|
||||
uint16_t
|
||||
trx_undo_page_report_insert(
|
||||
/*========================*/
|
||||
buf_block_t* undo_block, /*!< in: undo log page */
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
dict_index_t* index, /*!< in: clustered index */
|
||||
const dtuple_t* clust_entry, /*!< in: index entry which will be
|
||||
inserted to the clustered index */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
buf_block_t* undo_block,
|
||||
trx_t* trx,
|
||||
dict_index_t* index,
|
||||
const dtuple_t* clust_entry,
|
||||
mtr_t* mtr,
|
||||
bool write_empty)
|
||||
{
|
||||
ut_ad(index->is_primary());
|
||||
/* MariaDB 10.3.1+ in trx_undo_page_init() always initializes
|
||||
@@ -411,6 +417,13 @@ trx_undo_page_report_insert(
|
||||
*ptr++ = TRX_UNDO_INSERT_REC;
|
||||
ptr += mach_u64_write_much_compressed(ptr, trx->undo_no);
|
||||
ptr += mach_u64_write_much_compressed(ptr, index->table->id);
|
||||
|
||||
if (write_empty) {
|
||||
/* Table is in bulk operation */
|
||||
undo_block->frame[first_free + 2] = TRX_UNDO_EMPTY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*----------------------------------------*/
|
||||
/* Store then the fields required to uniquely determine the record
|
||||
to be inserted in the clustered index */
|
||||
@@ -488,7 +501,7 @@ trx_undo_rec_get_pars(
|
||||
type_cmpl &= ~TRX_UNDO_UPD_EXTERN;
|
||||
*type = type_cmpl & (TRX_UNDO_CMPL_INFO_MULT - 1);
|
||||
ut_ad(*type >= TRX_UNDO_RENAME_TABLE);
|
||||
ut_ad(*type <= TRX_UNDO_DEL_MARK_REC);
|
||||
ut_ad(*type <= TRX_UNDO_EMPTY);
|
||||
*cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
|
||||
|
||||
*undo_no = mach_read_next_much_compressed(&ptr);
|
||||
@@ -1965,7 +1978,6 @@ trx_undo_report_row_operation(
|
||||
undo log record */
|
||||
{
|
||||
trx_t* trx;
|
||||
mtr_t mtr;
|
||||
#ifdef UNIV_DEBUG
|
||||
int loop_count = 0;
|
||||
#endif /* UNIV_DEBUG */
|
||||
@@ -1981,6 +1993,34 @@ trx_undo_report_row_operation(
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
|
||||
ut_ad(!trx->in_rollback);
|
||||
|
||||
/* We must determine if this is the first time when this
|
||||
transaction modifies this table. */
|
||||
auto m = trx->mod_tables.emplace(index->table, trx->undo_no);
|
||||
ut_ad(m.first->second.valid(trx->undo_no));
|
||||
|
||||
bool bulk = !rec;
|
||||
|
||||
if (!bulk) {
|
||||
/* An UPDATE or DELETE must not be covered by an
|
||||
earlier start_bulk_insert(). */
|
||||
ut_ad(!m.first->second.is_bulk_insert());
|
||||
} else if (m.first->second.is_bulk_insert()) {
|
||||
/* Above, the emplace() tried to insert an object with
|
||||
!is_bulk_insert(). Only an explicit start_bulk_insert()
|
||||
(below) can set the flag. */
|
||||
ut_ad(!m.second);
|
||||
/* We already wrote a TRX_UNDO_EMPTY record. */
|
||||
return DB_SUCCESS;
|
||||
} else if (m.second
|
||||
&& thr->run_node
|
||||
&& que_node_get_type(thr->run_node) == QUE_NODE_INSERT
|
||||
&& static_cast<ins_node_t*>(thr->run_node)->bulk_insert) {
|
||||
m.first->second.start_bulk_insert();
|
||||
} else {
|
||||
bulk = false;
|
||||
}
|
||||
|
||||
mtr_t mtr;
|
||||
mtr.start();
|
||||
trx_undo_t** pundo;
|
||||
trx_rseg_t* rseg;
|
||||
@@ -2002,10 +2042,11 @@ trx_undo_report_row_operation(
|
||||
buf_block_t* undo_block = trx_undo_assign_low(trx, rseg, pundo,
|
||||
&err, &mtr);
|
||||
trx_undo_t* undo = *pundo;
|
||||
|
||||
ut_ad((err == DB_SUCCESS) == (undo_block != NULL));
|
||||
if (UNIV_UNLIKELY(undo_block == NULL)) {
|
||||
goto err_exit;
|
||||
err_exit:
|
||||
mtr.commit();
|
||||
return err;
|
||||
}
|
||||
|
||||
ut_ad(undo != NULL);
|
||||
@@ -2013,7 +2054,8 @@ trx_undo_report_row_operation(
|
||||
do {
|
||||
uint16_t offset = !rec
|
||||
? trx_undo_page_report_insert(
|
||||
undo_block, trx, index, clust_entry, &mtr)
|
||||
undo_block, trx, index, clust_entry, &mtr,
|
||||
bulk)
|
||||
: trx_undo_page_report_modify(
|
||||
undo_block, trx, index, rec, offsets, update,
|
||||
cmpl_info, clust_entry, &mtr);
|
||||
@@ -2051,6 +2093,12 @@ trx_undo_report_row_operation(
|
||||
trx_undo_free_last_page(undo, &mtr);
|
||||
mysql_mutex_unlock(&rseg->mutex);
|
||||
|
||||
if (m.second) {
|
||||
/* We are not going to modify
|
||||
this table after all. */
|
||||
trx->mod_tables.erase(m.first);
|
||||
}
|
||||
|
||||
err = DB_UNDO_RECORD_TOO_BIG;
|
||||
goto err_exit;
|
||||
} else {
|
||||
@@ -2082,28 +2130,24 @@ trx_undo_report_row_operation(
|
||||
ut_ad(!undo->empty());
|
||||
|
||||
if (!is_temp) {
|
||||
const undo_no_t limit = undo->top_undo_no;
|
||||
/* Determine if this is the first time
|
||||
when this transaction modifies a
|
||||
system-versioned column in this table. */
|
||||
trx_mod_table_time_t& time
|
||||
= trx->mod_tables.insert(
|
||||
trx_mod_tables_t::value_type(
|
||||
index->table, limit))
|
||||
.first->second;
|
||||
ut_ad(time.valid(limit));
|
||||
trx_mod_table_time_t& time = m.first->second;
|
||||
ut_ad(time.valid(undo->top_undo_no));
|
||||
|
||||
if (!time.is_versioned()
|
||||
&& index->table->versioned_by_id()
|
||||
&& (!rec /* INSERT */
|
||||
|| (update
|
||||
&& update->affects_versioned()))) {
|
||||
time.set_versioned(limit);
|
||||
time.set_versioned(undo->top_undo_no);
|
||||
}
|
||||
}
|
||||
|
||||
*roll_ptr = trx_undo_build_roll_ptr(
|
||||
!rec, rseg->id, undo->top_page_no, offset);
|
||||
if (!bulk) {
|
||||
*roll_ptr = trx_undo_build_roll_ptr(
|
||||
!rec, rseg->id, undo->top_page_no,
|
||||
offset);
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -2136,10 +2180,7 @@ trx_undo_report_row_operation(
|
||||
|
||||
/* Did not succeed: out of space */
|
||||
err = DB_OUT_OF_FILE_SPACE;
|
||||
|
||||
err_exit:
|
||||
mtr_commit(&mtr);
|
||||
return(err);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2020, MariaDB Corporation.
|
||||
Copyright (c) 2016, 2021, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@@ -137,7 +137,11 @@ inline void trx_t::rollback_low(trx_savept_t *savept)
|
||||
trx_mod_tables_t::iterator j= i++;
|
||||
ut_ad(j->second.valid());
|
||||
if (j->second.rollback(limit))
|
||||
{
|
||||
if (j->second.was_bulk_insert() && !j->first->is_temporary())
|
||||
lock_table_x_unlock(j->first, this);
|
||||
mod_tables.erase(j);
|
||||
}
|
||||
}
|
||||
lock.que_state= TRX_QUE_RUNNING;
|
||||
MONITOR_INC(MONITOR_TRX_ROLLBACK_SAVEPOINT);
|
||||
@@ -536,6 +540,8 @@ trx_savepoint_for_mysql(
|
||||
|
||||
UT_LIST_ADD_LAST(trx->trx_savepoints, savep);
|
||||
|
||||
trx->end_bulk_insert();
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,6 @@ const byte timestamp_max_bytes[7] = {
|
||||
|
||||
static const ulint MAX_DETAILED_ERROR_LEN = 256;
|
||||
|
||||
/** Set of table_id */
|
||||
typedef std::set<
|
||||
table_id_t,
|
||||
std::less<table_id_t>,
|
||||
ut_allocator<table_id_t> > table_id_set;
|
||||
|
||||
/*************************************************************//**
|
||||
Set detailed error message for the transaction. */
|
||||
void
|
||||
@@ -563,9 +557,6 @@ trx_resurrect_table_locks(
|
||||
trx_t* trx, /*!< in/out: transaction */
|
||||
const trx_undo_t* undo) /*!< in: undo log */
|
||||
{
|
||||
mtr_t mtr;
|
||||
table_id_set tables;
|
||||
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED));
|
||||
ut_ad(undo->rseg == trx->rsegs.m_redo.rseg);
|
||||
@@ -574,7 +565,9 @@ trx_resurrect_table_locks(
|
||||
return;
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
mtr_t mtr;
|
||||
std::map<table_id_t, bool> tables;
|
||||
mtr.start();
|
||||
|
||||
/* trx_rseg_mem_create() may have acquired an X-latch on this
|
||||
page, so we cannot acquire an S-latch. */
|
||||
@@ -599,19 +592,19 @@ trx_resurrect_table_locks(
|
||||
trx_undo_rec_get_pars(
|
||||
undo_rec, &type, &cmpl_info,
|
||||
&updated_extern, &undo_no, &table_id);
|
||||
tables.insert(table_id);
|
||||
|
||||
tables.emplace(table_id, type == TRX_UNDO_EMPTY);
|
||||
|
||||
undo_rec = trx_undo_get_prev_rec(
|
||||
block, page_offset(undo_rec), undo->hdr_page_no,
|
||||
undo->hdr_offset, false, &mtr);
|
||||
} while (undo_rec);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
mtr.commit();
|
||||
|
||||
for (table_id_set::const_iterator i = tables.begin();
|
||||
i != tables.end(); i++) {
|
||||
for (auto p : tables) {
|
||||
if (dict_table_t* table = dict_table_open_on_id(
|
||||
*i, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
|
||||
p.first, FALSE, DICT_TABLE_OP_LOAD_TABLESPACE)) {
|
||||
if (!table->is_readable()) {
|
||||
dict_sys.mutex_lock();
|
||||
dict_table_close(table, TRUE, FALSE);
|
||||
@@ -621,11 +614,14 @@ trx_resurrect_table_locks(
|
||||
}
|
||||
|
||||
if (trx->state == TRX_STATE_PREPARED) {
|
||||
trx->mod_tables.insert(
|
||||
trx_mod_tables_t::value_type(table,
|
||||
0));
|
||||
trx->mod_tables.emplace(table, 0);
|
||||
}
|
||||
|
||||
if (p.second) {
|
||||
lock_table_x_resurrect(table, trx);
|
||||
} else {
|
||||
lock_table_ix_resurrect(table, trx);
|
||||
}
|
||||
lock_table_ix_resurrect(table, trx);
|
||||
|
||||
DBUG_LOG("ib_trx",
|
||||
"resurrect " << ib::hex(trx->id)
|
||||
@@ -1230,7 +1226,6 @@ trx_update_mod_tables_timestamp(
|
||||
expensive here */
|
||||
const time_t now = time(NULL);
|
||||
|
||||
trx_mod_tables_t::const_iterator end = trx->mod_tables.end();
|
||||
#if defined SAFE_MUTEX && defined UNIV_DEBUG
|
||||
const bool preserve_tables = !innodb_evict_tables_on_commit_debug
|
||||
|| trx->is_recovered /* avoid trouble with XA recovery */
|
||||
@@ -1242,10 +1237,7 @@ trx_update_mod_tables_timestamp(
|
||||
;
|
||||
#endif
|
||||
|
||||
for (trx_mod_tables_t::const_iterator it = trx->mod_tables.begin();
|
||||
it != end;
|
||||
++it) {
|
||||
|
||||
for (const auto& p : trx->mod_tables) {
|
||||
/* This could be executed by multiple threads concurrently
|
||||
on the same table object. This is fine because time_t is
|
||||
word size or less. And _purely_ _theoretically_, even if
|
||||
@@ -1254,10 +1246,11 @@ trx_update_mod_tables_timestamp(
|
||||
"garbage" in table->update_time is justified because
|
||||
protecting it with a latch here would be too performance
|
||||
intrusive. */
|
||||
dict_table_t* table = it->first;
|
||||
dict_table_t* table = p.first;
|
||||
table->update_time = now;
|
||||
#if defined SAFE_MUTEX && defined UNIV_DEBUG
|
||||
if (preserve_tables || table->get_ref_count()
|
||||
|| table->is_temporary()
|
||||
|| UT_LIST_GET_LEN(table->locks)) {
|
||||
/* do not evict when committing DDL operations
|
||||
or if some other transaction is holding the
|
||||
@@ -1744,6 +1737,7 @@ trx_mark_sql_stat_end(
|
||||
fts_savepoint_laststmt_refresh(trx);
|
||||
}
|
||||
|
||||
trx->end_bulk_insert();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -593,6 +593,9 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
|
||||
inspected = "HA_EXTRA_NO_AUTOINC_LOCKING";
|
||||
break;
|
||||
#endif
|
||||
case HA_EXTRA_IGNORE_INSERT:
|
||||
inspected = "HA_EXTRA_IGNORE_INSERT";
|
||||
break;
|
||||
}
|
||||
return inspected;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user