2006-12-31 01:02:27 +01:00
|
|
|
/* Copyright (C) 2000-2006 MySQL AB
|
2000-12-09 00:41:06 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2000-12-09 00:41:06 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2000-12-09 00:41:06 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
2001-09-22 16:40:57 +02:00
|
|
|
/* open a MyISAM MERGE table */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-10-08 03:58:07 +02:00
|
|
|
#include "myrg_def.h"
|
2000-07-31 21:29:14 +02:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#ifdef VMS
|
|
|
|
#include "mrg_static.c"
|
|
|
|
#endif
|
|
|
|
|
2002-06-22 19:44:04 +02:00
|
|
|
/*
|
2001-09-22 16:40:57 +02:00
|
|
|
open a MyISAM MERGE table
|
2002-06-22 19:44:04 +02:00
|
|
|
if handle_locking is 0 then exit with error if some table is locked
|
|
|
|
if handle_locking is 1 then wait if table is locked
|
2000-07-31 21:29:14 +02:00
|
|
|
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
NOTE: This function is not used in the MySQL server. It is for
|
|
|
|
MERGE use independent from MySQL. Currently there is some code
|
|
|
|
duplication between myrg_open() and myrg_parent_open() +
|
|
|
|
myrg_attach_children(). Please duplicate changes in these
|
|
|
|
functions or make common sub-functions.
|
|
|
|
*/
|
2007-12-11 15:32:10 +01:00
|
|
|
/* purecov: begin deadcode */ /* not used in MySQL server */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-09-22 16:40:57 +02:00
|
|
|
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-08-23 13:43:55 +02:00
|
|
|
int save_errno,errpos=0;
|
2006-09-28 19:10:06 +02:00
|
|
|
uint files= 0, i, dir_length, length, key_parts, min_keys= 0;
|
2004-08-31 13:35:04 +02:00
|
|
|
ulonglong file_offset=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
|
2004-08-23 13:43:55 +02:00
|
|
|
MYRG_INFO *m_info=0;
|
2001-01-27 00:20:56 +01:00
|
|
|
File fd;
|
|
|
|
IO_CACHE file;
|
2004-08-23 13:43:55 +02:00
|
|
|
MI_INFO *isam=0;
|
2004-08-31 13:35:04 +02:00
|
|
|
uint found_merge_insert_method= 0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t name_buff_length;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("myrg_open");
|
|
|
|
|
2004-08-31 13:35:04 +02:00
|
|
|
LINT_INIT(key_parts);
|
|
|
|
|
2001-01-27 00:20:56 +01:00
|
|
|
bzero((char*) &file,sizeof(file));
|
2005-12-31 06:01:26 +01:00
|
|
|
if ((fd=my_open(fn_format(name_buff,name,"",MYRG_NAME_EXT,
|
|
|
|
MY_UNPACK_FILENAME|MY_APPEND_EXT),
|
2004-08-22 09:36:17 +02:00
|
|
|
O_RDONLY | O_SHARE,MYF(0))) < 0)
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
goto err;
|
|
|
|
errpos=1;
|
|
|
|
if (init_io_cache(&file, fd, 4*IO_SIZE, READ_CACHE, 0, 0,
|
2001-01-27 00:20:56 +01:00
|
|
|
MYF(MY_WME | MY_NABP)))
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
goto err;
|
|
|
|
errpos=2;
|
|
|
|
dir_length=dirname_part(name_buff, name, &name_buff_length);
|
2001-01-27 00:20:56 +01:00
|
|
|
while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-01-27 00:20:56 +01:00
|
|
|
if ((end=buff+length)[-1] == '\n')
|
2000-07-31 21:29:14 +02:00
|
|
|
end[-1]='\0';
|
2004-08-22 10:22:59 +02:00
|
|
|
if (buff[0] && buff[0] != '#')
|
2000-07-31 21:29:14 +02:00
|
|
|
files++;
|
|
|
|
}
|
2004-08-22 09:36:17 +02:00
|
|
|
|
|
|
|
my_b_seek(&file, 0);
|
2001-01-27 00:20:56 +01:00
|
|
|
while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-01-27 00:20:56 +01:00
|
|
|
if ((end=buff+length)[-1] == '\n')
|
2005-05-23 18:53:16 +02:00
|
|
|
*--end='\0';
|
2001-09-22 16:40:57 +02:00
|
|
|
if (!buff[0])
|
|
|
|
continue; /* Skip empty lines */
|
|
|
|
if (buff[0] == '#')
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-08-31 13:35:04 +02:00
|
|
|
if (!strncmp(buff+1,"INSERT_METHOD=",14))
|
2001-09-22 16:40:57 +02:00
|
|
|
{ /* Lookup insert method */
|
|
|
|
int tmp=find_type(buff+15,&merge_insert_method,2);
|
2004-08-31 13:35:04 +02:00
|
|
|
found_merge_insert_method = (uint) (tmp >= 0 ? tmp : 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2001-09-22 16:40:57 +02:00
|
|
|
continue; /* Skip comments */
|
|
|
|
}
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2005-04-28 18:28:50 +02:00
|
|
|
if (!has_path(buff))
|
2001-09-22 16:40:57 +02:00
|
|
|
{
|
|
|
|
VOID(strmake(name_buff+dir_length,buff,
|
|
|
|
sizeof(name_buff)-1-dir_length));
|
|
|
|
VOID(cleanup_dirname(buff,name_buff));
|
|
|
|
}
|
2005-05-23 18:53:16 +02:00
|
|
|
else
|
|
|
|
fn_format(buff, buff, "", "", 0);
|
2002-06-22 19:44:04 +02:00
|
|
|
if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
|
2006-09-19 22:40:59 +02:00
|
|
|
{
|
|
|
|
my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
|
2007-06-06 01:42:41 +02:00
|
|
|
if (handle_locking & HA_OPEN_FOR_REPAIR)
|
|
|
|
{
|
|
|
|
myrg_print_wrong_table(buff);
|
|
|
|
continue;
|
|
|
|
}
|
2004-08-31 13:35:04 +02:00
|
|
|
goto err;
|
2006-09-19 22:40:59 +02:00
|
|
|
}
|
2004-08-31 13:35:04 +02:00
|
|
|
if (!m_info) /* First file */
|
2004-08-22 10:22:59 +02:00
|
|
|
{
|
|
|
|
key_parts=isam->s->base.key_parts;
|
|
|
|
if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) +
|
|
|
|
files*sizeof(MYRG_TABLE) +
|
|
|
|
key_parts*sizeof(long),
|
|
|
|
MYF(MY_WME|MY_ZEROFILL))))
|
|
|
|
goto err;
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_ASSERT(files);
|
|
|
|
m_info->open_tables=(MYRG_TABLE *) (m_info+1);
|
|
|
|
m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files);
|
|
|
|
m_info->tables= files;
|
|
|
|
files= 0;
|
2004-08-22 10:22:59 +02:00
|
|
|
m_info->reclength=isam->s->base.reclength;
|
2006-09-28 19:10:06 +02:00
|
|
|
min_keys= isam->s->base.keys;
|
2004-08-22 10:22:59 +02:00
|
|
|
errpos=3;
|
|
|
|
}
|
2004-08-22 09:36:17 +02:00
|
|
|
m_info->open_tables[files].table= isam;
|
|
|
|
m_info->open_tables[files].file_offset=(my_off_t) file_offset;
|
|
|
|
file_offset+=isam->state->data_file_length;
|
2001-09-22 16:40:57 +02:00
|
|
|
files++;
|
2004-08-22 12:43:26 +02:00
|
|
|
if (m_info->reclength != isam->s->base.reclength)
|
2001-09-22 16:40:57 +02:00
|
|
|
{
|
2003-01-28 17:42:08 +01:00
|
|
|
my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
|
2007-06-06 01:42:41 +02:00
|
|
|
if (handle_locking & HA_OPEN_FOR_REPAIR)
|
|
|
|
{
|
|
|
|
myrg_print_wrong_table(buff);
|
|
|
|
continue;
|
|
|
|
}
|
2001-09-22 16:40:57 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-08-22 09:36:17 +02:00
|
|
|
m_info->options|= isam->s->options;
|
|
|
|
m_info->records+= isam->state->records;
|
|
|
|
m_info->del+= isam->state->del;
|
|
|
|
m_info->data_file_length+= isam->state->data_file_length;
|
2006-09-28 19:10:06 +02:00
|
|
|
if (min_keys > isam->s->base.keys)
|
|
|
|
min_keys= isam->s->base.keys;
|
2004-08-22 10:22:59 +02:00
|
|
|
for (i=0; i < key_parts; i++)
|
2004-08-31 13:35:04 +02:00
|
|
|
m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] /
|
|
|
|
m_info->tables);
|
2002-12-10 00:06:05 +01:00
|
|
|
}
|
2000-12-09 00:41:06 +01:00
|
|
|
|
2007-06-06 01:42:41 +02:00
|
|
|
if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
|
|
|
|
goto err;
|
2004-08-22 12:43:26 +02:00
|
|
|
if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO),
|
2004-08-31 13:35:04 +02:00
|
|
|
MYF(MY_WME | MY_ZEROFILL))))
|
2004-08-22 12:43:26 +02:00
|
|
|
goto err;
|
2003-07-15 20:43:57 +02:00
|
|
|
/* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
|
|
|
|
m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
|
2004-08-31 13:35:04 +02:00
|
|
|
m_info->merge_insert_method= found_merge_insert_method;
|
2001-05-12 13:03:53 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
|
|
|
|
{
|
|
|
|
my_errno=HA_ERR_RECORD_FILE_FULL;
|
|
|
|
goto err;
|
|
|
|
}
|
2006-09-28 19:10:06 +02:00
|
|
|
m_info->keys= min_keys;
|
2000-12-09 00:41:06 +01:00
|
|
|
bzero((char*) &m_info->by_key,sizeof(m_info->by_key));
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2000-12-15 01:43:13 +01:00
|
|
|
/* this works ok if the table list is empty */
|
2000-07-31 21:29:14 +02:00
|
|
|
m_info->end_table=m_info->open_tables+files;
|
|
|
|
m_info->last_used_table=m_info->open_tables;
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
m_info->children_attached= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-01-27 00:20:56 +01:00
|
|
|
VOID(my_close(fd,MYF(0)));
|
|
|
|
end_io_cache(&file);
|
2007-12-11 15:32:10 +01:00
|
|
|
VOID(pthread_mutex_init(&m_info->mutex, MY_MUTEX_INIT_FAST));
|
2000-07-31 21:29:14 +02:00
|
|
|
m_info->open_list.data=(void*) m_info;
|
|
|
|
pthread_mutex_lock(&THR_LOCK_open);
|
|
|
|
myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
|
|
|
|
pthread_mutex_unlock(&THR_LOCK_open);
|
|
|
|
DBUG_RETURN(m_info);
|
|
|
|
|
|
|
|
err:
|
|
|
|
save_errno=my_errno;
|
|
|
|
switch (errpos) {
|
2004-08-22 09:36:17 +02:00
|
|
|
case 3:
|
|
|
|
while (files)
|
|
|
|
mi_close(m_info->open_tables[--files].table);
|
2000-09-16 03:27:21 +02:00
|
|
|
my_free((char*) m_info,MYF(0));
|
|
|
|
/* Fall through */
|
2004-08-22 09:36:17 +02:00
|
|
|
case 2:
|
|
|
|
end_io_cache(&file);
|
|
|
|
/* Fall through */
|
2000-07-31 21:29:14 +02:00
|
|
|
case 1:
|
2001-01-27 00:20:56 +01:00
|
|
|
VOID(my_close(fd,MYF(0)));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
my_errno=save_errno;
|
|
|
|
DBUG_RETURN (NULL);
|
|
|
|
}
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
/* purecov: end */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Open parent table of a MyISAM MERGE table.
|
|
|
|
|
|
|
|
@detail Open MERGE meta file to get the table name paths for the child
|
|
|
|
tables. Count the children. Allocate and initialize MYRG_INFO
|
|
|
|
structure. Call a callback function for each child table.
|
|
|
|
|
|
|
|
@param[in] parent_name merge table name path as "database/table"
|
|
|
|
@param[in] callback function to call for each child table
|
|
|
|
@param[in] callback_param data pointer to give to the callback
|
|
|
|
|
|
|
|
@return MYRG_INFO pointer
|
|
|
|
@retval != NULL OK
|
|
|
|
@retval NULL Error
|
|
|
|
|
|
|
|
@note: Currently there is some code duplication between myrg_open()
|
|
|
|
and myrg_parent_open() + myrg_attach_children(). Please duplicate
|
|
|
|
changes in these functions or make common sub-functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
MYRG_INFO *myrg_parent_open(const char *parent_name,
|
|
|
|
int (*callback)(void*, const char*),
|
|
|
|
void *callback_param)
|
|
|
|
{
|
|
|
|
MYRG_INFO *m_info;
|
|
|
|
int rc;
|
|
|
|
int errpos;
|
|
|
|
int save_errno;
|
|
|
|
int insert_method;
|
|
|
|
uint length;
|
|
|
|
uint dir_length;
|
|
|
|
uint child_count;
|
|
|
|
size_t name_buff_length;
|
|
|
|
File fd;
|
|
|
|
IO_CACHE file_cache;
|
|
|
|
char parent_name_buff[FN_REFLEN * 2];
|
|
|
|
char child_name_buff[FN_REFLEN];
|
|
|
|
DBUG_ENTER("myrg_parent_open");
|
|
|
|
|
|
|
|
rc= 1;
|
|
|
|
errpos= 0;
|
|
|
|
bzero((char*) &file_cache, sizeof(file_cache));
|
|
|
|
|
|
|
|
/* Open MERGE meta file. */
|
|
|
|
if ((fd= my_open(fn_format(parent_name_buff, parent_name, "", MYRG_NAME_EXT,
|
|
|
|
MY_UNPACK_FILENAME|MY_APPEND_EXT),
|
|
|
|
O_RDONLY | O_SHARE, MYF(0))) < 0)
|
|
|
|
goto err; /* purecov: inspected */
|
|
|
|
errpos= 1;
|
|
|
|
|
|
|
|
if (init_io_cache(&file_cache, fd, 4 * IO_SIZE, READ_CACHE, 0, 0,
|
|
|
|
MYF(MY_WME | MY_NABP)))
|
|
|
|
goto err; /* purecov: inspected */
|
|
|
|
errpos= 2;
|
|
|
|
|
|
|
|
/* Count children. Determine insert method. */
|
|
|
|
child_count= 0;
|
|
|
|
insert_method= 0;
|
|
|
|
while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1)))
|
|
|
|
{
|
|
|
|
/* Remove line terminator. */
|
|
|
|
if (child_name_buff[length - 1] == '\n')
|
|
|
|
child_name_buff[--length]= '\0';
|
|
|
|
|
|
|
|
/* Skip empty lines. */
|
|
|
|
if (!child_name_buff[0])
|
|
|
|
continue; /* purecov: inspected */
|
|
|
|
|
|
|
|
/* Skip comments, but evaluate insert method. */
|
|
|
|
if (child_name_buff[0] == '#')
|
|
|
|
{
|
|
|
|
if (!strncmp(child_name_buff + 1, "INSERT_METHOD=", 14))
|
|
|
|
{
|
|
|
|
/* Compare buffer with global methods list: merge_insert_method. */
|
|
|
|
insert_method= find_type(child_name_buff + 15,
|
|
|
|
&merge_insert_method, 2);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Count the child. */
|
|
|
|
child_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate MERGE parent table structure. */
|
|
|
|
if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) +
|
|
|
|
child_count * sizeof(MYRG_TABLE),
|
|
|
|
MYF(MY_WME | MY_ZEROFILL))))
|
|
|
|
goto err; /* purecov: inspected */
|
|
|
|
errpos= 3;
|
|
|
|
m_info->open_tables= (MYRG_TABLE*) (m_info + 1);
|
|
|
|
m_info->tables= child_count;
|
|
|
|
m_info->merge_insert_method= insert_method > 0 ? insert_method : 0;
|
|
|
|
/* This works even if the table list is empty. */
|
|
|
|
m_info->end_table= m_info->open_tables + child_count;
|
|
|
|
if (!child_count)
|
|
|
|
{
|
|
|
|
/* Do not attach/detach an empty child list. */
|
|
|
|
m_info->children_attached= TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call callback for each child. */
|
|
|
|
dir_length= dirname_part(parent_name_buff, parent_name, &name_buff_length);
|
|
|
|
my_b_seek(&file_cache, 0);
|
|
|
|
while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1)))
|
|
|
|
{
|
|
|
|
/* Remove line terminator. */
|
|
|
|
if (child_name_buff[length - 1] == '\n')
|
|
|
|
child_name_buff[--length]= '\0';
|
|
|
|
|
|
|
|
/* Skip empty lines and comments. */
|
|
|
|
if (!child_name_buff[0] || (child_name_buff[0] == '#'))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!has_path(child_name_buff))
|
|
|
|
{
|
|
|
|
VOID(strmake(parent_name_buff + dir_length, child_name_buff,
|
|
|
|
sizeof(parent_name_buff) - 1 - dir_length));
|
|
|
|
VOID(cleanup_dirname(child_name_buff, parent_name_buff));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fn_format(child_name_buff, child_name_buff, "", "", 0);
|
|
|
|
DBUG_PRINT("info", ("child: '%s'", child_name_buff));
|
|
|
|
|
|
|
|
/* Callback registers child with handler table. */
|
|
|
|
if ((rc= (*callback)(callback_param, child_name_buff)))
|
|
|
|
goto err; /* purecov: inspected */
|
|
|
|
}
|
|
|
|
|
|
|
|
end_io_cache(&file_cache);
|
|
|
|
VOID(my_close(fd, MYF(0)));
|
2007-12-11 15:32:10 +01:00
|
|
|
VOID(pthread_mutex_init(&m_info->mutex, MY_MUTEX_INIT_FAST));
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
|
|
|
|
m_info->open_list.data= (void*) m_info;
|
|
|
|
pthread_mutex_lock(&THR_LOCK_open);
|
|
|
|
myrg_open_list= list_add(myrg_open_list, &m_info->open_list);
|
|
|
|
pthread_mutex_unlock(&THR_LOCK_open);
|
|
|
|
|
|
|
|
DBUG_RETURN(m_info);
|
|
|
|
|
|
|
|
/* purecov: begin inspected */
|
|
|
|
err:
|
|
|
|
save_errno= my_errno;
|
|
|
|
switch (errpos) {
|
|
|
|
case 3:
|
|
|
|
my_free((char*) m_info, MYF(0));
|
|
|
|
/* Fall through */
|
|
|
|
case 2:
|
|
|
|
end_io_cache(&file_cache);
|
|
|
|
/* Fall through */
|
|
|
|
case 1:
|
|
|
|
VOID(my_close(fd, MYF(0)));
|
|
|
|
}
|
|
|
|
my_errno= save_errno;
|
|
|
|
DBUG_RETURN (NULL);
|
|
|
|
/* purecov: end */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Attach children to a MyISAM MERGE parent table.
|
|
|
|
|
|
|
|
@detail Call a callback function for each child table.
|
|
|
|
The callback returns the MyISAM table handle of the child table.
|
|
|
|
Check table definition match.
|
|
|
|
|
|
|
|
@param[in] m_info MERGE parent table structure
|
|
|
|
@param[in] handle_locking if contains HA_OPEN_FOR_REPAIR, warn about
|
|
|
|
incompatible child tables, but continue
|
|
|
|
@param[in] callback function to call for each child table
|
|
|
|
@param[in] callback_param data pointer to give to the callback
|
|
|
|
|
|
|
|
@return status
|
|
|
|
@retval 0 OK
|
|
|
|
@retval != 0 Error
|
|
|
|
|
|
|
|
@note: Currently there is some code duplication between myrg_open()
|
|
|
|
and myrg_parent_open() + myrg_attach_children(). Please duplicate
|
|
|
|
changes in these functions or make common sub-functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
|
|
|
|
MI_INFO *(*callback)(void*),
|
|
|
|
void *callback_param)
|
|
|
|
{
|
|
|
|
ulonglong file_offset;
|
|
|
|
MI_INFO *myisam;
|
|
|
|
int rc;
|
|
|
|
int errpos;
|
|
|
|
int save_errno;
|
|
|
|
uint idx;
|
|
|
|
uint child_nr;
|
|
|
|
uint key_parts;
|
|
|
|
uint min_keys;
|
|
|
|
DBUG_ENTER("myrg_attach_children");
|
|
|
|
DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking));
|
|
|
|
|
2007-12-11 15:32:10 +01:00
|
|
|
/*
|
|
|
|
This function can be called while another thread is trying to abort
|
|
|
|
locks of this MERGE table. If the processor reorders instructions or
|
|
|
|
write to memory, 'children_attached' could be set before
|
|
|
|
'open_tables' has all the pointers to the children. Use of a mutex
|
|
|
|
here and in ha_myisammrg::store_lock() forces consistent data.
|
|
|
|
*/
|
|
|
|
pthread_mutex_lock(&m_info->mutex);
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
rc= 1;
|
|
|
|
errpos= 0;
|
|
|
|
file_offset= 0;
|
|
|
|
LINT_INIT(key_parts);
|
|
|
|
min_keys= 0;
|
|
|
|
child_nr= 0;
|
|
|
|
while ((myisam= (*callback)(callback_param)))
|
|
|
|
{
|
|
|
|
DBUG_PRINT("myrg", ("child_nr: %u table: '%s'",
|
|
|
|
child_nr, myisam->filename));
|
|
|
|
DBUG_ASSERT(child_nr < m_info->tables);
|
|
|
|
|
|
|
|
/* Special handling when the first child is attached. */
|
|
|
|
if (!child_nr)
|
|
|
|
{
|
|
|
|
m_info->reclength= myisam->s->base.reclength;
|
|
|
|
min_keys= myisam->s->base.keys;
|
|
|
|
key_parts= myisam->s->base.key_parts;
|
|
|
|
if (!m_info->rec_per_key_part)
|
|
|
|
{
|
|
|
|
if(!(m_info->rec_per_key_part= (ulong*)
|
|
|
|
my_malloc(key_parts * sizeof(long), MYF(MY_WME|MY_ZEROFILL))))
|
|
|
|
goto err; /* purecov: inspected */
|
|
|
|
errpos= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add MyISAM table info. */
|
|
|
|
m_info->open_tables[child_nr].table= myisam;
|
|
|
|
m_info->open_tables[child_nr].file_offset= (my_off_t) file_offset;
|
|
|
|
file_offset+= myisam->state->data_file_length;
|
|
|
|
|
|
|
|
/* Check table definition match. */
|
|
|
|
if (m_info->reclength != myisam->s->base.reclength)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("error", ("definition mismatch table: '%s' repair: %d",
|
|
|
|
myisam->filename,
|
|
|
|
(handle_locking & HA_OPEN_FOR_REPAIR)));
|
|
|
|
my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
|
|
|
|
if (handle_locking & HA_OPEN_FOR_REPAIR)
|
|
|
|
{
|
|
|
|
myrg_print_wrong_table(myisam->filename);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_info->options|= myisam->s->options;
|
|
|
|
m_info->records+= myisam->state->records;
|
|
|
|
m_info->del+= myisam->state->del;
|
|
|
|
m_info->data_file_length+= myisam->state->data_file_length;
|
|
|
|
if (min_keys > myisam->s->base.keys)
|
|
|
|
min_keys= myisam->s->base.keys; /* purecov: inspected */
|
|
|
|
for (idx= 0; idx < key_parts; idx++)
|
|
|
|
m_info->rec_per_key_part[idx]+= (myisam->s->state.rec_per_key_part[idx] /
|
|
|
|
m_info->tables);
|
|
|
|
child_nr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
|
|
|
|
goto err;
|
|
|
|
if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
|
|
|
|
{
|
|
|
|
my_errno= HA_ERR_RECORD_FILE_FULL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
/* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
|
|
|
|
m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
|
|
|
|
m_info->keys= min_keys;
|
|
|
|
m_info->last_used_table= m_info->open_tables;
|
|
|
|
m_info->children_attached= TRUE;
|
2007-12-11 15:32:10 +01:00
|
|
|
pthread_mutex_unlock(&m_info->mutex);
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
err:
|
|
|
|
save_errno= my_errno;
|
|
|
|
switch (errpos) {
|
|
|
|
case 1:
|
|
|
|
my_free((char*) m_info->rec_per_key_part, MYF(0));
|
|
|
|
m_info->rec_per_key_part= NULL;
|
|
|
|
}
|
2007-12-11 15:32:10 +01:00
|
|
|
pthread_mutex_unlock(&m_info->mutex);
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
my_errno= save_errno;
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Detach children from a MyISAM MERGE parent table.
|
|
|
|
|
|
|
|
@param[in] m_info MERGE parent table structure
|
|
|
|
|
|
|
|
@note Detach must not touch the children in any way.
|
|
|
|
They may have been closed at ths point already.
|
|
|
|
All references to the children should be removed.
|
|
|
|
|
|
|
|
@return status
|
|
|
|
@retval 0 OK
|
|
|
|
*/
|
|
|
|
|
|
|
|
int myrg_detach_children(MYRG_INFO *m_info)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("myrg_detach_children");
|
2007-12-11 15:32:10 +01:00
|
|
|
/* For symmetry with myrg_attach_children() we use the mutex here. */
|
|
|
|
pthread_mutex_lock(&m_info->mutex);
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
if (m_info->tables)
|
|
|
|
{
|
|
|
|
/* Do not attach/detach an empty child list. */
|
|
|
|
m_info->children_attached= FALSE;
|
|
|
|
bzero((char*) m_info->open_tables, m_info->tables * sizeof(MYRG_TABLE));
|
|
|
|
}
|
|
|
|
m_info->records= 0;
|
|
|
|
m_info->del= 0;
|
|
|
|
m_info->data_file_length= 0;
|
|
|
|
m_info->options= 0;
|
2007-12-11 15:32:10 +01:00
|
|
|
pthread_mutex_unlock(&m_info->mutex);
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|