You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flink.apache.org by "kim (Jira)" <ji...@apache.org> on 2026/07/22 09:53:00 UTC
[jira] [Created] (FLINK-40216) [cdc-base] Meta groups of finished snapshot splits become inconsistent after restore due to lexicographic re-sorting of assigned splits
kim created FLINK-40216:
---------------------------
Summary: [cdc-base] Meta groups of finished snapshot splits become inconsistent after restore due to lexicographic re-sorting of assigned splits
Key: FLINK-40216
URL: https://issues.apache.org/jira/browse/FLINK-40216
Project: Flink
Issue Type: Bug
Components: Flink CDC
Affects Versions: cdc-3.1.0, cdc-3.6.0
Reporter: kim
h3. Problem
In {{flink-cdc-base}}, the order of {{assignedSplits}} is not preserved across a checkpoint/savepoint restore, so the meta groups of finished snapshot splits are partitioned differently before and after a restart.
During a normal run, splits are appended to {{assignedSplits}} (a {{LinkedHashMap}}) in *assignment order* ({{SnapshotSplitAssigner#getNext}}). On restore, however:
# {{PendingSplitsStateSerializer#readAssignedSnapshotSplits}} deserializes the checkpointed splits into a plain {{HashMap}}, losing the checkpointed order.
# The restore constructor of {{SnapshotSplitAssigner}} then re-sorts the entries *lexicographically* by split id (introduced in FLINK-34634 as a workaround for the lost order):
{code:java}
this.assignedSplits =
assignedSplits.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
...
{code}
Split ids are generated as {{tableId + ":" + chunkId}} ({{SnapshotSplit#generateSplitId}}), so with 10+ chunks the lexicographic order ({{t:0, t:1, t:10, t:11, t:2, ...}}) differs from the assignment order ({{t:0, t:1, t:2, ..., t:11}}). The same happens across tables when the alphabetical order of table names differs from the capture order.
h3. Impact
{{IncrementalSourceEnumerator#sendStreamMetaRequestEvent}} partitions {{splitAssigner.getFinishedSplitInfos()}} by {{chunk-meta.group.size}} ({{Lists.partition}}) and serves the group requested by the reader. A reader whose stream split had synchronized only part of the meta groups before the restart resumes requesting from its next group id, but the enumerator now serves groups computed from a differently-ordered list.
We reproduced this with a unit test against current master (single table, 12 chunks, {{chunk-meta.group.size = 2}}, reader synchronized meta groups 0..2 before the restart, group ids computed with {{IncrementalSourceReader#getNextMetaGroupId}}): after the restore the reader ends up with
{code}
[t:0, t:1, t:2, t:3, t:4, t:5, t:4, t:5, t:6, t:7, t:8, t:9]
{code}
i.e. {{t:4}}/{{t:5}} are received twice and {{t:10}}/{{t:11}} are never delivered, while the stream split is considered complete because {{StreamSplit#isCompletedSplit}} only compares sizes. Subsequently {{IncrementalSourceStreamFetcher#shouldEmit}} finds no matching {{FinishedSnapshotSplitInfo}} for change events in the key ranges of the lost splits and silently drops them — permanent data loss in the stream phase. Depending on where the restart happens, the mismatch can also surface as the "invalid request meta group id" error.
The MySQL connector carried the identical re-sort and was fixed by FLINK-38218 (cdc-3.6.0), which removed it and made the whole pipeline preserve the assignment order. As its author noted there: "Note that other connectors that use SnapshotSplitAssigner from the flink-cdc-base package may be prone to this issue as well." {{flink-cdc-base}} still carries the identical code, affecting all connectors built on the base incremental framework: Postgres, MongoDB, Oracle, SqlServer, Db2 (and their SQL/pipeline wrappers). {{MySqlSnapshotSplitAssignerTest#testFinishedSnapshotSplitInfosAreInOrderOfAssignment}} guards this property on the MySQL side; {{flink-cdc-base}} has no equivalent test.
h3. Proposed fix
Port FLINK-38218 to {{flink-cdc-base}}:
* deserialize {{assignedSplits}} into a {{LinkedHashMap}} in {{PendingSplitsStateSerializer}} (the serialized form already preserves iteration order) and declare the order contract on the field, instead of re-sorting in the restore constructor of {{SnapshotSplitAssigner}};
* remove the lexicographic sort in {{HybridSplitAssigner#createStreamSplit}};
* replace the order-dependent deduplication in {{IncrementalSourceReader}} ({{getExistedSplitsOfLastGroup}}) with the order-agnostic prefix-discard approach from FLINK-38218;
* guard {{StreamSplit}} against duplicated split infos, mirroring {{MySqlBinlogSplit#ensureNoDuplicates}}.
This fix is independent of the metadata-transmission protocol redesign discussed in FLINK-38270 and can be applied separately.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)