summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-04-17 12:46:08 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2019-04-17 13:58:22 +0300
commit376bf4ede5c4b6af89ca52f1a5e8dac4e7d5443a (patch)
tree2e51db4e4fa9e5bc22ab0c6008e9d86dbf8d0dd1
parentbc8d173b9f9a629d6301f5e8eb011155b041de4a (diff)
downloadmariadb-git-376bf4ede5c4b6af89ca52f1a5e8dac4e7d5443a.tar.gz
MDEV-19241 InnoDB fails to write MLOG_INDEX_LOAD upon completing ALTER TABLE
Similar to what was done in commit aa3f7a107ce3a9a7f80daf3cadd442a61c5493ab for FULLTEXT INDEX, we must ensure that MLOG_INDEX_LOAD records will always be written if redo logging was disabled. row_merge_build_indexes(): Invoke row_merge_write_redo() also when online operation is not being executed or an error occurs. In case of an error, invoke flush_observer->interrupted() so that the pages will not be flushed but merely evicted from the buffer pool. Before resuming redo logging, it is crucial for the correctness of mariabackup and InnoDB crash recovery to flush or evict all affected pages and to write MLOG_INDEX_LOAD records.
-rw-r--r--mysql-test/suite/innodb/r/log_alter_table.result8
-rw-r--r--mysql-test/suite/innodb/t/log_alter_table.test8
-rw-r--r--storage/innobase/row/row0merge.cc41
3 files changed, 31 insertions, 26 deletions
diff --git a/mysql-test/suite/innodb/r/log_alter_table.result b/mysql-test/suite/innodb/r/log_alter_table.result
index a6f35543c04..9cb9ed77e33 100644
--- a/mysql-test/suite/innodb/r/log_alter_table.result
+++ b/mysql-test/suite/innodb/r/log_alter_table.result
@@ -7,11 +7,11 @@
#
CREATE TABLE t1 (a INT NOT NULL, b INT UNIQUE) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,2);
-ALTER TABLE t1 ADD PRIMARY KEY(a), ALGORITHM=INPLACE;
-ALTER TABLE t1 DROP INDEX b, ADD INDEX (b);
+ALTER TABLE t1 ADD PRIMARY KEY(a), LOCK=SHARED, ALGORITHM=INPLACE;
+ALTER TABLE t1 DROP INDEX b, ADD INDEX (b), LOCK=SHARED;
# Kill the server
-FOUND 1 /scan .*: multi-log rec MLOG_FILE_CREATE2.*page .*:0/ in mysqld.1.err
-FOUND 1 /scan .*: log rec MLOG_INDEX_LOAD/ in mysqld.1.err
+FOUND 2 /scan \d+: multi-log rec MLOG_FILE_CREATE2 len \d+ page \d+:0/ in mysqld.1.err
+FOUND 3 /scan \d+: log rec MLOG_INDEX_LOAD/ in mysqld.1.err
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
diff --git a/mysql-test/suite/innodb/t/log_alter_table.test b/mysql-test/suite/innodb/t/log_alter_table.test
index 6f12dfaf0b9..c92953f16a1 100644
--- a/mysql-test/suite/innodb/t/log_alter_table.test
+++ b/mysql-test/suite/innodb/t/log_alter_table.test
@@ -19,9 +19,9 @@ CREATE TABLE t1 (a INT NOT NULL, b INT UNIQUE) ENGINE=InnoDB;
# MLOG_INDEX_LOAD will not be emitted for empty tables. Insert a row.
INSERT INTO t1 VALUES (1,2);
# We should get two MLOG_INDEX_LOAD for this.
-ALTER TABLE t1 ADD PRIMARY KEY(a), ALGORITHM=INPLACE;
+ALTER TABLE t1 ADD PRIMARY KEY(a), LOCK=SHARED, ALGORITHM=INPLACE;
# And one MLOG_INDEX_LOAD for this.
-ALTER TABLE t1 DROP INDEX b, ADD INDEX (b);
+ALTER TABLE t1 DROP INDEX b, ADD INDEX (b), LOCK=SHARED;
--let CLEANUP_IF_CHECKPOINT=DROP TABLE t1;
--source include/no_checkpoint_end.inc
@@ -32,10 +32,10 @@ ALTER TABLE t1 DROP INDEX b, ADD INDEX (b);
let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_ABORT=NOT FOUND;
# ensure that we have exactly 2 records there.
-let SEARCH_PATTERN=scan .*: multi-log rec MLOG_FILE_CREATE2.*page .*:0;
+let SEARCH_PATTERN=scan \d+: multi-log rec MLOG_FILE_CREATE2 len \d+ page \d+:0;
--source include/search_pattern_in_file.inc
# ensure that we have exactly 3 records there.
-let SEARCH_PATTERN=scan .*: log rec MLOG_INDEX_LOAD;
+let SEARCH_PATTERN=scan \d+: log rec MLOG_INDEX_LOAD;
--source include/search_pattern_in_file.inc
CHECK TABLE t1;
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index e659654387f..3447ade7606 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -4893,23 +4893,28 @@ wait_again:
if (indexes[i]->type & DICT_FTS) {
row_fts_psort_info_destroy(psort_info, merge_info);
fts_psort_initiated = false;
- } else if (error != DB_SUCCESS || !online) {
- /* Do not apply any online log. */
+ } else if (dict_index_is_spatial(indexes[i])) {
+ /* We never disable redo logging for
+ creating SPATIAL INDEX. Avoid writing any
+ unnecessary MLOG_INDEX_LOAD record. */
} else if (old_table != new_table) {
ut_ad(!sort_idx->online_log);
ut_ad(sort_idx->online_status
== ONLINE_INDEX_COMPLETE);
- } else {
- if (dict_index_is_spatial(indexes[i])) {
- /* We never disable redo logging for
- creating SPATIAL INDEX. Avoid writing any
- unnecessary MLOG_INDEX_LOAD record. */
- } else if (FlushObserver* flush_observer =
- trx->get_flush_observer()) {
- flush_observer->flush();
- row_merge_write_redo(indexes[i]);
+ } else if (FlushObserver* flush_observer =
+ trx->get_flush_observer()) {
+ if (error != DB_SUCCESS) {
+ flush_observer->interrupted();
}
+ flush_observer->flush();
+ row_merge_write_redo(indexes[i]);
+ }
+ if (old_table != new_table
+ || (indexes[i]->type & (DICT_FTS | DICT_SPATIAL))
+ || error != DB_SUCCESS || !online) {
+ /* Do not apply any online log. */
+ } else {
if (global_system_variables.log_warnings > 2) {
sql_print_information(
"InnoDB: Online DDL : Applying"
@@ -5016,13 +5021,7 @@ func_exit:
flush_observer->flush();
- trx->remove_flush_observer();
-
- if (trx_is_interrupted(trx)) {
- error = DB_INTERRUPTED;
- }
-
- if (error == DB_SUCCESS && old_table != new_table) {
+ if (old_table != new_table) {
for (const dict_index_t* index
= dict_table_get_first_index(new_table);
index != NULL;
@@ -5033,6 +5032,12 @@ func_exit:
}
}
}
+
+ trx->remove_flush_observer();
+
+ if (trx_is_interrupted(trx)) {
+ error = DB_INTERRUPTED;
+ }
}
DBUG_RETURN(error);