3939import org .apache .beam .sdk .metrics .SourceMetrics ;
4040import org .apache .beam .sdk .options .PipelineOptions ;
4141import org .apache .beam .sdk .transforms .SerializableFunction ;
42+ import org .apache .beam .sdk .transforms .windowing .BoundedWindow ;
4243import org .apache .beam .sdk .values .PCollection ;
4344import org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .collect .ImmutableList ;
4445import org .checkerframework .checker .nullness .qual .Nullable ;
@@ -95,7 +96,8 @@ static BoundedSource<Long> createSourceForSubrange(long startIndex, long endInde
9596 /** Create a new {@link UnboundedCountingSource}. */
9697 // package-private to return a typed UnboundedCountingSource rather than the UnboundedSource type.
9798 static UnboundedCountingSource createUnboundedFrom (long start ) {
98- return new UnboundedCountingSource (start , 1 , 1L , Duration .ZERO , new NowTimestampFn ());
99+ return new UnboundedCountingSource (
100+ start , 1 , Long .MAX_VALUE , 1L , Duration .ZERO , new NowTimestampFn ());
99101 }
100102
101103 /**
@@ -130,7 +132,7 @@ public static UnboundedSource<Long, CounterMark> unbounded() {
130132 @ Deprecated
131133 public static UnboundedSource <Long , CounterMark > unboundedWithTimestampFn (
132134 SerializableFunction <Long , Instant > timestampFn ) {
133- return new UnboundedCountingSource (0 , 1 , 1L , Duration .ZERO , timestampFn );
135+ return new UnboundedCountingSource (0 , 1 , Long . MAX_VALUE , 1L , Duration .ZERO , timestampFn );
134136 }
135137
136138 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -267,11 +269,13 @@ public void close() throws IOException {}
267269 }
268270
269271 /** An implementation of {@link CountingSource} that produces an unbounded {@link PCollection}. */
270- static class UnboundedCountingSource extends UnboundedSource <Long , CounterMark > {
272+ public static class UnboundedCountingSource extends UnboundedSource <Long , CounterMark > {
271273 /** The first number (>= 0) generated by this {@link UnboundedCountingSource}. */
272274 private final long start ;
273275 /** The interval between numbers generated by this {@link UnboundedCountingSource}. */
274276 private final long stride ;
277+ /** The exclusive limit for the sequence. */
278+ private final long end ;
275279 /** The number of elements to produce each period. */
276280 private final long elementsPerPeriod ;
277281 /** The time between producing numbers from this {@link UnboundedCountingSource}. */
@@ -291,11 +295,13 @@ static class UnboundedCountingSource extends UnboundedSource<Long, CounterMark>
291295 private UnboundedCountingSource (
292296 long start ,
293297 long stride ,
298+ long end ,
294299 long elementsPerPeriod ,
295300 Duration period ,
296301 SerializableFunction <Long , Instant > timestampFn ) {
297302 this .start = start ;
298303 this .stride = stride ;
304+ this .end = end ;
299305 checkArgument (
300306 elementsPerPeriod > 0L ,
301307 "Must produce at least one element per period, got %s" ,
@@ -312,7 +318,8 @@ private UnboundedCountingSource(
312318 * will be produced with an interval between them equal to the period.
313319 */
314320 public UnboundedCountingSource withRate (long elementsPerPeriod , Duration period ) {
315- return new UnboundedCountingSource (start , stride , elementsPerPeriod , period , timestampFn );
321+ return new UnboundedCountingSource (
322+ start , stride , end , elementsPerPeriod , period , timestampFn );
316323 }
317324
318325 /**
@@ -324,7 +331,18 @@ public UnboundedCountingSource withRate(long elementsPerPeriod, Duration period)
324331 public UnboundedCountingSource withTimestampFn (
325332 SerializableFunction <Long , Instant > timestampFn ) {
326333 checkNotNull (timestampFn );
327- return new UnboundedCountingSource (start , stride , elementsPerPeriod , period , timestampFn );
334+ return new UnboundedCountingSource (
335+ start , stride , end , elementsPerPeriod , period , timestampFn );
336+ }
337+
338+ /**
339+ * Returns an {@link UnboundedCountingSource} like this one but with the specified exclusive
340+ * limit.
341+ */
342+ public UnboundedCountingSource to (long end ) {
343+ checkArgument (end >= start , "end (%s) must be >= start (%s)" , end , start );
344+ return new UnboundedCountingSource (
345+ start , stride , end , elementsPerPeriod , period , timestampFn );
328346 }
329347
330348 /**
@@ -348,7 +366,7 @@ public List<? extends UnboundedSource<Long, CountingSource.CounterMark>> split(
348366 // 0, 2, and 4.
349367 splits .add (
350368 new UnboundedCountingSource (
351- start + i * stride , newStride , elementsPerPeriod , period , timestampFn ));
369+ start + i * stride , newStride , end , elementsPerPeriod , period , timestampFn ));
352370 }
353371 return splits .build ();
354372 }
@@ -376,14 +394,15 @@ public boolean equals(@Nullable Object other) {
376394 UnboundedCountingSource that = (UnboundedCountingSource ) other ;
377395 return this .start == that .start
378396 && this .stride == that .stride
397+ && this .end == that .end
379398 && this .elementsPerPeriod == that .elementsPerPeriod
380399 && Objects .equals (this .period , that .period )
381400 && Objects .equals (this .timestampFn , that .timestampFn );
382401 }
383402
384403 @ Override
385404 public int hashCode () {
386- return Objects .hash (start , stride , elementsPerPeriod , period , timestampFn );
405+ return Objects .hash (start , stride , end , elementsPerPeriod , period , timestampFn );
387406 }
388407 }
389408
@@ -431,6 +450,9 @@ public boolean advance() throws IOException {
431450 return false ;
432451 }
433452 long nextValue = current + source .stride ;
453+ if (nextValue >= source .end ) {
454+ return false ;
455+ }
434456 if (expectedValue () < nextValue ) {
435457 return false ;
436458 }
@@ -453,7 +475,9 @@ private long expectedValue() {
453475
454476 @ Override
455477 public Instant getWatermark () {
456- return source .timestampFn .apply (current );
478+ return (current >= source .end - source .stride )
479+ ? BoundedWindow .TIMESTAMP_MAX_VALUE
480+ : source .timestampFn .apply (current );
457481 }
458482
459483 @ Override
0 commit comments