Skip to content

Commit cccaa75

Browse files
authored
Only retrieve the shared caches once during setup in ReadFromKafkaDoFn (#36028)
1 parent 9adc8dc commit cccaa75

1 file changed

Lines changed: 55 additions & 12 deletions

File tree

sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ReadFromKafkaDoFn.java

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@
7878
import org.apache.kafka.common.config.ConfigDef;
7979
import org.apache.kafka.common.errors.SerializationException;
8080
import org.apache.kafka.common.serialization.Deserializer;
81+
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
82+
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
8183
import org.checkerframework.checker.nullness.qual.Nullable;
84+
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
8285
import org.joda.time.Instant;
8386
import org.slf4j.Logger;
8487
import 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

Comments
 (0)