mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 20:07:13 +02:00
Bug#40675 MySQL 5.1 crash with index merge algorithm and Merge tables
A Query in the MyISAM merge table was crashing
if the index merge algorithm was being used
Index Merge optimization requires the reading of
multiple indexes at the same time. Reading multiple
indexes at once with current SE API means that we
need to have handler instance for each to-be-read
index. This is done by creating clones of the handlers
instances. The clone internally does a open of the handler.
The open for a MERGE engine is handled in the following
phases
1) open parent table
2) generate list of underlying
table
3) attach underlying tables
But the current implementation does only the first
phase (i.e.) open parent table.
The current patch fixes this at the MERGE engine level,
by handling the clone operation within the MERGE engine
rather than in the storage engine API. It opens and
attaches the MyISAM tables on the MyISAM storage engine
interface directly within the MERGE engine. The new MyISAM
table instances, as well as the MERGE clone itself, are not
visible in the table cache. This is not a problem because
all locking is handled by the original MERGE table from which
this is cloned of.
mysql-test/r/merge.result:
updated the result file to reflect the new tests
added to test the fix
mysql-test/t/merge.test:
Added new tests to verify that the index merge
algorithm does not crash in the merge engine.
storage/myisammrg/ha_myisammrg.cc:
Implement the clone method, that handles
1) Cloning the handler
2) Opening underlying MYISAM child tables
3) Copies the state of the original handler and the children
into the cloned instances
4) Sets the appropriate flags
storage/myisammrg/ha_myisammrg.h:
Added a flag that is set to indicate that the current
instance is cloned. Also added the prototype or the clone
method.
storage/myisammrg/myrg_open.c:
Since we do now again use myrg_open() in the server
removed the comments marking this as deadcode.
This commit is contained in:
parent
ccca4feca8
commit
e80537b791
5 changed files with 171 additions and 9 deletions
|
|
@ -116,7 +116,7 @@ static handler *myisammrg_create_handler(handlerton *hton,
|
|||
*/
|
||||
|
||||
ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
|
||||
:handler(hton, table_arg), file(0)
|
||||
:handler(hton, table_arg), file(0), is_cloned(0)
|
||||
{}
|
||||
|
||||
|
||||
|
|
@ -413,7 +413,28 @@ int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
|
|||
|
||||
/* retrieve children table list. */
|
||||
my_errno= 0;
|
||||
if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
|
||||
if (is_cloned)
|
||||
{
|
||||
/*
|
||||
Open and attaches the MyISAM tables,that are under the MERGE table
|
||||
parent, on the MyISAM storage engine interface directly within the
|
||||
MERGE engine. The new MyISAM table instances, as well as the MERGE
|
||||
clone itself, are not visible in the table cache. This is not a
|
||||
problem because all locking is handled by the original MERGE table
|
||||
from which this is cloned of.
|
||||
*/
|
||||
if (!(file= myrg_open(table->s->normalized_path.str, table->db_stat,
|
||||
HA_OPEN_IGNORE_IF_LOCKED)))
|
||||
{
|
||||
DBUG_PRINT("error", ("my_errno %d", my_errno));
|
||||
DBUG_RETURN(my_errno ? my_errno : -1);
|
||||
}
|
||||
|
||||
file->children_attached= TRUE;
|
||||
|
||||
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
|
||||
}
|
||||
else if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
|
||||
{
|
||||
DBUG_PRINT("error", ("my_errno %d", my_errno));
|
||||
DBUG_RETURN(my_errno ? my_errno : -1);
|
||||
|
|
@ -422,6 +443,55 @@ int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a cloned instance of the current handler.
|
||||
|
||||
@return A cloned handler instance.
|
||||
*/
|
||||
handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
|
||||
{
|
||||
MYRG_TABLE *u_table,*newu_table;
|
||||
ha_myisammrg *new_handler=
|
||||
(ha_myisammrg*) get_new_handler(table->s, mem_root, table->s->db_type());
|
||||
if (!new_handler)
|
||||
return NULL;
|
||||
|
||||
/* Inform ha_myisammrg::open() that it is a cloned handler */
|
||||
new_handler->is_cloned= TRUE;
|
||||
/*
|
||||
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= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
|
||||
{
|
||||
delete new_handler;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (new_handler->ha_open(table, table->s->normalized_path.str, table->db_stat,
|
||||
HA_OPEN_IGNORE_IF_LOCKED))
|
||||
{
|
||||
delete new_handler;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Iterate through the original child tables and
|
||||
copy the state into the cloned child tables.
|
||||
We need to do this because all the child tables
|
||||
can be involved in delete.
|
||||
*/
|
||||
newu_table= new_handler->file->open_tables;
|
||||
for (u_table= file->open_tables; u_table < file->end_table; u_table++)
|
||||
{
|
||||
newu_table->table->state= u_table->table->state;
|
||||
newu_table++;
|
||||
}
|
||||
|
||||
return new_handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Attach children to a MERGE table.
|
||||
|
|
@ -613,9 +683,10 @@ int ha_myisammrg::close(void)
|
|||
DBUG_ENTER("ha_myisammrg::close");
|
||||
/*
|
||||
Children must not be attached here. Unless the MERGE table has no
|
||||
children. In this case children_attached is always true.
|
||||
children or the handler instance has been cloned. In these cases
|
||||
children_attached is always true.
|
||||
*/
|
||||
DBUG_ASSERT(!this->file->children_attached || !this->file->tables);
|
||||
DBUG_ASSERT(!this->file->children_attached || !this->file->tables || this->is_cloned);
|
||||
rc= myrg_close(file);
|
||||
file= 0;
|
||||
DBUG_RETURN(rc);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
class ha_myisammrg: public handler
|
||||
{
|
||||
MYRG_INFO *file;
|
||||
my_bool is_cloned; /* This instance has been cloned */
|
||||
|
||||
public:
|
||||
TABLE_LIST *next_child_attach; /* next child to attach */
|
||||
|
|
@ -60,6 +61,7 @@ class ha_myisammrg: public handler
|
|||
int open(const char *name, int mode, uint test_if_locked);
|
||||
int attach_children(void);
|
||||
int detach_children(void);
|
||||
virtual handler *clone(MEM_ROOT *mem_root);
|
||||
int close(void);
|
||||
int write_row(uchar * buf);
|
||||
int update_row(const uchar * old_data, uchar * new_data);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
myrg_attach_children(). Please duplicate changes in these
|
||||
functions or make common sub-functions.
|
||||
*/
|
||||
/* purecov: begin deadcode */ /* not used in MySQL server */
|
||||
|
||||
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
|
||||
{
|
||||
|
|
@ -198,7 +197,6 @@ err:
|
|||
my_errno=save_errno;
|
||||
DBUG_RETURN (NULL);
|
||||
}
|
||||
/* purecov: end */
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue