Here is a slightly simpler test case. The important part is that the first byte of the record must be 0x69, matching the first byte of the infimum pseudo-record:
--source include/have_innodb.inc
CREATETABLE t (a TINYINT UNSIGNED PRIMARYKEY, KEY(a)) ENGINE=InnoDB;
INSERTINTO t VALUES (0x69);
--let $shutdown_timeout=0
--source include/restart_mysqld.inc
DROPTABLE t;
Marko Mäkelä
added a comment - Here is a slightly simpler test case. The important part is that the first byte of the record must be 0x69, matching the first byte of the infimum pseudo-record:
--source include/have_innodb.inc
CREATE TABLE t (a TINYINT UNSIGNED PRIMARY KEY , KEY (a)) ENGINE=InnoDB;
INSERT INTO t VALUES (0x69);
--let $shutdown_timeout=0
--source include/restart_mysqld.inc
DROP TABLE t;
@@ -393,7 +393,7 @@ struct log_phys_t : public log_rec_t
rlen-= ll;
l+= ll;
ll= mlog_decode_varint_length(*l);
- if (UNIV_UNLIKELY(ll > 3 || ll >= rlen))
+ if (UNIV_UNLIKELY(ll > 3 || ll > rlen))
goto record_corrupted;
size_t data_c= mlog_decode_varint(l);
ut_ad(data_c != MLOG_DECODE_ERROR);
In this case, the secondary index record is (a)=(0x69), and all of the data will have been copied from the infimum record. The data_len=rlen-ll that will be passed to page_apply_insert_dynamic() will be 0.
Marko Mäkelä
added a comment - The recovery fails because the log record parser throws an error. The problematic mini-transaction log is as follows:
bytes
explanation
0x34, 0x5, 0x4, 0x3f, 0x16,
WRITE , tablespace=5, page=4, offset=0x3f, bytes=0x16 (setting PAGE_MAX_TRX_ID =0x16)
0xa5, 0x6, 0x0, 0x0, 0x0, 0x1
EXTENDED , INSERT_HEAP_DYNAMIC
0x77, 0x5, 0x4, 0x0, 0xf7, 0xfd, 0x7a, 0xcd,
OPTION , PAGE_CHECKSUM
0x0
end of mini-transaction
Parsing the INSERT_HEAP_DYNAMIC record fails because of an off-by-one error:
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 7db0fdbefa5..2e7ad1f33a6 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -393,7 +393,7 @@ struct log_phys_t : public log_rec_t
rlen-= ll;
l+= ll;
ll= mlog_decode_varint_length(*l);
- if (UNIV_UNLIKELY(ll > 3 || ll >= rlen))
+ if (UNIV_UNLIKELY(ll > 3 || ll > rlen))
goto record_corrupted;
size_t data_c= mlog_decode_varint(l);
ut_ad(data_c != MLOG_DECODE_ERROR);
In this case, the secondary index record is (a)=(0x69), and all of the data will have been copied from the infimum record. The data_len=rlen-ll that will be passed to page_apply_insert_dynamic() will be 0.
The reason why a variant of this test case with ROW_FORMAT=REDUNDANT does not fail is that the INSERT_HEAP_REDUNDANT record would include 1 literal byte of record header. I even tried a variant where the length of the field would match the infimum pseudo-record:
--source include/have_innodb.inc
CREATETABLE t (a BINARY(8) PRIMARYKEY, KEY(a)) ENGINE=InnoDB
ROW_FORMAT=REDUNDANT;
INSERTINTO t VALUES (0x696e66696d756d00);
--let $shutdown_timeout=0
--source include/restart_mysqld.inc
CHECKTABLE t;
DROPTABLE t;
The reason why the header is not being copied from the infimum pseudo-record is that the following condition in page_cur_insert_rec_low() will not hold:
/* Find common header bytes with the preceding record. */
In other words, the following adjustment to the ROW_FORMAT=REDUNDANT parsing code is not strictly necessary, because some literal bytes will always be present in the log record:
@@ -420,7 +420,7 @@ struct log_phys_t : public log_rec_t
rlen-= ll;
l+= ll;
ll= mlog_decode_varint_length(*l);
- if (UNIV_UNLIKELY(ll > 2 || ll >= rlen))
+ if (UNIV_UNLIKELY(ll > 2 || ll > rlen))
goto record_corrupted;
size_t data_c= mlog_decode_varint(l);
rlen-= ll;
Marko Mäkelä
added a comment - The reason why a variant of this test case with ROW_FORMAT=REDUNDANT does not fail is that the INSERT_HEAP_REDUNDANT record would include 1 literal byte of record header. I even tried a variant where the length of the field would match the infimum pseudo-record:
--source include/have_innodb.inc
CREATE TABLE t (a BINARY (8) PRIMARY KEY , KEY (a)) ENGINE=InnoDB
ROW_FORMAT=REDUNDANT;
INSERT INTO t VALUES (0x696e66696d756d00);
--let $shutdown_timeout=0
--source include/restart_mysqld.inc
CHECK TABLE t;
DROP TABLE t;
The reason why the header is not being copied from the infimum pseudo-record is that the following condition in page_cur_insert_rec_low() will not hold:
if (c_start >=
&block->page.frame[PAGE_OLD_SUPREMUM_END + REC_N_OLD_EXTRA_BYTES])
{
/* Find common header bytes with the preceding record. */
In other words, the following adjustment to the ROW_FORMAT=REDUNDANT parsing code is not strictly necessary, because some literal bytes will always be present in the log record:
@@ -420,7 +420,7 @@ struct log_phys_t : public log_rec_t
rlen-= ll;
l+= ll;
ll= mlog_decode_varint_length(*l);
- if (UNIV_UNLIKELY(ll > 2 || ll >= rlen))
+ if (UNIV_UNLIKELY(ll > 2 || ll > rlen))
goto record_corrupted;
size_t data_c= mlog_decode_varint(l);
rlen-= ll;
2022-09-19 11:03:25 0 [ERROR] Plugin 'InnoDB' init function returned error.
2022-09-19 11:03:25 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
Marko Mäkelä
added a comment - An INSERT of a single record (not 2 records as in the test case) could fail like this:
10.5 3c8674edcc99605aa4634145771b2195c3f4f007
2022-09-19 11:03:24 0 [Note] InnoDB: Starting final batch to recover 61 pages from redo log.
2022-09-19 11:03:25 0 [ERROR] InnoDB: Plugin initialization aborted at srv0start.cc[1501] with error Data structure corruption
2022-09-19 11:03:25 0 [Note] InnoDB: Starting shutdown...
2022-09-19 11:03:25 0 [ERROR] Plugin 'InnoDB' init function returned error.
2022-09-19 11:03:25 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
I believe that this only affects secondary indexes where the keys are fixed length and the data encodes to a prefix of the string infimum and a NUL byte. This could affect the insert of the first record into any secondary index leaf page.
Marko Mäkelä
added a comment - I believe that this only affects secondary indexes where the keys are fixed length and the data encodes to a prefix of the string infimum and a NUL byte. This could affect the insert of the first record into any secondary index leaf page.
People
Marko Mäkelä
Elena Stepanova
Votes:
1Vote for this issue
Watchers:
3Start watching this issue
Dates
Created:
Updated:
Resolved:
Git Integration
Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.
{"report":{"fcp":849.5,"ttfb":266.2999999523163,"pageVisibility":"visible","entityId":114758,"key":"jira.project.issue.view-issue","isInitial":true,"threshold":1000,"elementTimings":{},"userDeviceMemory":8,"userDeviceProcessors":64,"apdex":1,"journeyId":"f39b723b-3548-4002-b8c6-6bb1273e48ca","navigationType":0,"readyForUser":922.7999999523163,"redirectCount":0,"resourceLoadedEnd":844.7999999523163,"resourceLoadedStart":271.60000002384186,"resourceTiming":[{"duration":75.19999992847443,"initiatorType":"link","name":"https://jira.mariadb.org/s/2c21342762a6a02add1c328bed317ffd-CDN/lu2cib/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/css/_super/batch.css","startTime":271.60000002384186,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":271.60000002384186,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":346.7999999523163,"responseStart":0,"secureConnectionStart":0},{"duration":75.5,"initiatorType":"link","name":"https://jira.mariadb.org/s/7ebd35e77e471bc30ff0eba799ebc151-CDN/lu2cib/820016/12ta74/494e4c556ecbb29f90a3d3b4f09cb99c/_/download/contextbatch/css/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true&whisper-enabled=true","startTime":271.89999997615814,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":271.89999997615814,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":347.39999997615814,"responseStart":0,"secureConnectionStart":0},{"duration":117.69999992847443,"initiatorType":"script","name":"https://jira.mariadb.org/s/0917945aaa57108d00c5076fea35e069-CDN/lu2cib/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/js/_super/batch.js?locale=en","startTime":272,"connectEnd":272,"connectStart":272,"domainLookupEnd":272,"domainLookupStart":272,"fetchStart":272,"redirectEnd":0,"redirectStart":0,"requestStart":350.89999997615814,"responseEnd":389.6999999284744,"responseStart":362.6999999284744,"secureConnectionStart":272},{"duration":129.5,"initiatorType":"script","name":"https://jira.mariadb.org/s/2d8175ec2fa4c816e8023260bd8c1786-CDN/lu2cib/820016/12ta74/494e4c556ecbb29f90a3d3b4f09cb99c/_/download/contextbatch/js/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true&whisper-enabled=true","startTime":272.1999999284744,"connectEnd":272.1999999284744,"connectStart":272.1999999284744,"domainLookupEnd":272.1999999284744,"domainLookupStart":272.1999999284744,"fetchStart":272.1999999284744,"redirectEnd":0,"redirectStart":0,"requestStart":351.5,"responseEnd":401.6999999284744,"responseStart":365.6999999284744,"secureConnectionStart":272.1999999284744},{"duration":93.10000002384186,"initiatorType":"script","name":"https://jira.mariadb.org/s/a9324d6758d385eb45c462685ad88f1d-CDN/lu2cib/820016/12ta74/c92c0caa9a024ae85b0ebdbed7fb4bd7/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en","startTime":272.5,"connectEnd":272.5,"connectStart":272.5,"domainLookupEnd":272.5,"domainLookupStart":272.5,"fetchStart":272.5,"redirectEnd":0,"redirectStart":0,"requestStart":352.60000002384186,"responseEnd":365.60000002384186,"responseStart":364.7999999523163,"secureConnectionStart":272.5},{"duration":102.79999995231628,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":272.60000002384186,"connectEnd":272.60000002384186,"connectStart":272.60000002384186,"domainLookupEnd":272.60000002384186,"domainLookupStart":272.60000002384186,"fetchStart":272.60000002384186,"redirectEnd":0,"redirectStart":0,"requestStart":354.60000002384186,"responseEnd":375.39999997615814,"responseStart":374.6999999284744,"secureConnectionStart":272.60000002384186},{"duration":103.20000004768372,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":272.7999999523163,"connectEnd":272.7999999523163,"connectStart":272.7999999523163,"domainLookupEnd":272.7999999523163,"domainLookupStart":272.7999999523163,"fetchStart":272.7999999523163,"redirectEnd":0,"redirectStart":0,"requestStart":355.5,"responseEnd":376,"responseStart":375.39999997615814,"secureConnectionStart":272.7999999523163},{"duration":82,"initiatorType":"link","name":"https://jira.mariadb.org/s/b04b06a02d1959df322d9cded3aeecc1-CDN/lu2cib/820016/12ta74/a2ff6aa845ffc9a1d22fe23d9ee791fc/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":273,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":273,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":355,"responseStart":0,"secureConnectionStart":0},{"duration":108.10000002384186,"initiatorType":"script","name":"https://jira.mariadb.org/rest/api/1.0/shortcuts/820016/47140b6e0a9bc2e4913da06536125810/shortcuts.js?context=issuenavigation&context=issueaction","startTime":273.1999999284744,"connectEnd":273.1999999284744,"connectStart":273.1999999284744,"domainLookupEnd":273.1999999284744,"domainLookupStart":273.1999999284744,"fetchStart":273.1999999284744,"redirectEnd":0,"redirectStart":0,"requestStart":358.7999999523163,"responseEnd":381.2999999523163,"responseStart":380.39999997615814,"secureConnectionStart":273.1999999284744},{"duration":83.10000002384186,"initiatorType":"link","name":"https://jira.mariadb.org/s/3ac36323ba5e4eb0af2aa7ac7211b4bb-CDN/lu2cib/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.css?jira.create.linked.issue=true","startTime":273.2999999523163,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":273.2999999523163,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":356.39999997615814,"responseStart":0,"secureConnectionStart":0},{"duration":102.89999997615814,"initiatorType":"script","name":"https://jira.mariadb.org/s/5d5e8fe91fbc506585e83ea3b62ccc4b-CDN/lu2cib/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.js?jira.create.linked.issue=true&locale=en","startTime":273.39999997615814,"connectEnd":361.2999999523163,"connectStart":361.2999999523163,"domainLookupEnd":361.2999999523163,"domainLookupStart":361.2999999523163,"fetchStart":273.39999997615814,"redirectEnd":0,"redirectStart":0,"requestStart":361.60000002384186,"responseEnd":376.2999999523163,"responseStart":372,"secureConnectionStart":361.2999999523163},{"duration":477.7999999523163,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-js/jira.webresources:bigpipe-js.js","startTime":283.10000002384186,"connectEnd":283.10000002384186,"connectStart":283.10000002384186,"domainLookupEnd":283.10000002384186,"domainLookupStart":283.10000002384186,"fetchStart":283.10000002384186,"redirectEnd":0,"redirectStart":0,"requestStart":639,"responseEnd":760.8999999761581,"responseStart":755.2999999523163,"secureConnectionStart":283.10000002384186},{"duration":551.8999999761581,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2cib/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-init/jira.webresources:bigpipe-init.js","startTime":292.89999997615814,"connectEnd":292.89999997615814,"connectStart":292.89999997615814,"domainLookupEnd":292.89999997615814,"domainLookupStart":292.89999997615814,"fetchStart":292.89999997615814,"redirectEnd":0,"redirectStart":0,"requestStart":833,"responseEnd":844.7999999523163,"responseStart":844.1000000238419,"secureConnectionStart":292.89999997615814},{"duration":222.60000002384186,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":593.2999999523163,"connectEnd":593.2999999523163,"connectStart":593.2999999523163,"domainLookupEnd":593.2999999523163,"domainLookupStart":593.2999999523163,"fetchStart":593.2999999523163,"redirectEnd":0,"redirectStart":0,"requestStart":773.3999999761581,"responseEnd":815.8999999761581,"responseStart":815.1999999284744,"secureConnectionStart":593.2999999523163},{"duration":163.10000002384186,"initiatorType":"script","name":"https://www.google-analytics.com/analytics.js","startTime":831.1999999284744,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":831.1999999284744,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":994.2999999523163,"responseStart":0,"secureConnectionStart":0},{"duration":172.70000004768372,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":853.7999999523163,"connectEnd":853.7999999523163,"connectStart":853.7999999523163,"domainLookupEnd":853.7999999523163,"domainLookupStart":853.7999999523163,"fetchStart":853.7999999523163,"redirectEnd":0,"redirectStart":0,"requestStart":988.8999999761581,"responseEnd":1026.5,"responseStart":1025.5,"secureConnectionStart":853.7999999523163}],"fetchStart":0,"domainLookupStart":0,"domainLookupEnd":0,"connectStart":0,"connectEnd":0,"requestStart":98,"responseStart":266,"responseEnd":293,"domLoading":270,"domInteractive":998,"domContentLoadedEventStart":999,"domContentLoadedEventEnd":1050,"domComplete":1363,"loadEventStart":1364,"loadEventEnd":1364,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[{"name":"bigPipe.sidebar-id.start","time":965.3999999761581},{"name":"bigPipe.sidebar-id.end","time":966.1000000238419},{"name":"bigPipe.activity-panel-pipe-id.start","time":966.2999999523163},{"name":"bigPipe.activity-panel-pipe-id.end","time":969.7999999523163},{"name":"activityTabFullyLoaded","time":1073.1000000238419}],"measures":[],"correlationId":"ad5238d45af722","effectiveType":"4g","downlink":9.6,"rtt":0,"serverDuration":102,"dbReadsTimeInMs":11,"dbConnsTimeInMs":20,"applicationHash":"9d11dbea5f4be3d4cc21f03a88dd11d8c8687422","experiments":[]}}
Here is a slightly simpler test case. The important part is that the first byte of the record must be 0x69, matching the first byte of the infimum pseudo-record:
--source include/have_innodb.inc
--let $shutdown_timeout=0
--source include/restart_mysqld.inc