Commit 6a3b581b authored by Monty's avatar Monty

MDEV-19745 BACKUP STAGE BLOCK_DDL hangs on flush sequence table

Problem was that FLUSH TABLES where trying to read latest sequence state
which conflicted with a running ALTER SEQUENCE. Removed the reading
of the state, when opening a table for FLUSH, as it's not needed in this
case.

Other thing:
- Fixed a potential issue with concurrently running ALTER SEQUENCE where
  the later ALTER could potentially read old data
parent 08d475c7
...@@ -55,6 +55,10 @@ ...@@ -55,6 +55,10 @@
*/ */
#define HA_OPEN_FOR_ALTER 8192U #define HA_OPEN_FOR_ALTER 8192U
/* Open table for FLUSH */
#define HA_OPEN_FOR_FLUSH 8192U
/* The following is parameter to ha_rkey() how to use key */ /* The following is parameter to ha_rkey() how to use key */
/* /*
......
...@@ -108,8 +108,12 @@ int ha_sequence::open(const char *name, int mode, uint flags) ...@@ -108,8 +108,12 @@ int ha_sequence::open(const char *name, int mode, uint flags)
MY_TEST(flags & HA_OPEN_INTERNAL_TABLE); MY_TEST(flags & HA_OPEN_INTERNAL_TABLE);
reset_statistics(); reset_statistics();
/* Don't try to read the initial row the call is part of create code */ /*
if (!(flags & (HA_OPEN_FOR_CREATE | HA_OPEN_FOR_REPAIR))) Don't try to read the initial row if the call is part of CREATE, REPAIR
or FLUSH
*/
if (!(flags & (HA_OPEN_FOR_CREATE | HA_OPEN_FOR_REPAIR |
HA_OPEN_FOR_FLUSH)))
{ {
if (unlikely((error= table->s->sequence->read_initial_values(table)))) if (unlikely((error= table->s->sequence->read_initial_values(table))))
file->ha_close(); file->ha_close();
...@@ -121,6 +125,7 @@ int ha_sequence::open(const char *name, int mode, uint flags) ...@@ -121,6 +125,7 @@ int ha_sequence::open(const char *name, int mode, uint flags)
The following is needed to fix comparison of rows in The following is needed to fix comparison of rows in
ha_update_first_row() for InnoDB ha_update_first_row() for InnoDB
*/ */
if (!error)
memcpy(table->record[1], table->s->default_values, table->s->reclength); memcpy(table->record[1], table->s->default_values, table->s->reclength);
} }
DBUG_RETURN(error); DBUG_RETURN(error);
......
...@@ -598,12 +598,15 @@ bool flush_tables(THD *thd, flush_tables_type flag) ...@@ -598,12 +598,15 @@ bool flush_tables(THD *thd, flush_tables_type flag)
else else
{ {
/* /*
HA_OPEN_FOR_ALTER is used to allow us to open the table even if HA_OPEN_FOR_FLUSH is used to allow us to open the table even if
TABLE_SHARE::incompatible_version is set. TABLE_SHARE::incompatible_version is set. It also will tell
SEQUENCE engine that we don't have to read the sequence information
(which may cause deadlocks with concurrently running ALTER TABLE or
ALTER SEQUENCE) as we will close the table at once.
*/ */
if (!open_table_from_share(thd, share, &empty_clex_str, if (!open_table_from_share(thd, share, &empty_clex_str,
HA_OPEN_KEYFILE, 0, HA_OPEN_KEYFILE, 0,
HA_OPEN_FOR_ALTER, HA_OPEN_FOR_ALTER | HA_OPEN_FOR_FLUSH,
tmp_table, FALSE, tmp_table, FALSE,
NULL)) NULL))
{ {
......
...@@ -453,7 +453,7 @@ int SEQUENCE::read_initial_values(TABLE *table) ...@@ -453,7 +453,7 @@ int SEQUENCE::read_initial_values(TABLE *table)
/* /*
There is already a mdl_ticket for this table. However, for list_fields There is already a mdl_ticket for this table. However, for list_fields
the MDL lock is of type MDL_SHARED_HIGH_PRIO which is not usable the MDL lock is of type MDL_SHARED_HIGH_PRIO which is not usable
for doing a able lock. Get a proper read lock to solve this. for doing a table lock. Get a proper read lock to solve this.
*/ */
if (table->mdl_ticket == 0) if (table->mdl_ticket == 0)
{ {
...@@ -929,6 +929,8 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) ...@@ -929,6 +929,8 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
table= first_table->table; table= first_table->table;
seq= table->s->sequence; seq= table->s->sequence;
seq->write_lock(table);
new_seq->reserved_until= seq->reserved_until; new_seq->reserved_until= seq->reserved_until;
/* Copy from old sequence those fields that the user didn't specified */ /* Copy from old sequence those fields that the user didn't specified */
...@@ -961,18 +963,18 @@ bool Sql_cmd_alter_sequence::execute(THD *thd) ...@@ -961,18 +963,18 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
first_table->db.str, first_table->db.str,
first_table->table_name.str); first_table->table_name.str);
error= 1; error= 1;
seq->write_unlock(table);
goto end; goto end;
} }
table->s->sequence->write_lock(table);
if (likely(!(error= new_seq->write(table, 1)))) if (likely(!(error= new_seq->write(table, 1))))
{ {
/* Store the sequence values in table share */ /* Store the sequence values in table share */
table->s->sequence->copy(new_seq); seq->copy(new_seq);
} }
else else
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
table->s->sequence->write_unlock(table); seq->write_unlock(table);
if (trans_commit_stmt(thd)) if (trans_commit_stmt(thd))
error= 1; error= 1;
if (trans_commit_implicit(thd)) if (trans_commit_implicit(thd))
......
...@@ -3891,7 +3891,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, ...@@ -3891,7 +3891,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
outparam->write_row_record= NULL; outparam->write_row_record= NULL;
if (share->incompatible_version && if (share->incompatible_version &&
!(ha_open_flags & (HA_OPEN_FOR_ALTER | HA_OPEN_FOR_REPAIR))) !(ha_open_flags & (HA_OPEN_FOR_ALTER | HA_OPEN_FOR_REPAIR |
HA_OPEN_FOR_FLUSH)))
{ {
/* one needs to run mysql_upgrade on the table */ /* one needs to run mysql_upgrade on the table */
error= OPEN_FRM_NEEDS_REBUILD; error= OPEN_FRM_NEEDS_REBUILD;
......
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