[FLINK-39478][mysql] Persist checkpointIdToFinish and expose enumerat or metrics#4410
Open
jubins wants to merge 1 commit into
Open
[FLINK-39478][mysql] Persist checkpointIdToFinish and expose enumerat or metrics#4410jubins wants to merge 1 commit into
jubins wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the purpose of the change
Fixes FLINK-39478 — when
scan.newly-added-table.enabled=trueand a job restarts mid-snapshot of a newly-added table, the affected table can silently stop emitting events for the rest of the job's lifetime. The root cause is thatMySqlSnapshotSplitAssigner.checkpointIdToFinish— the field that gates theNEWLY_ADDED_ASSIGNING → NEWLY_ADDED_ASSIGNING_SNAPSHOT_FINISHEDtransition — is transient (@Nullable, not inSnapshotPendingSplitsState), and on restore must be re-derived over two more checkpoint cycles (onesnapshotState()to set it, onenotifyCheckpointComplete()to act on it). If a second restart lands inside that recovery window, the field resets and the state machine stalls. The table remains in the pipeline config and the job appears healthy, but produces zero data thereafter. Reported in production on two ~100M-row tables; the non-deterministic "survived first restart, died on second" pattern is consistent with the timing race described above.This change persists
checkpointIdToFinishinto the checkpointed state so the state machine can resume in one step after restore, and adds enumerator-side metrics (assignerStatus, aggregate snapshot progress counters) so operators can observe whether the assigner is making progress during long newly-added-table snapshots — the lack of which made the original incident extremely hard to diagnose. The companion fix for the multi-stepBinlogSplitUpdateRequest/Ackhandshake between states 3→4 (fix direction #2 in the JIRA) is deferred to a follow-up because it touches the enumerator↔reader RPC protocol and has a larger blast radius — this PR addresses what we believe is the most likely root cause of the observed incidents, plus the observability gap.Brief change log
@Nullable Long checkpointIdToFinishtoSnapshotPendingSplitsState(flink-connector-mysql-cdc), with a new 11-arg constructor. The pre-existing 10-arg constructor is preserved as a delegating overload that defaults the new field tonull, so all existing call sites compile unchanged and no test fixture data needs to change.snapshotState()inMySqlSnapshotSplitAssignernow setscheckpointIdToFinishbefore building the state object, so the value is captured in the same checkpoint instead of the next one — eliminating the 2-checkpoint recovery window after a restart.PendingSplitsStateSerializerfromVERSION = 5toVERSION = 6. The serialize path writes a trailingboolean present + long value; the deserialize path reads the trailer only whenversion >= 6. v5 payloads continue to deserialize withcheckpointIdToFinish=null, so no savepoint migration is required.MySqlSourceEnumeratorMetrics(flink-connector-mysql-cdc) exposes the following gauges on the enumerator metric group:assignerStatus(status code),assignerStatusName(status name),numRemainingTables,numRemainingSnapshotSplits,numAssignedSnapshotSplits,numFinishedSnapshotSplits,numAlreadyProcessedTables. Registered fromMySqlSourceEnumerator#start, wrapped in a try/catch so metric-registration failures can never break enumerator startup.default int get*Count()accessors toMySqlSplitAssigner(getRemainingSplitsCount,getRemainingTablesCount,getAssignedSplitsCount,getFinishedSplitsCount,getAlreadyProcessedTablesCount). Default returns0, preserving source-compatibility for any external implementor. Overridden inMySqlSnapshotSplitAssignerand delegated inMySqlHybridSplitAssigner;MySqlBinlogSplitAssigneruses the no-op defaults (its phase has no snapshot work to report).PendingSplitsStateSerializerTestwith a new round-trip case carrying a non-nullcheckpointIdToFinish, plus a v5-payload backward-compat test confirming the field reads back asnullon the old code path.Verifying this change
This change persists one additional field and registers new metric gauges; no existing data path or split-assignment logic is altered. Verification:
PendingSplitsStateSerializerTest(getTestSnapshotPendingSplitsStateWithCheckpointIdToFinish) covers snapshot- and hybrid-state round-trips with a non-nullcheckpointIdToFinish(42L). All 31 tests in the class pass.testDeserializeV5MissingCheckpointIdToFinishasserts that a payload deserialized under the previous version number readscheckpointIdToFinish=nulland does not attempt to read the v6 trailer — exercises the version-gated read branch.equals/hashCoderound-trip inPendingSplitsStateSerializerTestnow also exercises the new field via state equality (the field is included in both methods).mvn test-compilepasses for the wholeflink-connector-mysql-cdcmodule, validating that the new interface defaults don't break any existing implementor (including the test-only assigner subclasses).mvn spotless:checkpasses on the changed module.Note:
MySqlSnapshotSplitAssignerTestandMySqlHybridSplitAssignerTestwere not runnable in the local environment because they spin up MySQL via testcontainers (Docker not available). They should pass unchanged in CI — none of their fixture data construction needed updating thanks to the preserved 10-arg constructor overload.A deterministic IT case that injects a restart between
snapshotState()settingcheckpointIdToFinishandnotifyCheckpointComplete()acting on it — i.e., a regression test that fails onmasterand passes on this branch — is the natural next step but is outside the scope of this PR. Happy to add it as a follow-up if reviewers prefer; it requires some thought about how to deterministically schedule the restart at the vulnerable window without flaking.Does this pull request potentially affect one of the following parts
@Public(Evolving): theMySqlSplitAssignerinterface is@Internal, not@PublicEvolving— the newdefaultmethods are nonetheless source- and binary-compatible for any external implementor (defaults return0).SnapshotPendingSplitsStateis also internal to the connector. No@PublicEvolvingsurface is touched.PendingSplitsStateSerializeris bumped from version 5 to version 6. The new payload appends aboolean + (optional) long. The deserializer accepts versions 1–6; v5 payloads deserialize unchanged (withcheckpointIdToFinish=null), so existing savepoints/checkpoints restore without migration.checkpointIdToFinishis read/written only at checkpoint and restore. Metric gauges are lazily evaluated by Flink's reporter; their suppliers areO(1)(size lookups + a field read).Documentation
assignerStatus, plus aggregate snapshot progress gauges) on the MySQL CDC source. The state-persistence change is a bug fix rather than a feature.MySqlSourceEnumeratorMetricsand on each metric-name constant documents the contract. The metric names follow the same convention as the existingSourceEnumeratorMetricsinflink-cdc-base. No standalone docs page change is required for this PR; if maintainers prefer, the MySQL connector's metrics table in the docs can be extended in a follow-up.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Opus 4.7