Eliaaazzz commented on code in PR #39823:
URL: https://github.com/apache/beam/pull/39823#discussion_r3999156878


##########
runners/spark/src/main/java/org/apache/beam/runners/spark/util/GlobalWatermarkHolder.java:
##########
@@ -240,7 +252,7 @@ private static Map<Integer, SparkWatermarks> 
computeNewWatermarks(BlockManager b
           new SparkWatermarks(nextLowWatermark, nextHighWatermark, 
nextSynchronizedProcessingTime));
     }
 
-    return newValues;
+    return hasUpdates ? newValues : new HashMap<>();

Review Comment:
   `hasUpdates` restores a signal the pre-change code got for free.
   
   The caller is `advance(batchId)`, which skips both publication calls when 
the returned map is empty:
   
   ```java
   final Map<Integer, SparkWatermarks> newWatermarks = 
computeNewWatermarks(blockManager);
   if (!newWatermarks.isEmpty()) {
     writeRemoteWatermarkBlock(newWatermarks, blockManager);
     writeLocalWatermarkCopy(newWatermarks);
   } else {
     LOG.info("No new watermarks could be computed upon completion of batch: 
{}", batchId);
   }
   ```
   
   Before this change `newValues` started empty and only a source with a queued 
update got an entry, so a batch where every queue was empty produced an empty 
map and `advance` published nothing. Seeding `newValues` from the stored map 
means a quiet batch now yields a non-empty map whenever a stored source still 
has `high < TIMESTAMP_MAX_VALUE`. `hasUpdates` is what keeps that batch from 
publishing.
   
   What it saves on such a batch is the `removeBlock` plus `putSingle` pair and 
the local copy assignment. The comments on `writeRemoteWatermarkBlock`, and 
#18426 which they link, describe the window where an executor fetching 
`WATERMARKS_BLOCK_ID` finds nothing. The saving is narrow: the block fetch, the 
seeding and the queue scan all still happen.
   
   One consequence is worth stating plainly. On a batch where every queue is 
empty, the stored block keeps a source whose high watermark already reached 
`TIMESTAMP_MAX_VALUE`, which seeding would have pruned. Such a source can still 
hold the effective low watermark back, because 
`SparkTimerInternals.forStreamFromSources` takes the slowest low watermark and 
a completed high watermark does not imply a completed low watermark. 
`testCompletedSourceAgesOut` uses exactly that shape, low at `+5ms` with high 
at `TIMESTAMP_MAX_VALUE`. The pre-change code also published nothing on an 
all-quiet batch, so that persistence predates this PR. What the guard defers is 
the pruning seeding introduced. A completed source drops out on the next 
published batch where its own queue is empty and another source supplies an 
update, and the update loop puts it back on any batch where it does report.
   
   Dropping the flag is not the same as publishing every batch. On a quiet 
batch it would publish the seeded map, which prunes completed sources as long 
as one unfinished source remains. Once every stored source has completed, 
seeding yields an empty map and `advance` publishes nothing regardless, so 
clearing that block would need `advance` to tell "nothing to publish" apart 
from "publish this empty map".
   
   The tests cover retention and pruning on a batch where another source 
updates. They do not cover the all-queues-empty path. I can add that case if 
you want the behavior pinned down.



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