summaryrefslogtreecommitdiff
path: root/storage/innobase/fil
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-07-17 15:55:45 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-07-20 14:48:56 +0300
commit57ec42bc321dee796ce8e711a4499cd665513009 (patch)
tree95d114483bfb0c7be68d28186ec83ea9d2823533 /storage/innobase/fil
parent98e2c17e9e20898bc8c1e58c57e0666502ec447e (diff)
downloadmariadb-git-57ec42bc321dee796ce8e711a4499cd665513009.tar.gz
MDEV-23190 InnoDB data file extension is not crash-safe
When InnoDB is extending a data file, it is updating the FSP_SIZE field in the first page of the data file. In commit 8451e09073e8b1a300f177d74a9e3a530776640a (MDEV-11556) we removed a work-around for this bug and made recovery stricter, by making it track changes to FSP_SIZE via redo log records, and extend the data files before any changes are being applied to them. It turns out that the function fsp_fill_free_list() is not crash-safe with respect to this when it is initializing the change buffer bitmap page (page 1, or generally, N*innodb_page_size+1). It uses a separate mini-transaction that is committed (and will be written to the redo log file) before the mini-transaction that actually extended the data file. Hence, recovery can observe a reference to a page that is beyond the current end of the data file. fsp_fill_free_list(): Initialize the change buffer bitmap page in the same mini-transaction. The rest of the changes are fixing a bug that the use of the separate mini-transaction was attempting to work around. Namely, we must ensure that no other thread will access the change buffer bitmap page before our mini-transaction has been committed and all page latches have been released. That is, for read-ahead as well as neighbour flushing, we must avoid accessing pages that might not yet be durably part of the tablespace. fil_space_t::committed_size: The size of the tablespace as persisted by mtr_commit(). fil_space_t::max_page_number_for_io(): Limit the highest page number for I/O batches to committed_size. MTR_MEMO_SPACE_X_LOCK: Replaces MTR_MEMO_X_LOCK for fil_space_t::latch. mtr_x_space_lock(): Replaces mtr_x_lock() for fil_space_t::latch. mtr_memo_slot_release_func(): When releasing MTR_MEMO_SPACE_X_LOCK, copy space->size to space->committed_size. In this way, read-ahead or flushing will never be invoked on pages that do not yet exist according to FSP_SIZE.
Diffstat (limited to 'storage/innobase/fil')
-rw-r--r--storage/innobase/fil/fil0fil.cc5
1 files changed, 4 insertions, 1 deletions
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index ac48db75624..62fb8deaf72 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -676,7 +676,7 @@ fil_node_open_file(
#ifdef UNIV_HOTBACKUP
add_size:
#endif /* UNIV_HOTBACKUP */
- space->size += node->size;
+ space->committed_size = space->size += node->size;
}
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(space->flags);
@@ -1151,6 +1151,9 @@ retry:
ut_a(success);
/* InnoDB data files cannot shrink. */
ut_a(space->size >= size);
+ if (size > space->committed_size) {
+ space->committed_size = size;
+ }
/* There could be multiple concurrent I/O requests for
this tablespace (multiple threads trying to extend