[MDEV-21899] INSERT into a secondary index with zero-data-length key is not crash-safe Created: 2020-03-09 Updated: 2020-03-27 Resolved: 2020-03-27 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | mariabackup, Storage Engine - InnoDB |
| Affects Version/s: | 10.5.2 |
| Fix Version/s: | 10.5.3 |
| Type: | Bug | Priority: | Major |
| Reporter: | Matthias Leich | Assignee: | Marko Mäkelä |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | None | ||
| Attachments: |
|
||||||||||||||||
| Issue Links: |
|
||||||||||||||||
| Description |
|
|
| Comments |
| Comment by Marko Mäkelä [ 2020-03-09 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
In the case that I analyzed, I observed 3 or 4 mini-transactions for the page:
We could detect the inconsistency earlier, by checking that the predecessor record is not beyond PAGE_HEAP_TOP. We could copy some further consistency checks from the INSERT function. Until we have a reasonably repeatable test case, it is not known what is causing this. It would seem that some log is missing. A bug in Mariabackup? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2020-03-26 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I think that I finally found the cause. It was rather challenging, so I am providing details for future reference, to aid in similar debugging. The patch is simple, and the cause is
In a provided dataset, there were at least 2 pages for which the record failed to apply: pages 5:9 and 5:12. I concentrated on page 5:9. For that one, I instrumented the crash recovery with gdb as follows:
There were 2 page_apply_delete_dynamic() calls to this page. The second one failed, because it was pointing to an area in the page that was filled with zero bytes. That is, the next-record loop to find the record owner in the sparse page directory would exceed n_recs and the page would correctly be regarded as corrupted. Aimed with the knowledge on the LSN and the redo log record contents, I used the provided rr replay environment. First, I think that I let it run to the end (to the SIGKILL that was originally initiated by RQG), and did when to see how many steps there are in total. It was above 4 million. Then, I did roughly the following in the end (omitting lots of steps):
The first hardware watchpoint is for PAGE_MAX_TRX_ID on the page. The page turned out to be a secondary index page. The second watchpoint is for a byte that used to be a delete-mark flag that was set back and forth by the test. It was accidentally hit by the page_cur_insert_rec_low(). Thanks to the breakpoint on mtr_buf_t::close, which was not called for that insert, I knew that something is wrong. So, I went back in time by issuing
and single-stepped through the function page_cur_insert_rec_low(). The condition that my patch above removed is redundant and outright harmful. It is a rare corner case that a secondary index record has no data payload at all. It is possible when the PRIMARY KEY consists of variable-length string columns that are all empty, and all secondary index columns are either NULL or the empty string. We failed to write the INSERT_REUSE_DYNAMIC redo log record for the following statement:
This was on the secondary index col_char_latin1_unique, and the value is (NULL,''), as expected. |