mirror of
https://github.com/MariaDB/server.git
synced 2025-08-05 13:16:09 +03:00
Fixed wrong assignment in calculate_block_sizes() for MEM_ROOT
The effect was that that ROOT_FLAG_THREAD_SPECIFIC was cleared and the memory allocated by memroot would be contributed the the system, not to the thread. This exposed a bug in how "show explain for ..." allocated data. - The thread that did provide the explain allocated data in the "show explain" threads mem_root, which is marked as THREAD_SPECIFIC. - Fixed by allocating the explain data in a temporary explain_mem_root which is not THREAD_SPECIFIC. Other things: - Added extra checks when using update_malloc_size() - Do not call update_malloc_size() for memory not registered with update_malloc_size(). This avoid some wrong 'memory not freed' reports. - Added a checking of 'thd->killed' to ensure that main.truncate_notembedded.test still works. Reported by: Yury Chaikou
This commit is contained in:
@@ -99,7 +99,7 @@ static void calculate_block_sizes(MEM_ROOT *mem_root, size_t block_size,
|
|||||||
{
|
{
|
||||||
size_t pre_alloc= *pre_alloc_size;
|
size_t pre_alloc= *pre_alloc_size;
|
||||||
|
|
||||||
if (mem_root->flags&= ROOT_FLAG_MPROTECT)
|
if (mem_root->flags & ROOT_FLAG_MPROTECT)
|
||||||
{
|
{
|
||||||
mem_root->block_size= MY_ALIGN(block_size, my_system_page_size);
|
mem_root->block_size= MY_ALIGN(block_size, my_system_page_size);
|
||||||
if (pre_alloc)
|
if (pre_alloc)
|
||||||
@@ -159,6 +159,8 @@ void init_alloc_root(PSI_memory_key key, MEM_ROOT *mem_root, size_t block_size,
|
|||||||
mem_root->min_malloc= 32 + REDZONE_SIZE;
|
mem_root->min_malloc= 32 + REDZONE_SIZE;
|
||||||
mem_root->block_size= MY_MAX(block_size, ROOT_MIN_BLOCK_SIZE);
|
mem_root->block_size= MY_MAX(block_size, ROOT_MIN_BLOCK_SIZE);
|
||||||
mem_root->flags= 0;
|
mem_root->flags= 0;
|
||||||
|
DBUG_ASSERT(!test_all_bits(mem_root->flags,
|
||||||
|
(MY_THREAD_SPECIFIC | MY_ROOT_USE_MPROTECT)));
|
||||||
if (my_flags & MY_THREAD_SPECIFIC)
|
if (my_flags & MY_THREAD_SPECIFIC)
|
||||||
mem_root->flags|= ROOT_FLAG_THREAD_SPECIFIC;
|
mem_root->flags|= ROOT_FLAG_THREAD_SPECIFIC;
|
||||||
if (my_flags & MY_ROOT_USE_MPROTECT)
|
if (my_flags & MY_ROOT_USE_MPROTECT)
|
||||||
|
@@ -44,15 +44,12 @@ typedef struct my_memory_header my_memory_header;
|
|||||||
@return 0 - ok
|
@return 0 - ok
|
||||||
1 - failure, abort the allocation
|
1 - failure, abort the allocation
|
||||||
*/
|
*/
|
||||||
static void dummy(long long size __attribute__((unused)),
|
|
||||||
my_bool is_thread_specific __attribute__((unused)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
static MALLOC_SIZE_CB update_malloc_size= dummy;
|
static MALLOC_SIZE_CB update_malloc_size= 0;
|
||||||
|
|
||||||
void set_malloc_size_cb(MALLOC_SIZE_CB func)
|
void set_malloc_size_cb(MALLOC_SIZE_CB func)
|
||||||
{
|
{
|
||||||
update_malloc_size= func ? func : dummy;
|
update_malloc_size= func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -106,7 +103,11 @@ void *my_malloc(PSI_memory_key key, size_t size, myf my_flags)
|
|||||||
int flag= MY_TEST(my_flags & MY_THREAD_SPECIFIC);
|
int flag= MY_TEST(my_flags & MY_THREAD_SPECIFIC);
|
||||||
mh->m_size= size | flag;
|
mh->m_size= size | flag;
|
||||||
mh->m_key= PSI_CALL_memory_alloc(key, size, & mh->m_owner);
|
mh->m_key= PSI_CALL_memory_alloc(key, size, & mh->m_owner);
|
||||||
update_malloc_size(size + HEADER_SIZE, flag);
|
if (update_malloc_size)
|
||||||
|
{
|
||||||
|
mh->m_size|=2;
|
||||||
|
update_malloc_size(size + HEADER_SIZE, flag);
|
||||||
|
}
|
||||||
point= HEADER_TO_USER(mh);
|
point= HEADER_TO_USER(mh);
|
||||||
if (my_flags & MY_ZEROFILL)
|
if (my_flags & MY_ZEROFILL)
|
||||||
bzero(point, size);
|
bzero(point, size);
|
||||||
@@ -143,11 +144,11 @@ void *my_realloc(PSI_memory_key key, void *old_point, size_t size, myf my_flags)
|
|||||||
DBUG_RETURN(my_malloc(key, size, my_flags));
|
DBUG_RETURN(my_malloc(key, size, my_flags));
|
||||||
|
|
||||||
old_mh= USER_TO_HEADER(old_point);
|
old_mh= USER_TO_HEADER(old_point);
|
||||||
old_size= old_mh->m_size & ~1;
|
old_size= old_mh->m_size & ~3;
|
||||||
old_flags= old_mh->m_size & 1;
|
old_flags= old_mh->m_size & 3;
|
||||||
|
|
||||||
DBUG_ASSERT(old_mh->m_key == key || old_mh->m_key == PSI_NOT_INSTRUMENTED);
|
DBUG_ASSERT(old_mh->m_key == key || old_mh->m_key == PSI_NOT_INSTRUMENTED);
|
||||||
DBUG_ASSERT(old_flags == MY_TEST(my_flags & MY_THREAD_SPECIFIC));
|
DBUG_ASSERT((old_flags & 1) == MY_TEST(my_flags & MY_THREAD_SPECIFIC));
|
||||||
|
|
||||||
size= ALIGN_SIZE(size);
|
size= ALIGN_SIZE(size);
|
||||||
mh= sf_realloc(old_mh, size + HEADER_SIZE, my_flags);
|
mh= sf_realloc(old_mh, size + HEADER_SIZE, my_flags);
|
||||||
@@ -171,7 +172,8 @@ void *my_realloc(PSI_memory_key key, void *old_point, size_t size, myf my_flags)
|
|||||||
{
|
{
|
||||||
mh->m_size= size | old_flags;
|
mh->m_size= size | old_flags;
|
||||||
mh->m_key= PSI_CALL_memory_realloc(key, old_size, size, & mh->m_owner);
|
mh->m_key= PSI_CALL_memory_realloc(key, old_size, size, & mh->m_owner);
|
||||||
update_malloc_size((longlong)size - (longlong)old_size, old_flags);
|
if (update_malloc_size && (old_flags & 2))
|
||||||
|
update_malloc_size((longlong)size - (longlong)old_size, old_flags & 1);
|
||||||
point= HEADER_TO_USER(mh);
|
point= HEADER_TO_USER(mh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,11 +199,12 @@ void my_free(void *ptr)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
mh= USER_TO_HEADER(ptr);
|
mh= USER_TO_HEADER(ptr);
|
||||||
old_size= mh->m_size & ~1;
|
old_size= mh->m_size & ~3;
|
||||||
old_flags= mh->m_size & 1;
|
old_flags= mh->m_size & 3;
|
||||||
PSI_CALL_memory_free(mh->m_key, old_size, mh->m_owner);
|
PSI_CALL_memory_free(mh->m_key, old_size, mh->m_owner);
|
||||||
|
|
||||||
update_malloc_size(- (longlong) old_size - HEADER_SIZE, old_flags);
|
if (update_malloc_size && (old_flags & 2))
|
||||||
|
update_malloc_size(- (longlong) old_size - HEADER_SIZE, old_flags & 1);
|
||||||
|
|
||||||
#ifndef SAFEMALLOC
|
#ifndef SAFEMALLOC
|
||||||
/*
|
/*
|
||||||
|
@@ -280,6 +280,12 @@ extern "C" sig_handler handle_fatal_signal(int sig);
|
|||||||
|
|
||||||
int init_io_cache_encryption();
|
int init_io_cache_encryption();
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
static void my_malloc_size_cb_func(long long size,
|
||||||
|
my_bool is_thread_specific);
|
||||||
|
}
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
|
|
||||||
#include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
|
#include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE
|
||||||
|
@@ -2988,7 +2988,7 @@ void Show_explain_request::call_in_target_thread()
|
|||||||
target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
|
target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
|
||||||
&backup_arena);
|
&backup_arena);
|
||||||
|
|
||||||
query_str.copy(target_thd->query(),
|
query_str.copy(target_thd->query(),
|
||||||
target_thd->query_length(),
|
target_thd->query_length(),
|
||||||
target_thd->query_charset());
|
target_thd->query_charset());
|
||||||
|
|
||||||
@@ -3139,6 +3139,8 @@ int fill_show_explain_or_analyze(THD *thd, TABLE_LIST *table, COND *cond,
|
|||||||
if ((tmp= find_thread_by_id(thread_id)))
|
if ((tmp= find_thread_by_id(thread_id)))
|
||||||
{
|
{
|
||||||
Security_context *tmp_sctx= tmp->security_ctx;
|
Security_context *tmp_sctx= tmp->security_ctx;
|
||||||
|
MEM_ROOT explain_mem_root, *save_mem_root;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If calling_user==NULL, calling thread has SUPER or PROCESS
|
If calling_user==NULL, calling thread has SUPER or PROCESS
|
||||||
privilege, and so can do SHOW EXPLAIN/SHOW ANALYZE on any user.
|
privilege, and so can do SHOW EXPLAIN/SHOW ANALYZE on any user.
|
||||||
@@ -3164,7 +3166,8 @@ int fill_show_explain_or_analyze(THD *thd, TABLE_LIST *table, COND *cond,
|
|||||||
bool bres;
|
bool bres;
|
||||||
/*
|
/*
|
||||||
Ok we've found the thread of interest and it won't go away because
|
Ok we've found the thread of interest and it won't go away because
|
||||||
we're holding its LOCK_thd_kill. Post it a SHOW EXPLAIN/SHOW ANALYZE request.
|
we're holding its LOCK_thd_kill. Post it a SHOW EXPLAIN/SHOW ANALYZE
|
||||||
|
request.
|
||||||
*/
|
*/
|
||||||
bool timed_out;
|
bool timed_out;
|
||||||
int timeout_sec= 30;
|
int timeout_sec= 30;
|
||||||
@@ -3172,7 +3175,9 @@ int fill_show_explain_or_analyze(THD *thd, TABLE_LIST *table, COND *cond,
|
|||||||
explain_req.is_json_format= json_format;
|
explain_req.is_json_format= json_format;
|
||||||
select_result_explain_buffer *explain_buf;
|
select_result_explain_buffer *explain_buf;
|
||||||
|
|
||||||
explain_buf= new select_result_explain_buffer(thd, table->table);
|
if (!(explain_buf= new (thd->mem_root)
|
||||||
|
select_result_explain_buffer(thd, table->table)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
explain_req.is_analyze= is_analyze;
|
explain_req.is_analyze= is_analyze;
|
||||||
explain_req.explain_buf= explain_buf;
|
explain_req.explain_buf= explain_buf;
|
||||||
@@ -3180,8 +3185,19 @@ int fill_show_explain_or_analyze(THD *thd, TABLE_LIST *table, COND *cond,
|
|||||||
explain_req.request_thd= thd;
|
explain_req.request_thd= thd;
|
||||||
explain_req.failed_to_produce= FALSE;
|
explain_req.failed_to_produce= FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do not use default memroot as this is only to be used by the
|
||||||
|
target thread (It's marked as thread MY_THREAD_SPECIFIC).
|
||||||
|
*/
|
||||||
|
init_sql_alloc(key_memory_thd_main_mem_root,
|
||||||
|
&explain_mem_root, 0, 8000, MYF(0));
|
||||||
|
save_mem_root= thd->mem_root;
|
||||||
|
thd->mem_root= &explain_mem_root;
|
||||||
|
|
||||||
/* Ok, we have a lock on target->LOCK_thd_kill, can call: */
|
/* Ok, we have a lock on target->LOCK_thd_kill, can call: */
|
||||||
bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out);
|
bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec,
|
||||||
|
&timed_out);
|
||||||
|
thd->mem_root= save_mem_root;
|
||||||
|
|
||||||
if (bres || explain_req.failed_to_produce)
|
if (bres || explain_req.failed_to_produce)
|
||||||
{
|
{
|
||||||
@@ -3226,6 +3242,7 @@ int fill_show_explain_or_analyze(THD *thd, TABLE_LIST *table, COND *cond,
|
|||||||
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
|
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||||
ER_YES, warning_text);
|
ER_YES, warning_text);
|
||||||
}
|
}
|
||||||
|
free_root(&explain_mem_root, MYF(0));
|
||||||
DBUG_RETURN(bres);
|
DBUG_RETURN(bres);
|
||||||
}
|
}
|
||||||
my_error(ER_NO_SUCH_THREAD, MYF(0), (ulong) thread_id);
|
my_error(ER_NO_SUCH_THREAD, MYF(0), (ulong) thread_id);
|
||||||
|
@@ -482,6 +482,14 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
|
|||||||
if (lock_table(thd, table_ref, &hton_can_recreate))
|
if (lock_table(thd, table_ref, &hton_can_recreate))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is mainly here for truncate_notembedded.test, but it is still
|
||||||
|
useful to check killed after we got the lock
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (thd->killed)
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
if (hton_can_recreate)
|
if (hton_can_recreate)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user