Commit a1e83978 authored by unknown's avatar unknown

BUG#27732 "Possible memory leak with index_merge"

The bug was that handler::clone/handler::ha_open() call caused allocation of 
cloned_copy->ref on the handler->table->mem_root. The allocated memory could not 
be reclaimed until the table is flushed, so it was possible to exhaust memory by 
repeatedly running index_merge queries without doing table flushes.  

The fix:
- make handler::clone() allocate new_handler->ref on the passed mem_root 
- make handler::ha_open() not allocate this->ref if it has already been allocated
There is no testcase as it is not possible to check small leaks from testsuite.


sql/handler.cc:
  BUG#27732 "Possible memory leak with index_merge"
  - make handler::clone() allocate new_handler->ref on the passed mem_root 
  - make handler::ha_open() not allocate this->ref if it has already been allocated
parent 65dfdcdf
...@@ -1381,6 +1381,13 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path, ...@@ -1381,6 +1381,13 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path,
handler *handler::clone(MEM_ROOT *mem_root) handler *handler::clone(MEM_ROOT *mem_root)
{ {
handler *new_handler= get_new_handler(table, mem_root, table->s->db_type); handler *new_handler= get_new_handler(table, mem_root, table->s->db_type);
/*
Allocate handler->ref here because otherwise ha_open will allocate it
on this->table->mem_root and we will not be able to reclaim that memory
when the clone handler object is destroyed.
*/
if (!(new_handler->ref= (byte*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
return NULL;
if (new_handler && !new_handler->ha_open(table->s->path, table->db_stat, if (new_handler && !new_handler->ha_open(table->s->path, table->db_stat,
HA_OPEN_IGNORE_IF_LOCKED)) HA_OPEN_IGNORE_IF_LOCKED))
return new_handler; return new_handler;
...@@ -1420,8 +1427,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) ...@@ -1420,8 +1427,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
DBUG_ASSERT(alloc_root_inited(&table->mem_root)); DBUG_ASSERT(alloc_root_inited(&table->mem_root));
/* ref is already allocated for us if we're called from handler::clone() */
if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2))) if (!ref && !(ref= (byte*) alloc_root(&table->mem_root,
ALIGN_SIZE(ref_length)*2)))
{ {
close(); close();
error=HA_ERR_OUT_OF_MEM; error=HA_ERR_OUT_OF_MEM;
......
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