gemini-code-assist[bot] commented on code in PR #39191:
URL: https://github.com/apache/beam/pull/39191#discussion_r3507357304


##########
runners/flink/src/main/java/org/apache/beam/runners/flink/translation/wrappers/streaming/ExecutableStageDoFnOperator.java:
##########
@@ -1009,9 +1010,17 @@ public <KeyT> void onTimer(
       Preconditions.checkNotNull(remoteBundle, "Call to onTimer outside of a 
bundle");
       if (StateAndTimerBundleCheckpointHandler.isSdfTimer(timerId)) {
         StateNamespace namespace = StateNamespaces.window(windowCoder, window);
-        WindowedValue stateValue =
-            keyedStateInternals.state(namespace, StateTags.value(timerId, 
residualCoder)).read();
+        // Residuals from pre-#27648 savepoints used per-residual ValueState 
tags and are not
+        // migrated; an older savepoint drops any in-flight SDF residual on 
this experimental path.
+        MapState<String, WindowedValue<InputT>> residualState =
+            keyedStateInternals.state(
+                namespace, 
StateAndTimerBundleCheckpointHandler.residualStateTag(residualCoder));
+        WindowedValue<InputT> stateValue = residualState.get(timerId).read();
         processElement(stateValue);

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   If an older savepoint is used, `residualState.get(timerId).read()` will 
return `null`. Passing `null` to `processElement` will cause a 
`NullPointerException`. We should add a null check to safely drop the residual 
as intended.
   
   ```suggestion
           WindowedValue<InputT> stateValue = residualState.get(timerId).read();
           if (stateValue != null) {
             processElement(stateValue);
           }
   ```



##########
runners/flink/src/main/java/org/apache/beam/runners/flink/translation/functions/FlinkExecutableStageFunction.java:
##########
@@ -284,11 +284,13 @@ public void mapPartition(
           List<WindowedValue<InputT>> residuals = new ArrayList<>();
           TimerInternals.TimerData timer;
           while ((timer = sdfTimerInternals.removeNextProcessingTimer()) != 
null) {
-            WindowedValue stateValue =
-                sdfStateInternals
-                    .state(timer.getNamespace(), 
StateTags.value(timer.getTimerId(), inputCoder))
-                    .read();
-
+            MapState<String, WindowedValue<InputT>> residualState =
+                sdfStateInternals.state(
+                    timer.getNamespace(),
+                    
BundleCheckpointHandlers.StateAndTimerBundleCheckpointHandler.residualStateTag(
+                        inputCoder));
+            WindowedValue<InputT> stateValue = 
residualState.get(timer.getTimerId()).read();
+            residualState.remove(timer.getTimerId());
             residuals.add(stateValue);

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   If an older savepoint is used, the residual state won't be found under the 
new `MapState` tag, and `residualState.get(timer.getTimerId()).read()` will 
return `null`. Adding `null` to `residuals` will lead to a 
`NullPointerException` during `processElements`. We should add a null check to 
safely drop the residual as intended.
   
   ```java
               WindowedValue<InputT> stateValue = 
residualState.get(timer.getTimerId()).read();
               residualState.remove(timer.getTimerId());
               if (stateValue != null) {
                 residuals.add(stateValue);
               }
   ```



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