Commit 9927b36e authored by Sergei Golubchik's avatar Sergei Golubchik

merge of "Bug#16216513 INPLACE ALTER DISABLED FOR PARTITIONED TABLES"

revno: 4777
committer: Marko Mäkelä <marko.makela@oracle.com>
branch nick: mysql-5.6
timestamp: Fri 2013-02-15 10:32:25 +0200
message:
  Bug#16216513 INPLACE ALTER DISABLED FOR PARTITIONED TABLES
parent 8db4a518
...@@ -8145,7 +8145,6 @@ class ha_partition_inplace_ctx : public inplace_alter_handler_ctx ...@@ -8145,7 +8145,6 @@ class ha_partition_inplace_ctx : public inplace_alter_handler_ctx
{ {
public: public:
inplace_alter_handler_ctx **handler_ctx_array; inplace_alter_handler_ctx **handler_ctx_array;
bool rollback_done;
private: private:
uint m_tot_parts; uint m_tot_parts;
...@@ -8153,7 +8152,6 @@ public: ...@@ -8153,7 +8152,6 @@ public:
ha_partition_inplace_ctx(THD *thd, uint tot_parts) ha_partition_inplace_ctx(THD *thd, uint tot_parts)
: inplace_alter_handler_ctx(), : inplace_alter_handler_ctx(),
handler_ctx_array(NULL), handler_ctx_array(NULL),
rollback_done(false),
m_tot_parts(tot_parts) m_tot_parts(tot_parts)
{} {}
...@@ -8172,14 +8170,11 @@ enum_alter_inplace_result ...@@ -8172,14 +8170,11 @@ enum_alter_inplace_result
ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
Alter_inplace_info *ha_alter_info) Alter_inplace_info *ha_alter_info)
{ {
#ifdef PARTITION_SUPPORTS_INPLACE_ALTER
uint index= 0; uint index= 0;
enum_alter_inplace_result result= HA_ALTER_INPLACE_NO_LOCK; enum_alter_inplace_result result= HA_ALTER_INPLACE_NO_LOCK;
ha_partition_inplace_ctx *part_inplace_ctx; ha_partition_inplace_ctx *part_inplace_ctx;
bool first_is_set= false;
THD *thd= ha_thd(); THD *thd= ha_thd();
#else
enum_alter_inplace_result result= HA_ALTER_INPLACE_NOT_SUPPORTED;
#endif
DBUG_ENTER("ha_partition::check_if_supported_inplace_alter"); DBUG_ENTER("ha_partition::check_if_supported_inplace_alter");
/* /*
...@@ -8190,32 +8185,18 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, ...@@ -8190,32 +8185,18 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
if (ha_alter_info->alter_info->flags == Alter_info::ALTER_PARTITION) if (ha_alter_info->alter_info->flags == Alter_info::ALTER_PARTITION)
DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK); DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK);
#ifndef PARTITION_SUPPORTS_INPLACE_ALTER
/*
Due to bug#14760210 partitions can be out-of-sync in case
commit_inplace_alter_table fails after the first partition.
Until we can either commit all partitions at the same time or
have an atomic recover on failure/crash we don't support any
inplace alter.
TODO: investigate what happens when indexes are out-of-sync
between partitions. If safe and possible to recover from,
then we could allow ADD/DROP INDEX.
*/
DBUG_RETURN(result);
#else
part_inplace_ctx= part_inplace_ctx=
new (thd->mem_root) ha_partition_inplace_ctx(thd, m_tot_parts); new (thd->mem_root) ha_partition_inplace_ctx(thd, m_tot_parts);
if (!part_inplace_ctx) if (!part_inplace_ctx)
DBUG_RETURN(HA_ALTER_ERROR); DBUG_RETURN(HA_ALTER_ERROR);
part_inplace_ctx->handler_ctx_array= (inplace_alter_handler_ctx **) part_inplace_ctx->handler_ctx_array= (inplace_alter_handler_ctx **)
thd->alloc(sizeof(inplace_alter_handler_ctx *) * m_tot_parts); thd->alloc(sizeof(inplace_alter_handler_ctx *) * (m_tot_parts + 1));
if (!part_inplace_ctx->handler_ctx_array) if (!part_inplace_ctx->handler_ctx_array)
DBUG_RETURN(HA_ALTER_ERROR); DBUG_RETURN(HA_ALTER_ERROR);
for (index= 0; index < m_tot_parts; index++) /* Set all to NULL, including the terminating one. */
for (index= 0; index <= m_tot_parts; index++)
part_inplace_ctx->handler_ctx_array[index]= NULL; part_inplace_ctx->handler_ctx_array[index]= NULL;
for (index= 0; index < m_tot_parts; index++) for (index= 0; index < m_tot_parts; index++)
...@@ -8225,15 +8206,32 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, ...@@ -8225,15 +8206,32 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
ha_alter_info); ha_alter_info);
part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
if (index == 0)
{
first_is_set= (ha_alter_info->handler_ctx != NULL);
}
else if (first_is_set != (ha_alter_info->handler_ctx != NULL))
{
/* Either none or all partitions must set handler_ctx! */
DBUG_ASSERT(0);
DBUG_RETURN(HA_ALTER_ERROR);
}
if (p_result < result) if (p_result < result)
result= p_result; result= p_result;
if (result == HA_ALTER_ERROR) if (result == HA_ALTER_ERROR)
break; break;
} }
ha_alter_info->handler_ctx= part_inplace_ctx; ha_alter_info->handler_ctx= part_inplace_ctx;
/*
To indicate for future inplace calls that there are several
partitions/handlers that need to be committed together,
we set group_commit_ctx to the NULL terminated array of
the partitions handlers.
*/
ha_alter_info->group_commit_ctx= part_inplace_ctx->handler_ctx_array;
DBUG_RETURN(result); DBUG_RETURN(result);
#endif
} }
...@@ -8314,8 +8312,8 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table, ...@@ -8314,8 +8312,8 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info, Alter_inplace_info *ha_alter_info,
bool commit) bool commit)
{ {
uint index= 0;
ha_partition_inplace_ctx *part_inplace_ctx; ha_partition_inplace_ctx *part_inplace_ctx;
bool error= false;
DBUG_ENTER("ha_partition::commit_inplace_alter_table"); DBUG_ENTER("ha_partition::commit_inplace_alter_table");
...@@ -8329,117 +8327,52 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table, ...@@ -8329,117 +8327,52 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table,
part_inplace_ctx= part_inplace_ctx=
static_cast<class ha_partition_inplace_ctx*>(ha_alter_info->handler_ctx); static_cast<class ha_partition_inplace_ctx*>(ha_alter_info->handler_ctx);
if (!commit && part_inplace_ctx->rollback_done) if (commit)
DBUG_RETURN(false); // We have already rolled back changes.
for (index= 0; index < m_tot_parts; index++)
{ {
ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index]; DBUG_ASSERT(ha_alter_info->group_commit_ctx ==
if (m_file[index]->ha_commit_inplace_alter_table(altered_table, part_inplace_ctx->handler_ctx_array);
ha_alter_info, commit)) ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[0];
error= m_file[0]->ha_commit_inplace_alter_table(altered_table,
ha_alter_info, commit);
if (error)
goto end;
if (ha_alter_info->group_commit_ctx)
{ {
part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; /*
goto err; If ha_alter_info->group_commit_ctx is not set to NULL,
} then the engine did only commit the first partition!
part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; The engine is probably new, since both innodb and the default
DBUG_EXECUTE_IF("ha_partition_fail_final_add_index", { implementation of handler::commit_inplace_alter_table sets it to NULL
/* Simulate failure by rollback of the second partition */ and simply return false, since it allows metadata changes only.
if (m_tot_parts > 1) Loop over all other partitions as to follow the protocol!
*/
uint i;
DBUG_ASSERT(0);
for (i= 1; i < m_tot_parts; i++)
{ {
index++; ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i];
ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index]; error|= m_file[i]->ha_commit_inplace_alter_table(altered_table,
m_file[index]->ha_commit_inplace_alter_table(altered_table, ha_alter_info,
ha_alter_info, false); true);
part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
goto err;
} }
});
} }
ha_alter_info->handler_ctx= part_inplace_ctx;
DBUG_RETURN(false);
err:
ha_alter_info->handler_ctx= part_inplace_ctx;
/*
Reverting committed changes is (for now) only possible for ADD INDEX
For other changes we will just try to rollback changes.
*/
if (index > 0 &&
ha_alter_info->handler_flags & (Alter_inplace_info::ADD_INDEX |
Alter_inplace_info::ADD_UNIQUE_INDEX |
Alter_inplace_info::ADD_PK_INDEX))
{
Alter_inplace_info drop_info(ha_alter_info->create_info,
ha_alter_info->alter_info,
NULL, 0,
ha_alter_info->modified_part_info,
ha_alter_info->ignore);
if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX)
drop_info.handler_flags|= Alter_inplace_info::DROP_INDEX;
if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_UNIQUE_INDEX)
drop_info.handler_flags|= Alter_inplace_info::DROP_UNIQUE_INDEX;
if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX)
drop_info.handler_flags|= Alter_inplace_info::DROP_PK_INDEX;
drop_info.index_drop_count= ha_alter_info->index_add_count;
drop_info.index_drop_buffer=
(KEY**) ha_thd()->alloc(sizeof(KEY*) * drop_info.index_drop_count);
if (!drop_info.index_drop_buffer)
{
sql_print_error("Failed with error handling of adding index:\n"
"committing index failed, and when trying to revert "
"already committed partitions we failed allocating\n"
"memory for the index for table '%s'",
table_share->table_name.str);
DBUG_RETURN(true);
}
for (uint i= 0; i < drop_info.index_drop_count; i++)
drop_info.index_drop_buffer[i]=
&ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]];
// Drop index for each partition where we already committed new index.
for (uint i= 0; i < index; i++)
{
bool error= m_file[i]->ha_prepare_inplace_alter_table(altered_table,
&drop_info);
error|= m_file[i]->ha_inplace_alter_table(altered_table, &drop_info);
error|= m_file[i]->ha_commit_inplace_alter_table(altered_table,
&drop_info, true);
if (error)
sql_print_error("Failed with error handling of adding index:\n"
"committing index failed, and when trying to revert "
"already committed partitions we failed removing\n"
"the index for table '%s' partition nr %d",
table_share->table_name.str, i);
} }
else
// Rollback uncommitted changes. {
for (uint i= index+1; i < m_tot_parts; i++) uint i;
for (i= 0; i < m_tot_parts; i++)
{ {
/* Rollback, commit == false, is done for each partition! */
ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i]; ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i];
if (m_file[i]->ha_commit_inplace_alter_table(altered_table, if (m_file[i]->ha_commit_inplace_alter_table(altered_table,
ha_alter_info, false)) ha_alter_info, false))
{ error= true;
/* How could this happen? */
sql_print_error("Failed with error handling of adding index:\n"
"Rollback of add_index failed for table\n"
"'%s' partition nr %d",
table_share->table_name.str, i);
} }
part_inplace_ctx->handler_ctx_array[i]= ha_alter_info->handler_ctx;
} }
end:
// We have now reverted/rolled back changes. Set flag to prevent
// it from being done again.
part_inplace_ctx->rollback_done= true;
print_error(HA_ERR_NO_PARTITION_FOUND, MYF(0));
}
ha_alter_info->handler_ctx= part_inplace_ctx; ha_alter_info->handler_ctx= part_inplace_ctx;
DBUG_RETURN(true); DBUG_RETURN(error);
} }
......
...@@ -1860,6 +1860,18 @@ public: ...@@ -1860,6 +1860,18 @@ public:
*/ */
inplace_alter_handler_ctx *handler_ctx; inplace_alter_handler_ctx *handler_ctx;
/**
If the table uses several handlers, like ha_partition uses one handler
per partition, this contains a Null terminated array of ctx pointers
that should all be committed together.
Or NULL if only handler_ctx should be committed.
Set to NULL if the low level handler::commit_inplace_alter_table uses it,
to signal to the main handler that everything was committed as atomically.
@see inplace_alter_handler_ctx for information about object lifecycle.
*/
inplace_alter_handler_ctx **group_commit_ctx;
/** /**
Flags describing in detail which operations the storage engine is to execute. Flags describing in detail which operations the storage engine is to execute.
*/ */
...@@ -1908,6 +1920,7 @@ public: ...@@ -1908,6 +1920,7 @@ public:
index_add_count(0), index_add_count(0),
index_add_buffer(NULL), index_add_buffer(NULL),
handler_ctx(NULL), handler_ctx(NULL),
group_commit_ctx(NULL),
handler_flags(0), handler_flags(0),
modified_part_info(modified_part_info_arg), modified_part_info(modified_part_info_arg),
ignore(ignore_arg), ignore(ignore_arg),
...@@ -3627,6 +3640,10 @@ protected: ...@@ -3627,6 +3640,10 @@ protected:
@note In case of partitioning, this function might be called for rollback @note In case of partitioning, this function might be called for rollback
without prepare_inplace_alter_table() having been called first. without prepare_inplace_alter_table() having been called first.
Also partitioned tables sets ha_alter_info->group_commit_ctx to a NULL
terminated array of the partitions handlers and if all of them are
committed as one, then group_commit_ctx should be set to NULL to indicate
to the partitioning handler that all partitions handlers are committed.
@see prepare_inplace_alter_table(). @see prepare_inplace_alter_table().
@param altered_table TABLE object for new version of table. @param altered_table TABLE object for new version of table.
...@@ -3641,7 +3658,11 @@ protected: ...@@ -3641,7 +3658,11 @@ protected:
virtual bool commit_inplace_alter_table(TABLE *altered_table, virtual bool commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info, Alter_inplace_info *ha_alter_info,
bool commit) bool commit)
{ return false; } {
/* Nothing to commit/rollback, mark all handlers committed! */
ha_alter_info->group_commit_ctx= NULL;
return false;
}
/** /**
......
...@@ -5388,6 +5388,7 @@ ha_innobase::commit_inplace_alter_table( ...@@ -5388,6 +5388,7 @@ ha_innobase::commit_inplace_alter_table(
if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) { if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) {
DBUG_ASSERT(!ctx0); DBUG_ASSERT(!ctx0);
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
ha_alter_info->group_commit_ctx = NULL;
DBUG_RETURN(false); DBUG_RETURN(false);
} }
...@@ -5396,12 +5397,17 @@ ha_innobase::commit_inplace_alter_table( ...@@ -5396,12 +5397,17 @@ ha_innobase::commit_inplace_alter_table(
inplace_alter_handler_ctx** ctx_array; inplace_alter_handler_ctx** ctx_array;
inplace_alter_handler_ctx* ctx_single[2]; inplace_alter_handler_ctx* ctx_single[2];
if (ha_alter_info->group_commit_ctx) {
ctx_array = ha_alter_info->group_commit_ctx;
} else {
ctx_single[0] = ctx0; ctx_single[0] = ctx0;
ctx_single[1] = NULL; ctx_single[1] = NULL;
ctx_array = ctx_single; ctx_array = ctx_single;
}
DBUG_ASSERT(ctx0 == ctx_array[0]); DBUG_ASSERT(ctx0 == ctx_array[0]);
ut_ad(prebuilt->table == ctx0->old_table); ut_ad(prebuilt->table == ctx0->old_table);
ha_alter_info->group_commit_ctx = NULL;
/* Free the ctx->trx of other partitions, if any. We will only /* Free the ctx->trx of other partitions, if any. We will only
use the ctx0->trx here. Others may have been allocated in use the ctx0->trx here. Others may have been allocated in
......
...@@ -5403,6 +5403,7 @@ ha_innobase::commit_inplace_alter_table( ...@@ -5403,6 +5403,7 @@ ha_innobase::commit_inplace_alter_table(
if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) { if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) {
DBUG_ASSERT(!ctx0); DBUG_ASSERT(!ctx0);
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE); MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
ha_alter_info->group_commit_ctx = NULL;
DBUG_RETURN(false); DBUG_RETURN(false);
} }
...@@ -5411,12 +5412,17 @@ ha_innobase::commit_inplace_alter_table( ...@@ -5411,12 +5412,17 @@ ha_innobase::commit_inplace_alter_table(
inplace_alter_handler_ctx** ctx_array; inplace_alter_handler_ctx** ctx_array;
inplace_alter_handler_ctx* ctx_single[2]; inplace_alter_handler_ctx* ctx_single[2];
if (ha_alter_info->group_commit_ctx) {
ctx_array = ha_alter_info->group_commit_ctx;
} else {
ctx_single[0] = ctx0; ctx_single[0] = ctx0;
ctx_single[1] = NULL; ctx_single[1] = NULL;
ctx_array = ctx_single; ctx_array = ctx_single;
}
DBUG_ASSERT(ctx0 == ctx_array[0]); DBUG_ASSERT(ctx0 == ctx_array[0]);
ut_ad(prebuilt->table == ctx0->old_table); ut_ad(prebuilt->table == ctx0->old_table);
ha_alter_info->group_commit_ctx = NULL;
/* Free the ctx->trx of other partitions, if any. We will only /* Free the ctx->trx of other partitions, if any. We will only
use the ctx0->trx here. Others may have been allocated in use the ctx0->trx here. Others may have been allocated in
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment