1996fanrui commented on code in PR #28652:
URL: https://github.com/apache/flink/pull/28652#discussion_r3555410806


##########
flink-runtime/src/main/java/org/apache/flink/runtime/io/network/partition/consumer/RemoteInputChannel.java:
##########
@@ -713,30 +889,110 @@ private void checkAnnouncedOnlyOnce(SequenceBuffer 
sequenceBuffer) {
     }
 
     /**
-     * Spills all queued buffers on checkpoint start. If barrier has already 
been received (and
-     * reordered), spill only the overtaken buffers.
+     * Persists inflight data on checkpoint start. During recovery, persists 
recovered buffers
+     * before the matching RecoveryCheckpointBarrier sentinel; after recovery, 
uses the normal
+     * remote-channel barrier sequence tracking and persists overtaken live 
buffers.
      */
     public void checkpointStarted(CheckpointBarrier barrier) throws 
CheckpointException {
-        synchronized (receivedBuffers) {
-            if (barrier.getId() < lastBarrierId) {
-                throw new CheckpointException(
-                        String.format(
-                                "Sequence number for checkpoint %d is not 
known (it was likely been overwritten by a newer checkpoint %d)",
-                                barrier.getId(), lastBarrierId),
-                        CheckpointFailureReason
-                                .CHECKPOINT_SUBSUMED); // currently, at most 
one active unaligned
-                // checkpoint is possible
-            } else if (barrier.getId() > lastBarrierId) {
-                // This channel has received some obsolete barrier, older 
compared to the
-                // checkpointId
-                // which we are processing right now, and we should ignore 
that obsoleted checkpoint
-                // barrier sequence number.
-                resetLastBarrier();
+        try {
+            List<Buffer> toPersist;
+            synchronized (receivedBuffers) {
+                if (inRecovery) {
+                    toPersist = collectPreRecoveryBarrier(barrier.getId());
+                } else {
+                    if (barrier.getId() < lastBarrierId) {
+                        // Currently, at most one active unaligned checkpoint 
is possible.
+                        throw new CheckpointException(
+                                String.format(
+                                        "Sequence number for checkpoint %d is 
not known (it was likely been overwritten by a newer checkpoint %d)",
+                                        barrier.getId(), lastBarrierId),
+                                CheckpointFailureReason.CHECKPOINT_SUBSUMED);
+                    } else if (barrier.getId() > lastBarrierId) {
+                        // This channel has received some obsolete barrier, 
older compared to the
+                        // checkpointId which we are processing right now, and 
we should ignore that
+                        // obsoleted checkpoint barrier sequence number.
+                        resetLastBarrier();
+                    }
+                    toPersist = getInflightBuffersUnsafe(barrier.getId());
+                }
+                channelStatePersister.startPersisting(barrier.getId(), 
toPersist);
+            }
+        } catch (IOException e) {
+            throw new CheckpointException(
+                    "Failed to extract recovered buffers for checkpoint " + 
barrier.getId(),
+                    CheckpointFailureReason.CHECKPOINT_DECLINED,
+                    e);
+        }
+    }
+
+    /**
+     * Walks {@link #receivedBuffers} (skipping priority events) up to the 
{@link
+     * RecoveryCheckpointBarrier} sentinel matching {@code checkpointId}, 
retaining each pre-barrier
+     * recovered data buffer and removing the sentinel. During recovery the 
upstream has no credit,
+     * so {@code receivedBuffers} holds only recovered buffers, sentinels, and 
priority events — no
+     * live data buffers.
+     *
+     * @throws IOException if no sentinel matching {@code checkpointId} is 
found (the snapshot
+     *     protocol guarantees one must be present while the channel is in 
recovery).
+     */
+    @GuardedBy("receivedBuffers")
+    private List<Buffer> collectPreRecoveryBarrier(long checkpointId) throws 
IOException {
+        assert Thread.holdsLock(receivedBuffers);
+        List<Buffer> retained = new ArrayList<>();
+        SequenceBuffer sentinel = null;
+        try {
+            Iterator<SequenceBuffer> it = receivedBuffers.iterator();
+            // Priority events are stored separately at the head and never 
carry recovered data.
+            Iterators.advance(it, receivedBuffers.getNumPriorityElements());
+            while (it.hasNext()) {
+                SequenceBuffer sb = it.next();
+                if (isRecoveryCheckpointBarrier(sb.buffer, checkpointId)) {
+                    sentinel = sb;
+                    break;
+                }
+                // Skip non-data events (e.g. the 
EndOfFetchedChannelStateEvent sentinel appended
+                // after the recovered buffers): only recovered data buffers 
are snapshotted.
+                if (sb.buffer.isBuffer()) {

Review Comment:
   yes, you are correct.
   
   `RecoveryCheckpointBarrier` is added before step6 since channel is 
`inRecovery`.
   
   Added a comment via 6684c478dca58af11c86c088f0a6f4e60aa36c89
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to