| Bug #120595 | Contribution by Tencent: Relax max row size restriction for INSTANT DDL | ||
|---|---|---|---|
| Submitted: | 2 Jun 4:45 | Modified: | 16 Oct 7:22 |
| Reporter: | Yin Peng (OCA) | Email Updates: | |
| Status: | Need Feedback | Impact on me: | |
| Category: | MySQL Server: InnoDB storage engine | Severity: | S4 (Feature request) |
| Version: | 9.7.0 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[2 Jun 4:45]
Yin Peng
[2 Jun 4:46]
Yin Peng
Relax max row size restriction for INSTANT DDL (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: patch.txt (text/plain), 99.50 KiB.
[2 Jun 4:49]
Yin Peng
See also: https://bugs.mysql.com/bug.php?id=119280
[12 Oct 8:23]
Mayank Prasad
The maximum-row-size check is a correctness safeguard for UPDATE/ROLLBACK, not just a restriction on the size of newly inserted rows. If not there, it can allow an UPDATE to succeed even though that UPDATE cannot subsequently be rolled back. For simplicity, assume an 8,000-byte maximum in-page record size, ignore record overhead, and assume off-page storage cannot make the oversized record fit. 1. An existing row occupies 7,500 bytes. 2. We perform an instant ADD COLUMN whose default value occupies 1,000 bytes. If we allow this operation, the existing physical row still occupies 7,500 bytes because the default is supplied from metadata rather than stored in the row. 3. In a subsequent transaction, an UPDATE changes an existing column’s value from 3,000 bytes to 1,000 bytes. When the row is rewritten, the instant added column’s default is also materialized. The resulting size is: 7500 − 2000 + 1000 = 6500 bytes This fits, so the UPDATE succeeds. 4. Then we rollback the transaction. Rollback restores the original column value, adding back 2,000 bytes. However, the instantly added default remains materialized: 6500 + 2000 = 8500 bytes The restored record now exceeds the 8,000-byte limit. 5. Rollback fails, which causes the server to crash. 6. Checking the actual row size during INSERT/UPDATE does not prevent this: the updated row fits; the record needed to undo the update does not. 7. Moreover, recovery can encounter the same failure when retrying rollback and it may cause a repeated crash recovery loop. The maximum-row-size check prevents this situation without scanning existing rows, preserving the metadata-only nature of instant ADD. This rationale is also documented in `materialize_instant_default()`.
[12 Oct 8:34]
Mayank Prasad
I see this has also been identified by you and there is a proposal to solve it: ``` To solve this, this patch records the original row_version of each record in the undo log during UPDATE/DELETE operations, and uses that original version (instead of current_row_version) when rebuilding the record during rollback and MVCC version construction. This ensures the restored record contains only the columns visible at its original version, maintaining the original compact physical format. ``` Thanks for the idea and efforts! However, these are very low level changes and to be evaluated/tested for correctness and regression. I wonder if you could please provide some insight on the testing performed for this patch for evaluation. For example : - Does it take care of all row formats (say Redundant?) - Does it take care of legacy row format (instant add done pre 8.0.29 and rows inserted after that and then there is upgrade). Because upgrade doesn't change anything on rows, so all the legacy rows shall be handled. - We also support drop column with INSTANT. And it doesn't change the rows on disk. So once a column is dropped, an existing row might have dropped col value, but when we do UPDATE/ROLLBACK, how do we restore the row to original version with the value of dropped column. These are the few questions which come to my mind.
