Skip to content

Unify PKE selection semantics across schemadiff consumers - #19602

Open
varundeepsaini wants to merge 1 commit into
vitessio:mainfrom
varundeepsaini:unify-pke-selection
Open

varundeepsaini wants to merge 1 commit into
vitessio:mainfrom
varundeepsaini:unify-pke-selection

Conversation

@varundeepsaini

@varundeepsaini varundeepsaini commented Mar 7, 2026 •

Copy link
Copy Markdown
Contributor

Description

Unifies Primary Key Equivalent (PKE) selection for OnlineDDL and VReplication on a single schemadiff implementation, replacing the legacy information_schema query in mysqlctl.

  • New schemadiff.GetPrimaryKeyEquivalent() parses CREATE TABLE and ranks keys by total type cost, then column count — same semantics as the legacy SQL. Ties broken by index name.
  • vdiff, vreplicator, and vstreamer now use it; mysqlctl.GetPrimaryKeyEquivalentColumns is deprecated. A parity test runs both against a real MySQL.
  • OnlineDDL's PrioritizedUniqueKeys now uses the same whole-key cost ranking (behavior change, see release notes). VReplication selection unchanged.
  • Source tablet now rejects a resumed copy lastpk generated with different key columns instead of resuming from the wrong position.

Related Issue(s)

Checklist

  • "Backport to:" labels have been added if this change should be back-ported to release branches
  • If this change is to be back-ported to previous releases, a justification is included in the PR description
  • Tests were added or are not required
  • Did the new or modified tests pass consistently locally and on CI?
  • Documentation was added or is not required

Behavior change; not intended for backporting.

Deployment Notes

See v25 release notes (changelog/25.0/25.0.0/summary.md): OnlineDDL may pick a different (still valid) unique key; expression keys are no longer PKE candidates; unparseable no-PK schemas fall back to all columns with a warning; in-flight no-PK copies may need a restart across the upgrade.

AI Disclosure

Took help of opus 4.8

@codecov

codecov Bot commented Mar 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.85714% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.49%. Comparing base (70c7a72) to head (58f0c28).
⚠️ Report is 596 commits behind head on main.

Files with missing lines Patch % Lines
go/vt/vttablet/tabletmanager/vdiff/table_differ.go 61.76% 13 Missing ⚠️
go/vt/schemadiff/onlineddl.go 89.18% 4 Missing ⚠️
...vttablet/tabletmanager/vreplication/vreplicator.go 76.47% 4 Missing ⚠️
go/vt/vttablet/tabletserver/tabletserver.go 0.00% 4 Missing ⚠️
go/vt/vttablet/tabletmanager/vdiff/table_plan.go 86.95% 3 Missing ⚠️
go/vt/vttablet/tabletserver/vstreamer/engine.go 89.28% 3 Missing ⚠️
...t/tabletmanager/vreplication/external_connector.go 50.00% 2 Missing ⚠️
.../vt/vttablet/tabletserver/vstreamer/rowstreamer.go 95.12% 2 Missing ⚠️
go/vt/schemadiff/mysql.go 75.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main   #19602       +/-   ##
===========================================
+ Coverage   69.67%   74.49%    +4.82%     
===========================================
  Files        1614      238     -1376     
  Lines      216793    41159   -175634     
===========================================
- Hits       151044    30662   -120382     
+ Misses      65749    10497    -55252     
Flag Coverage Δ
partial 74.49% <82.85%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR consolidates Primary Key Equivalent (PKE) selection so OnlineDDL and VReplication workflows share a single canonical implementation in schemadiff, and migrates VReplication-related call sites away from mysqlctl.GetPrimaryKeyEquivalentColumns.

Changes:

  • Added schemadiff.GetPrimaryKeyEquivalent (plus supporting type-cost ranking utilities) and updated OnlineDDL key prioritization to use the same ranking approach.
  • Migrated VReplication consumers (vstreamer, vdiff, vreplicator) to derive PKE from SHOW CREATE TABLE + SQL parsing instead of querying information_schema.
  • Deprecated mysqlctl.GetPrimaryKeyEquivalentColumns and expanded tests to validate parity.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
