diff options
Diffstat (limited to 'storage/innobase/log/log0recv.cc')
-rw-r--r-- | storage/innobase/log/log0recv.cc | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 7d23001962b..add2f6b123c 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -737,8 +737,10 @@ static struct bool reinit_all() { retry: + log_sys.latch.wr_unlock(); bool fail= false; buf_block_t *free_block= buf_LRU_get_free_block(false); + log_sys.latch.wr_lock(SRW_LOCK_CALL); mysql_mutex_lock(&recv_sys.mutex); for (auto d= defers.begin(); d != defers.end(); ) @@ -1944,7 +1946,7 @@ inline bool page_recv_t::trim(lsn_t start_lsn) { while (log.head) { - if (log.head->lsn >= start_lsn) return false; + if (log.head->lsn > start_lsn) return false; last_offset= 1; /* the next record must not be same_page */ log_rec_t *next= log.head->next; recv_sys.free(log.head); @@ -2570,6 +2572,9 @@ inline recv_sys_t::parse_mtr_result recv_sys_t::parse(store_t store, source &l) goto record_corrupted; static_assert(UT_ARR_SIZE(truncated_undo_spaces) == TRX_SYS_MAX_UNDO_SPACES, "compatibility"); + /* The entire undo tablespace will be reinitialized by + innodb_undo_log_truncate=ON. Discard old log for all pages. */ + trim({space_id, 0}, lsn); truncated_undo_spaces[space_id - srv_undo_space_id_start]= { lsn, page_no }; if (undo_space_trunc) @@ -3459,7 +3464,12 @@ void recv_sys_t::apply(bool last_batch) const trunc& t= truncated_undo_spaces[id]; if (t.lsn) { - trim(page_id_t(id + srv_undo_space_id_start, 0), t.lsn); + /* The entire undo tablespace will be reinitialized by + innodb_undo_log_truncate=ON. Discard old log for all pages. + Even though we recv_sys_t::parse() already invoked trim(), + this will be needed in case recovery consists of multiple batches + (there was an invocation with !last_batch). */ + trim({id + srv_undo_space_id_start, 0}, t.lsn); if (fil_space_t *space = fil_space_get(id + srv_undo_space_id_start)) { ut_ad(UT_LIST_GET_LEN(space->chain) == 1); @@ -3473,8 +3483,21 @@ void recv_sys_t::apply(bool last_batch) fil_system.extend_to_recv_size(); + /* We must release log_sys.latch and recv_sys.mutex before + invoking buf_LRU_get_free_block(). Allocating a block may initiate + a redo log write and therefore acquire log_sys.latch. To avoid + deadlocks, log_sys.latch must not be acquired while holding + recv_sys.mutex. */ + mysql_mutex_unlock(&mutex); + if (!last_batch) + log_sys.latch.wr_unlock(); + buf_block_t *free_block= buf_LRU_get_free_block(false); + if (!last_batch) + log_sys.latch.wr_lock(SRW_LOCK_CALL); + mysql_mutex_lock(&mutex); + for (map::iterator p= pages.begin(); p != pages.end(); ) { const page_id_t page_id= p->first; @@ -3520,7 +3543,11 @@ erase_for_space: { next_free_block: mysql_mutex_unlock(&mutex); + if (!last_batch) + log_sys.latch.wr_unlock(); free_block= buf_LRU_get_free_block(false); + if (!last_batch) + log_sys.latch.wr_lock(SRW_LOCK_CALL); mysql_mutex_lock(&mutex); break; } @@ -4244,6 +4271,11 @@ read_only_recovery: || recv_sys.is_corrupt_fs()) { goto err_exit; } + + /* In case of multi-batch recovery, + redo log for the last batch is not + applied yet. */ + ut_d(recv_sys.after_apply = false); } } else { ut_ad(recv_sys.pages.empty()); |