Merge branch 'bb-10.5-release' into bb-10.6-release

This commit is contained in:
Sergei Golubchik 2023-06-05 18:26:06 +02:00
commit a42a6fa99b
22 changed files with 379 additions and 116 deletions

View file

@ -1,4 +1,4 @@
MYSQL_VERSION_MAJOR=10
MYSQL_VERSION_MINOR=6
MYSQL_VERSION_PATCH=13
MYSQL_VERSION_PATCH=14
SERVER_MATURITY=stable

View file

@ -18331,4 +18331,98 @@ 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 <derived3> 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 <derived3> 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

View file

@ -3973,4 +3973,45 @@ 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

View file

@ -823,5 +823,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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -3573,13 +3573,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);
@ -4869,13 +4862,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);
@ -4887,13 +4873,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);

View file

@ -664,7 +664,8 @@ add_ext_keyuse_for_splitting(Dynamic_array<KEYUSE_EXT> *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;

View file

@ -7897,6 +7897,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");
@ -28988,7 +28989,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);
}

View file

@ -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);

View file

@ -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);
/**

View file

@ -1548,7 +1548,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);
@ -1559,8 +1559,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);
@ -1577,7 +1581,7 @@ static bool srv_purge_should_exit()
return false;
}
return !trx_sys.any_active_transactions();
return !active;
}
/*********************************************************************//**
@ -1719,7 +1723,7 @@ fewer_threads:
break;
}
if (!srv_purge_should_exit())
if (!srv_purge_should_exit(history_size))
goto loop;
}
@ -1915,15 +1919,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();
}
}

View file

@ -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 */
@ -420,12 +407,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;
@ -469,23 +457,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<uint16_t>(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=
@ -613,7 +602,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 +684,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();

View file

@ -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;
}