go/vt/wrangler/fake_tablet_test.go Updates test wiring for new vdiff.NewEngine signature using vtenv.Environment.
go/vt/vttablet/tabletserver/vstreamer/engine.go Switches PKE discovery to SHOW CREATE TABLE + schemadiff.GetPrimaryKeyEquivalent.
go/vt/vttablet/tabletmanager/vreplication/vreplicator.go Uses schemadiff.GetPrimaryKeyEquivalent based on td.Schema instead of mysqlctl PKE selection.
go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go Adds parity checks between deprecated mysqlctl function and schemadiff.GetPrimaryKeyEquivalent.
go/vt/vttablet/tabletmanager/vdiff/workflow_differ_test.go Updates mocked DB expectations to SHOW CREATE TABLE flow.
go/vt/vttablet/tabletmanager/vdiff/table_plan.go Changes PKE lookup to parse SHOW CREATE TABLE output via schemadiff.
go/vt/vttablet/tabletmanager/vdiff/table_differ.go Uses schemadiff parsing of sourceTable.Schema to determine PKE columns.
go/vt/vttablet/tabletmanager/vdiff/engine.go Simplifies engine construction to accept a single *vtenv.Environment.
go/vt/schemadiff/onlineddl.go Introduces IsValidPKEquivalent and GetPrimaryKeyEquivalent; updates key ranking to use type-cost sum.
go/vt/schemadiff/onlineddl_test.go Adds coverage for GetPrimaryKeyEquivalent and updates ordering expectations.
go/vt/schemadiff/mysql.go Adds shared type-cost table and TypeCost() helper for PKE ranking.
go/vt/schemadiff/key.go Adds index-level TypeCost() aggregation for ranking.
go/vt/schemadiff/column.go Adds column-level TypeCost() used by index ranking.
go/vt/schemadiff/env.go Adds NewEnvWithDefaults for consistent schemadiff environment creation.
go/vt/mysqlctl/schema.go Deprecates GetPrimaryKeyEquivalentColumns in favor of schemadiff API.
go/cmd/vttablet/cli/cli.go Updates vttablet initialization to use new vdiff.NewEngine(ts, tablet, env) signature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go Outdated
Comment thread go/vt/wrangler/fake_tablet_test.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread go/vt/schemadiff/onlineddl.go Outdated
@mattlord

Copy link
Copy Markdown
Member

I dug through the schemadiff ranking changes and the downstream call sites in vreplication/vdiff/vstreamer. I like the goal of deduplicating the logic, but I think this currently changes PKE selection semantics in a couple of important ways.

  1. P0 - GetPrimaryKeyEquivalent() now prefers PRIMARY even when mysqlctl would have picked a cheaper secondary unique key

    In go/vt/schemadiff/onlineddl.go, PrioritizedUniqueKeys() forces PRIMARY to sort first, and GetPrimaryKeyEquivalent() just returns the first valid key.

    That is not what mysqlctl.GetPrimaryKeyEquivalentColumns() did. The legacy implementation ranked all eligible unique indexes purely by type_cost, col_count, with no special case for PRIMARY.

    So for a table like:

    • PRIMARY KEY (bigint_id)
    • UNIQUE KEY tiny_uid (tinyint_col NOT NULL)

    the old code can pick tiny_uid, while the new code will always pick PRIMARY.

    Since this PR moves vreplication / vdiff / vstreamer over to the new implementation, that becomes a silent behavioral change in row-identity selection, not just a refactor.

  2. P0 - prefix unique indexes are still considered valid PKEs, but they are now ranked differently from mysqlctl

    IsValidPKEquivalent() explicitly allows prefix keys, which matches the old behavior.

    But PrioritizedUniqueKeys() hard-prioritizes non-prefix keys before type cost. The old mysqlctl query did not apply any prefix penalty at all; it only sorted by type_cost, col_count.

    So a lower-cost unique prefix key that mysqlctl would have selected can no longer beat any non-prefix unique key in the new code.

    That is another semantic divergence that now affects:

    • go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
    • go/vt/vttablet/tabletmanager/vdiff/table_differ.go
    • go/vt/vttablet/tabletmanager/vdiff/table_plan.go
    • go/vt/vttablet/tabletserver/vstreamer/engine.go

