Copilot commented on code in PR #4323:
URL: https://github.com/apache/flink-cdc/pull/4323#discussion_r3007809516


##########
flink-cdc-connect/flink-cdc-source-connectors/flink-connector-postgres-cdc/src/main/java/org/apache/flink/cdc/connectors/postgres/source/offset/PostgresOffset.java:
##########
@@ -43,7 +44,34 @@ public class PostgresOffset extends Offset {
 
     // used by PostgresOffsetFactory
     PostgresOffset(Map<String, String> offset) {
-        this.offset = offset;
+        Map<String, String> filtered = new HashMap<>(offset);
+        // When a checkpoint is taken right after a COMMIT (state-3a), all 
three LSN fields
+        // converge to the same value: lsn == lsn_proc == lsn_commit.
+        // Recovering from such a checkpoint constructs WalPositionLocator(C0, 
C0), which
+        // causes the first new transaction's DML records (data_start=C0 in 
pgoutput) to be
+        // silently dropped: they are added to lsnSeen during the find phase, 
but
+        // startStreamingLsn is set to the next COMMIT (C1), so they are 
filtered in the
+        // stream phase.
+        //
+        // Fix: when lsn == lsn_proc == lsn_commit, remove lsn_proc and 
lsn_commit so that
+        // WalPositionLocator is constructed with lastCommitStoredLsn=null, 
which triggers
+        // the fast path: startStreamingLsn=firstLsnReceived=C0, all messages 
pass through.
+        //
+        // The triple-equality condition is safe: mid-transaction checkpoints 
(state-3b) have
+        // lsn_commit pointing to the previous commit, so lsn_commit != lsn, 
and this branch
+        // is not taken.
+        //
+        // This workaround can be removed once Debezium is upgraded to a 
version that
+        // includes DBZ-6204:
+        // 
https://github.com/debezium/debezium/commit/3b5740f1a836c8b438888f2458ebb1554320bac7
+        String lsnVal = filtered.get(SourceInfo.LSN_KEY);
+        String lsnProc = 
filtered.get(PostgresOffsetContext.LAST_COMPLETELY_PROCESSED_LSN_KEY);
+        String lsnCommit = 
filtered.get(PostgresOffsetContext.LAST_COMMIT_LSN_KEY);
+        if (lsnVal != null && lsnVal.equals(lsnProc) && 
lsnVal.equals(lsnCommit)) {
+            
filtered.remove(PostgresOffsetContext.LAST_COMPLETELY_PROCESSED_LSN_KEY);
+            filtered.remove(PostgresOffsetContext.LAST_COMMIT_LSN_KEY);
+        }
+        this.offset = filtered;

Review Comment:
   This change addresses a data-loss scenario after checkpoint recovery, but 
there’s no accompanying regression test exercising recovery with `lsn == 
lsn_proc == lsn_commit` and pgoutput non-streaming where the first new 
transaction reuses the prior COMMIT `data_start`. Adding an ITCase/unit test 
that fails on the old behavior and passes with this filtering would help 
prevent regressions (e.g., extend existing checkpoint/restore tests in 
`PostgreSQLSourceTest`).



##########
flink-cdc-connect/flink-cdc-source-connectors/flink-connector-postgres-cdc/src/main/java/org/apache/flink/cdc/connectors/postgres/source/offset/PostgresOffset.java:
##########
@@ -43,7 +44,34 @@ public class PostgresOffset extends Offset {
 
     // used by PostgresOffsetFactory
     PostgresOffset(Map<String, String> offset) {
-        this.offset = offset;
+        Map<String, String> filtered = new HashMap<>(offset);
+        // When a checkpoint is taken right after a COMMIT (state-3a), all 
three LSN fields

Review Comment:
   `PostgresOffset.of(...)` already builds a new `HashMap` (`offsetStrMap`) and 
then this constructor creates another `HashMap` copy (`filtered`). Since 
`getStreamOffset()` is called per streamed record (see 
`IncrementalSourceStreamFetcher.shouldEmit`), this adds an extra allocation per 
event. Consider avoiding the second copy in the common case (e.g., only copy 
when the triple-equality condition is met, otherwise keep the passed-in map), 
or perform the filtering before constructing the `PostgresOffset` when the 
input map is known to be newly created.



##########
flink-cdc-connect/flink-cdc-source-connectors/flink-connector-postgres-cdc/src/main/java/org/apache/flink/cdc/connectors/postgres/source/offset/PostgresOffset.java:
##########
@@ -43,7 +44,34 @@ public class PostgresOffset extends Offset {
 
     // used by PostgresOffsetFactory
     PostgresOffset(Map<String, String> offset) {
-        this.offset = offset;
+        Map<String, String> filtered = new HashMap<>(offset);
+        // When a checkpoint is taken right after a COMMIT (state-3a), all 
three LSN fields
+        // converge to the same value: lsn == lsn_proc == lsn_commit.
+        // Recovering from such a checkpoint constructs WalPositionLocator(C0, 
C0), which
+        // causes the first new transaction's DML records (data_start=C0 in 
pgoutput) to be
+        // silently dropped: they are added to lsnSeen during the find phase, 
but
+        // startStreamingLsn is set to the next COMMIT (C1), so they are 
filtered in the
+        // stream phase.
+        //
+        // Fix: when lsn == lsn_proc == lsn_commit, remove lsn_proc and 
lsn_commit so that
+        // WalPositionLocator is constructed with lastCommitStoredLsn=null, 
which triggers
+        // the fast path: startStreamingLsn=firstLsnReceived=C0, all messages 
pass through.
+        //
+        // The triple-equality condition is safe: mid-transaction checkpoints 
(state-3b) have
+        // lsn_commit pointing to the previous commit, so lsn_commit != lsn, 
and this branch
+        // is not taken.
+        //
+        // This workaround can be removed once Debezium is upgraded to a 
version that
+        // includes DBZ-6204:
+        // 
https://github.com/debezium/debezium/commit/3b5740f1a836c8b438888f2458ebb1554320bac7
+        String lsnVal = filtered.get(SourceInfo.LSN_KEY);
+        String lsnProc = 
filtered.get(PostgresOffsetContext.LAST_COMPLETELY_PROCESSED_LSN_KEY);
+        String lsnCommit = 
filtered.get(PostgresOffsetContext.LAST_COMMIT_LSN_KEY);
+        if (lsnVal != null && lsnVal.equals(lsnProc) && 
lsnVal.equals(lsnCommit)) {
+            
filtered.remove(PostgresOffsetContext.LAST_COMPLETELY_PROCESSED_LSN_KEY);
+            filtered.remove(PostgresOffsetContext.LAST_COMMIT_LSN_KEY);
+        }

Review Comment:
   The PR description says to remove `lsn_proc` and `lsn_commit` from 
`PostgresOffset` when constructed from a Debezium source offset, but the 
implementation only removes them when `lsn == lsn_proc == lsn_commit`. Please 
clarify whether the fix is intentionally limited to this state-3a case; if so, 
update the PR description accordingly, otherwise broaden the filtering logic so 
recovery offsets always omit those keys as described.



-- 
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