mirror of
https://github.com/MariaDB/server.git
synced 2025-11-27 05:41:41 +03:00
Several race conditions between MDEV-15562 instant ALTER TABLE and purge were observed. The most obvious race condition resulted in a reported assertion failure in dict_index_t::instant_add_field(): instant.n_core_fields == n_core_fields would not hold if the table was emptied by purge after the time dict_table_t::prepare_instant() was called. During purge, it can turn out that the table is logically empty, only containing a metadata record. If the metadata record is of the type created by MDEV-11369 instant ADD COLUMN, it can be removed and dict_index_t::clear_instant_add() can be called. This will convert the table to the canonical non-instant format. (If the metadata record is of the MDEV-15562 type, then it can only be deleted if the table becomes empty as the result of rollback of an instant ALTER TABLE operation.) row_purge_remove_clust_if_poss_low(): Add a debug check that ensures that purge can never remove a MDEV-15562 metadata record. ha_innobase::open(): Add a comment about the necessity of rolling back any recovered instant ALTER TABLE transaction on the table. instant_metadata_lock(): An auxiliary function to acquire a page latch on the metadata record, to prevent race conditions. dict_table_t::prepare_instant(), dict_index_t::instant_add_field(), dict_table_t::rollback_instant(), innobase_instant_try(): Invoke instant_metadata_lock() in order to prevent race conditions. dict_index_t::instant_add_field(): Correct debug assertions. The == was guaranteed by code in dict_table_t::prepare_instant() that was introduced in MDEV-15562. Due to the race condition, we could occasionally have <=, but never >= like the code was after MDEV-11369. ha_innobase_inplace_ctx::instant_column(): Wrapper for dict_table_t::instant_column(). Add debug assertions.
47 lines
1.4 KiB
Plaintext
47 lines
1.4 KiB
Plaintext
SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
|
#
|
|
# MDEV-17793 Crash in purge after instant DROP and emptying the table
|
|
#
|
|
connect prevent_purge,localhost,root;
|
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
|
connection default;
|
|
CREATE TABLE t1 (f1 INT, f2 INT) ENGINE=InnoDB;
|
|
INSERT INTO t1 () VALUES ();
|
|
ALTER TABLE t1 DROP f2, ADD COLUMN f2 INT;
|
|
ALTER TABLE t1 DROP f1;
|
|
DELETE FROM t1;
|
|
connection prevent_purge;
|
|
COMMIT;
|
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
|
connection default;
|
|
ALTER TABLE t1 ADD COLUMN extra TINYINT UNSIGNED NOT NULL DEFAULT 42;
|
|
InnoDB 1 transactions not purged
|
|
ALTER TABLE t1 DROP extra;
|
|
disconnect prevent_purge;
|
|
InnoDB 0 transactions not purged
|
|
DROP TABLE t1;
|
|
#
|
|
# MDEV-17813 Crash in instant ALTER TABLE due to purge
|
|
# concurrently emptying table
|
|
#
|
|
CREATE TABLE t1 (f2 INT) ENGINE=InnoDB;
|
|
INSERT INTO t1 SET f2=1;
|
|
ALTER TABLE t1 ADD COLUMN f1 INT;
|
|
connect purge_control,localhost,root;
|
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
|
connection default;
|
|
DELETE FROM t1;
|
|
SET DEBUG_SYNC='innodb_commit_inplace_alter_table_enter SIGNAL go WAIT_FOR do';
|
|
ALTER TABLE t1 ADD COLUMN f3 INT;
|
|
connection purge_control;
|
|
SET DEBUG_SYNC='now WAIT_FOR go';
|
|
COMMIT;
|
|
InnoDB 0 transactions not purged
|
|
SET DEBUG_SYNC='now SIGNAL do';
|
|
disconnect purge_control;
|
|
connection default;
|
|
SET DEBUG_SYNC=RESET;
|
|
DROP TABLE t1;
|
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|