Tests I think are missing before this can safely merge:

  • a parity test with PRIMARY plus a cheaper secondary unique key, asserting schemadiff matches mysqlctl
  • a parity test where a cheaper unique prefix key competes with a more expensive non-prefix unique key
  • one consumer-level test (vdiff or vstreamer) proving the selected PKE / PKIndexName still matches the legacy selection rules

The call-site cleanup itself looks reasonable to me. The risky part is that the canonical ranking logic is not actually canonical with the legacy behavior yet.

@varundeepsaini varundeepsaini changed the title Unify PKE key selection between OnlineDDL and VReplication Unify PKE selection semantics across schemadiff consumers Mar 14, 2026
@mattlord mattlord modified the milestones: v24.0.0, v25.0.0 Apr 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR is being marked as stale because it has been open for 30 days with no activity. To rectify, you may do any of the following:

  • Push additional commits to the associated branch.
  • Remove the stale label.
  • Add a comment indicating why it is not stale.

If no action is taken within 7 days, this PR will be closed.

@github-actions github-actions Bot added the Stale Marks PRs as stale after a period of inactivity, which are then closed after a grace period. label May 14, 2026
@varundeepsaini

Copy link
Copy Markdown
Contributor Author

Don't close

@github-actions github-actions Bot removed the Stale Marks PRs as stale after a period of inactivity, which are then closed after a grace period. label May 15, 2026
Copilot AI review requested due to automatic review settings June 10, 2026 04:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Comment thread go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
Comment thread go/vt/vttablet/tabletmanager/vdiff/table_differ.go
Comment thread go/vt/schemadiff/mysql.go Outdated
Comment thread go/vt/vttablet/tabletserver/vstreamer/engine.go
@mattlord
mattlord requested review from mhamza15 and removed request for beingnoble03, harshit-gangal, rohit-nayak-ps, shlomi-noach and systay July 18, 2026 20:03
@mattlord

Copy link
Copy Markdown
Member

@codex-maintainers please review

@mattlord mattlord added Type: Enhancement Logical improvement (somewhere between a bug and feature) Component: VReplication Component: Online DDL Online DDL (vitess/native/gh-ost/pt-osc) labels Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e6d2d1aac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread go/vt/vttablet/tabletserver/vstreamer/engine.go Outdated
Copilot AI review requested due to automatic review settings July 19, 2026 04:20
@varundeepsaini

Copy link
Copy Markdown
Contributor Author

@codex review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 28 changed files in this pull request and generated no new comments.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: c653cafb9e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@mattlord mattlord left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not treat an unparseable schema as having no PKE. It seems like this fallback can silently skip rows. For example, given a nullable column before a non-null unique key:

(payload TEXT NULL, id BIGINT NOT NULL, UNIQUE KEY (id))

an unsupported table option makes parsing fail, so RowStreamer uses every column instead of id. If a copy cycle checkpoints on a row where payload IS NULL, the resume predicate contains payload = NULL / payload > NULL, which never matches, and subsequent rows can be omitted. It also replaces an indexed traversal with a full filesort.

I think we should distinguish “schema could not be parsed” from “schema has no PKE”: either use a safe metadata-based fallback or fail closed. Could we add a multi-cycle resume test with a nullable column, a valid PKE, and an unsupported table option?

Copilot AI review requested due to automatic review settings August 3, 2026 18:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.

