[MDEV-23190] Assertion `id.page_no() < space.size' during recovery Created: 2020-07-16 Updated: 2020-10-15 Resolved: 2020-07-20 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - InnoDB |
| Affects Version/s: | 10.1, 10.2, 10.3, 10.4, 10.5 |
| Fix Version/s: | 10.1.46, 10.2.33, 10.3.24, 10.4.14, 10.5.5 |
| Type: | Bug | Priority: | Major |
| Reporter: | Thirunarayanan Balathandayuthapani | Assignee: | Marko Mäkelä |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | rr-profile-analyzed | ||
| Issue Links: |
|
||||||||||||
| Description |
|
This issue was happened while testing bb-10.5-thiru for
Error log contains the following:
Problem: During recovery, InnoDB encounters INIT_PAGE for page 1. So it does buf_page_create() and add the page 1 to flush list. It never encounters INIT_PAGE for page0 and FSP_SIZE redo log also. So InnoDB never sets the size for the tablespace. While flushing, InnoDB fails in assert `id.page_no() < space.size' Root cause is that InnoDB does mtr_commit separately for page 1 before doing commit for page 0 and FSP_SIZE In the reported case, fsp_header_init() is being called from dict_build_table_def_step()
Inside fsp_header_init(), InnoDB does fsp_fill_free_list() to add the new extent to free list. In fsp_fill_free_list(), the following code does have seperate mtr to commit ibuf bitmap page.
So InnoDB should commit everything within same mtr or handle the scenario during recovery. |
| Comments |
| Comment by Marko Mäkelä [ 2020-07-16 ] | ||||
|
It indeed seems to be the case that the use of a ‘sub-minitransaction’ ibuf_mtr in fsp_fill_free_list() is ‘overtaking’ the write of FSP_SIZE. I believe that the reason for using a separate ibuf_mtr in fsp_fill_free_list() is to avoid trouble with any caller that could access further pages while the change buffer bitmap page latch is being held. I see two alternative fixes:
The transitive closure of all callers of fsp_fill_free_list() in that compilation unit is as follows:
None of the functions are invoking mtr_t::commit(). The last 4 functions are global, and hence we must conduct a transitive closure of them in all files until the mtr_t::commit() call. Here is the closure of fseg_create_general(), fseg_create(), fseg_alloc_free_page_general() but not fsp_header_init():
If we let the fsp_alloc_free_extent() call in fseg_alloc_free_extent() continue to use a sub-minitransaction, the transitive closure of affected callers would be limited to fsp_header_init(), which is listed below:
| ||||
| Comment by Marko Mäkelä [ 2020-07-16 ] | ||||
|
We should also check the transitive closure of callers of the following functions, which are modifying FSP_SIZE. No redo log for referring to newly added pages must be written ahead of the FSP_SIZE modification:
I do not yet see how a deadlock involving the change buffer could be possible, as implied by the comment:
Any page allocation operation should be protected by an exclusive fil_space_t::latch. Other threads should not be able to access any of the newly allocated pages (including the change buffer bitmap page) while our mini-transaction is holding the tablespace latch. The only exception that I can think of would be read-ahead. In both buf_read_ahead_random() and buf_read_ahead_linear() we are reading fil_space_t::size without holding fil_space_t::latch, which should be protecting it. If we introduce the proper protection to fil_space_t::size, we should be able to eliminate the sub-minitransaction. If the tablespace is being extended while a read-ahead operation is executing, it would either block until the extension has been completed, or it would limit the read-ahead to pages that were not extended yet. Because introducing extra synchronization is expensive, we might rather replace the problematic use of fil_space_t::size with fil_space_t::free_limit. It should not make sense to read-ahead any unallocated pages in any case. | ||||
| Comment by Marko Mäkelä [ 2020-07-16 ] | ||||
|
I prototyped 3 different solutions on 10.1 so far:
Once I have a workable solution for preventing read-ahead or flushing from accessing a newly extended change buffer bitmap page, I can remove the ibuf_mtr and use the single mini-transaction object in fsp_fill_free_list(), to fix the ordering problem that is breaking the recovery. | ||||
| Comment by Marko Mäkelä [ 2020-07-17 ] | ||||
|
I pushed a fix to bb-10.1-marko and merged it up to bb-10.5-MDEV-23190, with some conflict resolution in each of 10.2, 10.3, 10.4, 10.5. mleich, please test. | ||||
| Comment by Marko Mäkelä [ 2020-07-20 ] | ||||
|
I pushed this to 10.1 and merged up to 10.5. Between each major version, some additional conflict resolution was needed. |