mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-36227 Race condition between ALTER TABLE…EXCHANGE PARTITION and SELECT
In commit 6e6a1b316c
(MDEV-35000)
a race condition was exposed.
ha_innobase::check_if_incompatible_data(): If the statistics have
already been initialized for the table, skip the invocation of
innobase_copy_frm_flags_from_create_info() in order to avoid
unexpectedly ruining things for other threads that are concurrently
accessing the table.
dict_stats_save(): Add debug instrumentation that is necessary for
reproducing the interlocking of the failure scenario.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB
|
CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB
|
||||||
|
STATS_PERSISTENT=1 STATS_AUTO_RECALC=0
|
||||||
PARTITION BY RANGE(a)
|
PARTITION BY RANGE(a)
|
||||||
(PARTITION pa VALUES LESS THAN (3),
|
(PARTITION pa VALUES LESS THAN (3),
|
||||||
PARTITION pb VALUES LESS THAN (5));
|
PARTITION pb VALUES LESS THAN (5));
|
||||||
@@ -19,9 +20,30 @@ connection ddl;
|
|||||||
ERROR 23000: Duplicate entry '2-two' for key 'a'
|
ERROR 23000: Duplicate entry '2-two' for key 'a'
|
||||||
connection default;
|
connection default;
|
||||||
DELETE FROM t1;
|
DELETE FROM t1;
|
||||||
disconnect ddl;
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 check status OK
|
test.t1 check status OK
|
||||||
DROP TABLE t1;
|
CREATE TABLE t(a INT, b VARCHAR(10)) ENGINE=InnoDB
|
||||||
|
STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
|
||||||
|
RENAME TABLE t TO u;
|
||||||
|
DELETE FROM mysql.innodb_table_stats WHERE table_name='u';
|
||||||
|
DELETE FROM mysql.innodb_index_stats WHERE table_name='u';
|
||||||
|
SET STATEMENT debug_dbug='+d,dict_stats_save_exit_notify_and_wait' FOR
|
||||||
|
SELECT * FROM u;
|
||||||
|
connection ddl;
|
||||||
|
SET DEBUG_SYNC='open_tables_after_open_and_process_table
|
||||||
|
WAIT_FOR dict_stats_save_finished';
|
||||||
|
ALTER TABLE t1 EXCHANGE PARTITION pb WITH TABLE u;
|
||||||
|
connect sync,localhost,root;
|
||||||
|
SET DEBUG_SYNC='now SIGNAL dict_stats_save_unblock';
|
||||||
|
disconnect sync;
|
||||||
|
connection default;
|
||||||
|
a b
|
||||||
|
connection ddl;
|
||||||
|
disconnect ddl;
|
||||||
|
connection default;
|
||||||
|
SELECT * FROM u;
|
||||||
|
a b
|
||||||
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
DROP TABLE t1,u;
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
--source include/have_debug_sync.inc
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB
|
CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB
|
||||||
|
STATS_PERSISTENT=1 STATS_AUTO_RECALC=0
|
||||||
PARTITION BY RANGE(a)
|
PARTITION BY RANGE(a)
|
||||||
(PARTITION pa VALUES LESS THAN (3),
|
(PARTITION pa VALUES LESS THAN (3),
|
||||||
PARTITION pb VALUES LESS THAN (5));
|
PARTITION pb VALUES LESS THAN (5));
|
||||||
@@ -26,9 +27,46 @@ reap;
|
|||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
DELETE FROM t1;
|
DELETE FROM t1;
|
||||||
disconnect ddl;
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
DROP TABLE t1;
|
|
||||||
|
CREATE TABLE t(a INT, b VARCHAR(10)) ENGINE=InnoDB
|
||||||
|
STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
|
||||||
|
RENAME TABLE t TO u;
|
||||||
|
DELETE FROM mysql.innodb_table_stats WHERE table_name='u';
|
||||||
|
DELETE FROM mysql.innodb_index_stats WHERE table_name='u';
|
||||||
|
|
||||||
|
send SET STATEMENT debug_dbug='+d,dict_stats_save_exit_notify_and_wait' FOR
|
||||||
|
SELECT * FROM u;
|
||||||
|
|
||||||
|
connection ddl;
|
||||||
|
SET DEBUG_SYNC='open_tables_after_open_and_process_table
|
||||||
|
WAIT_FOR dict_stats_save_finished';
|
||||||
|
send ALTER TABLE t1 EXCHANGE PARTITION pb WITH TABLE u;
|
||||||
|
|
||||||
|
connect sync,localhost,root;
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = 'debug sync point: now'
|
||||||
|
and info like 'SET STATEMENT debug_dbug%SELECT * FROM u';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
let $wait_condition=
|
||||||
|
select count(*) = 1 from information_schema.processlist
|
||||||
|
where state = 'Waiting for table metadata lock'
|
||||||
|
and info like 'ALTER TABLE t1 EXCHANGE PARTITION pb WITH TABLE u';
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
SET DEBUG_SYNC='now SIGNAL dict_stats_save_unblock';
|
||||||
|
disconnect sync;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
connection ddl;
|
||||||
|
reap;
|
||||||
|
disconnect ddl;
|
||||||
|
connection default;
|
||||||
|
SELECT * FROM u;
|
||||||
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
|
||||||
|
DROP TABLE t1,u;
|
||||||
|
@@ -2887,6 +2887,13 @@ dberr_t dict_stats_save(dict_table_t* table, index_id_t index_id)
|
|||||||
STRING_WITH_LEN("now SIGNAL dict_stats_save_finished"));
|
STRING_WITH_LEN("now SIGNAL dict_stats_save_finished"));
|
||||||
});
|
});
|
||||||
);
|
);
|
||||||
|
DBUG_EXECUTE_IF("dict_stats_save_exit_notify_and_wait",
|
||||||
|
SCOPE_EXIT([] {
|
||||||
|
debug_sync_set_action(current_thd,
|
||||||
|
STRING_WITH_LEN("now SIGNAL dict_stats_save_finished"
|
||||||
|
" WAIT_FOR dict_stats_save_unblock"));
|
||||||
|
});
|
||||||
|
);
|
||||||
#endif /* ENABLED_DEBUG_SYNC */
|
#endif /* ENABLED_DEBUG_SYNC */
|
||||||
|
|
||||||
if (high_level_read_only) {
|
if (high_level_read_only) {
|
||||||
|
@@ -17424,7 +17424,12 @@ ha_innobase::check_if_incompatible_data(
|
|||||||
param_new = info->option_struct;
|
param_new = info->option_struct;
|
||||||
param_old = table->s->option_struct;
|
param_old = table->s->option_struct;
|
||||||
|
|
||||||
innobase_copy_frm_flags_from_create_info(m_prebuilt->table, info);
|
m_prebuilt->table->stats_mutex_lock();
|
||||||
|
if (!m_prebuilt->table->stat_initialized()) {
|
||||||
|
innobase_copy_frm_flags_from_create_info(
|
||||||
|
m_prebuilt->table, info);
|
||||||
|
}
|
||||||
|
m_prebuilt->table->stats_mutex_unlock();
|
||||||
|
|
||||||
if (table_changes != IS_EQUAL_YES) {
|
if (table_changes != IS_EQUAL_YES) {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user