mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-34171: Memory leakage is detected on running the test versioning.partition
One of possible use cases that reproduces the memory leakage listed below: set timestamp= unix_timestamp('2000-01-01 00:00:00'); create or replace table t1 (x int) with system versioning partition by system_time interval 1 hour auto partitions 3; create table t2 (x int); create trigger tr after insert on t2 for each row update t1 set x= 11; create or replace procedure sp2() insert into t2 values (5); set timestamp= unix_timestamp('2000-01-01 04:00:00'); call sp2; set timestamp= unix_timestamp('2000-01-01 13:00:00'); call sp2; # <<=== Memory leak happens there. In case MariaDB server is built with the option -DWITH_PROTECT_STATEMENT_MEMROOT, the second execution would hit assert failure. The reason of leaking a memory is that once a new partition be created the table should be closed and re-opened. It results in calling the function extend_table_list() that indirectly invokes the function sp_add_used_routine() to add routines implicitly used by the statement that makes a new memory allocation. To fix it, don't remove routines and tables the statement implicitly depends on when a table being closed for subsequent re-opening.
This commit is contained in:
@@ -4656,7 +4656,8 @@ restart:
|
||||
have failed to open since closing tables can trigger removal of
|
||||
elements from the table list (if MERGE tables are involved),
|
||||
*/
|
||||
close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp());
|
||||
close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp(),
|
||||
ot_ctx.remove_implicitly_used_deps());
|
||||
|
||||
/*
|
||||
Here we rely on the fact that 'tables' still points to the valid
|
||||
@@ -4724,10 +4725,10 @@ restart:
|
||||
/* F.ex. deadlock happened */
|
||||
if (ot_ctx.can_recover_from_failed_open())
|
||||
{
|
||||
DBUG_ASSERT(ot_ctx.get_action() !=
|
||||
Open_table_context::OT_ADD_HISTORY_PARTITION);
|
||||
DBUG_ASSERT(ot_ctx.remove_implicitly_used_deps());
|
||||
close_tables_for_reopen(thd, start,
|
||||
ot_ctx.start_of_statement_svp());
|
||||
ot_ctx.start_of_statement_svp(),
|
||||
ot_ctx.remove_implicitly_used_deps());
|
||||
if (ot_ctx.recover_from_failed_open())
|
||||
goto error;
|
||||
|
||||
@@ -6017,14 +6018,19 @@ bool restart_trans_for_tables(THD *thd, TABLE_LIST *table)
|
||||
trying to reopen tables. NULL if no metadata locks
|
||||
were held and thus all metadata locks should be
|
||||
released.
|
||||
@param[in] remove_implicit_deps True in case routines and tables implicitly
|
||||
used by a statement should be removed.
|
||||
*/
|
||||
|
||||
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
|
||||
const MDL_savepoint &start_of_statement_svp)
|
||||
const MDL_savepoint &start_of_statement_svp,
|
||||
bool remove_implicit_deps)
|
||||
{
|
||||
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
|
||||
TABLE_LIST *tmp;
|
||||
|
||||
if (remove_implicit_deps)
|
||||
{
|
||||
/*
|
||||
If table list consists only from tables from prelocking set, table list
|
||||
for new attempt should be empty, so we have to update list's root pointer.
|
||||
@@ -6032,12 +6038,14 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
|
||||
if (first_not_own_table == *tables)
|
||||
*tables= 0;
|
||||
thd->lex->chop_off_not_own_tables();
|
||||
|
||||
/* Reset MDL tickets for procedures/functions */
|
||||
for (Sroutine_hash_entry *rt=
|
||||
(Sroutine_hash_entry*)thd->lex->sroutines_list.first;
|
||||
rt; rt= rt->next)
|
||||
rt->mdl_request.ticket= NULL;
|
||||
sp_remove_not_own_routines(thd->lex);
|
||||
}
|
||||
for (tmp= *tables; tmp; tmp= tmp->next_global)
|
||||
{
|
||||
tmp->table= 0;
|
||||
|
@@ -156,7 +156,8 @@ thr_lock_type read_lock_type_for_table(THD *thd,
|
||||
|
||||
my_bool mysql_rm_tmp_tables(void);
|
||||
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
|
||||
const MDL_savepoint &start_of_statement_svp);
|
||||
const MDL_savepoint &start_of_statement_svp,
|
||||
bool remove_implicit_dependencies);
|
||||
bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
|
||||
LEX_CSTRING *table, thr_lock_type lock_type);
|
||||
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
@@ -566,9 +567,21 @@ public:
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
enum_open_table_action get_action() const
|
||||
/**
|
||||
Return true in case tables and routines the statement implicilty
|
||||
dependent on should be removed, else return false.
|
||||
|
||||
@note The use case when routines and tables the statement implicitly
|
||||
dependent on shouldn't be removed is the one when a new partition be
|
||||
created on handling the INSERT statement against a versioning partitioned
|
||||
table. For this case re-opening a versioning table would result in adding
|
||||
implicitly dependent routines (e.g. table's triggers) that lead to
|
||||
allocation of memory on PS mem_root and so leaking a memory until the PS
|
||||
statement be deallocated.
|
||||
*/
|
||||
bool remove_implicitly_used_deps() const
|
||||
{
|
||||
return m_action;
|
||||
return m_action != OT_ADD_HISTORY_PARTITION;
|
||||
}
|
||||
|
||||
uint get_flags() const { return m_flags; }
|
||||
|
@@ -2945,7 +2945,7 @@ retry:
|
||||
Deadlock occurred during upgrade of metadata lock.
|
||||
Let us restart acquring and opening tables for LOCK TABLES.
|
||||
*/
|
||||
close_tables_for_reopen(thd, &tables, mdl_savepoint);
|
||||
close_tables_for_reopen(thd, &tables, mdl_savepoint, true);
|
||||
if (thd->open_temporary_tables(tables))
|
||||
goto err;
|
||||
goto retry;
|
||||
|
Reference in New Issue
Block a user