diff options
-rw-r--r-- | mysql-test/main/selectivity.result | 56 | ||||
-rw-r--r-- | mysql-test/main/selectivity.test | 32 | ||||
-rw-r--r-- | mysql-test/main/selectivity_innodb.result | 56 | ||||
-rw-r--r-- | mysql-test/suite/binlog_encryption/rpl_corruption.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/rpl/include/rpl_corruption.inc | 8 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_corruption.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_semi_sync_gtid_reconnect.result | 40 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test | 74 | ||||
-rw-r--r-- | scripts/wsrep_sst_mariabackup.sh | 7 | ||||
-rw-r--r-- | sql/sql_repl.cc | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 | ||||
-rw-r--r-- | sql/table.cc | 20 | ||||
-rw-r--r-- | sql/table.h | 1 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 236 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.ic | 55 | ||||
-rw-r--r-- | storage/innobase/include/mtr0types.h | 17 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 40 | ||||
-rw-r--r-- | storage/innobase/mtr/mtr0mtr.cc | 382 |
18 files changed, 543 insertions, 498 deletions
diff --git a/mysql-test/main/selectivity.result b/mysql-test/main/selectivity.result index c548748b242..4366ef6a564 100644 --- a/mysql-test/main/selectivity.result +++ b/mysql-test/main/selectivity.result @@ -1810,5 +1810,61 @@ b a a b 9 9 10 10 set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; drop table t1,t2,t3; +# +# MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4 +# +create table t1 (id int, a int, PRIMARY KEY(id), key(a)); +insert into t1 select seq,seq from seq_1_to_100; +create table t2 (id int, a int, b int, PRIMARY KEY(id), key(a), key(b)); +insert into t2 select seq,seq,seq from seq_1_to_100; +set optimizer_switch='exists_to_in=off'; +set optimizer_use_condition_selectivity=2; +SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id a +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +explain SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where +2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 +2 DEPENDENT SUBQUERY t2 ref a,b a 5 test.A.id 1 Using where +EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1 +1 SIMPLE B ref a a 5 const 1 +explain SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 100 Using where +2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 +2 DEPENDENT SUBQUERY t2 ref a,b a 5 test.A.id 1 Using where +set optimizer_switch= @save_optimizer_switch; +set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +drop table t1,t2; # End of 10.1 tests set @@global.histogram_size=@save_histogram_size; diff --git a/mysql-test/main/selectivity.test b/mysql-test/main/selectivity.test index 3cf4f320994..d0158fb717e 100644 --- a/mysql-test/main/selectivity.test +++ b/mysql-test/main/selectivity.test @@ -1235,6 +1235,38 @@ set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; drop table t1,t2,t3; + +--echo # +--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4 +--echo # + + + +create table t1 (id int, a int, PRIMARY KEY(id), key(a)); +insert into t1 select seq,seq from seq_1_to_100; + +create table t2 (id int, a int, b int, PRIMARY KEY(id), key(a), key(b)); +insert into t2 select seq,seq,seq from seq_1_to_100; + +set optimizer_switch='exists_to_in=off'; +set optimizer_use_condition_selectivity=2; + +let $query= SELECT * FROM t1 + WHERE + EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id + WHERE A.a=t1.a AND t2.b < 20); + +eval $query; +eval explain $query; + +EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65; + +eval explain $query; + +set optimizer_switch= @save_optimizer_switch; +set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +drop table t1,t2; + --echo # End of 10.1 tests # diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result index b293f6adb5f..062b2da7b4f 100644 --- a/mysql-test/main/selectivity_innodb.result +++ b/mysql-test/main/selectivity_innodb.result @@ -1820,6 +1820,62 @@ b a a b 9 9 10 10 set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; drop table t1,t2,t3; +# +# MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4 +# +create table t1 (id int, a int, PRIMARY KEY(id), key(a)); +insert into t1 select seq,seq from seq_1_to_100; +create table t2 (id int, a int, b int, PRIMARY KEY(id), key(a), key(b)); +insert into t2 select seq,seq,seq from seq_1_to_100; +set optimizer_switch='exists_to_in=off'; +set optimizer_use_condition_selectivity=2; +SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id a +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +explain SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index +2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index +2 DEPENDENT SUBQUERY t2 ref a,b a 5 test.A.id 1 Using where +EXPLAIN SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A const PRIMARY,a PRIMARY 4 const 1 +1 SIMPLE B ref a a 5 const 1 Using index +explain SELECT * FROM t1 +WHERE +EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id +WHERE A.a=t1.a AND t2.b < 20); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 5 NULL 100 Using where; Using index +2 DEPENDENT SUBQUERY A ref PRIMARY,a a 5 test.t1.a 1 Using index +2 DEPENDENT SUBQUERY t2 ref a,b a 5 test.A.id 1 Using where +set optimizer_switch= @save_optimizer_switch; +set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +drop table t1,t2; # End of 10.1 tests set @@global.histogram_size=@save_histogram_size; set optimizer_switch=@save_optimizer_switch_for_selectivity_test; diff --git a/mysql-test/suite/binlog_encryption/rpl_corruption.result b/mysql-test/suite/binlog_encryption/rpl_corruption.result index 14a67b3a3a5..25a82fd60cd 100644 --- a/mysql-test/suite/binlog_encryption/rpl_corruption.result +++ b/mysql-test/suite/binlog_encryption/rpl_corruption.result @@ -30,7 +30,7 @@ SET GLOBAL master_verify_checksum=0; SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set"; connection slave; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1913] +include/wait_for_slave_io_error.inc [errno=1595,1743] connection master; SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set"; SET GLOBAL debug_dbug= ""; @@ -39,7 +39,7 @@ SET GLOBAL master_verify_checksum=1; connection slave; SET GLOBAL debug_dbug="+d,corrupt_queue_event"; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1913] +include/wait_for_slave_io_error.inc [errno=1595,1743] SET GLOBAL debug_dbug="-d,corrupt_queue_event"; # 6. Slave. Corruption in relay log SET GLOBAL debug_dbug="+d,corrupt_read_log_event_char"; diff --git a/mysql-test/suite/rpl/include/rpl_corruption.inc b/mysql-test/suite/rpl/include/rpl_corruption.inc index 048a9d74249..1726ee4ba2f 100644 --- a/mysql-test/suite/rpl/include/rpl_corruption.inc +++ b/mysql-test/suite/rpl/include/rpl_corruption.inc @@ -122,11 +122,11 @@ SET GLOBAL master_verify_checksum=0; SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set"; --connection slave START SLAVE IO_THREAD; -# When the checksum error is detected, the slave sets error code 1913 +# When the checksum error is detected, the slave sets error code 1743 # (ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE) in queue_event(), then immediately # sets error 1595 (ER_SLAVE_RELAY_LOG_WRITE_FAILURE) in handle_slave_io(). -# So we usually get 1595, but it is occasionally possible to get 1913. -let $slave_io_errno= 1595,1913; +# So we usually get 1595, but it is occasionally possible to get 1743. +let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE --source include/wait_for_slave_io_error.inc --connection master SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set"; @@ -138,7 +138,7 @@ SET GLOBAL master_verify_checksum=1; --connection slave SET GLOBAL debug_dbug="+d,corrupt_queue_event"; START SLAVE IO_THREAD; -let $slave_io_errno= 1595,1913; +let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE --source include/wait_for_slave_io_error.inc SET GLOBAL debug_dbug="-d,corrupt_queue_event"; diff --git a/mysql-test/suite/rpl/r/rpl_corruption.result b/mysql-test/suite/rpl/r/rpl_corruption.result index 14a67b3a3a5..25a82fd60cd 100644 --- a/mysql-test/suite/rpl/r/rpl_corruption.result +++ b/mysql-test/suite/rpl/r/rpl_corruption.result @@ -30,7 +30,7 @@ SET GLOBAL master_verify_checksum=0; SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set"; connection slave; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1913] +include/wait_for_slave_io_error.inc [errno=1595,1743] connection master; SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set"; SET GLOBAL debug_dbug= ""; @@ -39,7 +39,7 @@ SET GLOBAL master_verify_checksum=1; connection slave; SET GLOBAL debug_dbug="+d,corrupt_queue_event"; START SLAVE IO_THREAD; -include/wait_for_slave_io_error.inc [errno=1595,1913] +include/wait_for_slave_io_error.inc [errno=1595,1743] SET GLOBAL debug_dbug="-d,corrupt_queue_event"; # 6. Slave. Corruption in relay log SET GLOBAL debug_dbug="+d,corrupt_read_log_event_char"; diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_gtid_reconnect.result b/mysql-test/suite/rpl/r/rpl_semi_sync_gtid_reconnect.result new file mode 100644 index 00000000000..4285228f162 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_gtid_reconnect.result @@ -0,0 +1,40 @@ +include/master-slave.inc +[connection master] +connection master; +RESET MASTER; +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +connection slave; +include/stop_slave.inc +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; +include/start_slave.inc +connection master; +CREATE TABLE t1 (a INT); +INSERT INTO t1 SET a = 1; +include/save_master_gtid.inc +FLUSH LOGS; +INSERT INTO t1 SET a = 2; +connection slave; +connection slave; +include/stop_slave_sql.inc +connection master; +INSERT INTO t1 SET a = 3; +include/sync_slave_io_with_master.inc +connection slave; +include/stop_slave_io.inc +connection master; +RESET MASTER; +SET @@global.gtid_binlog_state = '0-1-2'; +connection slave; +CHANGE MASTER TO MASTER_USE_GTID = slave_pos; +SET @@global.gtid_slave_pos = '0-1-2'; +include/start_slave.inc +connection master; +INSERT INTO t1 SET a = 4; +connection master; +DROP TABLE t1; +SET @@GLOBAL. rpl_semi_sync_master_enabled = 0; +connection slave; +include/stop_slave.inc +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 0; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test b/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test new file mode 100644 index 00000000000..96f7e805fc5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test @@ -0,0 +1,74 @@ +source include/not_embedded.inc; +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +# +# Semisync initialization +# +--connection master +RESET MASTER; +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--connection slave +source include/stop_slave.inc; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +# Prove fixes to +# MDEV-19376 Assert (!m_active_tranxs->is_tranx_end_pos(trx_wait_binlog_name...) +# +# +# Run few queries to replicate/execute on slave. +# Stop the slave applier. +# Replicate/not-executed few more. +# Restart the slave. +# +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 SET a = 1; +--source include/save_master_gtid.inc +--let $resume_gtid = $master_pos +FLUSH LOGS; +INSERT INTO t1 SET a = 2; + +--sync_slave_with_master +--connection slave +--source include/stop_slave_sql.inc + +--connection master +INSERT INTO t1 SET a = 3; + +# the sync connection is 'slave' by default +--source include/sync_slave_io_with_master.inc +--connection slave +--source include/stop_slave_io.inc + +--connection master +RESET MASTER; +--eval SET @@global.gtid_binlog_state = '$resume_gtid' + +# The resume gtid is set up to point to the very first binlog file +--connection slave +CHANGE MASTER TO MASTER_USE_GTID = slave_pos; +--eval SET @@global.gtid_slave_pos = '$resume_gtid' +# Yet the slave io first submits the last received binlog file name:pos. +--source include/start_slave.inc + +# Here goes the cracker. +--connection master +INSERT INTO t1 SET a = 4; + +# +# Clean up +# +--connection master +DROP TABLE t1; +--eval SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--sync_slave_with_master +source include/stop_slave.inc; +--eval SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave +source include/start_slave.inc; +--source include/rpl_end.inc diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 36deeff779d..8d1a36561d3 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -83,7 +83,14 @@ fi pcmd="pv $pvopts" declare -a RC +set +e INNOBACKUPEX_BIN=$(which mariabackup) +if test -z $INNOBACKUPEX_BIN +then + wsrep_log_error 'mariabackup binary not found in $PATH' + exit 42 +fi +set -e XBSTREAM_BIN=mbstream XBCRYPT_BIN=xbcrypt # Not available in MariaBackup diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a0f952955d5..9f7413241b6 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2824,7 +2824,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, /* Check if the dump thread is created by a slave with semisync enabled. */ thd->semi_sync_slave = is_semi_sync_slave(); - if (repl_semisync_master.dump_start(thd, log_ident, pos)) + + DBUG_ASSERT(pos == linfo.pos); + + if (repl_semisync_master.dump_start(thd, linfo.log_file_name, linfo.pos)) { info->errmsg= "Failed to run hook 'transmit_start'"; info->error= ER_UNKNOWN_ERROR; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 896135db7be..a05c2f81b10 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9087,7 +9087,6 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, something went wrong. */ sel /= (double)table->quick_rows[key] / (double) table->stat_records(); - // MDEV-20595 FIXME: DBUG_ASSERT(sel > 0 && sel <= 2.0); set_if_smaller(sel, 1.0); used_range_selectivity= true; } @@ -9136,7 +9135,6 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, if (table->field[fldno]->cond_selectivity > 0) { sel /= table->field[fldno]->cond_selectivity; - // MDEV-20595 FIXME: DBUG_ASSERT(sel > 0 && sel <= 2.0); set_if_smaller(sel, 1.0); } /* @@ -9194,7 +9192,6 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, if (field->cond_selectivity > 0) { sel/= field->cond_selectivity; - // MDEV-20595 FIXME: DBUG_ASSERT(sel > 0 && sel <= 2.0); set_if_smaller(sel, 1.0); } break; @@ -9206,7 +9203,6 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, sel*= table_multi_eq_cond_selectivity(join, idx, s, rem_tables, keyparts, ref_keyuse_steps); - DBUG_ASSERT(0.0 < sel && sel <= 1.0); return sel; } diff --git a/sql/table.cc b/sql/table.cc index 9b027a8b31b..0a7d2c9547a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5109,6 +5109,8 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) update_handler= NULL; check_unique_buf= NULL; vers_write= s->versioned; + quick_condition_rows=0; + initialize_quick_structures(); #ifdef HAVE_REPLICATION /* used in RBR Triggers */ master_had_triggers= 0; @@ -9608,3 +9610,21 @@ bool TABLE::export_structure(THD *thd, Row_definition_list *defs) } return false; } + +/* + @brief + Initialize all the quick structures that are used to stored the + estimates when the range optimizer is run. + @details + This is specifically needed when we read the TABLE structure from the + table cache. There can be some garbage data from previous queries + that need to be reset here. +*/ + +void TABLE::initialize_quick_structures() +{ + bzero(quick_rows, sizeof(quick_rows)); + bzero(quick_key_parts, sizeof(quick_key_parts)); + bzero(quick_costs, sizeof(quick_costs)); + bzero(quick_n_ranges, sizeof(quick_n_ranges)); +} diff --git a/sql/table.h b/sql/table.h index 8297774c4d2..700c5f036fd 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1518,6 +1518,7 @@ public: bool is_filled_at_execution(); bool update_const_key_parts(COND *conds); + void initialize_quick_structures(); my_ptrdiff_t default_values_offset() const { return (my_ptrdiff_t) (s->default_values - record[0]); } diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 63878773e05..0dbfc14c68f 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -130,62 +130,7 @@ struct mtr_memo_slot_t { /** Mini-transaction handle and buffer */ struct mtr_t { - - /** State variables of the mtr */ - struct Impl { - - /** memo stack for locks etc. */ - mtr_buf_t m_memo; - - /** mini-transaction log */ - mtr_buf_t m_log; - - /** true if mtr has made at least one buffer pool page dirty */ - bool m_made_dirty; - - /** true if inside ibuf changes */ - bool m_inside_ibuf; - - /** true if the mini-transaction modified buffer pool pages */ - bool m_modifications; - - /** Count of how many page initial log records have been - written to the mtr log */ - ib_uint32_t m_n_log_recs; - - /** specifies which operations should be logged; default - value MTR_LOG_ALL */ - mtr_log_t m_log_mode; -#ifdef UNIV_DEBUG - /** Persistent user tablespace associated with the - mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */ - ulint m_user_space_id; -#endif /* UNIV_DEBUG */ - /** User tablespace that is being modified by the - mini-transaction */ - fil_space_t* m_user_space; - - /** State of the transaction */ - mtr_state_t m_state; - - /** Flush Observer */ - FlushObserver* m_flush_observer; - -#ifdef UNIV_DEBUG - /** For checking corruption. */ - ulint m_magic_n; -#endif /* UNIV_DEBUG */ - - /** Owning mini-transaction */ - mtr_t* m_mtr; - }; - - mtr_t() - { - m_impl.m_state = MTR_STATE_INIT; - } - - ~mtr_t() { } + mtr_t() : m_state(MTR_STATE_INIT) {} /** Start a mini-transaction. */ void start(); @@ -207,14 +152,7 @@ struct mtr_t { /** Return current size of the buffer. @return savepoint */ - ulint get_savepoint() const - MY_ATTRIBUTE((warn_unused_result)) - { - ut_ad(is_active()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - - return(m_impl.m_memo.size()); - } + ulint get_savepoint() const {ut_ad(is_active()); return m_memo.size();} /** Release the (index tree) s-latch stored in an mtr memo after a savepoint. @@ -251,11 +189,11 @@ struct mtr_t { the same set of tablespaces as this one */ void set_spaces(const mtr_t& mtr) { - ut_ad(!m_impl.m_user_space_id); - ut_ad(!m_impl.m_user_space); + ut_ad(!m_user_space_id); + ut_ad(!m_user_space); - ut_d(m_impl.m_user_space_id = mtr.m_impl.m_user_space_id); - m_impl.m_user_space = mtr.m_impl.m_user_space; + ut_d(m_user_space_id = mtr.m_user_space_id); + m_user_space = mtr.m_user_space; } /** Set the tablespace associated with the mini-transaction @@ -264,16 +202,16 @@ struct mtr_t { @return the tablespace */ fil_space_t* set_named_space_id(ulint space_id) { - ut_ad(!m_impl.m_user_space_id); - ut_d(m_impl.m_user_space_id = space_id); + ut_ad(!m_user_space_id); + ut_d(m_user_space_id = space_id); if (!space_id) { return fil_system.sys_space; } else { - ut_ad(m_impl.m_user_space_id == space_id); - ut_ad(!m_impl.m_user_space); - m_impl.m_user_space = fil_space_get(space_id); - ut_ad(m_impl.m_user_space); - return m_impl.m_user_space; + ut_ad(m_user_space_id == space_id); + ut_ad(!m_user_space); + m_user_space = fil_space_get(space_id); + ut_ad(m_user_space); + return m_user_space; } } @@ -282,10 +220,10 @@ struct mtr_t { @param[in] space user or system tablespace */ void set_named_space(fil_space_t* space) { - ut_ad(!m_impl.m_user_space_id); - ut_d(m_impl.m_user_space_id = space->id); + ut_ad(!m_user_space_id); + ut_d(m_user_space_id = space->id); if (space->id) { - m_impl.m_user_space = space; + m_user_space = space; } } @@ -345,18 +283,12 @@ struct mtr_t { void release_page(const void* ptr, mtr_memo_type_t type); /** Note that the mini-transaction has modified data. */ - void set_modified() - { - m_impl.m_modifications = true; - } + void set_modified() { m_modifications = true; } /** Set the state to not-modified. This will not log the changes. This is only used during redo log apply, to avoid logging the changes. */ - void discard_modifications() - { - m_impl.m_modifications = false; - } + void discard_modifications() { m_modifications = false; } /** Get the LSN of commit(). @return the commit LSN @@ -368,45 +300,28 @@ struct mtr_t { } /** Note that we are inside the change buffer code. */ - void enter_ibuf() - { - m_impl.m_inside_ibuf = true; - } + void enter_ibuf() { m_inside_ibuf = true; } /** Note that we have exited from the change buffer code. */ - void exit_ibuf() - { - m_impl.m_inside_ibuf = false; - } + void exit_ibuf() { m_inside_ibuf = false; } /** @return true if we are inside the change buffer code */ - bool is_inside_ibuf() const - { - return(m_impl.m_inside_ibuf); - } + bool is_inside_ibuf() const { return m_inside_ibuf; } /* @return true if the mini-transaction is active */ - bool is_active() const - { - return(m_impl.m_state == MTR_STATE_ACTIVE); - } + bool is_active() const { return m_state == MTR_STATE_ACTIVE; } /** Get flush observer @return flush observer */ - FlushObserver* get_flush_observer() const - { - return(m_impl.m_flush_observer); - } + FlushObserver* get_flush_observer() const { return m_flush_observer; } /** Set flush observer @param[in] observer flush observer */ void set_flush_observer(FlushObserver* observer) { - ut_ad(observer == NULL - || m_impl.m_log_mode == MTR_LOG_NO_REDO); - - m_impl.m_flush_observer = observer; + ut_ad(observer == NULL || m_log_mode == MTR_LOG_NO_REDO); + m_flush_observer = observer; } #ifdef UNIV_DEBUG @@ -446,65 +361,31 @@ struct mtr_t { void print() const; /** @return true if the mini-transaction has committed */ - bool has_committed() const - { - return(m_impl.m_state == MTR_STATE_COMMITTED); - } - - /** @return true if the mini-transaction is committing */ - bool is_committing() const - { - return(m_impl.m_state == MTR_STATE_COMMITTING); - } + bool has_committed() const { return m_state == MTR_STATE_COMMITTED; } /** @return true if mini-transaction contains modifications. */ - bool has_modifications() const - { - return(m_impl.m_modifications); - } + bool has_modifications() const { return m_modifications; } /** @return the memo stack */ - const mtr_buf_t* get_memo() const - { - return(&m_impl.m_memo); - } + const mtr_buf_t* get_memo() const { return &m_memo; } /** @return the memo stack */ - mtr_buf_t* get_memo() - { - return(&m_impl.m_memo); - } + mtr_buf_t* get_memo() { return &m_memo; } #endif /* UNIV_DEBUG */ /** @return true if a record was added to the mini-transaction */ - bool is_dirty() const - { - return(m_impl.m_made_dirty); - } + bool is_dirty() const { return m_made_dirty; } /** Note that a record has been added to the log */ - void added_rec() - { - ++m_impl.m_n_log_recs; - } + void added_rec() { ++m_n_log_recs; } /** Get the buffered redo log of this mini-transaction. @return redo log */ - const mtr_buf_t* get_log() const - { - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - - return(&m_impl.m_log); - } + const mtr_buf_t* get_log() const { return &m_log; } /** Get the buffered redo log of this mini-transaction. @return redo log */ - mtr_buf_t* get_log() - { - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - - return(&m_impl.m_log); - } + mtr_buf_t* get_log() { return &m_log; } /** Push an object to an mtr memo stack. @param object object @@ -518,15 +399,56 @@ struct mtr_t { MY_ATTRIBUTE((warn_unused_result)); private: - class Command; + /** Prepare to write the mini-transaction log to the redo log buffer. + @return number of bytes to write in finish_write() */ + inline ulint prepare_write(); - friend class Command; + /** Append the redo log records to the redo log buffer. + @param[in] len number of bytes to write + @return start_lsn */ + inline lsn_t finish_write(ulint len); -private: - Impl m_impl; + /** Release the resources */ + inline void release_resources(); + + /** memo stack for locks etc. */ + mtr_buf_t m_memo; + + /** mini-transaction log */ + mtr_buf_t m_log; + + /** true if mtr has made at least one buffer pool page dirty */ + bool m_made_dirty; + + /** true if inside ibuf changes */ + bool m_inside_ibuf; + + /** true if the mini-transaction modified buffer pool pages */ + bool m_modifications; + + /** Count of how many page initial log records have been + written to the mtr log */ + ib_uint32_t m_n_log_recs; + + /** specifies which operations should be logged; default + value MTR_LOG_ALL */ + mtr_log_t m_log_mode; +#ifdef UNIV_DEBUG + /** Persistent user tablespace associated with the + mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */ + ulint m_user_space_id; +#endif /* UNIV_DEBUG */ + /** User tablespace that is being modified by the mini-transaction */ + fil_space_t* m_user_space; + + /** State of the transaction */ + mtr_state_t m_state; + + /** Flush Observer */ + FlushObserver* m_flush_observer; /** LSN at commit time */ - volatile lsn_t m_commit_lsn; + lsn_t m_commit_lsn; }; #include "mtr0mtr.ic" diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 99057303c90..7f991269d46 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -49,7 +49,6 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type) ut_ad(object != NULL); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); ut_ad(type <= MTR_MEMO_SX_LOCK); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(ut_is_2pow(type)); /* If this mtr has x-fixed a clean page then we set @@ -58,15 +57,13 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type) can insert the dirtied page to the flush list. */ if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) - && !m_impl.m_made_dirty) { + && !m_made_dirty) { - m_impl.m_made_dirty = is_block_dirtied( + m_made_dirty = is_block_dirtied( reinterpret_cast<const buf_block_t*>(object)); } - mtr_memo_slot_t* slot; - - slot = m_impl.m_memo.push<mtr_memo_slot_t*>(sizeof(*slot)); + mtr_memo_slot_t* slot = m_memo.push<mtr_memo_slot_t*>(sizeof(*slot)); slot->type = type; slot->object = object; @@ -81,11 +78,9 @@ mtr_t::release_s_latch_at_savepoint( rw_lock_t* lock) { ut_ad(is_active()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - - ut_ad(m_impl.m_memo.size() > savepoint); + ut_ad(m_memo.size() > savepoint); - mtr_memo_slot_t* slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint); + mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); ut_ad(slot->object == lock); ut_ad(slot->type == MTR_MEMO_S_LOCK); @@ -104,8 +99,7 @@ mtr_t::sx_latch_at_savepoint( buf_block_t* block) { ut_ad(is_active()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - ut_ad(m_impl.m_memo.size() > savepoint); + ut_ad(m_memo.size() > savepoint); ut_ad(!memo_contains_flagged( block, @@ -113,9 +107,7 @@ mtr_t::sx_latch_at_savepoint( | MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - mtr_memo_slot_t* slot; - - slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint); + mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); ut_ad(slot->object == block); @@ -124,8 +116,8 @@ mtr_t::sx_latch_at_savepoint( rw_lock_sx_lock(&block->lock); - if (!m_impl.m_made_dirty) { - m_impl.m_made_dirty = is_block_dirtied(block); + if (!m_made_dirty) { + m_made_dirty = is_block_dirtied(block); } slot->type = MTR_MEMO_PAGE_SX_FIX; @@ -140,8 +132,7 @@ mtr_t::x_latch_at_savepoint( buf_block_t* block) { ut_ad(is_active()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - ut_ad(m_impl.m_memo.size() > savepoint); + ut_ad(m_memo.size() > savepoint); ut_ad(!memo_contains_flagged( block, @@ -149,9 +140,7 @@ mtr_t::x_latch_at_savepoint( | MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - mtr_memo_slot_t* slot; - - slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint); + mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); ut_ad(slot->object == block); @@ -160,8 +149,8 @@ mtr_t::x_latch_at_savepoint( rw_lock_x_lock(&block->lock); - if (!m_impl.m_made_dirty) { - m_impl.m_made_dirty = is_block_dirtied(block); + if (!m_made_dirty) { + m_made_dirty = is_block_dirtied(block); } slot->type = MTR_MEMO_PAGE_X_FIX; @@ -176,11 +165,8 @@ mtr_t::release_block_at_savepoint( buf_block_t* block) { ut_ad(is_active()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - - mtr_memo_slot_t* slot; - slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint); + mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); ut_a(slot->object == block); @@ -198,10 +184,10 @@ Gets the logging mode of a mini-transaction. mtr_log_t mtr_t::get_log_mode() const { - ut_ad(m_impl.m_log_mode >= MTR_LOG_ALL); - ut_ad(m_impl.m_log_mode <= MTR_LOG_SHORT_INSERTS); + ut_ad(m_log_mode >= MTR_LOG_ALL); + ut_ad(m_log_mode <= MTR_LOG_SHORT_INSERTS); - return(m_impl.m_log_mode); + return m_log_mode; } /** @@ -214,7 +200,7 @@ mtr_t::set_log_mode(mtr_log_t mode) ut_ad(mode >= MTR_LOG_ALL); ut_ad(mode <= MTR_LOG_SHORT_INSERTS); - const mtr_log_t old_mode = m_impl.m_log_mode; + const mtr_log_t old_mode = m_log_mode; switch (old_mode) { case MTR_LOG_NO_REDO: @@ -233,9 +219,8 @@ mtr_t::set_log_mode(mtr_log_t mode) case MTR_LOG_ALL: /* MTR_LOG_NO_REDO can only be set before generating any redo log records. */ - ut_ad(mode != MTR_LOG_NO_REDO - || m_impl.m_n_log_recs == 0); - m_impl.m_log_mode = mode; + ut_ad(mode != MTR_LOG_NO_REDO || m_n_log_recs == 0); + m_log_mode = mode; return(old_mode); } diff --git a/storage/innobase/include/mtr0types.h b/storage/innobase/include/mtr0types.h index 1a4fd590f6e..bf7484b2337 100644 --- a/storage/innobase/include/mtr0types.h +++ b/storage/innobase/include/mtr0types.h @@ -36,18 +36,18 @@ struct mtr_t; /** Logging modes for a mini-transaction */ enum mtr_log_t { /** Default mode: log all operations modifying disk-based data */ - MTR_LOG_ALL = 21, + MTR_LOG_ALL = 0, /** Log no operations and dirty pages are not added to the flush list. Set when applying log in crash recovery or when a modification of a ROW_FORMAT=COMPRESSED page is attempted. */ - MTR_LOG_NONE = 22, + MTR_LOG_NONE, /** Don't generate REDO log but add dirty pages to flush list */ - MTR_LOG_NO_REDO = 23, + MTR_LOG_NO_REDO, /** Inserts are logged in a shorter form */ - MTR_LOG_SHORT_INSERTS = 24 + MTR_LOG_SHORT_INSERTS }; /** @name Log item types @@ -278,15 +278,10 @@ enum mtr_memo_type_t { }; #endif /* !UNIV_CHECKSUM */ -#ifdef UNIV_DEBUG -# define MTR_MAGIC_N 54551 -#endif /* UNIV_DEBUG */ - enum mtr_state_t { MTR_STATE_INIT = 0, - MTR_STATE_ACTIVE = 12231, - MTR_STATE_COMMITTING = 56456, - MTR_STATE_COMMITTED = 34676 + MTR_STATE_ACTIVE, + MTR_STATE_COMMITTED }; #endif /* mtr0types_h */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 422434734fa..9aecee0c217 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -27,7 +27,6 @@ Created 9/20/1997 Heikki Tuuri #include "univ.i" -#include <vector> #include <map> #include <string> #include <my_service_manager.h> @@ -3894,32 +3893,25 @@ recv_recovery_rollback_active(void) @param[in] page_no page number @return page frame @retval NULL if no page was found */ - const byte* recv_dblwr_t::find_page(ulint space_id, ulint page_no) { - std::vector<const byte*, ut_allocator<const byte*> > matches; - const byte* result = 0; - - for (const byte* page : pages) { - if (page_get_space_id(page) == space_id - && page_get_page_no(page) == page_no) { - matches.push_back(page); - } - } - - lsn_t max_lsn = 0; - - for (const byte* page : matches) { - lsn_t page_lsn = mach_read_from_8(page + FIL_PAGE_LSN); - - if (page_lsn > max_lsn) { - max_lsn = page_lsn; - result = page; - } - } - - return(result); + const byte *result= NULL; + lsn_t max_lsn= 0; + + for (const byte *page : pages) + { + if (page_get_page_no(page) != page_no || + page_get_space_id(page) != space_id) + continue; + const lsn_t lsn= mach_read_from_8(page + FIL_PAGE_LSN); + if (lsn <= max_lsn) + continue; + max_lsn= lsn; + result= page; + } + + return result; } #ifndef DBUG_OFF diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 2c255478969..dbaae5e72bd 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -343,6 +343,7 @@ struct ReleaseAll { } }; +#ifdef UNIV_DEBUG /** Check that all slots have been handled. */ struct DebugCheck { /** @return true always. */ @@ -352,6 +353,7 @@ struct DebugCheck { return(true); } }; +#endif /** Release a resource acquired by the mini-transaction. */ struct ReleaseBlocks { @@ -404,59 +406,6 @@ struct ReleaseBlocks { FlushObserver* m_flush_observer; }; -class mtr_t::Command { -public: - /** Constructor. - Takes ownership of the mtr->m_impl, is responsible for deleting it. - @param[in,out] mtr mini-transaction */ - explicit Command(mtr_t* mtr) : m_impl(&mtr->m_impl), m_locks_released() - {} - - /** Destructor */ - ~Command() - { - ut_ad(m_impl == 0); - } - - /** Write the redo log record, add dirty pages to the flush list and - release the resources. */ - void execute(); - - /** Release the blocks used in this mini-transaction. */ - void release_blocks(); - - /** Release the latches acquired by the mini-transaction. */ - void release_latches(); - - /** Release both the latches and blocks used in the mini-transaction. */ - void release_all(); - - /** Release the resources */ - void release_resources(); - - /** Append the redo log records to the redo log buffer. - @param[in] len number of bytes to write */ - void finish_write(ulint len); - -private: - /** Prepare to write the mini-transaction log to the redo log buffer. - @return number of bytes to write in finish_write() */ - ulint prepare_write(); - - /** The mini-transaction state. */ - mtr_t::Impl* m_impl; - - /** Set to 1 after the user thread releases the latches. The log - writer thread must wait for this to be set to 1. */ - volatile ulint m_locks_released; - - /** Start lsn of the possible log entry for this mtr */ - lsn_t m_start_lsn; - - /** End lsn of the possible log entry for this mtr */ - lsn_t m_end_lsn; -}; - /** Write the block contents to the REDO log */ struct mtr_write_log_t { /** Append a block to the redo log buffer. @@ -490,76 +439,75 @@ mtr_write_log( /** Start a mini-transaction. */ void mtr_t::start() { - UNIV_MEM_INVALID(this, sizeof(*this)); - - UNIV_MEM_INVALID(&m_impl, sizeof(m_impl)); - - m_commit_lsn = 0; - - new(&m_impl.m_log) mtr_buf_t(); - new(&m_impl.m_memo) mtr_buf_t(); - - m_impl.m_mtr = this; - m_impl.m_log_mode = MTR_LOG_ALL; - m_impl.m_inside_ibuf = false; - m_impl.m_modifications = false; - m_impl.m_made_dirty = false; - m_impl.m_n_log_recs = 0; - m_impl.m_state = MTR_STATE_ACTIVE; - ut_d(m_impl.m_user_space_id = TRX_SYS_SPACE); - m_impl.m_user_space = NULL; - m_impl.m_flush_observer = NULL; - - ut_d(m_impl.m_magic_n = MTR_MAGIC_N); + UNIV_MEM_INVALID(this, sizeof *this); + + new(&m_memo) mtr_buf_t(); + new(&m_log) mtr_buf_t(); + + m_made_dirty= false; + m_inside_ibuf= false; + m_modifications= false; + m_n_log_recs= 0; + m_log_mode= MTR_LOG_ALL; + ut_d(m_user_space_id= TRX_SYS_SPACE); + m_user_space= NULL; + m_state= MTR_STATE_ACTIVE; + m_flush_observer= NULL; + m_commit_lsn= 0; } /** Release the resources */ -void -mtr_t::Command::release_resources() +inline void mtr_t::release_resources() { - ut_ad(m_impl->m_magic_n == MTR_MAGIC_N); - - /* Currently only used in commit */ - ut_ad(m_impl->m_state == MTR_STATE_COMMITTING); - - ut_d(m_impl->m_memo.for_each_block_in_reverse(CIterate<DebugCheck>())); - - /* Reset the mtr buffers */ - m_impl->m_log.erase(); - - m_impl->m_memo.erase(); - - m_impl->m_state = MTR_STATE_COMMITTED; - - m_impl = 0; + ut_d(m_memo.for_each_block_in_reverse(CIterate<DebugCheck>())); + m_log.erase(); + m_memo.erase(); + m_state= MTR_STATE_COMMITTED; } /** Commit a mini-transaction. */ void mtr_t::commit() { - ut_ad(is_active()); - ut_ad(!is_inside_ibuf()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - m_impl.m_state = MTR_STATE_COMMITTING; + ut_ad(is_active()); + ut_ad(!is_inside_ibuf()); - /* This is a dirty read, for debugging. */ - ut_ad(!m_impl.m_modifications || !recv_no_log_write); + /* This is a dirty read, for debugging. */ + ut_ad(!m_modifications || !recv_no_log_write); + ut_ad(!m_modifications || m_log_mode != MTR_LOG_NONE); - Command cmd(this); + if (m_modifications + && (m_n_log_recs || m_log_mode == MTR_LOG_NO_REDO)) + { + ut_ad(!srv_read_only_mode || m_log_mode == MTR_LOG_NO_REDO); - if (m_impl.m_modifications - && (m_impl.m_n_log_recs > 0 - || m_impl.m_log_mode == MTR_LOG_NO_REDO)) { + lsn_t start_lsn; - ut_ad(!srv_read_only_mode - || m_impl.m_log_mode == MTR_LOG_NO_REDO); + if (const ulint len= prepare_write()) + start_lsn= finish_write(len); + else + start_lsn= m_commit_lsn; - cmd.execute(); - } else { - cmd.release_all(); - cmd.release_resources(); - } + if (m_made_dirty) + log_flush_order_mutex_enter(); + + /* It is now safe to release the log mutex because the + flush_order mutex will ensure that we are the first one + to insert into the flush list. */ + log_mutex_exit(); + + m_memo.for_each_block_in_reverse(CIterate<const ReleaseBlocks> + (ReleaseBlocks(start_lsn, m_commit_lsn, + m_flush_observer))); + if (m_made_dirty) + log_flush_order_mutex_exit(); + + m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>()); + } + else + m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>()); + + release_resources(); } /** Commit a mini-transaction that did not modify any pages, @@ -578,35 +526,31 @@ mtr_t::commit_checkpoint( ut_ad(log_mutex_own()); ut_ad(is_active()); ut_ad(!is_inside_ibuf()); - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(get_log_mode() == MTR_LOG_ALL); - ut_ad(!m_impl.m_made_dirty); - ut_ad(m_impl.m_memo.size() == 0); + ut_ad(!m_made_dirty); + ut_ad(m_memo.size() == 0); ut_ad(!srv_read_only_mode); - ut_d(m_impl.m_state = MTR_STATE_COMMITTING); - ut_ad(write_mlog_checkpoint || m_impl.m_n_log_recs > 1); + ut_ad(write_mlog_checkpoint || m_n_log_recs > 1); - switch (m_impl.m_n_log_recs) { + switch (m_n_log_recs) { case 0: break; case 1: - *m_impl.m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG; + *m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG; break; default: - mlog_catenate_ulint( - &m_impl.m_log, MLOG_MULTI_REC_END, MLOG_1BYTE); + mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END, MLOG_1BYTE); } if (write_mlog_checkpoint) { - byte* ptr = m_impl.m_log.push<byte*>(SIZE_OF_MLOG_CHECKPOINT); + byte* ptr = m_log.push<byte*>(SIZE_OF_MLOG_CHECKPOINT); compile_time_assert(SIZE_OF_MLOG_CHECKPOINT == 1 + 8); *ptr = MLOG_CHECKPOINT; mach_write_to_8(ptr + 1, checkpoint_lsn); } - Command cmd(this); - cmd.finish_write(m_impl.m_log.size()); - cmd.release_resources(); + finish_write(m_log.size()); + release_resources(); if (write_mlog_checkpoint) { DBUG_PRINT("ib_log", @@ -623,8 +567,7 @@ mtr_t::commit_checkpoint( bool mtr_t::is_named_space(ulint space) const { - ut_ad(!m_impl.m_user_space - || m_impl.m_user_space->id != TRX_SYS_SPACE); + ut_ad(!m_user_space || m_user_space->id != TRX_SYS_SPACE); switch (get_log_mode()) { case MTR_LOG_NONE: @@ -632,7 +575,7 @@ mtr_t::is_named_space(ulint space) const return(true); case MTR_LOG_ALL: case MTR_LOG_SHORT_INSERTS: - return(m_impl.m_user_space_id == space + return(m_user_space_id == space || is_predefined_tablespace(space)); } @@ -645,21 +588,19 @@ mtr_t::is_named_space(ulint space) const @return whether the mini-transaction is associated with the space */ bool mtr_t::is_named_space(const fil_space_t* space) const { - ut_ad(!m_impl.m_user_space - || m_impl.m_user_space->id != TRX_SYS_SPACE); - - switch (get_log_mode()) { - case MTR_LOG_NONE: - case MTR_LOG_NO_REDO: - return true; - case MTR_LOG_ALL: - case MTR_LOG_SHORT_INSERTS: - return(m_impl.m_user_space == space - || is_predefined_tablespace(space->id)); - } - - ut_error; - return false; + ut_ad(!m_user_space || m_user_space->id != TRX_SYS_SPACE); + + switch (get_log_mode()) { + case MTR_LOG_NONE: + case MTR_LOG_NO_REDO: + return true; + case MTR_LOG_ALL: + case MTR_LOG_SHORT_INSERTS: + return m_user_space == space || is_predefined_tablespace(space->id); + } + + ut_error; + return false; } #endif /* UNIV_DEBUG */ @@ -674,12 +615,11 @@ mtr_t::x_lock_space(ulint space_id, const char* file, unsigned line) { fil_space_t* space; - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(is_active()); if (space_id == TRX_SYS_SPACE) { space = fil_system.sys_space; - } else if ((space = m_impl.m_user_space) && space_id == space->id) { + } else if ((space = m_user_space) && space_id == space->id) { } else { space = fil_space_get(space_id); ut_ad(get_log_mode() != MTR_LOG_NO_REDO @@ -702,16 +642,15 @@ mtr_t::x_lock_space(ulint space_id, const char* file, unsigned line) bool mtr_t::memo_release(const void* object, ulint type) { - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(is_active()); /* We cannot release a page that has been written to in the middle of a mini-transaction. */ - ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX); + ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX); Iterate<Find> iteration(Find(object, type)); - if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) { + if (!m_memo.for_each_block_in_reverse(iteration)) { memo_slot_release(iteration.functor.m_slot); return(true); } @@ -725,16 +664,15 @@ mtr_t::memo_release(const void* object, ulint type) void mtr_t::release_page(const void* ptr, mtr_memo_type_t type) { - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(is_active()); /* We cannot release a page that has been written to in the middle of a mini-transaction. */ - ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX); + ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX); Iterate<FindPage> iteration(FindPage(ptr, type)); - if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) { + if (!m_memo.for_each_block_in_reverse(iteration)) { memo_slot_release(iteration.functor.get_slot()); return; } @@ -745,27 +683,20 @@ mtr_t::release_page(const void* ptr, mtr_memo_type_t type) /** Prepare to write the mini-transaction log to the redo log buffer. @return number of bytes to write in finish_write() */ -ulint -mtr_t::Command::prepare_write() +inline ulint mtr_t::prepare_write() { ut_ad(!recv_no_log_write); - switch (m_impl->m_log_mode) { - case MTR_LOG_SHORT_INSERTS: - ut_ad(0); - /* fall through */ - case MTR_LOG_NO_REDO: - case MTR_LOG_NONE: - ut_ad(m_impl->m_log.size() == 0); + if (UNIV_UNLIKELY(m_log_mode != MTR_LOG_ALL)) { + ut_ad(m_log_mode == MTR_LOG_NO_REDO); + ut_ad(m_log.size() == 0); log_mutex_enter(); - m_end_lsn = m_start_lsn = log_sys.lsn; - return(0); - case MTR_LOG_ALL: - break; + m_commit_lsn = log_sys.lsn; + return 0; } - ulint len = m_impl->m_log.size(); - ulint n_recs = m_impl->m_n_log_recs; + ulint len = m_log.size(); + ulint n_recs = m_n_log_recs; ut_ad(len > 0); ut_ad(n_recs > 0); @@ -773,9 +704,9 @@ mtr_t::Command::prepare_write() log_buffer_extend(ulong((len + 1) * 2)); } - ut_ad(m_impl->m_n_log_recs == n_recs); + ut_ad(m_n_log_recs == n_recs); - fil_space_t* space = m_impl->m_user_space; + fil_space_t* space = m_user_space; if (space != NULL && is_predefined_tablespace(space->id)) { /* Omit MLOG_FILE_NAME for predefined tablespaces. */ @@ -784,35 +715,32 @@ mtr_t::Command::prepare_write() log_mutex_enter(); - if (fil_names_write_if_was_clean(space, m_impl->m_mtr)) { + if (fil_names_write_if_was_clean(space, this)) { /* This mini-transaction was the first one to modify this tablespace since the latest checkpoint, so some MLOG_FILE_NAME records were appended to m_log. */ - ut_ad(m_impl->m_n_log_recs > n_recs); - mlog_catenate_ulint( - &m_impl->m_log, MLOG_MULTI_REC_END, MLOG_1BYTE); - len = m_impl->m_log.size(); + ut_ad(m_n_log_recs > n_recs); + mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END, MLOG_1BYTE); + len = m_log.size(); } else { /* This was not the first time of dirtying a tablespace since the latest checkpoint. */ - ut_ad(n_recs == m_impl->m_n_log_recs); + ut_ad(n_recs == m_n_log_recs); if (n_recs <= 1) { ut_ad(n_recs == 1); /* Flag the single log record as the only record in this mini-transaction. */ - *m_impl->m_log.front()->begin() - |= MLOG_SINGLE_REC_FLAG; + *m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG; } else { /* Because this mini-transaction comprises multiple log records, append MLOG_MULTI_REC_END at the end. */ - mlog_catenate_ulint( - &m_impl->m_log, MLOG_MULTI_REC_END, - MLOG_1BYTE); + mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END, + MLOG_1BYTE); len++; } } @@ -824,98 +752,37 @@ mtr_t::Command::prepare_write() } /** Append the redo log records to the redo log buffer -@param[in] len number of bytes to write */ -void -mtr_t::Command::finish_write( - ulint len) +@param[in] len number of bytes to write +@return start_lsn */ +inline lsn_t mtr_t::finish_write(ulint len) { - ut_ad(m_impl->m_log_mode == MTR_LOG_ALL); + ut_ad(m_log_mode == MTR_LOG_ALL); ut_ad(log_mutex_own()); - ut_ad(m_impl->m_log.size() == len); + ut_ad(m_log.size() == len); ut_ad(len > 0); - if (m_impl->m_log.is_small()) { - const mtr_buf_t::block_t* front = m_impl->m_log.front(); + lsn_t start_lsn; + + if (m_log.is_small()) { + const mtr_buf_t::block_t* front = m_log.front(); ut_ad(len <= front->used()); - m_end_lsn = log_reserve_and_write_fast( - front->begin(), len, &m_start_lsn); + m_commit_lsn = log_reserve_and_write_fast(front->begin(), len, + &start_lsn); - if (m_end_lsn > 0) { - return; + if (m_commit_lsn) { + return start_lsn; } } /* Open the database log for log_write_low */ - m_start_lsn = log_reserve_and_open(len); + start_lsn = log_reserve_and_open(len); mtr_write_log_t write_log; - m_impl->m_log.for_each_block(write_log); - - m_end_lsn = log_close(); -} - -/** Release the latches and blocks acquired by this mini-transaction */ -void -mtr_t::Command::release_all() -{ - m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>()); - - /* Note that we have released the latches. */ - m_locks_released = 1; -} - -/** Release the latches acquired by this mini-transaction */ -void -mtr_t::Command::release_latches() -{ - m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>()); + m_log.for_each_block(write_log); - /* Note that we have released the latches. */ - m_locks_released = 1; -} - -/** Release the blocks used in this mini-transaction */ -void -mtr_t::Command::release_blocks() -{ - m_impl->m_memo.for_each_block_in_reverse( - CIterate<const ReleaseBlocks>( - ReleaseBlocks(m_start_lsn, m_end_lsn, - m_impl->m_flush_observer))); -} - -/** Write the redo log record, add dirty pages to the flush list and release -the resources. */ -void -mtr_t::Command::execute() -{ - ut_ad(m_impl->m_log_mode != MTR_LOG_NONE); - - if (const ulint len = prepare_write()) { - finish_write(len); - } - - if (m_impl->m_made_dirty) { - log_flush_order_mutex_enter(); - } - - /* It is now safe to release the log mutex because the - flush_order mutex will ensure that we are the first one - to insert into the flush list. */ - log_mutex_exit(); - - m_impl->m_mtr->m_commit_lsn = m_end_lsn; - - release_blocks(); - - if (m_impl->m_made_dirty) { - log_flush_order_mutex_exit(); - } - - release_latches(); - - release_resources(); + m_commit_lsn = log_close(); + return start_lsn; } #ifdef UNIV_DEBUG @@ -1014,10 +881,9 @@ struct FlaggedCheck { bool mtr_t::memo_contains_flagged(const void* ptr, ulint flags) const { - ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); - ut_ad(is_committing() || is_active()); + ut_ad(is_active()); - return !m_impl.m_memo.for_each_block_in_reverse( + return !m_memo.for_each_block_in_reverse( CIterate<FlaggedCheck>(FlaggedCheck(ptr, flags))); } @@ -1033,7 +899,7 @@ mtr_t::memo_contains_page_flagged( ulint flags) const { Iterate<FindPage> iteration(FindPage(ptr, flags)); - return m_impl.m_memo.for_each_block_in_reverse(iteration) + return m_memo.for_each_block_in_reverse(iteration) ? NULL : iteration.functor.get_block(); } @@ -1056,7 +922,7 @@ void mtr_t::print() const { ib::info() << "Mini-transaction handle: memo size " - << m_impl.m_memo.size() << " bytes log size " + << m_memo.size() << " bytes log size " << get_log()->size() << " bytes"; } |