7878import org .apache .kafka .common .config .ConfigDef ;
7979import org .apache .kafka .common .errors .SerializationException ;
8080import org .apache .kafka .common .serialization .Deserializer ;
81+ import org .checkerframework .checker .nullness .qual .EnsuresNonNull ;
82+ import org .checkerframework .checker .nullness .qual .MonotonicNonNull ;
8183import org .checkerframework .checker .nullness .qual .Nullable ;
84+ import org .checkerframework .checker .nullness .qual .RequiresNonNull ;
8285import org .joda .time .Instant ;
8386import org .slf4j .Logger ;
8487import org .slf4j .LoggerFactory ;
@@ -316,6 +319,16 @@ public Consumer<byte[], byte[]> load(
316319 private final SerializableSupplier <LoadingCache <KafkaSourceDescriptor , Consumer <byte [], byte []>>>
317320 pollConsumerCacheSupplier ;
318321
322+ private transient @ MonotonicNonNull LoadingCache <KafkaSourceDescriptor , MovingAvg >
323+ avgRecordSizeCache ;
324+
325+ private transient @ MonotonicNonNull LoadingCache <
326+ KafkaSourceDescriptor , KafkaLatestOffsetEstimator >
327+ latestOffsetEstimatorCache ;
328+
329+ private transient @ MonotonicNonNull LoadingCache <KafkaSourceDescriptor , Consumer <byte [], byte []>>
330+ pollConsumerCache ;
331+
319332 // Valid between bundle start and bundle finish.
320333 private transient @ Nullable Deserializer <K > keyDeserializerInstance = null ;
321334 private transient @ Nullable Deserializer <V > valueDeserializerInstance = null ;
@@ -433,9 +446,12 @@ private void refresh() {
433446 }
434447
435448 @ GetInitialRestriction
449+ @ RequiresNonNull ({"pollConsumerCache" })
436450 public OffsetRange initialRestriction (@ Element KafkaSourceDescriptor kafkaSourceDescriptor ) {
437- final Consumer <byte [], byte []> consumer =
438- pollConsumerCacheSupplier .get ().getUnchecked (kafkaSourceDescriptor );
451+ final LoadingCache <KafkaSourceDescriptor , Consumer <byte [], byte []>> pollConsumerCache =
452+ this .pollConsumerCache ;
453+
454+ final Consumer <byte [], byte []> consumer = pollConsumerCache .getUnchecked (kafkaSourceDescriptor );
439455
440456 final long startOffset ;
441457 final long stopOffset ;
@@ -513,12 +529,16 @@ public WatermarkEstimator<Instant> newWatermarkEstimator(
513529 }
514530
515531 @ GetSize
532+ @ RequiresNonNull ({"avgRecordSizeCache" , "latestOffsetEstimatorCache" })
516533 public double getSize (
517534 @ Element KafkaSourceDescriptor kafkaSourceDescriptor , @ Restriction OffsetRange offsetRange ) {
535+ final LoadingCache <KafkaSourceDescriptor , MovingAvg > avgRecordSizeCache =
536+ this .avgRecordSizeCache ;
537+
518538 // If present, estimates the record size to offset gap ratio. Compacted topics may hold less
519539 // records than the estimated offset range due to record deletion within a partition.
520540 final @ Nullable MovingAvg avgRecordSize =
521- avgRecordSizeCacheSupplier . get () .getIfPresent (kafkaSourceDescriptor );
541+ avgRecordSizeCache .getIfPresent (kafkaSourceDescriptor );
522542 // The tracker estimates the offset range by subtracting the last claimed position from the
523543 // currently observed end offset for the partition belonging to this split.
524544 final double estimatedOffsetRange =
@@ -533,8 +553,12 @@ public double getSize(
533553 }
534554
535555 @ NewTracker
556+ @ RequiresNonNull ({"latestOffsetEstimatorCache" })
536557 public OffsetRangeTracker restrictionTracker (
537558 @ Element KafkaSourceDescriptor kafkaSourceDescriptor , @ Restriction OffsetRange restriction ) {
559+ final LoadingCache <KafkaSourceDescriptor , KafkaLatestOffsetEstimator >
560+ latestOffsetEstimatorCache = this .latestOffsetEstimatorCache ;
561+
538562 if (restriction .getTo () < Long .MAX_VALUE ) {
539563 return new OffsetRangeTracker (restriction );
540564 }
@@ -543,22 +567,28 @@ public OffsetRangeTracker restrictionTracker(
543567 // so we want to minimize the amount of connections that we start and track with Kafka. Another
544568 // point is that it has a memoized backlog, and this should make that more reusable estimations.
545569 return new GrowableOffsetRangeTracker (
546- restriction .getFrom (),
547- latestOffsetEstimatorCacheSupplier .get ().getUnchecked (kafkaSourceDescriptor ));
570+ restriction .getFrom (), latestOffsetEstimatorCache .getUnchecked (kafkaSourceDescriptor ));
548571 }
549572
550573 @ ProcessElement
574+ @ RequiresNonNull ({"avgRecordSizeCache" , "latestOffsetEstimatorCache" , "pollConsumerCache" })
551575 public ProcessContinuation processElement (
552576 @ Element KafkaSourceDescriptor kafkaSourceDescriptor ,
553577 RestrictionTracker <OffsetRange , Long > tracker ,
554578 WatermarkEstimator <Instant > watermarkEstimator ,
555579 MultiOutputReceiver receiver )
556580 throws Exception {
557- final MovingAvg avgRecordSize = avgRecordSizeCacheSupplier .get ().get (kafkaSourceDescriptor );
581+ final LoadingCache <KafkaSourceDescriptor , MovingAvg > avgRecordSizeCache =
582+ this .avgRecordSizeCache ;
583+ final LoadingCache <KafkaSourceDescriptor , KafkaLatestOffsetEstimator >
584+ latestOffsetEstimatorCache = this .latestOffsetEstimatorCache ;
585+ final LoadingCache <KafkaSourceDescriptor , Consumer <byte [], byte []>> pollConsumerCache =
586+ this .pollConsumerCache ;
587+
588+ final MovingAvg avgRecordSize = avgRecordSizeCache .get (kafkaSourceDescriptor );
558589 final KafkaLatestOffsetEstimator latestOffsetEstimator =
559- latestOffsetEstimatorCacheSupplier .get ().get (kafkaSourceDescriptor );
560- final Consumer <byte [], byte []> consumer =
561- pollConsumerCacheSupplier .get ().get (kafkaSourceDescriptor );
590+ latestOffsetEstimatorCache .get (kafkaSourceDescriptor );
591+ final Consumer <byte [], byte []> consumer = pollConsumerCache .get (kafkaSourceDescriptor );
562592 final Deserializer <K > keyDeserializerInstance =
563593 Preconditions .checkStateNotNull (this .keyDeserializerInstance );
564594 final Deserializer <V > valueDeserializerInstance =
@@ -746,7 +776,12 @@ public Coder<OffsetRange> restrictionCoder() {
746776 }
747777
748778 @ Setup
779+ @ EnsuresNonNull ({"avgRecordSizeCache" , "latestOffsetEstimatorCache" , "pollConsumerCache" })
749780 public void setup () throws Exception {
781+ avgRecordSizeCache = avgRecordSizeCacheSupplier .get ();
782+ latestOffsetEstimatorCache = latestOffsetEstimatorCacheSupplier .get ();
783+ pollConsumerCache = pollConsumerCacheSupplier .get ();
784+
750785 keyDeserializerInstance = keyDeserializerProvider .getDeserializer (consumerConfig , true );
751786 valueDeserializerInstance = valueDeserializerProvider .getDeserializer (consumerConfig , false );
752787 if (checkStopReadingFn != null ) {
@@ -755,7 +790,15 @@ public void setup() throws Exception {
755790 }
756791
757792 @ Teardown
793+ @ RequiresNonNull ({"avgRecordSizeCache" , "latestOffsetEstimatorCache" , "pollConsumerCache" })
758794 public void teardown () throws Exception {
795+ final LoadingCache <KafkaSourceDescriptor , MovingAvg > avgRecordSizeCache =
796+ this .avgRecordSizeCache ;
797+ final LoadingCache <KafkaSourceDescriptor , KafkaLatestOffsetEstimator >
798+ latestOffsetEstimatorCache = this .latestOffsetEstimatorCache ;
799+ final LoadingCache <KafkaSourceDescriptor , Consumer <byte [], byte []>> pollConsumerCache =
800+ this .pollConsumerCache ;
801+
759802 try {
760803 if (valueDeserializerInstance != null ) {
761804 Closeables .close (valueDeserializerInstance , true );
@@ -773,9 +816,9 @@ public void teardown() throws Exception {
773816 }
774817
775818 // Allow the cache to perform clean up tasks when this instance is about to be deleted.
776- avgRecordSizeCacheSupplier . get () .cleanUp ();
777- latestOffsetEstimatorCacheSupplier . get () .cleanUp ();
778- pollConsumerCacheSupplier . get () .cleanUp ();
819+ avgRecordSizeCache .cleanUp ();
820+ latestOffsetEstimatorCache .cleanUp ();
821+ pollConsumerCache .cleanUp ();
779822 }
780823
781824 private static Instant ensureTimestampWithinBounds (Instant timestamp ) {
0 commit comments