1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge c-0409e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/bug19122

into  c-0409e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/bug19305
This commit is contained in:
mikael@c-0409e253.1238-1-64736c10.cust.bredbandsbolaget.se
2006-06-12 17:49:38 -04:00
10 changed files with 586 additions and 69 deletions

View File

@ -5378,6 +5378,79 @@ static void release_log_entries(partition_info *part_info)
}
/*
Get a lock on table name to avoid that anyone can open the table in
a critical part of the ALTER TABLE.
SYNOPSIS
get_name_lock()
lpt Struct carrying parameters
RETURN VALUES
FALSE Success
TRUE Failure
*/
static int get_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
{
int error= 0;
DBUG_ENTER("get_name_lock");
bzero(&lpt->table_list, sizeof(lpt->table_list));
lpt->table_list.db= (char*)lpt->db;
lpt->table_list.table= lpt->table;
lpt->table_list.table_name= (char*)lpt->table_name;
pthread_mutex_lock(&LOCK_open);
error= lock_table_name(lpt->thd, &lpt->table_list, FALSE);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(error);
}
/*
Unlock and close table before renaming and dropping partitions
SYNOPSIS
alter_close_tables()
lpt Struct carrying parameters
RETURN VALUES
0
*/
static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
{
THD *thd= lpt->thd;
TABLE *table= lpt->table;
DBUG_ENTER("alter_close_tables");
/*
We need to also unlock tables and close all handlers.
We set lock to zero to ensure we don't do this twice
and we set db_stat to zero to ensure we don't close twice.
*/
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
table->file->close();
table->db_stat= 0;
DBUG_RETURN(0);
}
/*
Release a lock name
SYNOPSIS
release_name_lock()
lpt
RETURN VALUES
0
*/
static int release_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
{
DBUG_ENTER("release_name_lock");
pthread_mutex_lock(&LOCK_open);
unlock_table_name(lpt->thd, &lpt->table_list);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(0);
}
/*
Handle errors for ALTER TABLE for partitioning
SYNOPSIS
@ -5528,7 +5601,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> *create_list,
List<Key> *key_list, const char *db,
List<Key> *key_list, char *db,
const char *table_name,
uint fast_alter_partition)
{
@ -5669,8 +5742,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
2) Write the ddl log to ensure that the operation is completed
even in the presence of a MySQL Server crash
3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to
the table have completed
4) Write the bin log
the table have completed. This ensures that other threads can not
execute on the table in parallel.
4) Get a name lock on the table. This ensures that we can release all
locks on the table and since no one can open the table, there can
be no new threads accessing the table. They will be hanging on the
name lock.
5) Close all tables that have already been opened but didn't stumble on
the abort locked previously. This is done as part of the
get_name_lock call.
6) We are now ready to release all locks we got in this thread.
7) Write the bin log
Unfortunately the writing of the binlog is not synchronised with
other logging activities. So no matter in which order the binlog
is written compared to other activities there will always be cases
@ -5681,14 +5763,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
require writing the statement first in the ddl log and then
when recovering from the crash read the binlog and insert it into
the binlog if not written already.
5) Install the previously written shadow frm file
6) Ensure that any users that has opened the table but not yet
reached the abort lock do that before downgrading the lock.
7) Prepare MyISAM handlers for drop of partitions
8) Drop the partitions
9) Remove entries from ddl log
10) Wait until all accesses using the old frm file has completed
11) Complete query
8) Install the previously written shadow frm file
9) Prepare handlers for drop of partitions
10) Drop the partitions
11) Remove entries from ddl log
12) Release name lock so that all other threads can access the table
again.
13) Complete query
We insert Error injections at all places where it could be interesting
to test if recovery is properly done.
@ -5701,22 +5782,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_drop_partition_3") ||
(not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
ERROR_INJECT_CRASH("crash_drop_partition_4") ||
get_name_lock(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
alter_close_tables(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_6") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_drop_partition_4") ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
ERROR_INJECT_CRASH("crash_drop_partition_7") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
((frm_install= FALSE), FALSE) ||
(close_open_tables_and_downgrade(lpt), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_6") ||
mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_7") ||
(write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_8") ||
(mysql_wait_completed_table(lpt, table), FALSE))
mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_9") ||
(write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_10") ||
(release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, TRUE, frm_install);
DBUG_RETURN(TRUE);
@ -5742,15 +5825,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing.
4) Write binlog
5) Now the change is completed except for the installation of the
4) Get a name lock on the table. This ensures that we can release all
locks on the table and since no one can open the table, there can
be no new threads accessing the table. They will be hanging on the
name lock.
5) Close all tables that have already been opened but didn't stumble on
the abort locked previously. This is done as part of the
get_name_lock call.
6) Close all table handlers and unlock all handlers but retain name lock
7) Write binlog
8) Now the change is completed except for the installation of the
new frm file. We thus write an action in the log to change to
the shadow frm file
6) Install the new frm file of the table where the partitions are
9) Install the new frm file of the table where the partitions are
added to the table.
7) Wait until all accesses using the old frm file has completed
8) Remove entries from ddl log
9) Complete query
10)Wait until all accesses using the old frm file has completed
11)Remove entries from ddl log
12)Release name lock
13)Complete query
*/
if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_1") ||
@ -5759,19 +5851,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_3") ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
ERROR_INJECT_CRASH("crash_add_partition_3") ||
get_name_lock(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_4") ||
alter_close_tables(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_5") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_add_partition_4") ||
ERROR_INJECT_CRASH("crash_add_partition_6") ||
write_log_rename_frm(lpt) ||
(not_completed= FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_5") ||
ERROR_INJECT_CRASH("crash_add_partition_7") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_add_partition_6") ||
(close_open_tables_and_downgrade(lpt), FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_8") ||
(write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_7"))
ERROR_INJECT_CRASH("crash_add_partition_9") ||
(release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE);
@ -5821,16 +5918,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
5) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing.
6) Prepare MyISAM handlers for rename and delete of partitions
7) Rename the reorged partitions such that they are no longer
used and rename those added to their real new names.
8) Write bin log
9) Install the shadow frm file
10) Wait until all accesses using the old frm file has completed
11) Drop the reorganised partitions
12) Remove log entry
13)Wait until all accesses using the old frm file has completed
14)Complete query
6) Get a name lock of the table
7) Close all tables opened but not yet locked, after this call we are
certain that no other thread is in the lock wait queue or has
opened the table. The name lock will ensure that they are blocked
on the open call. This is achieved also by get_name_lock call.
8) Close all partitions opened by this thread, but retain name lock.
9) Write bin log
10) Prepare handlers for rename and delete of partitions
11) Rename and drop the reorged partitions such that they are no
longer used and rename those added to their real new names.
12) Install the shadow frm file
13) Release the name lock to enable other threads to start using the
table again.
14) Complete query
*/
if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_1") ||
@ -5842,24 +5943,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_change_partition_4") ||
(not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
ERROR_INJECT_CRASH("crash_change_partition_5") ||
get_name_lock(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
alter_close_tables(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_5") ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_9") ||
mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_61") ||
ERROR_INJECT_CRASH("crash_change_partition_10") ||
mysql_rename_partitions(lpt) ||
((frm_install= TRUE), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
(close_open_tables_and_downgrade(lpt), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_9") ||
ERROR_INJECT_CRASH("crash_change_partition_11") ||
(write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_10") ||
(mysql_wait_completed_table(lpt, table), FALSE))
ERROR_INJECT_CRASH("crash_change_partition_12") ||
(release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE);