Commit cf9e30b8 authored by unknown's avatar unknown

Implementation of Monty's idea about clear_alloc_root() optimization and cleanup of work

with memory roots in THD/Statement/Item_arena.
Added assertions preventing memory allocation on bzero'ed MEM_ROOT since it is worked by 
pure luck and was very ineffective.


include/my_sys.h:
  Reimplementation of Monty's optimization of clear_alloc_root().
  Now clear_alloc_root() can be used only for detaching memory associated with MEM_ROOT
  (e.g. to avoid its freeing). It can not be used for MEM_ROOT initialization any longer 
  (it was bad idea anyway since memory allocation on such MEM_ROOT was very ineffective 
  and worked by pure luck).
  Introduced ALLOC_ROOT_MIN_BLOCK_SIZE constant.
mysys/my_alloc.c:
  Added description of init_alloc_root().
  Added assertions to alloc_root() and reset_root_defaults() so now they can only be used
  on previosly initialized MEM_ROOT. (It worked for bzeroed MEM_ROOT before but 
  by pure luck and very inefficiently). Calling free_root() on bzero'ed MEM_ROOT
  is still ok (we can't remove this easily because of static MEM_ROOTs).
  Also now using ALLOC_ROOT_MIN_BLOCK_SIZE constant inside these functions.
sql/opt_range.cc:
  Fixed get_quick_select_for_ref() function to not use bzero'ed MEM_ROOT for allocation.
  Also QUICK_RANGEs created in this function should be created in memory root of QUICK_SELECT.
sql/sql_class.cc:
  Implementation of Monty's idea about clear_alloc_root() optimization and cleanup of work 
  with memory roots in THD/Statement/Item_arena.
  Now we are always initing THD::transaction.mem_root and THD::mem_root in THD constructor 
  (without memory allocation and with minimal block size) and then later change their
  parameters in THD::init_for_queries() (this is partially because we can't allocate anything
  on bzero'ed memory roots anymore).
  Item_arena() constructor is now trivial and is used only then Item_arena is created as backup
  storage for other Item_arena (we use Item_arena(bool) now if it is part of Statement).
  Both trivial Item_arena constructor and destructor are now inline.
  Removed unneeded clear_alloc_root from Item_arena::restore_backup_item_arena().
sql/sql_class.h:
  Both trivial Item_arena constructor and destructor are now inline.
  Commented various Item_arena constructors.
parent f7613e9e
...@@ -725,7 +725,8 @@ extern void my_free_lock(byte *ptr,myf flags); ...@@ -725,7 +725,8 @@ extern void my_free_lock(byte *ptr,myf flags);
#define my_free_lock(A,B) my_free((A),(B)) #define my_free_lock(A,B) my_free((A),(B))
#endif #endif
#define alloc_root_inited(A) ((A)->min_malloc != 0) #define alloc_root_inited(A) ((A)->min_malloc != 0)
#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT)) #define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8)
#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; } while(0)
extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
uint pre_alloc_size); uint pre_alloc_size);
extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
......
...@@ -22,6 +22,27 @@ ...@@ -22,6 +22,27 @@
#undef EXTRA_DEBUG #undef EXTRA_DEBUG
#define EXTRA_DEBUG #define EXTRA_DEBUG
/*
Initialize memory root
SYNOPSIS
init_alloc_root()
mem_root - memory root to initialize
block_size - size of chunks (blocks) used for memory allocation
(It is external size of chunk i.e. it should include
memory required for internal structures, thus it
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
pre_alloc_size - if non-0, then size of block that should be
pre-allocated during memory root initialization.
DESCRIPTION
This function prepares memory root for further use, sets initial size of
chunk for memory allocation and pre-allocates first block if specified.
Altough error can happen during execution of this function if pre_alloc_size
is non-0 it won't be reported. Instead it will be reported as error in first
alloc_root() on this memory root.
*/
void init_alloc_root(MEM_ROOT *mem_root, uint block_size, void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
uint pre_alloc_size __attribute__((unused))) uint pre_alloc_size __attribute__((unused)))
{ {
...@@ -29,7 +50,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, ...@@ -29,7 +50,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
DBUG_PRINT("enter",("root: 0x%lx", mem_root)); DBUG_PRINT("enter",("root: 0x%lx", mem_root));
mem_root->free= mem_root->used= mem_root->pre_alloc= 0; mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
mem_root->min_malloc= 32; mem_root->min_malloc= 32;
mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
mem_root->error_handler= 0; mem_root->error_handler= 0;
mem_root->block_num= 4; /* We shift this with >>2 */ mem_root->block_num= 4; /* We shift this with >>2 */
mem_root->first_block_usage= 0; mem_root->first_block_usage= 0;
...@@ -54,9 +75,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, ...@@ -54,9 +75,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
SYNOPSIS SYNOPSIS
reset_root_defaults() reset_root_defaults()
mem_root memory root to change defaults of mem_root memory root to change defaults of
block_size new value of block size. Must be block_size new value of block size. Must be greater or equal
greater than ~68 bytes (the exact value depends on than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
platform and compilation flags) 68 bytes and depends on platform and compilation flags)
pre_alloc_size new size of preallocated block. If not zero, pre_alloc_size new size of preallocated block. If not zero,
must be equal to or greater than block size, must be equal to or greater than block size,
otherwise means 'no prealloc'. otherwise means 'no prealloc'.
...@@ -70,7 +91,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, ...@@ -70,7 +91,9 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
uint pre_alloc_size __attribute__((unused))) uint pre_alloc_size __attribute__((unused)))
{ {
mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; DBUG_ASSERT(alloc_root_inited(mem_root));
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG)) #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size) if (pre_alloc_size)
{ {
...@@ -123,6 +146,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) ...@@ -123,6 +146,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
DBUG_ENTER("alloc_root"); DBUG_ENTER("alloc_root");
DBUG_PRINT("enter",("root: 0x%lx", mem_root)); DBUG_PRINT("enter",("root: 0x%lx", mem_root));
DBUG_ASSERT(alloc_root_inited(mem_root));
Size+=ALIGN_SIZE(sizeof(USED_MEM)); Size+=ALIGN_SIZE(sizeof(USED_MEM));
if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME)))) if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
{ {
...@@ -140,6 +165,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) ...@@ -140,6 +165,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
reg1 USED_MEM *next= 0; reg1 USED_MEM *next= 0;
reg2 USED_MEM **prev; reg2 USED_MEM **prev;
DBUG_ASSERT(alloc_root_inited(mem_root));
Size= ALIGN_SIZE(Size); Size= ALIGN_SIZE(Size);
if ((*(prev= &mem_root->free)) != NULL) if ((*(prev= &mem_root->free)) != NULL)
{ {
......
...@@ -2554,7 +2554,8 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) ...@@ -2554,7 +2554,8 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{ {
QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1); MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
QUICK_SELECT *quick= new QUICK_SELECT(thd, table, ref->key);
KEY *key_info = &table->key_info[ref->key]; KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part; KEY_PART *key_part;
QUICK_RANGE *range; QUICK_RANGE *range;
...@@ -2566,7 +2567,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) ...@@ -2566,7 +2567,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{ {
if (thd->is_fatal_error) if (thd->is_fatal_error)
goto err; // out of memory goto err; // out of memory
return quick; // empty range goto ok; // empty range
} }
if (!(range= new QUICK_RANGE())) if (!(range= new QUICK_RANGE()))
...@@ -2613,9 +2614,12 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) ...@@ -2613,9 +2614,12 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
goto err; goto err;
} }
ok:
my_pthread_setspecific_ptr(THR_MALLOC, old_root);
return quick; return quick;
err: err:
my_pthread_setspecific_ptr(THR_MALLOC, old_root);
delete quick; delete quick;
return 0; return 0;
} }
......
...@@ -221,7 +221,6 @@ THD::THD() ...@@ -221,7 +221,6 @@ THD::THD()
init(); init();
/* Initialize sub structures */ /* Initialize sub structures */
clear_alloc_root(&transaction.mem_root);
init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
user_connect=(USER_CONN *)0; user_connect=(USER_CONN *)0;
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
...@@ -258,6 +257,7 @@ THD::THD() ...@@ -258,6 +257,7 @@ THD::THD()
transaction.trans_log.end_of_file= max_binlog_cache_size; transaction.trans_log.end_of_file= max_binlog_cache_size;
} }
#endif #endif
init_alloc_root(&transaction.mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
{ {
ulong tmp=sql_rnd_with_mutex(); ulong tmp=sql_rnd_with_mutex();
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
...@@ -303,12 +303,12 @@ void THD::init(void) ...@@ -303,12 +303,12 @@ void THD::init(void)
void THD::init_for_queries() void THD::init_for_queries()
{ {
ha_enable_transaction(this,TRUE); ha_enable_transaction(this,TRUE);
init_sql_alloc(&mem_root,
variables.query_alloc_block_size, reset_root_defaults(&mem_root, variables.query_alloc_block_size,
variables.query_prealloc_size); variables.query_prealloc_size);
init_sql_alloc(&transaction.mem_root, reset_root_defaults(&transaction.mem_root,
variables.trans_alloc_block_size, variables.trans_alloc_block_size,
variables.trans_prealloc_size); variables.trans_prealloc_size);
} }
...@@ -1331,6 +1331,17 @@ void select_dumpvar::cleanup() ...@@ -1331,6 +1331,17 @@ void select_dumpvar::cleanup()
} }
/*
Create arena for already constructed THD.
SYNOPSYS
Item_arena()
thd - thread for which arena is created
DESCRIPTION
Create arena for already existing THD using its variables as parameters
for memory root initialization.
*/
Item_arena::Item_arena(THD* thd) Item_arena::Item_arena(THD* thd)
:free_list(0), :free_list(0),
state(INITIALIZED) state(INITIALIZED)
...@@ -1341,24 +1352,31 @@ Item_arena::Item_arena(THD* thd) ...@@ -1341,24 +1352,31 @@ Item_arena::Item_arena(THD* thd)
} }
/* This constructor is called when Item_arena is a subobject of THD */ /*
Create arena and optionally initialize memory root.
Item_arena::Item_arena() SYNOPSYS
:free_list(0), Item_arena()
state(CONVENTIONAL_EXECUTION) init_mem_root - whenever we need to initialize memory root
{
clear_alloc_root(&mem_root);
}
DESCRIPTION
Create arena and optionally initialize memory root with minimal
possible parameters.
NOTE
We use this constructor when arena is part of THD, but reinitialize
its memory root in THD::init_for_queries() before execution of real
statements.
*/
Item_arena::Item_arena(bool init_mem_root) Item_arena::Item_arena(bool init_mem_root)
:free_list(0), :free_list(0),
state(INITIALIZED) state(CONVENTIONAL_EXECUTION)
{ {
if (init_mem_root) if (init_mem_root)
clear_alloc_root(&mem_root); init_alloc_root(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
} }
Item_arena::Type Item_arena::type() const Item_arena::Type Item_arena::type() const
{ {
DBUG_ASSERT("Item_arena::type()" == "abstract"); DBUG_ASSERT("Item_arena::type()" == "abstract");
...@@ -1366,10 +1384,6 @@ Item_arena::Type Item_arena::type() const ...@@ -1366,10 +1384,6 @@ Item_arena::Type Item_arena::type() const
} }
Item_arena::~Item_arena()
{}
/* /*
Statement functions Statement functions
*/ */
...@@ -1393,7 +1407,8 @@ Statement::Statement(THD *thd) ...@@ -1393,7 +1407,8 @@ Statement::Statement(THD *thd)
*/ */
Statement::Statement() Statement::Statement()
:id(0), :Item_arena((bool)TRUE),
id(0),
set_query_id(1), set_query_id(1),
allow_sum_func(0), /* initialized later */ allow_sum_func(0), /* initialized later */
lex(&main_lex), lex(&main_lex),
...@@ -1461,8 +1476,16 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup) ...@@ -1461,8 +1476,16 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
{ {
set->set_item_arena(this); set->set_item_arena(this);
set_item_arena(backup); set_item_arena(backup);
// reset backup mem_root to avoid its freeing #ifdef NOT_NEEDED_NOW
init_alloc_root(&backup->mem_root, 0, 0); /*
Reset backup mem_root to avoid its freeing.
Since Item_arena's mem_root is freed only when it is part of Statement
we need this only if we use some Statement's arena as backup storage.
But we do this only with THD::stmt_backup and this Statement is specially
handled in this respect. So this code is not really needed now.
*/
clear_alloc_root(&backup->mem_root);
#endif
} }
void Item_arena::set_item_arena(Item_arena *set) void Item_arena::set_item_arena(Item_arena *set)
......
...@@ -441,11 +441,23 @@ class Item_arena ...@@ -441,11 +441,23 @@ class Item_arena
STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
}; };
/*
This constructor is used only when Item_arena is created as
backup storage for another instance of Item_arena.
*/
Item_arena() {};
/*
Create arena for already constructed THD using its variables as
parameters for memory root initialization.
*/
Item_arena(THD *thd); Item_arena(THD *thd);
Item_arena(); /*
Create arena and optionally init memory root with minimal values.
Particularly used if Item_arena is part of Statement.
*/
Item_arena(bool init_mem_root); Item_arena(bool init_mem_root);
virtual Type type() const; virtual Type type() const;
virtual ~Item_arena(); virtual ~Item_arena() {};
inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment