| Bug #69780 | Fix for bug 14606334 in 5.6.11 breaks backward compatibility for InnoDB recovery | ||
|---|---|---|---|
| Submitted: | 18 Jul 2013 14:03 | Modified: | 9 Oct 2015 8:58 |
| Reporter: | Alexey Kopytov | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: InnoDB storage engine | Severity: | S3 (Non-critical) |
| Version: | 5.6.12 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[18 Jul 2013 14:12]
Alexey Kopytov
Debug log: ... # The following deletes the last record on the page record type = 42 PAGE_HEAP_TOP=15408 # Page heap is reset in 5.6.11+ record type = 8 PAGE_HEAP_TOP=120 PAGE_N_RECS=0 record type = 38 PAGE_HEAP_TOP=120 PAGE_N_RECS=0 offset=99 record type = 38 PAGE_HEAP_TOP=128 PAGE_N_RECS=1 offset=125 record type = 38 PAGE_HEAP_TOP=136 PAGE_N_RECS=2 offset=133 record type = 38 PAGE_HEAP_TOP=144 PAGE_N_RECS=3 offset=141 # The following applies just fine with MySQL < 5.6.11, because the heap # is not reset, but crashes on 5.6.11+ record type = 38 PAGE_HEAP_TOP=152 PAGE_N_RECS=4 offset=8093
[29 Jul 2013 11:49]
MySQL Verification Team
looks like my internally filed: Bug 16996584 - 5.6.11+ REGRESSION: MULTIPLE CRASHES DURING CRASH RECOVERY
[29 Jul 2013 11:57]
MySQL Verification Team
Hello Alexey, Thank you for the bug report. As Shane pointed out, this is duplicate of internally reported Bug 16996584 - 5.6.11+ REGRESSION: MULTIPLE CRASHES DURING CRASH RECOVERY Thanks, Umesh
[5 Aug 2013 9:54]
Marko Mäkelä
I am sorry for introducing this regression. The new function page_create_empty() should not have been invoked when applying redo log entries for deleting records, because this could bring the PAGE_FREE list out of sync with subsequent redo log entries for the page. We should improve our cross-version regression testing. This is somewhat of a corner case, requiring a suitable combination of INSERT, UPDATE and DELETE operations and giving the purge an opportunity to run.
[9 Oct 2015 8:58]
MySQL Verification Team
Noted in 5.6.14, 5.7.2 changelogs. "A regression introduced in the fix for Bug #14606334 would cause crashes on startup during crash recovery."
[15 Jul 2016 9:53]
zhai weixiang
Hi, I just check the code and find that page_create_empty may still be invoked in function page_delete_rec_list_start during crash recovery process. All other places that invoke page_create_empty have checked if recv_recovery_is_on() Do i miss something ? Thank you for any comment :)

Description: The following fix in 5.6.11 / 5.7.1 introduced a change that can make InnoDB crash on recovery when replaying redo logs created on earlier versions: "InnoDB: The server could exit during an attempt by InnoDB to reorganize or compress a compressed secondary index page. (Bug #14606334)" With that fix InnoDB resets an index page after deleting the last record on the page. This is from page_cur_delete_rec(): if (page_get_n_recs(page) == 1) { ... page_create_empty(page_cur_get_block(cursor), const_cast<dict_index_t*>(index), mtr); return; } In particular, page_create_empty() resets the records heap. Now, since InnoDB doesn't do that in server versions < 5.6.11, it may later insert records into free slots on the heap (and store the corresponding offsets in MLOG_COMP_REC_INSERT records in redo log). But if later versions replay MLOG_COMP_REC_DELETE on recovery, and have to delete the last record on a page, the records heap will be reset. Which leads to a crash if a MLOG_COMP_REC_INSERT record has to be replayed later with an offset which is beyond the new heap bounds. Naturally, this change also makes XtraBackup/MEB incompatible with previous server versions. How to repeat: The testcase can likely be reduced, but the following procedure is simple enough: 1. Download the Sakila DB from http://dev.mysql.com/doc/index-other.html 2. Use the following script with MySQL < 5.6.11 (I tested on 5.6.10): --- #!/bin/sh # Download the sakila db and unpack it to /tmp set -e mysql -uroot -e "DROP DATABASE IF EXISTS sakila" mysql -uroot < /tmp/sakila-db/sakila-schema.sql mysql -uroot < /tmp/sakila-db/sakila-data.sql for t in actor address category city country customer film film_actor film_category film_text inventory language payment rental staff store; do mysql -uroot sakila <<EOF SET foreign_key_checks=0; DELETE FROM $t; EOF done killall -9 mysqld --- 3. After the script kills mysqld, upgrade to 5.6.11/5.6.12 4. InnoDB will crash on recovery. Release builds crash with a segfault, debug ones crash with the following assertion failure: --- 2013-07-18 17:25:30 130ffc000 InnoDB: Assertion failure in thread 5117034496 in file page0page.ic line 657 InnoDB: Failing assertion: page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP) InnoDB: We intentionally generate a memory trap. InnoDB: Submit a detailed bug report to http://bugs.mysql.com. InnoDB: If you get repeated assertion failures or crashes, even InnoDB: immediately after the mysqld startup, there may be InnoDB: corruption in the InnoDB tablespace. Please refer to InnoDB: http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html InnoDB: about forcing recovery. ---