diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result index 96db48cee61..7afabb4c304 100644 --- a/mysql-test/main/group_min_max.result +++ b/mysql-test/main/group_min_max.result @@ -4204,6 +4204,30 @@ a b s1 2 2 t2:t2a-null;min_t3_b:t3b-null 3 3 t2:1;min_t3_b:3 drop table t1,t2,t3; +# +# MDEV-31380: Assertion `s->table->opt_range_condition_rows <= s->found_records' failed +# (assertion in 10.6+, DBL_MAX costs in 10.5) +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a), KEY(b)) ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; +SET +@tmp=@@optimizer_use_condition_selectivity, +optimizer_use_condition_selectivity = 1, +@tmp2=@@optimizer_trace, +optimizer_trace=1; +SELECT DISTINCT * FROM t1 WHERE a IN (1, 2); +a b +1 1 +2 2 +select +CAST(json_value(json_extract(trace, '$**.chosen_access_method.cost'), '$[0]') +as DOUBLE) < 1.0e100 +from information_schema.optimizer_trace; +CAST(json_value(json_extract(trace, '$**.chosen_access_method.cost'), '$[0]') +as DOUBLE) < 1.0e100 +1 +set optimizer_use_condition_selectivity = @tmp, optimizer_trace=@tmp2; +drop table t1; # # End of 10.5 tests # diff --git a/mysql-test/main/group_min_max.test b/mysql-test/main/group_min_max.test index 9d056473537..5d6f555d33c 100644 --- a/mysql-test/main/group_min_max.test +++ b/mysql-test/main/group_min_max.test @@ -7,6 +7,7 @@ --source include/default_optimizer_switch.inc --source include/have_sequence.inc --source include/have_innodb.inc +--source include/have_sequence.inc # # TODO: # Add queries with: @@ -1859,6 +1860,30 @@ from t1; drop table t1,t2,t3; +--echo # +--echo # MDEV-31380: Assertion `s->table->opt_range_condition_rows <= s->found_records' failed +--echo # (assertion in 10.6+, DBL_MAX costs in 10.5) +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY(a), KEY(b)) ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100; + +SET + @tmp=@@optimizer_use_condition_selectivity, + optimizer_use_condition_selectivity = 1, + @tmp2=@@optimizer_trace, + optimizer_trace=1; + +SELECT DISTINCT * FROM t1 WHERE a IN (1, 2); + +select + CAST(json_value(json_extract(trace, '$**.chosen_access_method.cost'), '$[0]') + as DOUBLE) < 1.0e100 +from information_schema.optimizer_trace; + +set optimizer_use_condition_selectivity = @tmp, optimizer_trace=@tmp2; +drop table t1; + --echo # --echo # End of 10.5 tests --echo # diff --git a/mysql-test/suite/gcol/r/gcol_purge.result b/mysql-test/suite/gcol/r/gcol_purge.result index 11063c7cd6f..a130485f219 100644 --- a/mysql-test/suite/gcol/r/gcol_purge.result +++ b/mysql-test/suite/gcol/r/gcol_purge.result @@ -16,7 +16,7 @@ INSERT INTO t1 (f1, f2) VALUES(1,2); set global debug_dbug="+d,ib_purge_virtual_index_callback"; connection con1; COMMIT; -InnoDB 0 transactions not purged +SET GLOBAL innodb_max_purge_lag_wait=1; connection con2; commit; disconnect con1; diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result index 3f3b2db8f32..89711a2d8bb 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result @@ -78,7 +78,7 @@ SET DEBUG_SYNC= 'now WAIT_FOR uncommitted'; # enable purge COMMIT; # wait for purge to process the deleted records. -InnoDB 0 transactions not purged +InnoDB 1 transactions not purged SET DEBUG_SYNC= 'now SIGNAL purged'; connection default; /* connection default */ ALTER TABLE t1 ADD COLUMN c INT GENERATED ALWAYS AS(a+b), ADD INDEX idx (c), ALGORITHM=INPLACE, LOCK=SHARED; diff --git a/mysql-test/suite/gcol/t/gcol_purge.test b/mysql-test/suite/gcol/t/gcol_purge.test index ecfd89f4469..8fff375cdc2 100644 --- a/mysql-test/suite/gcol/t/gcol_purge.test +++ b/mysql-test/suite/gcol/t/gcol_purge.test @@ -23,7 +23,7 @@ set global debug_dbug="+d,ib_purge_virtual_index_callback"; connection con1; COMMIT; ---source ../innodb/include/wait_all_purged.inc +SET GLOBAL innodb_max_purge_lag_wait=1; connection con2; commit; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test index d9b764a75a7..e7bf8eb485b 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test @@ -113,7 +113,9 @@ SET DEBUG_SYNC= 'now WAIT_FOR uncommitted'; COMMIT; --echo # wait for purge to process the deleted records. +let $wait_all_purged = 1; --source ../../innodb/include/wait_all_purged.inc +let $wait_all_purged = 0; SET DEBUG_SYNC= 'now SIGNAL purged'; diff --git a/mysql-test/suite/innodb/r/cursor-restore-locking.result b/mysql-test/suite/innodb/r/cursor-restore-locking.result index 48263151ceb..6259cfd58ca 100644 --- a/mysql-test/suite/innodb/r/cursor-restore-locking.result +++ b/mysql-test/suite/innodb/r/cursor-restore-locking.result @@ -1,31 +1,34 @@ SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; -CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB; +CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB, STATS_PERSISTENT=0; InnoDB 0 transactions not purged connect prevent_purge,localhost,root,,; start transaction with consistent snapshot; connect con_del_1,localhost,root,,; INSERT INTO t VALUES (20,20); SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_mvcc_finished WAIT_FOR first_del_cont'; -DELETE FROM t WHERE b = 20; +DELETE FROM t WHERE b = 20 # trx_1; connect con_ins_1,localhost,root,,; SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished'; SET DEBUG_SYNC = 'lock_wait_start SIGNAL first_ins_locked'; SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont'; -INSERT INTO t VALUES(10, 20); +INSERT INTO t VALUES(10, 20) # trx_2; connect con_del_2,localhost,root,,; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked'; SET DEBUG_SYNC = 'lock_wait_start SIGNAL second_del_locked'; -DELETE FROM t WHERE b = 20; +DELETE FROM t WHERE b = 20 # trx_3; connection default; SET DEBUG_SYNC = 'now WAIT_FOR second_del_locked'; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="d,enable_row_purge_del_mark_exit_sync_point"; SET DEBUG_SYNC = 'now SIGNAL first_del_cont'; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_row_inserted'; connection con_del_1; connection default; disconnect prevent_purge; -InnoDB 0 transactions not purged +SET DEBUG_SYNC = 'now WAIT_FOR row_purge_del_mark_finished'; +SET @@GLOBAL.debug_dbug = @saved_dbug; SET DEBUG_SYNC = 'now SIGNAL first_ins_cont'; connection con_del_2; connection con_ins_1; diff --git a/mysql-test/suite/innodb/r/dml_purge.result b/mysql-test/suite/innodb/r/dml_purge.result index 38273d571c0..75a5f0fec6c 100644 --- a/mysql-test/suite/innodb/r/dml_purge.result +++ b/mysql-test/suite/innodb/r/dml_purge.result @@ -19,7 +19,7 @@ BEGIN; UPDATE t1 SET b=4 WHERE a=3; disconnect prevent_purge; connection default; -InnoDB 0 transactions not purged +SET GLOBAL innodb_max_purge_lag_wait=1; connection con1; ROLLBACK; disconnect con1; diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 5f74c234260..0b6d44aedc3 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -390,11 +390,12 @@ connection stop_purge; COMMIT; disconnect stop_purge; connection default; -InnoDB 0 transactions not purged +InnoDB 1 transactions not purged SET DEBUG_SYNC='now SIGNAL s2'; connection dml; disconnect dml; connection default; +InnoDB 0 transactions not purged SET DEBUG_SYNC=RESET; DROP TABLE t1; # End of 10.3 tests diff --git a/mysql-test/suite/innodb/r/instant_alter_purge.result b/mysql-test/suite/innodb/r/instant_alter_purge.result index 1179ff62ecc..261356bad12 100644 --- a/mysql-test/suite/innodb/r/instant_alter_purge.result +++ b/mysql-test/suite/innodb/r/instant_alter_purge.result @@ -1,5 +1,6 @@ SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; +InnoDB 0 transactions not purged # # MDEV-17793 Crash in purge after instant DROP and emptying the table # @@ -16,7 +17,7 @@ COMMIT; START TRANSACTION WITH CONSISTENT SNAPSHOT; connection default; ALTER TABLE t1 ADD COLUMN extra TINYINT UNSIGNED NOT NULL DEFAULT 42; -InnoDB 1 transactions not purged +SET GLOBAL innodb_max_purge_lag_wait=1; ALTER TABLE t1 DROP extra; disconnect prevent_purge; InnoDB 0 transactions not purged diff --git a/mysql-test/suite/innodb/t/cursor-restore-locking.test b/mysql-test/suite/innodb/t/cursor-restore-locking.test index f8d00f57a5e..b65d3773ba2 100644 --- a/mysql-test/suite/innodb/t/cursor-restore-locking.test +++ b/mysql-test/suite/innodb/t/cursor-restore-locking.test @@ -5,7 +5,7 @@ source include/have_debug_sync.inc; SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; -CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB; +CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB, STATS_PERSISTENT=0; --source include/wait_all_purged.inc --connect(prevent_purge,localhost,root,,) @@ -14,20 +14,20 @@ start transaction with consistent snapshot; --connect(con_del_1,localhost,root,,) INSERT INTO t VALUES (20,20); SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_mvcc_finished WAIT_FOR first_del_cont'; ---send DELETE FROM t WHERE b = 20 +--send DELETE FROM t WHERE b = 20 # trx_1 --connect(con_ins_1,localhost,root,,) SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished'; # It's supposed the following INSERT will be suspended just after # lock_wait_start syncpoint, and will be awaken -# after the previous DELETE commits. ib_after_row_insert will be executed -# after the INSERT is woken up. The previous DELETE will wait for +# after trx_1 DELETE commits. ib_after_row_insert will be executed +# after the trx_2 INSERT is woken up. The trx_1 DELETE will wait for # first_del_cont signal before commit, and this signal will be sent later. # So it's safe to use two signals in a row here, it's guaranted the first # signal will be received before the second signal is sent. SET DEBUG_SYNC = 'lock_wait_start SIGNAL first_ins_locked'; SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont'; ---send INSERT INTO t VALUES(10, 20) +--send INSERT INTO t VALUES(10, 20) # trx_2 --connect(con_del_2,localhost,root,,) # After MDEV-30225 is fixed, the following DELETE creates next-key lock for @@ -36,24 +36,26 @@ SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR fir SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked'; SET DEBUG_SYNC = 'lock_wait_start SIGNAL second_del_locked'; -############################################################################### -# This DELETE is locked by the previous DELETE, after that DELETE is -# committed, it will still be locked by the next INSERT on delete-marked -# heap_no 2 record. After that INSERT inserted the record with heap_no 3, -# and after heap_no 2 record is purged, this DELETE will be unlocked and +############################################################################## +# trx_3 DELETE is locked by trx_1 DELETE, after trx_1 DELETE is +# committed, it will still be locked by trx_2 INSERT on delete-marked +# heap_no 2 record. After trx_2 INSERT inserted the record with heap_no 3, +# and after heap_no 2 record is purged, trx_3 DELETE will be unlocked and # must restore persistent cursor position at heap_no 3 record, as it has the # same secondary key value as former heap_no 2 record. Then it must be blocked -# by the previous INSERT, and after the INSERT is committed, it must -# delete the record, inserted by the previous INSERT, and the last INSERT(see +# by trx_2 INSERT, and after trx_2 INSERT is committed, it must +# delete the record, inserted by trx_2 INSERT, and trx_4 INSERT(see # below) must be finished without error. But instead this DELETE restores # persistent cursor position to supremum, as a result, it does not delete the -# record, inserted by the previous INSERT, and the last INSERT is finished with +# record, inserted by trx_2 INSERT, and trx_4 INSERT is finished with # duplicate key check error. ############################################################################### ---send DELETE FROM t WHERE b = 20 +--send DELETE FROM t WHERE b = 20 # trx_3 --connection default SET DEBUG_SYNC = 'now WAIT_FOR second_del_locked'; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="d,enable_row_purge_del_mark_exit_sync_point"; SET DEBUG_SYNC = 'now SIGNAL first_del_cont'; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_row_inserted'; --connection con_del_1 @@ -61,7 +63,8 @@ SET DEBUG_SYNC = 'now WAIT_FOR first_ins_row_inserted'; --connection default --disconnect prevent_purge ---source include/wait_all_purged.inc +SET DEBUG_SYNC = 'now WAIT_FOR row_purge_del_mark_finished'; +SET @@GLOBAL.debug_dbug = @saved_dbug; SET DEBUG_SYNC = 'now SIGNAL first_ins_cont'; --connection con_del_2 @@ -74,7 +77,7 @@ SET DEBUG_SYNC = 'now SIGNAL first_ins_cont'; ############################################################################### # Duplicate key error is expected if the bug is not fixed. ############################################################################### -INSERT INTO t VALUES(30, 20); +INSERT INTO t VALUES(30, 20); # trx_4 --disconnect con_ins_1 --disconnect con_del_1 diff --git a/mysql-test/suite/innodb/t/dml_purge.test b/mysql-test/suite/innodb/t/dml_purge.test index 7034939aa4e..c13ff22572b 100644 --- a/mysql-test/suite/innodb/t/dml_purge.test +++ b/mysql-test/suite/innodb/t/dml_purge.test @@ -32,7 +32,7 @@ UPDATE t1 SET b=4 WHERE a=3; --connection default # Initiate a full purge, which should reset the DB_TRX_ID except for a=3. ---source include/wait_all_purged.inc +SET GLOBAL innodb_max_purge_lag_wait=1; # Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3. --connection con1 ROLLBACK; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index c6eca884907..917226a6c26 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -450,7 +450,9 @@ COMMIT; disconnect stop_purge; connection default; +let $wait_all_purged = 1; --source include/wait_all_purged.inc +let $wait_all_purged = 0; SET DEBUG_SYNC='now SIGNAL s2'; connection dml; @@ -458,6 +460,7 @@ reap; disconnect dml; connection default; +--source include/wait_all_purged.inc SET DEBUG_SYNC=RESET; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_purge.test b/mysql-test/suite/innodb/t/instant_alter_purge.test index 9ccf3347d7b..88a56141a1f 100644 --- a/mysql-test/suite/innodb/t/instant_alter_purge.test +++ b/mysql-test/suite/innodb/t/instant_alter_purge.test @@ -6,6 +6,7 @@ if ($have_debug) { SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; +--source include/wait_all_purged.inc --echo # --echo # MDEV-17793 Crash in purge after instant DROP and emptying the table @@ -27,8 +28,7 @@ START TRANSACTION WITH CONSISTENT SNAPSHOT; connection default; ALTER TABLE t1 ADD COLUMN extra TINYINT UNSIGNED NOT NULL DEFAULT 42; -let $wait_all_purged= 1; ---source include/wait_all_purged.inc +SET GLOBAL innodb_max_purge_lag_wait=1; ALTER TABLE t1 DROP extra; disconnect prevent_purge; let $wait_all_purged= 0; diff --git a/mysql-test/suite/innodb/t/purge_secondary.test b/mysql-test/suite/innodb/t/purge_secondary.test index 1a0d178f66a..a7f75f56b53 100644 --- a/mysql-test/suite/innodb/t/purge_secondary.test +++ b/mysql-test/suite/innodb/t/purge_secondary.test @@ -1,6 +1,10 @@ --source include/have_innodb.inc --source include/have_sequence.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Difficult to find free blocks in the buffer pool"); +--enable_query_log + # Ensure that the history list length will actually be decremented by purge. SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3bbb6144c0b..0e09eba5d4a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3030,8 +3030,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, restore_nonrange_trees(¶m, tree, backup_keys); if ((group_trp= get_best_group_min_max(¶m, tree, read_time))) { - param.table->opt_range_condition_rows= MY_MIN(group_trp->records, - head->stat_records()); + set_if_smaller(param.table->opt_range_condition_rows, + group_trp->records); Json_writer_object grp_summary(thd, "best_group_range_summary"); if (unlikely(thd->trace_started())) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0a56c2b691c..d45433fd97c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19422,10 +19422,17 @@ static MYSQL_SYSVAR_ULONG(purge_rseg_truncate_frequency, " purge rollback segment(s) on every Nth iteration of purge invocation", NULL, NULL, 128, 1, 128, 0); +static void innodb_undo_log_truncate_update(THD *thd, struct st_mysql_sys_var*, + void*, const void *save) +{ + if ((srv_undo_log_truncate= *static_cast(save))) + srv_wake_purge_thread_if_not_active(); +} + static MYSQL_SYSVAR_BOOL(undo_log_truncate, srv_undo_log_truncate, PLUGIN_VAR_OPCMDARG, "Enable or Disable Truncate of UNDO tablespace.", - NULL, NULL, FALSE); + NULL, innodb_undo_log_truncate_update, FALSE); static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h index bf6f6eb8eff..79b5c294e2a 100644 --- a/storage/innobase/include/trx0purge.h +++ b/storage/innobase/include/trx0purge.h @@ -39,13 +39,20 @@ Remove the undo log segment from the rseg slot if it is too big for reuse. @param[in,out] mtr mini-transaction */ void trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr); + +/** +Remove unnecessary history data from rollback segments. NOTE that when this +function is called, the caller (purge_coordinator_callback) +must not have any latches on undo log pages! +*/ +void trx_purge_truncate_history(); + /** Run a purge batch. @param n_tasks number of purge tasks to submit to the queue @param history_size trx_sys.history_size() -@param truncate whether to truncate the history at the end of the batch @return number of undo log pages handled in the batch */ -ulint trx_purge(ulint n_tasks, ulint history_size, bool truncate); +ulint trx_purge(ulint n_tasks, ulint history_size); /** Rollback segements from a given transaction with trx-no scheduled for purge. */ @@ -285,6 +292,18 @@ public: typically via purge_sys_t::view_guard. */ return view.low_limit_no(); } + /** A wrapper around ReadView::sees(). */ + trx_id_t sees(trx_id_t id) const + { + /* This function may only be called by purge_coordinator_callback(). + + The purge coordinator task may call this without holding any latch, + because it is the only thread that may modify purge_sys.view. + + Any other threads that access purge_sys.view must hold purge_sys.latch, + typically via purge_sys_t::view_guard. */ + return view.sees(id); + } /** A wrapper around trx_sys_t::clone_oldest_view(). */ template void clone_oldest_view() diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 92403fa739d..ec717e1ded6 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -47,6 +47,7 @@ Created 3/14/1997 Heikki Tuuri #include "handler.h" #include "ha_innodb.h" #include "fil0fil.h" +#include "debug_sync.h" #include /************************************************************************* @@ -631,7 +632,17 @@ row_purge_del_mark( mem_heap_free(heap); } - return row_purge_remove_clust_if_poss(node); + bool result= row_purge_remove_clust_if_poss(node); + +#ifdef ENABLED_DEBUG_SYNC + DBUG_EXECUTE_IF("enable_row_purge_del_mark_exit_sync_point", + debug_sync_set_action + (current_thd, + STRING_WITH_LEN("now SIGNAL row_purge_del_mark_finished")); + ); +#endif + + return result; } void purge_sys_t::wait_SYS() @@ -850,6 +861,9 @@ skip_secondaries: buf_page_get(page_id_t(rseg.space->id, page_no), 0, RW_X_LATCH, &mtr)) { + block->page.set_accessed(); + buf_page_make_young_if_needed(&block->page); + byte* data_field = block->page.frame + offset + internal_offset; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 41ef2bccdc4..8a4df1b0d14 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1296,17 +1296,14 @@ static tpool::waitable_task purge_coordinator_task static tpool::timer *purge_coordinator_timer; /** Wake up the purge threads if there is work to do. */ -void -srv_wake_purge_thread_if_not_active() +void srv_wake_purge_thread_if_not_active() { - ut_ad(!srv_read_only_mode); + ut_ad(!srv_read_only_mode); - if (purge_sys.enabled() && !purge_sys.paused() - && trx_sys.history_exists()) { - if(++purge_state.m_running == 1) { - srv_thread_pool->submit_task(&purge_coordinator_task); - } - } + if (purge_sys.enabled() && !purge_sys.paused() && + (srv_undo_log_truncate || trx_sys.history_exists()) && + ++purge_state.m_running == 1) + srv_thread_pool->submit_task(&purge_coordinator_task); } /** @return whether the purge tasks are active */ @@ -1697,13 +1694,20 @@ fewer_threads: m_history_length= history_size; if (!history_size) + { srv_dml_needed_delay= 0; - else if (trx_purge(n_use_threads, history_size, - !(++count % srv_purge_rseg_truncate_frequency) || - purge_sys.truncate.current || - (srv_shutdown_state != SRV_SHUTDOWN_NONE && - srv_fast_shutdown == 0))) - continue; + trx_purge_truncate_history(); + } + else + { + ulint n_pages_handled= trx_purge(n_use_threads, history_size); + if (!(++count % srv_purge_rseg_truncate_frequency) || + purge_sys.truncate.current || + (srv_shutdown_state != SRV_SHUTDOWN_NONE && srv_fast_shutdown == 0)) + trx_purge_truncate_history(); + if (n_pages_handled) + continue; + } if (srv_dml_needed_delay); else if (m_running == sigcount) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 9537f66ec75..c2fdda33090 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -363,7 +363,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) TRX_UNDO_NEEDS_PURGE, 1U); } - /** Free an undo log segment. @param block rollback segment header page @param mtr mini-transaction */ @@ -561,10 +560,11 @@ __attribute__((optimize(0))) # endif #endif /** -Removes unnecessary history data from rollback segments. NOTE that when this -function is called, the caller must not have any latches on undo log pages! +Remove unnecessary history data from rollback segments. NOTE that when this +function is called, the caller (purge_coordinator_callback) +must not have any latches on undo log pages! */ -TRANSACTIONAL_TARGET static void trx_purge_truncate_history() +TRANSACTIONAL_TARGET void trx_purge_truncate_history() { ut_ad(purge_sys.head <= purge_sys.tail); purge_sys_t::iterator &head= purge_sys.head.trx_no @@ -586,7 +586,7 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head, !rseg.is_referenced() && - rseg.needs_purge <= head.trx_no)) + purge_sys.sees(rseg.needs_purge))) err= e; rseg.latch.wr_unlock(); } @@ -644,7 +644,7 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() rseg.latch.rd_lock(SRW_LOCK_CALL); ut_ad(rseg.skip_allocation()); - if (rseg.is_referenced() || rseg.needs_purge > head.trx_no) + if (rseg.is_referenced() || !purge_sys.sees(rseg.needs_purge)) { not_free: rseg.latch.rd_unlock(); @@ -658,7 +658,7 @@ not_free: for (const trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo; undo= UT_LIST_GET_NEXT(undo_list, undo)) { - if (head.trx_no < undo->trx_id) + if (head.trx_no && head.trx_no < undo->trx_id) goto not_free; else cached+= undo->size; @@ -791,7 +791,7 @@ not_free: continue; ut_ad(!rseg.is_referenced()); - ut_ad(rseg.needs_purge <= head.trx_no); + ut_ad(!head.trx_no || rseg.needs_purge <= head.trx_no); buf_block_t *rblock= trx_rseg_header_create(&space, &rseg - trx_sys.rseg_array, @@ -1264,10 +1264,8 @@ TRANSACTIONAL_INLINE void purge_sys_t::clone_end_view() Run a purge batch. @param n_tasks number of purge tasks to submit to the queue @param history_size trx_sys.history_size() -@param truncate whether to truncate the history at the end of the batch @return number of undo log pages handled in the batch */ -TRANSACTIONAL_TARGET -ulint trx_purge(ulint n_tasks, ulint history_size, bool truncate) +TRANSACTIONAL_TARGET ulint trx_purge(ulint n_tasks, ulint history_size) { que_thr_t* thr = NULL; ulint n_pages_handled; @@ -1319,10 +1317,6 @@ ulint trx_purge(ulint n_tasks, ulint history_size, bool truncate) purge_sys.clone_end_view(); - if (truncate) { - trx_purge_truncate_history(); - } - MONITOR_INC_VALUE(MONITOR_PURGE_INVOKED, 1); MONITOR_INC_VALUE(MONITOR_PURGE_N_PAGE_HANDLED, n_pages_handled);