Comment thread go/vt/vttablet/tabletserver/vstreamer/engine.go
Comment thread go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
Comment thread go/vt/vttablet/tabletmanager/vdiff/table_plan.go
Comment thread go/vt/vttablet/tabletmanager/vdiff/table_differ.go
Replace duplicated primary-key-equivalent selection: OnlineDDL's
first-column heuristics and mysqlctl's information_schema query are
superseded by schemadiff.GetPrimaryKeyEquivalent, which parses CREATE
TABLE and ranks unique non-NULLable keys by total type cost, then
column count, then index name. vdiff, vreplicator, and vstreamer now
use it.

A CREATE TABLE statement the parser cannot handle (e.g. one using the
SECONDARY_ENGINE option) is not treated as having no PKE: that would
key the stream on every column, where resuming a copy from a
checkpoint holding a NULL value builds a resume predicate that never
matches and silently skips the remaining rows. Such tables fall back
to the retained mysqlctl information_schema lookup, now hardened to
reject unique keys containing functional (expression) key parts --
previously it could return such a key as a corrupt, non-unique column
list.

- Online DDL key prioritization now ranks by whole-key type-cost sum;
  behavior change documented in the v25 release notes. VReplication
  PKE selection semantics are unchanged.
- Resumed lastpk values are validated against the currently selected
  key columns to fail closed if the key changes across an upgrade.
- Warn when no CREATE TABLE schema is available to derive a PKE.

Closes vitessio#10259

Signed-off-by: Varun Deep Saini <deepsainivarun@gmail.com>
Copilot AI review requested due to automatic review settings August 3, 2026 19:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 28 changed files in this pull request and generated no new comments.

@mattlord mattlord left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Blocking: I think VDiff needs to persist the physical source key field names. rowstreamer.go:276-284 now compares lastpk.Fields with the physical source key columns, but table_differ.go:877-899 builds both the target and source checkpoints from the target table fields. For a supported transform such as select c0 as c1, a resumed VDiff supplies c1 while the source key is still c0, so the new check rejects a valid resume. I think we should capture the source stream’s Pkfields or translate aliases back to source names, with a stop/resume regression test using a renamed key column.

  2. Blocking: I think the key-selection change needs a mixed-version-safe rollout. A new source tablet validates the stored field names, but an older source tablet discards that metadata and only checks the number of values. During a rolling upgrade, VReplication can checkpoint against a newly selected PKE, reconnect to an older eligible source tablet, and have that tablet resume the values against a different same-width key. That seems like it can silently skip or duplicate rows. I think we should either stage the selection change across releases or otherwise preserve the legacy selection while old source tablets may still serve streams, and add an upgrade/downgrade copy-resume test.

  3. Blocking: I think the fallback query should use the same deterministic tie-break as the parser path. GetPrimaryKeyEquivalent() uses the index name after cost and column count, but mysqlctl/schema.go:626 still orders only by type_cost, col_count. Equal-cost keys can therefore resolve differently when the parser fallback is used, causing a later tablet switch or parser upgrade to stop the copy under the new validation. Adding INDEX_NAME to the fallback ordering and a real-MySQL parity case with tied keys should keep both implementations aligned.

@github-actions

Copy link
Copy Markdown
Contributor

This PR is being marked as stale because it has been open for 30 days with no activity. To rectify, you may do any of the following:

  • Push additional commits to the associated branch.
  • Remove the stale label.
  • Add a comment indicating why it is not stale.

If no action is taken within 7 days, this PR will be closed.

@github-actions github-actions Bot added the Stale Marks PRs as stale after a period of inactivity, which are then closed after a grace period. label Sep 24, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: Online DDL Online DDL (vitess/native/gh-ost/pt-osc) Component: VReplication Stale Marks PRs as stale after a period of inactivity, which are then closed after a grace period. Type: Enhancement Logical improvement (somewhere between a bug and feature)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify / De-Duplicate Key Selection and Management between OnlineDDL and other VReplication workflows

4 participants