diff --git a/VERSION b/VERSION index d2c4c84b782..47b4b206e8d 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=9 -MYSQL_VERSION_PATCH=6 +MYSQL_VERSION_PATCH=7 SERVER_MATURITY=stable diff --git a/debian/mariadb-server.mariadb.init b/debian/mariadb-server.mariadb.init index f4051d4b007..3178a5d2244 100644 --- a/debian/mariadb-server.mariadb.init +++ b/debian/mariadb-server.mariadb.init @@ -86,7 +86,7 @@ sanity_checks() { datadir=`mariadbd_get_param datadir` # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024 # 4096 blocks is then lower than 4 MB - df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1` + df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$datadir" | tail -n 1)" if [ "$df_available_blocks" -lt "4096" ]; then log_failure_msg "$0: ERROR: The partition with $datadir is too full!" echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER diff --git a/debian/mariadb-server.preinst b/debian/mariadb-server.preinst index 2204d230bdd..46659344218 100644 --- a/debian/mariadb-server.preinst +++ b/debian/mariadb-server.preinst @@ -210,7 +210,7 @@ fi # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024 # 4096 blocks is then lower than 4 MB -df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1` +df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$mysql_datadir" | tail -n 1)" if [ "$df_available_blocks" -lt "4096" ]; then echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2 db_stop diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 33afb47e4dd..d516e3fe522 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -20787,6 +20787,100 @@ a deallocate prepare stmt; drop view v1; drop table t1; +# +# MDEV-31240: condition pushed into splittable derived has reference to +# outer column and does not refer to any column of embedding +# select +# +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; +create table t3 (a int); +insert into t3 values (3), (1); +analyze table t1, t2, t3 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 2 +3 LATERAL DERIVED t2 ref a a 5 test.t1.a 10 +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=804 +2 1=1056 +3 1=846 +4 1=947 +5 1=973 +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; +analyze table t2 persistent for all; +Table Op Msg_type Msg_text +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status Table is already up to date +explain select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 100 +3 DERIVED t2 ALL a NULL NULL NULL 1000 Using temporary; Using filesort +select +a, +( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +from t1 limit 5; +a ( select concat(t3.a,'=',dt.s) +from +(select a, sum(b) as s from t2 group by a) as dt, +t3 +where dt.a=t1.a and t3.a < 3 +) +1 1=11858 +2 1=11380 +3 1=11588 +4 1=11373 +5 1=11612 +drop table t1,t2,t3; # End of 10.4 tests # # MDEV-28958: condition pushable into view after simplification diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index 06b15f75a0b..7c87785ccc1 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -3973,6 +3973,47 @@ deallocate prepare stmt; drop view v1; drop table t1; +--echo # +--echo # MDEV-31240: condition pushed into splittable derived has reference to +--echo # outer column and does not refer to any column of embedding +--echo # select +--echo # + +create table t1 (a int); +insert into t1 select seq from seq_1_to_1000; + +create table t2 (a int, b int, key (a)); +insert into t2 select mod(seq,100), rand(13) * mod(seq,500) from seq_1_to_1000; + +create table t3 (a int); +insert into t3 values (3), (1); + +analyze table t1, t2, t3 persistent for all; + +let $q= +select + a, + ( select concat(t3.a,'=',dt.s) + from + (select a, sum(b) as s from t2 group by a) as dt, + t3 + where dt.a=t1.a and t3.a < 3 + ) +from t1 limit 5; + +eval explain $q; +eval $q; + +truncate table t2; +insert into t2 select mod(seq,10), rand(15) * mod(seq,500) from seq_1_to_1000; + +analyze table t2 persistent for all; + +eval explain $q; +eval $q; + +drop table t1,t2,t3; + --echo # End of 10.4 tests --echo # diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index aba4f88493c..aba9ae85622 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -839,5 +839,20 @@ SELECT t1.* FROM t1 JOIN (SELECT id, COUNT(*) FROM t2 GROUP BY id) sq ON sq.id= a set optimizer_switch= @tmp1, join_cache_level= @tmp2; DROP TABLE t1, t2; +# +# MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); +a b +DROP VIEW v; +DROP TABLE t1, t2, t3; # End of 10.4 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 6ccbc31d886..bccda42d778 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -466,6 +466,27 @@ set optimizer_switch= @tmp1, join_cache_level= @tmp2; # Cleanup DROP TABLE t1, t2; +--echo # +--echo # MDEV-31403: Server crashes in st_join_table::choose_best_splitting (still) +--echo # +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15); + +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (100),(200); + +CREATE TABLE t3 (c INT, d INT, KEY(c)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,1),(2,2); + +CREATE VIEW v AS SELECT c, d FROM t3 GROUP BY c, d; + +SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); + +# Cleanup +DROP VIEW v; +DROP TABLE t1, t2, t3; + --echo # End of 10.4 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/explain_non_select.result b/mysql-test/main/explain_non_select.result index 03259fff62b..74d8103f130 100644 --- a/mysql-test/main/explain_non_select.result +++ b/mysql-test/main/explain_non_select.result @@ -277,3 +277,22 @@ EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 drop table t1,t2; +# +# MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); +EXPLAIN EXTENDED UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 system NULL NULL NULL NULL 1 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 update `test`.`t1` set `test`.`t2`.`b` = 4 where `test`.`t1`.`a` in (6,2) +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); +SELECT * from t2; +b +4 +DROP TABLE t1, t2; +# End of 10.4 tests diff --git a/mysql-test/main/explain_non_select.test b/mysql-test/main/explain_non_select.test index d9ff0fb7245..f87a5d9ec8d 100644 --- a/mysql-test/main/explain_non_select.test +++ b/mysql-test/main/explain_non_select.test @@ -250,3 +250,23 @@ PREPARE stmt FROM 'EXPLAIN INSERT INTO t1 SELECT * FROM t2'; EXECUTE stmt; drop table t1,t2; +--echo # +--echo # MDEV-31224: EXPLAIN EXTENDED for multi-table update of system table +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3); + +let $q= +UPDATE t1, t2 SET b = 4 WHERE a IN (6,2); + +eval EXPLAIN EXTENDED $q; +eval $q; +SELECT * from t2; + +DROP TABLE t1, t2; + +--echo # End of 10.4 tests diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 210679ba29e..61fa42d1596 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -2689,7 +2689,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Warnings: -Note 1003 update `test`.`t1` set NULL = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 @@ -2734,7 +2734,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 system NULL NULL NULL NULL 0 0.00 Const row not found 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 update `test`.`t1` set NULL = 10 where `test`.`t1`.`c3` = 10 +Note 1003 update `test`.`t1` set `test`.`t2`.`c2` = 10 where `test`.`t1`.`c3` = 10 # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 7 diff --git a/mysql-test/suite/galera/r/MDEV-24143.result b/mysql-test/suite/galera/r/MDEV-24143.result new file mode 100644 index 00000000000..860d8a35834 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-24143.result @@ -0,0 +1,23 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +get_lock ('test2', 0) +1 +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +c1 +INSERT INTO t1 VALUES (4),(3),(1),(2); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +ERROR 42S01: Table 't1' already exists +ALTER TABLE t1 DROP COLUMN c2; +ERROR 42000: Can't DROP COLUMN `c2`; check that it exists +SELECT get_lock ('test', 1.5); +get_lock ('test', 1.5) +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result new file mode 100644 index 00000000000..0ef2a1a72c6 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result @@ -0,0 +1,18 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +connection node_2a; +SELECT GET_LOCK("foo", 1000); +GET_LOCK("foo", 1000) +1 +connection node_2; +SET AUTOCOMMIT=OFF; +INSERT INTO t1 VALUES (1); +SELECT GET_LOCK("foo", 1000);; +connection node_1; +INSERT INTO t1 VALUES (1); +connection node_2; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_locks_funcs.result b/mysql-test/suite/galera/r/galera_locks_funcs.result deleted file mode 100644 index 25d3bbe28f5..00000000000 --- a/mysql-test/suite/galera/r/galera_locks_funcs.result +++ /dev/null @@ -1,24 +0,0 @@ -connection node_2; -connection node_1; -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); -SELECT GET_LOCK('a',1); -ERROR 42000: This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'GET_LOCK in cluster (WSREP_ON=ON)' -SELECT * FROM t; -c c2 -1 1 -SELECT RELEASE_LOCK('a'); -ERROR 42000: This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'RELEASE_LOCK in cluster (WSREP_ON=ON)' -SELECT RELEASE_ALL_LOCKS(); -ERROR 42000: This version of MariaDB doesn't yet support 'RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)' -SHOW WARNINGS; -Level Code Message -Error 1235 This version of MariaDB doesn't yet support 'RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)' -COMMIT; -DROP TABLE t; diff --git a/mysql-test/suite/galera/t/MDEV-24143.test b/mysql-test/suite/galera/t/MDEV-24143.test new file mode 100644 index 00000000000..e58f147cb7c --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-24143.test @@ -0,0 +1,20 @@ +--source include/galera_cluster.inc +--source include/have_sequence.inc + +CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME); +SELECT get_lock ('test2', 0); +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SET SESSION wsrep_trx_fragment_size=10; +SET SESSION autocommit=0; +SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC; +--error ER_LOCK_DEADLOCK +INSERT INTO t1 VALUES (4),(3),(1),(2); +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP COLUMN c2; +SELECT get_lock ('test', 1.5); +DROP TABLE t1; + diff --git a/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test new file mode 100644 index 00000000000..72fc1c5b583 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_get_lock.test @@ -0,0 +1,36 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# Test a local transaction being aborted by a slave one while it is running a GET_LOCK() +# + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; + +--let $galera_connection_name = node_2a +--let $galera_server_number = 2 +--source include/galera_connect.inc +--connection node_2a +SELECT GET_LOCK("foo", 1000); + +--connection node_2 +SET AUTOCOMMIT=OFF; +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` +INSERT INTO t1 VALUES (1); +--send SELECT GET_LOCK("foo", 1000); + +--connection node_1 +INSERT INTO t1 VALUES (1); + +--connection node_2 +--error ER_LOCK_DEADLOCK +--reap + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +# Check that wsrep_local_bf_aborts has been incremented by exactly 1 +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_locks_funcs.test b/mysql-test/suite/galera/t/galera_locks_funcs.test deleted file mode 100644 index 42838e9585c..00000000000 --- a/mysql-test/suite/galera/t/galera_locks_funcs.test +++ /dev/null @@ -1,18 +0,0 @@ ---source include/galera_cluster.inc - -CREATE TABLE t (c DOUBLE,c2 INT,PRIMARY KEY(c)) ENGINE=InnoDB; -INSERT INTO t values (1,1); ---error ER_NOT_SUPPORTED_YET -SELECT GET_LOCK('a',1); -SHOW WARNINGS; -SELECT * FROM t; ---error ER_NOT_SUPPORTED_YET -SELECT RELEASE_LOCK('a'); -SHOW WARNINGS; -# New in 10.5 ---error ER_NOT_SUPPORTED_YET -SELECT RELEASE_ALL_LOCKS(); -SHOW WARNINGS; -COMMIT; -DROP TABLE t; - diff --git a/mysql-test/suite/innodb/r/monitor.result b/mysql-test/suite/innodb/r/monitor.result index 221c92faaea..174fd530c72 100644 --- a/mysql-test/suite/innodb/r/monitor.result +++ b/mysql-test/suite/innodb/r/monitor.result @@ -1,10 +1,9 @@ -set global innodb_monitor_disable = All; select name, if(enabled,'enabled','disabled') status from information_schema.innodb_metrics; name status metadata_table_handles_opened disabled -lock_deadlocks disabled -lock_timeouts disabled +lock_deadlocks enabled +lock_timeouts enabled lock_rec_lock_waits disabled lock_table_lock_waits disabled lock_rec_lock_requests disabled @@ -14,32 +13,32 @@ lock_rec_locks disabled lock_table_lock_created disabled lock_table_lock_removed disabled lock_table_locks disabled -lock_row_lock_current_waits disabled -lock_row_lock_time disabled -lock_row_lock_time_max disabled -lock_row_lock_waits disabled -lock_row_lock_time_avg disabled -buffer_pool_size disabled -buffer_pool_reads disabled -buffer_pool_read_requests disabled -buffer_pool_write_requests disabled -buffer_pool_wait_free disabled -buffer_pool_read_ahead disabled -buffer_pool_read_ahead_evicted disabled -buffer_pool_pages_total disabled -buffer_pool_pages_misc disabled -buffer_pool_pages_data disabled -buffer_pool_bytes_data disabled -buffer_pool_pages_dirty disabled -buffer_pool_bytes_dirty disabled -buffer_pool_pages_free disabled -buffer_pages_created disabled -buffer_pages_written disabled -buffer_pages_read disabled -buffer_index_sec_rec_cluster_reads disabled -buffer_index_sec_rec_cluster_reads_avoided disabled -buffer_data_reads disabled -buffer_data_written disabled +lock_row_lock_current_waits enabled +lock_row_lock_time enabled +lock_row_lock_time_max enabled +lock_row_lock_waits enabled +lock_row_lock_time_avg enabled +buffer_pool_size enabled +buffer_pool_reads enabled +buffer_pool_read_requests enabled +buffer_pool_write_requests enabled +buffer_pool_wait_free enabled +buffer_pool_read_ahead enabled +buffer_pool_read_ahead_evicted enabled +buffer_pool_pages_total enabled +buffer_pool_pages_misc enabled +buffer_pool_pages_data enabled +buffer_pool_bytes_data enabled +buffer_pool_pages_dirty enabled +buffer_pool_bytes_dirty enabled +buffer_pool_pages_free enabled +buffer_pages_created enabled +buffer_pages_written enabled +buffer_pages_read enabled +buffer_index_sec_rec_cluster_reads enabled +buffer_index_sec_rec_cluster_reads_avoided enabled +buffer_data_reads enabled +buffer_data_written enabled buffer_flush_batch_scanned disabled buffer_flush_batch_num_scan disabled buffer_flush_batch_scanned_per_call disabled @@ -72,8 +71,8 @@ buffer_flush_background_pages disabled buffer_LRU_batch_scanned disabled buffer_LRU_batch_num_scan disabled buffer_LRU_batch_scanned_per_call disabled -buffer_LRU_batch_flush_total_pages disabled -buffer_LRU_batch_evict_total_pages disabled +buffer_LRU_batch_flush_total_pages enabled +buffer_LRU_batch_evict_total_pages enabled buffer_LRU_single_flush_failure_count disabled buffer_LRU_get_free_search disabled buffer_LRU_search_scanned disabled @@ -114,21 +113,21 @@ buffer_page_written_blob disabled buffer_page_written_zblob disabled buffer_page_written_zblob2 disabled buffer_page_written_other disabled -os_data_reads disabled -os_data_writes disabled -os_data_fsyncs disabled -os_pending_reads disabled -os_pending_writes disabled -os_log_bytes_written disabled +os_data_reads enabled +os_data_writes enabled +os_data_fsyncs enabled +os_pending_reads enabled +os_pending_writes enabled +os_log_bytes_written enabled trx_rw_commits disabled trx_ro_commits disabled trx_nl_ro_commits disabled trx_commits_insert_update disabled trx_rollbacks disabled trx_rollbacks_savepoint disabled -trx_rseg_history_len disabled +trx_rseg_history_len enabled trx_undo_slots_used disabled -trx_undo_slots_cached disabled +trx_undo_slots_cached enabled trx_rseg_current_size disabled purge_del_mark_records disabled purge_upd_exist_or_extern_records disabled @@ -144,9 +143,9 @@ log_lsn_current disabled log_lsn_checkpoint_age disabled log_lsn_buf_pool_oldest disabled log_max_modified_age_async disabled -log_waits disabled -log_write_requests disabled -log_writes disabled +log_waits enabled +log_write_requests enabled +log_writes enabled compress_pages_compressed disabled compress_pages_decompressed disabled compression_pad_increments disabled @@ -164,42 +163,42 @@ index_page_merge_successful disabled index_page_reorg_attempts disabled index_page_reorg_successful disabled index_page_discards disabled -adaptive_hash_searches disabled -adaptive_hash_searches_btree disabled +adaptive_hash_searches enabled +adaptive_hash_searches_btree enabled adaptive_hash_pages_added disabled adaptive_hash_pages_removed disabled adaptive_hash_rows_added disabled adaptive_hash_rows_removed disabled adaptive_hash_rows_deleted_no_hash_entry disabled adaptive_hash_rows_updated disabled -file_num_open_files disabled -ibuf_merges_insert disabled -ibuf_merges_delete_mark disabled -ibuf_merges_delete disabled -ibuf_merges_discard_insert disabled -ibuf_merges_discard_delete_mark disabled -ibuf_merges_discard_delete disabled -ibuf_merges disabled -ibuf_size disabled +file_num_open_files enabled +ibuf_merges_insert enabled +ibuf_merges_delete_mark enabled +ibuf_merges_delete enabled +ibuf_merges_discard_insert enabled +ibuf_merges_discard_delete_mark enabled +ibuf_merges_discard_delete enabled +ibuf_merges enabled +ibuf_size enabled innodb_master_thread_sleeps disabled -innodb_activity_count disabled +innodb_activity_count enabled innodb_master_active_loops disabled innodb_master_idle_loops disabled innodb_log_flush_usec disabled innodb_dict_lru_usec disabled innodb_dict_lru_count_active disabled innodb_dict_lru_count_idle disabled -innodb_dblwr_writes disabled -innodb_dblwr_pages_written disabled -innodb_page_size disabled +innodb_dblwr_writes enabled +innodb_dblwr_pages_written enabled +innodb_page_size enabled dml_reads disabled -dml_inserts disabled -dml_deletes disabled -dml_updates disabled -dml_system_reads disabled -dml_system_inserts disabled -dml_system_deletes disabled -dml_system_updates disabled +dml_inserts enabled +dml_deletes enabled +dml_updates enabled +dml_system_reads enabled +dml_system_inserts enabled +dml_system_deletes enabled +dml_system_updates enabled ddl_background_drop_indexes disabled ddl_online_create_index disabled ddl_pending_alter_table disabled @@ -209,6 +208,9 @@ icp_attempts disabled icp_no_match disabled icp_out_of_range disabled icp_match disabled +set global innodb_monitor_disable = All; +select name from information_schema.innodb_metrics where enabled; +name set global innodb_monitor_enable = all; select name from information_schema.innodb_metrics where not enabled; name diff --git a/mysql-test/suite/innodb/t/monitor.test b/mysql-test/suite/innodb/t/monitor.test index d6fa3f2fbc9..65a93e5a97a 100644 --- a/mysql-test/suite/innodb/t/monitor.test +++ b/mysql-test/suite/innodb/t/monitor.test @@ -5,12 +5,14 @@ # sys_vars.innodb_monitor_enable_basic --source include/have_innodb.inc -set global innodb_monitor_disable = All; # Test turn on/off the monitor counter with "all" option # By default, they will be off. select name, if(enabled,'enabled','disabled') status from information_schema.innodb_metrics; +set global innodb_monitor_disable = All; +select name from information_schema.innodb_metrics where enabled; + # Turn on all monitor counters set global innodb_monitor_enable = all; diff --git a/mysql-test/suite/innodb_zip/r/page_size.result b/mysql-test/suite/innodb_zip/r/page_size.result index 47effe06884..48b954c945b 100644 --- a/mysql-test/suite/innodb_zip/r/page_size.result +++ b/mysql-test/suite/innodb_zip/r/page_size.result @@ -608,4 +608,25 @@ SET GLOBAL innodb_compression_level=0; INSERT INTO t1 VALUES (''); SET GLOBAL innodb_compression_level= @save_innodb_compression_level; DROP TABLE t1; +# +# MDEV-31158 Assertion ...MTR_MEMO_X_LOCKED in btr_attach_half_pages() +# +SET @save_compression_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +CREATE TEMPORARY TABLE t(a SERIAL, prefix VARBINARY(4), pad INT); +INSERT INTO t(prefix, pad) VALUES +(_binary 0xff,160),('',19),(_binary 0x0001,253),(_binary 0x0b11,169), +(_binary 0x0b010001,23),(_binary 0x0b100001,251),(_binary 0x0d,163), +(_binary 0xb3,254),(_binary 0x96,254),(_binary 0xeb,61), +(_binary 0xf231,253),(_binary 0x1db0,253),(_binary 0x0005,101), +(_binary 0x6370,253),(_binary 0x0b12,112),(_binary 0x0b010002,23), +(_binary 0x0b100002,80),(_binary 0x181984,163),(_binary 0x181926,168), +(_binary 0xe1,176),(_binary 0xe2,187),(_binary 0xe6,254),(_binary 0xbb,51), +(_binary 0x1c,248),(_binary 0x8a,94),(_binary 0x14,254); +CREATE TABLE u(a SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, +b VARBINARY(255), KEY(b)) ENGINE=InnoDB +KEY_BLOCK_SIZE=1 ROW_FORMAT=COMPRESSED; +INSERT INTO u SELECT a,CONCAT(prefix,REPEAT(chr(0),pad)) FROM t; +DROP TABLE u, t; +SET GLOBAL innodb_compression_level=@save_compression_level; # End of 10.6 tests diff --git a/mysql-test/suite/innodb_zip/t/page_size.test b/mysql-test/suite/innodb_zip/t/page_size.test index 16d65a139cf..3455ef8ed94 100644 --- a/mysql-test/suite/innodb_zip/t/page_size.test +++ b/mysql-test/suite/innodb_zip/t/page_size.test @@ -888,4 +888,28 @@ INSERT INTO t1 VALUES (''); SET GLOBAL innodb_compression_level= @save_innodb_compression_level; DROP TABLE t1; +--echo # +--echo # MDEV-31158 Assertion ...MTR_MEMO_X_LOCKED in btr_attach_half_pages() +--echo # +--source include/have_innodb.inc + +SET @save_compression_level=@@GLOBAL.innodb_compression_level; +SET GLOBAL innodb_compression_level=0; +CREATE TEMPORARY TABLE t(a SERIAL, prefix VARBINARY(4), pad INT); +INSERT INTO t(prefix, pad) VALUES +(_binary 0xff,160),('',19),(_binary 0x0001,253),(_binary 0x0b11,169), +(_binary 0x0b010001,23),(_binary 0x0b100001,251),(_binary 0x0d,163), +(_binary 0xb3,254),(_binary 0x96,254),(_binary 0xeb,61), +(_binary 0xf231,253),(_binary 0x1db0,253),(_binary 0x0005,101), +(_binary 0x6370,253),(_binary 0x0b12,112),(_binary 0x0b010002,23), +(_binary 0x0b100002,80),(_binary 0x181984,163),(_binary 0x181926,168), +(_binary 0xe1,176),(_binary 0xe2,187),(_binary 0xe6,254),(_binary 0xbb,51), +(_binary 0x1c,248),(_binary 0x8a,94),(_binary 0x14,254); +CREATE TABLE u(a SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + b VARBINARY(255), KEY(b)) ENGINE=InnoDB + KEY_BLOCK_SIZE=1 ROW_FORMAT=COMPRESSED; +INSERT INTO u SELECT a,CONCAT(prefix,REPEAT(chr(0),pad)) FROM t; +DROP TABLE u, t; +SET GLOBAL innodb_compression_level=@save_compression_level; + --echo # End of 10.6 tests diff --git a/sql/item_create.cc b/sql/item_create.cc index 5d28cfca111..2143ecaf6ac 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3666,13 +3666,6 @@ Create_func_get_lock Create_func_get_lock::s_singleton; Item* Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "GET_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_get_lock(thd, arg1, arg2); @@ -4997,13 +4990,6 @@ Create_func_release_all_locks Create_func_release_all_locks::s_singleton; Item* Create_func_release_all_locks::create_builder(THD *thd) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RELEASE_ALL_LOCKS in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_all_locks(thd); @@ -5015,13 +5001,6 @@ Create_func_release_lock Create_func_release_lock::s_singleton; Item* Create_func_release_lock::create_1_arg(THD *thd, Item *arg1) { -#ifdef WITH_WSREP - if (WSREP_ON && WSREP(thd)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RELEASE_LOCK in cluster (WSREP_ON=ON)"); - return NULL; - } -#endif /* WITH_WSREP */ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_lock(thd, arg1); diff --git a/sql/opt_split.cc b/sql/opt_split.cc index e00a26e3328..43cd5517b6c 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -664,7 +664,8 @@ add_ext_keyuse_for_splitting(Dynamic_array *ext_keyuses, keyuse_ext.cond_guard= added_key_field->cond_guard; keyuse_ext.sj_pred_no= added_key_field->sj_pred_no; keyuse_ext.validity_ref= 0; - keyuse_ext.needed_in_prefix= added_key_field->val->used_tables(); + keyuse_ext.needed_in_prefix= added_key_field->val->used_tables() & + ~(OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); keyuse_ext.validity_var= false; return ext_keyuses->push(keyuse_ext); } @@ -945,6 +946,7 @@ void reset_validity_vars_for_keyuses(KEYUSE_EXT *key_keyuse_ext_start, SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary) { SplM_opt_info *spl_opt_info= table->spl_opt_info; @@ -1042,7 +1044,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, else { table_map last_found= this->table->map; - for (POSITION *pos= &this->join->positions[idx - 1]; ; pos--) + for (const POSITION *pos= &join_positions[idx - 1]; ; pos--) { if (pos->table->table->map & excluded_tables) continue; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 13ce0188247..c53477978ee 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7921,6 +7921,7 @@ best_access_path(JOIN *join, if (s->table->is_splittable()) spl_plan= s->choose_best_splitting(idx, remaining_tables, + join_positions, &spl_pd_boundary); Json_writer_array trace_paths(thd, "considered_access_paths"); @@ -29019,7 +29020,7 @@ void st_select_lex::print_set_clause(THD *thd, String *str, else str->append(','); - item->print(str, query_type); + item->print(str, (enum_query_type) (query_type | QT_NO_DATA_EXPANSION)); str->append(STRING_WITH_LEN(" = ")); val->print(str, query_type); } diff --git a/sql/sql_select.h b/sql/sql_select.h index d5ca921d8d5..455799fec21 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -700,6 +700,7 @@ typedef struct st_join_table { void add_keyuses_for_splitting(); SplM_plan_info *choose_best_splitting(uint idx, table_map remaining_tables, + const POSITION *join_positions, table_map *spl_pd_boundary); bool fix_splitting(SplM_plan_info *spl_plan, table_map excluded_tables, bool is_const_table); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index a33f8f0ee43..59ba6eaa2b4 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -748,18 +748,24 @@ btr_cur_will_modify_tree( /** Detects whether the modifying record might need a opposite modification to the intention. -@param page page -@param lock_intention lock intention for the tree operation +@param bpage buffer pool page +@param is_clust whether this is a clustered index +@param lock_intention lock intention for the tree operation @param node_ptr_max_size the maximum size of a node pointer @param compress_limit BTR_CUR_PAGE_COMPRESS_LIMIT(index) -@param rec record (current node_ptr) -@return true if tree modification is needed */ -static bool btr_cur_need_opposite_intention(const page_t *page, +@param rec record (current node_ptr) +@return true if tree modification is needed */ +static bool btr_cur_need_opposite_intention(const buf_page_t &bpage, + bool is_clust, btr_intention_t lock_intention, ulint node_ptr_max_size, ulint compress_limit, const rec_t *rec) { + if (UNIV_LIKELY_NULL(bpage.zip.data) && + !page_zip_available(&bpage.zip, is_clust, node_ptr_max_size, 1)) + return true; + const page_t *const page= bpage.frame; if (lock_intention != BTR_INTENTION_INSERT) { /* We compensate also for btr_cur_compress_recommendation() */ @@ -1343,7 +1349,8 @@ release_tree: !btr_block_get(*index(), btr_page_get_next(block->page.frame), RW_X_LATCH, false, mtr, &err)) goto func_exit; - if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + if (btr_cur_need_opposite_intention(block->page, index()->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) goto need_opposite_intention; @@ -1399,7 +1406,8 @@ release_tree: default: break; case BTR_MODIFY_TREE: - if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + if (btr_cur_need_opposite_intention(block->page, index()->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) /* If the rec is the first or last in the page for pessimistic @@ -1949,7 +1957,7 @@ index_locked: break; if (!index->lock.have_x() && - btr_cur_need_opposite_intention(block->page.frame, + btr_cur_need_opposite_intention(block->page, index->is_clust(), lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) @@ -1996,7 +2004,8 @@ index_locked: ut_ad(latch_mode != BTR_MODIFY_TREE || upper_rw_latch == RW_X_LATCH); if (latch_mode != BTR_MODIFY_TREE); - else if (btr_cur_need_opposite_intention(block->page.frame, lock_intention, + else if (btr_cur_need_opposite_intention(block->page, index->is_clust(), + lock_intention, node_ptr_max_size, compress_limit, page_cur.rec)) { diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index acfef5daad2..52f31b8cc0a 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2430,6 +2430,7 @@ static void buf_flush_page_cleaner() else if (buf_pool.ran_out()) { buf_pool.page_cleaner_set_idle(false); + buf_pool.get_oldest_modification(0); mysql_mutex_unlock(&buf_pool.flush_list_mutex); n= srv_max_io_capacity; mysql_mutex_lock(&buf_pool.mutex); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8a67192c5da..ed2179bd040 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -945,7 +945,8 @@ static SHOW_VAR innodb_status_variables[]= { {"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T}, {"buffer_pool_read_ahead_evicted", &buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T}, - {"buffer_pool_read_requests", &buf_pool.stat.n_page_gets, SHOW_SIZE_T}, + {"buffer_pool_read_requests", + &export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T}, {"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T}, {"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T}, {"buffer_pool_write_requests", &buf_pool.flush_list_requests, SHOW_SIZE_T}, diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index f02c10b603b..7520dae0dab 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -652,6 +652,8 @@ struct export_var_t{ #ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */ #endif /* UNIV_DEBUG */ + /** buf_pool.stat.n_page_gets (a sharded counter) */ + ulint innodb_buffer_pool_read_requests; ulint innodb_checkpoint_age; ulint innodb_checkpoint_max_age; ulint innodb_data_pending_reads; /*!< Pending reads */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 245b981974b..4ac33a37ecd 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1053,7 +1053,7 @@ public: void close(); /** @return total number of active (non-prepared) transactions */ - ulint any_active_transactions(); + size_t any_active_transactions(size_t *prepared= nullptr); /** diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 30592d1db53..4837cccaf5f 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -686,7 +686,7 @@ static monitor_info_t innodb_counter_info[] = {"trx_rseg_history_len", "transaction", "Length of the TRX_RSEG_HISTORY list", static_cast( - MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT), + MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT | MONITOR_DEFAULT_ON), MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN}, {"trx_undo_slots_used", "transaction", "Number of undo slots used", diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 19632884a00..8c0da639444 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -997,6 +997,9 @@ srv_export_innodb_status(void) export_vars.innodb_data_written = srv_stats.data_written + (dblwr << srv_page_size_shift); + export_vars.innodb_buffer_pool_read_requests + = buf_pool.stat.n_page_gets; + export_vars.innodb_buffer_pool_bytes_data = buf_pool.stat.LRU_bytes + (UT_LIST_GET_LEN(buf_pool.unzip_LRU) @@ -1514,7 +1517,7 @@ void srv_master_callback(void*) } /** @return whether purge should exit due to shutdown */ -static bool srv_purge_should_exit() +static bool srv_purge_should_exit(size_t old_history_size) { ut_ad(srv_shutdown_state <= SRV_SHUTDOWN_CLEANUP); @@ -1525,8 +1528,12 @@ static bool srv_purge_should_exit() return true; /* Slow shutdown was requested. */ + size_t prepared, active= trx_sys.any_active_transactions(&prepared); const size_t history_size= trx_sys.history_size(); - if (history_size) + + if (!history_size); + else if (!active && history_size == old_history_size && prepared); + else { static time_t progress_time; time_t now= time(NULL); @@ -1543,7 +1550,7 @@ static bool srv_purge_should_exit() return false; } - return !trx_sys.any_active_transactions(); + return !active; } /*********************************************************************//** @@ -1686,7 +1693,7 @@ fewer_threads: break; } - if (!srv_purge_should_exit()) + if (!srv_purge_should_exit(history_size)) goto loop; } @@ -1882,15 +1889,19 @@ ulint srv_get_task_queue_length() /** Shut down the purge threads. */ void srv_purge_shutdown() { - if (purge_sys.enabled()) { - if (!srv_fast_shutdown && !opt_bootstrap) - srv_update_purge_thread_count(innodb_purge_threads_MAX); - while(!srv_purge_should_exit()) { - ut_a(!purge_sys.paused()); - srv_wake_purge_thread_if_not_active(); - purge_coordinator_task.wait(); - } - purge_sys.coordinator_shutdown(); - srv_shutdown_purge_tasks(); - } + if (purge_sys.enabled()) + { + if (!srv_fast_shutdown && !opt_bootstrap) + srv_update_purge_thread_count(innodb_purge_threads_MAX); + size_t history_size= trx_sys.history_size(); + while (!srv_purge_should_exit(history_size)) + { + history_size= trx_sys.history_size(); + ut_a(!purge_sys.paused()); + srv_wake_purge_thread_if_not_active(); + purge_coordinator_task.wait(); + } + purge_sys.coordinator_shutdown(); + srv_shutdown_purge_tasks(); + } } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 99263394fef..ce3a5ed89fc 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -369,19 +369,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) undo = NULL; } -MY_ATTRIBUTE((nonnull, warn_unused_result)) -/** Remove undo log header from the history list. -@param[in,out] rseg rollback segment header page -@param[in] log undo log segment header page -@param[in] offset byte offset in the undo log segment header page -@param[in,out] mtr mini-transaction */ -static dberr_t trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log, - uint16_t offset, mtr_t *mtr) -{ - return flst_remove(rseg, TRX_RSEG + TRX_RSEG_HISTORY, log, - uint16_t(offset + TRX_UNDO_HISTORY_NODE), mtr); -} - /** Free an undo log segment. @param block rollback segment header page @param mtr mini-transaction */ @@ -391,7 +378,7 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) block->page.frame, &mtr)) { block->fix(); - const page_id_t id{block->page.id()}; + ut_d(const page_id_t id{block->page.id()}); mtr.commit(); /* NOTE: If the server is killed after the log that was produced up to this point was written, and before the log from the mtr.commit() @@ -403,16 +390,8 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) log_free_check(); mtr.start(); block->page.lock.x_lock(); - if (UNIV_UNLIKELY(block->page.id() != id)) - { - block->unfix(); - block->page.lock.x_unlock(); - block= buf_page_get_gen(id, 0, RW_X_LATCH, nullptr, BUF_GET, &mtr); - if (!block) - return; - } - else - mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); + ut_ad(block->page.id() == id); + mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); } while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + @@ -420,12 +399,13 @@ static void trx_purge_free_segment(buf_block_t *block, mtr_t &mtr) } /** Remove unnecessary history data from a rollback segment. -@param[in,out] rseg rollback segment -@param[in] limit truncate anything before this +@param rseg rollback segment +@param limit truncate anything before this +@param all whether everything can be truncated @return error code */ static dberr_t -trx_purge_truncate_rseg_history(trx_rseg_t& rseg, - const purge_sys_t::iterator& limit) +trx_purge_truncate_rseg_history(trx_rseg_t &rseg, + const purge_sys_t::iterator &limit, bool all) { fil_addr_t hdr_addr; mtr_t mtr; @@ -434,7 +414,6 @@ trx_purge_truncate_rseg_history(trx_rseg_t& rseg, mtr.start(); dberr_t err; -reget: buf_block_t *rseg_hdr= rseg.get(&mtr, &err); if (!rseg_hdr) { @@ -469,23 +448,24 @@ loop: goto func_exit; } + if (!all) + goto func_exit; + fil_addr_t prev_hdr_addr= flst_get_prev_addr(b->page.frame + hdr_addr.boffset + TRX_UNDO_HISTORY_NODE); prev_hdr_addr.boffset= static_cast(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - err= trx_purge_remove_log_hdr(rseg_hdr, b, hdr_addr.boffset, &mtr); + + err= flst_remove(rseg_hdr, TRX_RSEG + TRX_RSEG_HISTORY, b, + uint16_t(hdr_addr.boffset + TRX_UNDO_HISTORY_NODE), &mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) goto func_exit; rseg_hdr->fix(); - if (mach_read_from_2(b->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG) || - rseg.is_referenced() || - rseg.needs_purge > (purge_sys.head.trx_no - ? purge_sys.head.trx_no - : purge_sys.tail.trx_no)) - /* We cannot free the entire undo page. */; + if (mach_read_from_2(b->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) + /* We cannot free the entire undo log segment. */; else { const uint32_t seg_size= @@ -510,9 +490,9 @@ loop: if (undo->hdr_page_no == hdr_addr.page) goto found_cached; ut_ad("inconsistent undo logs" == 0); - break; - found_cached: - UT_LIST_REMOVE(rseg.undo_cached, undo); + if (false) + found_cached: + UT_LIST_REMOVE(rseg.undo_cached, undo); static_assert(FIL_NULL == 0xffffffff, ""); if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rseg_hdr->page.frame))) @@ -535,12 +515,7 @@ loop: log_free_check(); mtr.start(); rseg_hdr->page.lock.x_lock(); - if (UNIV_UNLIKELY(rseg_hdr->page.id() != rseg.page_id())) - { - rseg_hdr->unfix(); - rseg_hdr->page.lock.x_unlock(); - goto reget; - } + ut_ad(rseg_hdr->page.id() == rseg.page_id()); mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); goto loop; @@ -613,7 +588,10 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() { ut_ad(rseg.is_persistent()); rseg.latch.wr_lock(SRW_LOCK_CALL); - if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head)) + if (dberr_t e= + trx_purge_truncate_rseg_history(rseg, head, + !rseg.is_referenced() && + rseg.needs_purge <= head.trx_no)) err= e; rseg.latch.wr_unlock(); } @@ -692,7 +670,8 @@ not_free: } ut_ad(rseg.curr_size > cached); - if (rseg.curr_size > cached + 1) + if (rseg.curr_size > cached + 1 && + (rseg.history_size || srv_fast_shutdown || srv_undo_sources)) goto not_free; rseg.latch.rd_unlock(); @@ -706,6 +685,7 @@ not_free: mtr_t mtr; mtr.start(); mtr.x_lock_space(&space); + const auto space_id= space.id; /* Lock all modified pages of the tablespace. @@ -715,8 +695,8 @@ not_free: mini-transaction commit and the server was killed, then discarding the to-be-trimmed pages without flushing would break crash recovery. */ + rescan: mysql_mutex_lock(&buf_pool.flush_list_mutex); - for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) { ut_ad(bpage->oldest_modification()); @@ -724,46 +704,47 @@ not_free: buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); - if (bpage->id().space() == space.id && - bpage->oldest_modification() != 1) + if (bpage->oldest_modification() > 2 && bpage->id().space() == space_id) { ut_ad(bpage->frame); - auto block= reinterpret_cast(bpage); - if (!bpage->lock.x_lock_try()) + bpage->fix(); { - rescan: - /* Let buf_pool_t::release_freed_page() proceed. */ + /* Try to acquire an exclusive latch while the cache line is + fresh after fix(). */ + const bool got_lock{bpage->lock.x_lock_try()}; + buf_pool.flush_hp.set(prev); mysql_mutex_unlock(&buf_pool.flush_list_mutex); - mysql_mutex_lock(&buf_pool.mutex); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - mysql_mutex_unlock(&buf_pool.mutex); - bpage= UT_LIST_GET_LAST(buf_pool.flush_list); - continue; + if (!got_lock) + bpage->lock.x_lock(); } - buf_pool.flush_hp.set(prev); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index); /* There is no AHI on undo tablespaces. */ + /* There is no AHI on undo tablespaces. */ + ut_ad(!reinterpret_cast(bpage)->index); #endif - bpage->fix(); ut_ad(!bpage->is_io_fixed()); - mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(bpage->id().space() == space_id); - if (bpage->oldest_modification() > 1) + if (bpage->oldest_modification() > 2) { + mtr.memo_push(reinterpret_cast(bpage), + MTR_MEMO_PAGE_X_FIX); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(bpage->oldest_modification() > 2); bpage->reset_oldest_modification(); - mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); } else { bpage->unfix(); bpage->lock.x_unlock(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); } if (prev != buf_pool.flush_hp.get()) - /* Rescan, because we may have lost the position. */ + { + mysql_mutex_unlock(&buf_pool.flush_list_mutex); goto rescan; + } } bpage= prev; diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index ee27e8f51c1..dfc9baa3a16 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -343,15 +343,29 @@ trx_sys_t::close() } /** @return total number of active (non-prepared) transactions */ -ulint trx_sys_t::any_active_transactions() +size_t trx_sys_t::any_active_transactions(size_t *prepared) { - uint32_t total_trx= 0; + size_t total_trx= 0, prepared_trx= 0; - trx_sys.trx_list.for_each([&total_trx](const trx_t &trx) { - if (trx.state == TRX_STATE_COMMITTED_IN_MEMORY || - (trx.state == TRX_STATE_ACTIVE && trx.id)) + trx_sys.trx_list.for_each([&](const trx_t &trx) { + switch (trx.state) { + case TRX_STATE_NOT_STARTED: + break; + case TRX_STATE_ACTIVE: + if (!trx.id) + break; + /* fall through */ + case TRX_STATE_COMMITTED_IN_MEMORY: total_trx++; + break; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + prepared_trx++; + } }); + if (prepared) + *prepared= prepared_trx; + return total_trx; }