-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Flink: FlinkSink data loss with unaligned checkpoints #15913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -423,21 +423,53 @@ public void endInput() throws IOException { | |||||||
| } | ||||||||
|
|
||||||||
| private void writeToManifestUptoLatestCheckpoint(long checkpointId) throws IOException { | ||||||||
| if (!writeResultsSinceLastSnapshot.containsKey(checkpointId)) { | ||||||||
|
|
||||||||
| if (!dataFilesPerCheckpoint.containsKey(checkpointId)) { | ||||||||
| dataFilesPerCheckpoint.put(checkpointId, EMPTY_MANIFEST_DATA); | ||||||||
| } | ||||||||
|
|
||||||||
| for (Map.Entry<Long, List<WriteResult>> writeResultsOfCheckpoint : | ||||||||
| writeResultsSinceLastSnapshot.entrySet()) { | ||||||||
| dataFilesPerCheckpoint.put( | ||||||||
| writeResultsOfCheckpoint.getKey(), | ||||||||
| writeToManifest(writeResultsOfCheckpoint.getKey(), writeResultsOfCheckpoint.getValue())); | ||||||||
| Map<Long, List<WriteResult>> pendingWriteResults = Maps.newHashMap(); | ||||||||
| for (Map.Entry<Long, List<WriteResult>> entry : writeResultsSinceLastSnapshot.entrySet()) { | ||||||||
| long assignedCheckpointId = computeCheckpointId(checkpointId, entry); | ||||||||
| pendingWriteResults | ||||||||
| .computeIfAbsent(assignedCheckpointId, k -> Lists.newArrayList()) | ||||||||
| .addAll(entry.getValue()); | ||||||||
| } | ||||||||
|
|
||||||||
| for (Map.Entry<Long, List<WriteResult>> entry : pendingWriteResults.entrySet()) { | ||||||||
| dataFilesPerCheckpoint.put(entry.getKey(), writeToManifest(entry.getKey(), entry.getValue())); | ||||||||
| } | ||||||||
|
|
||||||||
| // Clear the local buffer for current checkpoint. | ||||||||
| writeResultsSinceLastSnapshot.clear(); | ||||||||
| } | ||||||||
|
|
||||||||
| /** | ||||||||
| * in case of unaligned checkpoints, data files that were part of checkpoint N in the writer may | ||||||||
| * have to become part of a later checkpoint in the committer if: | ||||||||
| * | ||||||||
| * <ul> | ||||||||
| * <li>previous files were already committed for checkpoint N. We have to keep the manifests for | ||||||||
| * new files under a later key, otherwise they are discarded during recovery after a crash | ||||||||
| * <li>we already have a manifest of files to be committed for checkpoint N, even though it | ||||||||
| * might not have been committed yet. In this case, we must not overwrite the manifests we | ||||||||
| * already have, and we must keep them consistent with our checkpoint | ||||||||
| * </ul> | ||||||||
| */ | ||||||||
| private long computeCheckpointId(long checkpointId, Map.Entry<Long, List<WriteResult>> entry) { | ||||||||
| long sourceCheckpointId = entry.getKey(); | ||||||||
|
|
||||||||
| boolean sourceCheckpointIdAlreadyCommitted = sourceCheckpointId <= maxCommittedCheckpointId; | ||||||||
| boolean sourceCheckpointIdHasDataInSnapshot = | ||||||||
| dataFilesPerCheckpoint.containsKey(sourceCheckpointId); | ||||||||
| // for aligned checkpoints, both conditions will be false and the upstream operator's checkpoint | ||||||||
| // ID | ||||||||
| // will be chosen. | ||||||||
|
Comment on lines
+466
to
+467
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
NIT |
||||||||
| return sourceCheckpointIdAlreadyCommitted || sourceCheckpointIdHasDataInSnapshot | ||||||||
| ? checkpointId | ||||||||
| : sourceCheckpointId; | ||||||||
|
Comment on lines
+468
to
+470
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this correct under all scenarios? This will mean that we include files of an older snapshot into the current checkpoint, but IMHO they need to be in the following snapshot ( Otherwise, we violate the order in case of deletions. |
||||||||
| } | ||||||||
|
|
||||||||
| /** | ||||||||
| * Write all the complete data files to a newly created manifest file and return the manifest's | ||||||||
| * avro serialized bytes. | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT