dm: ignore ghost/trash table DDL without gh-ost comment when online-ddl is enabled#12565
dm: ignore ghost/trash table DDL without gh-ost comment when online-ddl is enabled#12565Takashi-kun wants to merge 1 commit intopingcap:masterfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @Takashi-kun. Thanks for your PR. I'm waiting for a pingcap member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
Welcome @Takashi-kun! |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves an issue where DM would erroneously attempt to replay stored DDLs during manual Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request correctly fixes an issue where manual renames of gh-ost ghost tables were incorrectly treated as gh-ost cutovers, leading to DDL replay errors. The approach of checking for the /* gh-ost */ comment in the RENAME TABLE statement is a solid and reliable way to distinguish between automated cutovers and manual operations. The implementation is clean, and the addition of TestGhostTableRenameWithoutGhostComment provides good test coverage for both the new and existing logic paths. I have one suggestion to improve code readability.
dm/syncer/ddl.go
Outdated
| if _, ok := ddlInfo.stmtCache.(*ast.RenameTableStmt); ok && | ||
| len(ddlInfo.sourceTables) == parserpkg.SingleRenameTableNameNum && | ||
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[0].Name) == onlineddl.GhostTable && | ||
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[1].Name) == onlineddl.RealTable && | ||
| !ghostCommentRegexp.MatchString(qec.originSQL) { | ||
| return []string{ddlInfo.originDDL}, nil | ||
| } |
There was a problem hiding this comment.
This if condition is a bit long and combines several checks, which can be hard to parse. To improve readability, consider breaking down the logic into a few named boolean variables that describe each part of the condition.
| if _, ok := ddlInfo.stmtCache.(*ast.RenameTableStmt); ok && | |
| len(ddlInfo.sourceTables) == parserpkg.SingleRenameTableNameNum && | |
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[0].Name) == onlineddl.GhostTable && | |
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[1].Name) == onlineddl.RealTable && | |
| !ghostCommentRegexp.MatchString(qec.originSQL) { | |
| return []string{ddlInfo.originDDL}, nil | |
| } | |
| if _, ok := ddlInfo.stmtCache.(*ast.RenameTableStmt); ok { | |
| isGhostToRealRename := len(ddlInfo.sourceTables) == parserpkg.SingleRenameTableNameNum && | |
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[0].Name) == onlineddl.GhostTable && | |
| ddl.onlineDDL.TableType(ddlInfo.sourceTables[1].Name) == onlineddl.RealTable | |
| isManualRename := isGhostToRealRename && !ghostCommentRegexp.MatchString(qec.originSQL) | |
| if isManualRename { | |
| return []string{ddlInfo.originDDL}, nil | |
| } | |
| } |
…dl is enabled When a gh-ost migration leaves behind ghost/trash tables (_gho, _ghc, _del), operators may manually rename or drop them for cleanup. Because DM identifies these tables purely by table-name regex, it was treating any GhostTable→RealTable RENAME as a gh-ost cutover and replaying stored ALTER TABLE DDLs against the destination, blocking replication. gh-ost embeds a /* gh-ost */ comment in every SQL statement it issues (CREATE, ALTER, RENAME, DROP). Since ghost/trash tables never exist in TiDB (DM never replicates their creation), any DDL on these tables without the gh-ost comment is a manual operation and must be silently ignored. In processOneDDL, before calling Apply(), check whether the first source table is a ghost or trash table and the raw binlog SQL lacks the /* gh-ost */ marker. If so, return nil — no downstream DDL is emitted and replication continues unblocked. close pingcap#12564 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
What problem does this PR solve?
Issue Number: close #12564
When a gh-ost migration leaves behind a ghost table (e.g.
_t_gho), an operator may manually rename it for cleanup:Because DM identifies gh-ost tables purely by table-name regex, it treats any
GhostTable → RealTablerename as a gh-ost cutover and tries to replay storedALTER TABLEstatements against the destination. Since that table doesn't exist in TiDB, the apply fails and blocks replication.What is changed and how it works?
gh-ost embeds a
/* gh-ost */comment in all SQL statements it issues —CREATE TABLE,ALTER TABLE,RENAME TABLE,DROP TABLE, etc.:This comment is preserved verbatim in the MySQL binlog QUERY event.
Since ghost/trash tables (
_gho,_ghc,_del) never exist in TiDB (DM does not replicate their creation downstream), any DDL on these tables that lacks the/* gh-ost */comment is a manual operation and must be silently ignored. InprocessOneDDL, before callingApply(), we now check the first source table type and the presence of the comment. Without the comment on a ghost/trash table, the event returnsniland replication continues unblocked.Why not pass the statement through?
The initial approach returned the statement as-is for manual renames. But since ghost tables never exist in TiDB, executing
RENAME TABLE _t_gho TO will_be_deleteddownstream would also fail. Returningnil(ignore) is the correct behaviour.Check List
Tests
TestGhostTableDDLWithoutGhostComment)/* gh-ost */comment) is stored; cutover RENAME (with comment) replays the stored ALTER — existing behaviour preservedQuestions
Will it cause performance regression or break compatibility?
No. The added check only runs when
onlineDDLis enabled (online-ddl: true). The regexp match is O(n) on the raw SQL string and is negligible compared to the rest of DDL processing.Do you need to update user documentation, design documentation or monitoring documentation?
No.
Release note