From 2ac4e8e7a868b9760e0d6ab0cb9cca994b50fd53 Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 13:53:25 +0200 Subject: [PATCH 1/7] KIP-1352: Ranges and Range Aggregations in the Kafka Streams DSL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces rangeOver() on KGroupedStream, which lets users aggregate a sliding window of records relative to each incoming record (the "anchor") without waiting for a window boundary to close. Public API additions: - Range — abstract base; defines gracePeriodMs, fetch(), and retentionMs() = rangeRetentionMs() + grace - EventTimeRange — time-bounded range [anchor.ts-before, anchor.ts+after]; static factories ofTimeBoundsWithNoGrace / AndGrace - EventCountRange — count-bounded range (before records back, after records forward) bounded by maxTimeBefore; static factories ofCountBoundsWithNoGrace / AndGrace - RangeAggregator — @FunctionalInterface (anchor, Iterable) -> VR - RangedKStream — aggregate(RangeAggregator) and count() - KGroupedStream.rangeOver(Range) / rangeOver(Range, Materialized) Internal topology (two-processor design): - KStreamRangeBuffer — writes records to a retainDuplicates WindowStore, enforces grace period, forwards downstream - KStreamRangeAggregate — on each record calls range.fetch() against the shared buffer store, applies the aggregator - RangeWindowStoreMaterializer — configures the WindowStore (plain, not timestamped; retainDuplicates=true enforced) - RangedKStreamImpl — wires aggregate() calls as separate downstream ProcessorGraphNodes sharing the same buffer store - GroupedStreamAggregateBuilder.prepareRangedBuffer() — handles repartitioning before attaching the buffer processor node Co-Authored-By: Claude Sonnet 4.6 --- .../streams/kstream/EventCountRange.java | 205 ++++++++++ .../kafka/streams/kstream/EventTimeRange.java | 160 ++++++++ .../kafka/streams/kstream/KGroupedStream.java | 46 +++ .../apache/kafka/streams/kstream/Range.java | 84 ++++ .../streams/kstream/RangeAggregator.java | 45 +++ .../kafka/streams/kstream/RangedKStream.java | 51 +++ .../GroupedStreamAggregateBuilder.java | 42 ++ .../kstream/internals/KGroupedStreamImpl.java | 59 +++ .../internals/KStreamRangeAggregate.java | 91 +++++ .../kstream/internals/KStreamRangeBuffer.java | 134 +++++++ .../RangeWindowStoreMaterializer.java | 124 ++++++ .../kstream/internals/RangedKStreamImpl.java | 85 ++++ .../streams/kstream/EventCountRangeTest.java | 111 ++++++ .../streams/kstream/EventTimeRangeTest.java | 121 ++++++ .../internals/RangedKStreamImplTest.java | 374 ++++++++++++++++++ 15 files changed, 1732 insertions(+) create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/Range.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/RangedKStream.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeBuffer.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangeWindowStoreMaterializer.java create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImpl.java create mode 100644 streams/src/test/java/org/apache/kafka/streams/kstream/EventCountRangeTest.java create mode 100644 streams/src/test/java/org/apache/kafka/streams/kstream/EventTimeRangeTest.java create mode 100644 streams/src/test/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImplTest.java diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java new file mode 100644 index 0000000000000..bf12619db1231 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.internals.ApiUtils; +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.state.ReadOnlyWindowStore; +import org.apache.kafka.streams.state.WindowStoreIterator; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * A count-based {@link Range} that includes up to {@code before} records preceding the anchor and + * up to {@code after} records following it in event-time order. A required time floor + * {@code maxTimeBefore} prevents looking back arbitrarily far. + * + *

Use {@link #ofCountBoundsWithNoGrace} or {@link #ofCountBoundsAndGrace} to create instances. + * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceiling on the forward direction. + */ +public final class EventCountRange extends Range { + + private final int before; + private final int after; + private final long maxTimeBeforeMs; + private Long maxTimeAfterMs = null; + + private EventCountRange(final int before, final int after, final long maxTimeBeforeMs, final long gracePeriodMs) { + super(gracePeriodMs); + this.before = before; + this.after = after; + this.maxTimeBeforeMs = maxTimeBeforeMs; + } + + /** + * Create an {@link EventCountRange} including {@code before} records before and {@code after} + * records after the anchor record in event-time order. {@code maxTimeBefore} sets a required + * time floor: records older than {@code anchor.timestamp() - maxTimeBefore} are excluded + * regardless of count. Records that arrive out of order are immediately dropped. + * Use {@link #ofCountBoundsAndGrace} to tolerate late arrivals. + * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceiling. + * + * @param before the number of records before the anchor to include. Must not be negative. + * @param after the number of records after the anchor to include. Must not be negative. + * @param maxTimeBefore the maximum time before the anchor's timestamp to look back. Must not be + * negative. + * @return a new {@link EventCountRange} with no grace period + * @throws IllegalArgumentException if any count is negative or the duration cannot be + * represented as {@code long} milliseconds + */ + public static EventCountRange ofCountBoundsWithNoGrace(final int before, final int after, final Duration maxTimeBefore) { + validateNonNegativeCount(before, "before"); + validateNonNegativeCount(after, "after"); + final long maxTimeBeforeMs = validateNonNegativeMs(maxTimeBefore, "maxTimeBefore"); + return new EventCountRange<>(before, after, maxTimeBeforeMs, 0L); + } + + /** + * Create an {@link EventCountRange} including {@code before} records before and {@code after} + * records after the anchor record in event-time order, accepting late records up to + * {@code grace} beyond the range boundary. {@code maxTimeBefore} sets a required time floor. + * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceiling. + * + * @param before the number of records before the anchor to include. Must not be negative. + * @param after the number of records after the anchor to include. Must not be negative. + * @param maxTimeBefore the maximum time before the anchor's timestamp to look back. Must not be + * negative. + * @param grace the grace period to tolerate late-arriving records. Must not be negative. + * @return a new {@link EventCountRange} with the specified grace period + * @throws IllegalArgumentException if any count is negative or any duration cannot be + * represented as {@code long} milliseconds + */ + public static EventCountRange ofCountBoundsAndGrace(final int before, final int after, final Duration maxTimeBefore, final Duration grace) { + validateNonNegativeCount(before, "before"); + validateNonNegativeCount(after, "after"); + final long maxTimeBeforeMs = validateNonNegativeMs(maxTimeBefore, "maxTimeBefore"); + final long graceMs = validateNonNegativeMs(grace, "grace"); + return new EventCountRange<>(before, after, maxTimeBeforeMs, graceMs); + } + + /** + * Set an optional time ceiling on the forward direction. Records newer than + * {@code anchor.timestamp() + maxTimeAfter} are excluded regardless of count. + * + * @param maxTimeAfter the maximum time after the anchor's timestamp to look forward. Must not + * be negative. + * @return this {@link EventCountRange} + * @throws IllegalArgumentException if the duration is negative or cannot be represented as + * {@code long} milliseconds + */ + public EventCountRange withMaxTimeAfter(final Duration maxTimeAfter) { + this.maxTimeAfterMs = validateNonNegativeMs(maxTimeAfter, "maxTimeAfter"); + return this; + } + + @Override + public Iterable> fetch(final Record anchor, final ReadOnlyWindowStore store) { + final long from = anchor.timestamp() - maxTimeBeforeMs; + final long forwardTo = maxTimeAfterMs != null ? anchor.timestamp() + maxTimeAfterMs : Long.MAX_VALUE; + + // Backward fetch: collect `before+1` records (anchor + up to `before` before it), oldest first + final List> backwardRecords = new ArrayList<>(before + 1); + try (final WindowStoreIterator backIt = store.backwardFetch( + anchor.key(), + Instant.ofEpochMilli(from), + Instant.ofEpochMilli(anchor.timestamp()))) { + int count = 0; + while (backIt.hasNext() && count <= before) { + final KeyValue kv = backIt.next(); + backwardRecords.add(0, new Record<>(anchor.key(), kv.value, kv.key)); + count++; + } + } + + // Forward fetch: up to `after` records strictly after the anchor's timestamp + final WindowStoreIterator forwardIt = store.fetch( + anchor.key(), + Instant.ofEpochMilli(anchor.timestamp() + 1), + Instant.ofEpochMilli(forwardTo) + ); + + return () -> new ConcatenatingIterator<>(backwardRecords.iterator(), forwardIt, anchor.key(), after); + } + + @Override + protected long rangeRetentionMs() { + return maxTimeBeforeMs; + } + + private static void validateNonNegativeCount(final int count, final String name) { + if (count < 0) { + throw new IllegalArgumentException(name + " must not be negative, got: " + count); + } + } + + private static long validateNonNegativeMs(final Duration duration, final String name) { + final long ms = ApiUtils.validateMillisecondDuration(duration, name); + if (ms < 0) { + throw new IllegalArgumentException(name + " must not be negative, got: " + duration); + } + return ms; + } + + private static final class ConcatenatingIterator implements Iterator> { + + private final Iterator> backwardPart; + private final WindowStoreIterator forwardIt; + private final K key; + private final int afterLimit; + private int forwardCount = 0; + private boolean forwardDone = false; + + ConcatenatingIterator( + final Iterator> backwardPart, + final WindowStoreIterator forwardIt, + final K key, + final int afterLimit + ) { + this.backwardPart = backwardPart; + this.forwardIt = forwardIt; + this.key = key; + this.afterLimit = afterLimit; + } + + @Override + public boolean hasNext() { + if (backwardPart.hasNext()) return true; + if (forwardDone) return false; + if (forwardCount >= afterLimit || !forwardIt.hasNext()) { + forwardIt.close(); + forwardDone = true; + return false; + } + return true; + } + + @Override + public Record next() { + if (!hasNext()) throw new NoSuchElementException(); + if (backwardPart.hasNext()) return backwardPart.next(); + final KeyValue kv = forwardIt.next(); + forwardCount++; + return new Record<>(key, kv.value, kv.key); + } + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java b/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java new file mode 100644 index 0000000000000..59e9dcca44bd8 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.internals.ApiUtils; +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.state.ReadOnlyWindowStore; +import org.apache.kafka.streams.state.WindowStoreIterator; + +import java.time.Duration; +import java.time.Instant; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A time-based {@link Range} that includes all records whose timestamps fall within + * [{@code anchor.timestamp() - before}, {@code anchor.timestamp() + after}]. + * + *

Use {@link #ofTimeBoundsWithNoGrace} or {@link #ofTimeBoundsAndGrace} to create instances. + * Use {@link #withMaxRecords(int)} to cap the number of included records. + */ +public final class EventTimeRange extends Range { + + private final long beforeMs; + private final long afterMs; + private int maxRecords = Integer.MAX_VALUE; + + private EventTimeRange(final long beforeMs, final long afterMs, final long gracePeriodMs) { + super(gracePeriodMs); + this.beforeMs = beforeMs; + this.afterMs = afterMs; + } + + /** + * Create an {@link EventTimeRange} spanning {@code before} time before and {@code after} time + * after the anchor record's timestamp. Records that arrive out of order are immediately dropped. + * Use {@link #ofTimeBoundsAndGrace} to tolerate late arrivals. + * Use {@link #withMaxRecords(int)} to cap the number of records included. + * + * @param before the time before the anchor record's timestamp that defines the start of the + * range. Must not be negative. + * @param after the time after the anchor record's timestamp that defines the end of the range. + * Must not be negative. + * @return a new {@link EventTimeRange} with no grace period + * @throws IllegalArgumentException if either duration is negative or cannot be represented as + * {@code long} milliseconds + */ + public static EventTimeRange ofTimeBoundsWithNoGrace(final Duration before, final Duration after) { + final long beforeMs = validateNonNegativeMs(before, "before"); + final long afterMs = validateNonNegativeMs(after, "after"); + return new EventTimeRange<>(beforeMs, afterMs, 0L); + } + + /** + * Create an {@link EventTimeRange} spanning {@code before} time before and {@code after} time + * after the anchor record's timestamp, accepting late records up to {@code grace} beyond the + * range boundary. Use {@link #withMaxRecords(int)} to cap the number of records included. + * + * @param before the time before the anchor record's timestamp that defines the start of the + * range. Must not be negative. + * @param after the time after the anchor record's timestamp that defines the end of the range. + * Must not be negative. + * @param grace the grace period to tolerate late-arriving records. Must not be negative. + * @return a new {@link EventTimeRange} with the specified grace period + * @throws IllegalArgumentException if any duration is negative or cannot be represented as + * {@code long} milliseconds + */ + public static EventTimeRange ofTimeBoundsAndGrace(final Duration before, final Duration after, final Duration grace) { + final long beforeMs = validateNonNegativeMs(before, "before"); + final long afterMs = validateNonNegativeMs(after, "after"); + final long graceMs = validateNonNegativeMs(grace, "grace"); + return new EventTimeRange<>(beforeMs, afterMs, graceMs); + } + + /** + * Cap the number of records included in the range. If more records fall within the time + * boundaries, the newest records are dropped. + * + * @param maxRecords the maximum number of records to include. Must be positive. + * @return this {@link EventTimeRange} + * @throws IllegalArgumentException if {@code maxRecords} is not positive + */ + public EventTimeRange withMaxRecords(final int maxRecords) { + if (maxRecords <= 0) { + throw new IllegalArgumentException("maxRecords must be positive, got: " + maxRecords); + } + this.maxRecords = maxRecords; + return this; + } + + @Override + public Iterable> fetch(final Record anchor, final ReadOnlyWindowStore store) { + final Instant from = Instant.ofEpochMilli(anchor.timestamp() - beforeMs); + final Instant to = Instant.ofEpochMilli(anchor.timestamp() + afterMs); + final int limit = maxRecords; + return () -> new LimitingWindowStoreIterator<>(store.fetch(anchor.key(), from, to), anchor.key(), limit); + } + + @Override + protected long rangeRetentionMs() { + return beforeMs; + } + + private static long validateNonNegativeMs(final Duration duration, final String name) { + final long ms = ApiUtils.validateMillisecondDuration(duration, name); + if (ms < 0) { + throw new IllegalArgumentException(name + " must not be negative, got: " + duration); + } + return ms; + } + + private static final class LimitingWindowStoreIterator implements Iterator> { + + private final WindowStoreIterator inner; + private final K key; + private final int limit; + private int count = 0; + private boolean done = false; + + LimitingWindowStoreIterator(final WindowStoreIterator inner, final K key, final int limit) { + this.inner = inner; + this.key = key; + this.limit = limit; + } + + @Override + public boolean hasNext() { + if (done) return false; + if (count >= limit || !inner.hasNext()) { + inner.close(); + done = true; + return false; + } + return true; + } + + @Override + public Record next() { + if (!hasNext()) throw new NoSuchElementException(); + final KeyValue kv = inner.next(); + count++; + return new Record<>(key, kv.value, kv.key); + } + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/KGroupedStream.java b/streams/src/main/java/org/apache/kafka/streams/kstream/KGroupedStream.java index 9f6d020baf36c..daf93d903f1f9 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/KGroupedStream.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/KGroupedStream.java @@ -26,6 +26,7 @@ import org.apache.kafka.streams.state.KeyValueStore; import org.apache.kafka.streams.state.ReadOnlyKeyValueStore; import org.apache.kafka.streams.state.TimestampedKeyValueStore; +import org.apache.kafka.streams.state.WindowStore; /** * {@code KGroupedStream} is an abstraction of a grouped record stream of {@link Record key-value} pairs. @@ -561,6 +562,51 @@ KTable aggregate(final Initializer initializer, */ SessionWindowedKStream windowedBy(final SessionWindows windows); + /** + * Create a new {@link RangedKStream} instance with a default internal buffer store. + * The store is auto-named, uses the Serdes of this grouped stream, and its retention is set + * to {@link Range#retentionMs()} — the minimum required to serve the range. Use + * {@link #rangeOver(Range, Materialized)} to name the store, override Serdes, or increase + * retention. + * + *

Records with {@code null} key or {@code null} value are dropped and not written to the + * buffer store. The {@code dropped-records-total} metric is incremented for each dropped record. + * + * @param range the range definition, determining which records are included for each anchor + * record + * @return an instance of {@link RangedKStream} + */ + RangedKStream rangeOver(final Range range); + + /** + * Create a new {@link RangedKStream} instance that can be used to perform ranged aggregations + * on the grouped stream. The range of the aggregation is defined by the provided {@link Range} + * instance. Built-in implementations are provided via {@link EventTimeRange} and + * {@link EventCountRange}. Custom implementations of {@link Range} can also be provided. + * + *

The {@code materialized} parameter configures the underlying buffer store, which holds + * the raw records used by the range definition to fetch records on each trigger. This store is + * materialized at this step, not at aggregation time, because the aggregation result is emitted + * as a {@link KStream} and not persisted. + * + *

Records with {@code null} key or {@code null} value are dropped and not written to the + * buffer store. The {@code dropped-records-total} metric is incremented for each dropped record. + * + * @param range the range definition, determining which records are included for each + * anchor record + * @param materialized the configuration for the underlying buffer state store + * @return an instance of {@link RangedKStream} + * @throws IllegalArgumentException if the retention period specified in {@code materialized} is + * smaller than {@link Range#retentionMs()} + * @throws IllegalArgumentException if a custom {@link org.apache.kafka.streams.state.WindowBytesStoreSupplier} + * in {@code materialized} has {@code retainDuplicates} set to + * {@code false} + */ + RangedKStream rangeOver( + final Range range, + final Materialized> materialized + ); + /** * Create a new {@link CogroupedKStream} from this grouped KStream to allow cogrouping other * {@code KGroupedStream} to it. diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java b/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java new file mode 100644 index 0000000000000..dd7476cd4f50c --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.state.ReadOnlyWindowStore; +import org.apache.kafka.streams.state.WindowStore; + +/** + * Defines a range of records around an anchor record, and fetches them from the buffer store. + * Built-in implementations are provided via {@link EventTimeRange} and {@link EventCountRange}. + * Custom subclasses can be provided to define arbitrary range logic. + * + * @param the key type + * @param the value type + */ +public abstract class Range { + + private final long gracePeriodMs; + + /** + * @param gracePeriodMs the grace period in milliseconds. Must not be negative. + */ + protected Range(final long gracePeriodMs) { + this.gracePeriodMs = gracePeriodMs; + } + + /** + * Fetch the records that fall within this range for the given anchor record. + * The anchor record itself should be included in the returned iterable. + * Records should be ordered by their timestamps in ascending order. + * + *

Note: headers are not preserved in the returned records, as they are not stored in the + * underlying {@link WindowStore}. Headers are only available on the {@code anchor} record. + * + * @param anchor the record that triggered the range evaluation + * @param store the buffer store holding records for the anchor's group key + * @return an iterable of records that fall within the defined range + */ + public abstract Iterable> fetch(Record anchor, ReadOnlyWindowStore store); + + /** + * @return the grace period in milliseconds. Records arriving after stream time has advanced + * beyond the range's natural boundary plus this value will be dropped. + */ + public long gracePeriodMs() { + return gracePeriodMs; + } + + /** + * The minimum retention the buffer {@link WindowStore} must be configured with, excluding + * the grace period. Implementations should return the oldest a record can be relative to an + * anchor's timestamp and still fall within the range (e.g. {@code before} for + * {@link EventTimeRange}, {@code maxTimeBefore} for {@link EventCountRange}). + * + * @return the range-specific retention in milliseconds, excluding grace period + */ + protected abstract long rangeRetentionMs(); + + /** + * The minimum retention the buffer {@link WindowStore} must be configured with to correctly + * serve this range, including the grace period. This is what {@code rangeOver()} validates + * against the {@link Materialized} retention. + * + * @return the total required retention in milliseconds + */ + public long retentionMs() { + return rangeRetentionMs() + gracePeriodMs; + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java b/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java new file mode 100644 index 0000000000000..4fb71b72167e1 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.state.WindowStore; + +/** + * A functional interface for range aggregations on a {@link RangedKStream}. + * + * @param the key type + * @param the value type of the input records + * @param the result type of the aggregation + */ +@FunctionalInterface +public interface RangeAggregator { + + /** + * Apply the aggregation logic to the records in the defined range for a given key. + * + * @param anchor the record that triggered the aggregation + * @param rangeRecords an iterable of records that fall within the defined range of the anchor + * record, including the anchor record itself. Records are ordered by + * timestamp in ascending order. + * Note: headers are not preserved in {@code rangeRecords} as they are not + * stored in the underlying {@link WindowStore}. Headers are only available + * on the {@code anchor} record. + * @return the result of the aggregation + */ + VR apply(Record anchor, Iterable> rangeRecords); +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/RangedKStream.java b/streams/src/main/java/org/apache/kafka/streams/kstream/RangedKStream.java new file mode 100644 index 0000000000000..adb3e8c943428 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/RangedKStream.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +/** + * {@code RangedKStream} is an intermediate representation of a grouped record stream that has been + * annotated with a {@link Range} definition. It is obtained from a {@link KGroupedStream} via + * {@link KGroupedStream#rangeOver(Range)}. + * + *

Multiple independent aggregations can be applied to the same {@code RangedKStream} instance. + * The underlying buffer store is shared across all aggregations and is written to once per incoming + * record. + * + * @param the key type + * @param the value type + */ +public interface RangedKStream { + + /** + * Perform an aggregation on the records in the range defined for this stream. + * The aggregation is triggered for each incoming record and includes all records that fall + * within the defined range of that record. + * + * @param aggregator the aggregator function to apply to the records in the range + * @param the type of the aggregated value + * @return a {@link KStream} containing the aggregated result for each anchor record + */ + KStream aggregate(final RangeAggregator aggregator); + + /** + * Count the number of records in this range by the grouped key. + * + * @return a {@link KStream} that contains records with unmodified keys and {@link Long} values + * that represent the count of records in the defined range for each anchor record + */ + KStream count(); +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/GroupedStreamAggregateBuilder.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/GroupedStreamAggregateBuilder.java index 023513d0704f0..5f88090e20b35 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/GroupedStreamAggregateBuilder.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/GroupedStreamAggregateBuilder.java @@ -171,4 +171,46 @@ private String createRepartitionSource(final String repartitionTopicNamePrefix, isRepartitionTopicNameProvidedByUser); } + + /** + * Prepares the topology for a ranged buffer by handling repartitioning if needed. + * Returns the effective parent node (after repartitioning) and the effective source nodes. + */ + RangedBufferBuildResult prepareRangedBuffer(final String storeName) { + String sourceName = this.name; + GraphNode parentNode = graphNode; + + if (repartitionRequired) { + final OptimizableRepartitionNodeBuilder repartitionNodeBuilder = optimizableRepartitionNodeBuilder(); + final String repartitionTopicPrefix = userProvidedRepartitionTopicName != null + ? userProvidedRepartitionTopicName + : storeName; + sourceName = createRepartitionSource( + repartitionTopicPrefix, + repartitionNodeBuilder, + userProvidedRepartitionTopicName != null + ); + if (repartitionNode == null || userProvidedRepartitionTopicName == null) { + repartitionNode = repartitionNodeBuilder.build(); + } + builder.addGraphNode(parentNode, repartitionNode); + parentNode = repartitionNode; + } + + final Set effectiveSourceNodes = sourceName.equals(this.name) + ? subTopologySourceNodes + : Collections.singleton(sourceName); + + return new RangedBufferBuildResult(parentNode, effectiveSourceNodes); + } + + static final class RangedBufferBuildResult { + final GraphNode parentNode; + final Set sourceNodes; + + RangedBufferBuildResult(final GraphNode parentNode, final Set sourceNodes) { + this.parentNode = parentNode; + this.sourceNodes = sourceNodes; + } + } } diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KGroupedStreamImpl.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KGroupedStreamImpl.java index 72af21601ac4d..a1fa01c9f74e9 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KGroupedStreamImpl.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KGroupedStreamImpl.java @@ -25,6 +25,8 @@ import org.apache.kafka.streams.kstream.KTable; import org.apache.kafka.streams.kstream.Materialized; import org.apache.kafka.streams.kstream.Named; +import org.apache.kafka.streams.kstream.Range; +import org.apache.kafka.streams.kstream.RangedKStream; import org.apache.kafka.streams.kstream.Reducer; import org.apache.kafka.streams.kstream.SessionWindowedKStream; import org.apache.kafka.streams.kstream.SessionWindows; @@ -32,9 +34,13 @@ import org.apache.kafka.streams.kstream.TimeWindowedKStream; import org.apache.kafka.streams.kstream.Window; import org.apache.kafka.streams.kstream.Windows; +import org.apache.kafka.streams.kstream.internals.GroupedStreamAggregateBuilder.RangedBufferBuildResult; import org.apache.kafka.streams.kstream.internals.graph.GraphNode; +import org.apache.kafka.streams.kstream.internals.graph.ProcessorGraphNode; +import org.apache.kafka.streams.kstream.internals.graph.ProcessorParameters; import org.apache.kafka.streams.state.KeyValueStore; import org.apache.kafka.streams.state.VersionedBytesStoreSupplier; +import org.apache.kafka.streams.state.WindowStore; import java.util.Objects; import java.util.Set; @@ -43,6 +49,7 @@ class KGroupedStreamImpl extends AbstractStream implements KGroupedS static final String REDUCE_NAME = "KSTREAM-REDUCE-"; static final String AGGREGATE_NAME = "KSTREAM-AGGREGATE-"; + static final String RANGE_BUFFER_NAME = "KSTREAM-RANGE-BUFFER-"; private final GroupedStreamAggregateBuilder aggregateBuilder; final boolean repartitionRequired; @@ -195,6 +202,58 @@ private KTable doCount(final Named named, final Materialized rangeOver(final Range range) { + Objects.requireNonNull(range, "range can't be null"); + final Materialized> materialized = Materialized.with(keySerde, valueSerde); + return rangeOver(range, materialized); + } + + @Override + public RangedKStream rangeOver( + final Range range, + final Materialized> materialized + ) { + Objects.requireNonNull(range, "range can't be null"); + Objects.requireNonNull(materialized, "materialized can't be null"); + + final MaterializedInternal> materializedInternal = + new MaterializedInternal<>(materialized, builder, RANGE_BUFFER_NAME); + + if (materializedInternal.keySerde() == null) { + materializedInternal.withKeySerde(keySerde); + } + if (materializedInternal.valueSerde() == null) { + materializedInternal.withValueSerde(valueSerde); + } + + final RangeWindowStoreMaterializer storeFactory = + new RangeWindowStoreMaterializer<>(materializedInternal, range); + + final RangedBufferBuildResult result = aggregateBuilder.prepareRangedBuffer(storeFactory.storeName()); + + final String bufferName = builder.newProcessorName(RANGE_BUFFER_NAME); + final KStreamRangeBuffer bufferSupplier = new KStreamRangeBuffer<>(storeFactory, range.gracePeriodMs()); + + final ProcessorGraphNode bufferNode = new ProcessorGraphNode<>( + bufferName, + new ProcessorParameters<>(bufferSupplier, bufferName) + ); + + builder.addGraphNode(result.parentNode, bufferNode); + + return new RangedKStreamImpl<>( + range, + storeFactory, + bufferName, + builder, + result.sourceNodes, + materializedInternal.keySerde(), + materializedInternal.valueSerde(), + bufferNode + ); + } + @Override public TimeWindowedKStream windowedBy(final Windows windows) { diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java new file mode 100644 index 0000000000000..682b2791775be --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream.internals; + +import org.apache.kafka.streams.kstream.Range; +import org.apache.kafka.streams.kstream.RangeAggregator; +import org.apache.kafka.streams.processor.api.ContextualProcessor; +import org.apache.kafka.streams.processor.api.Processor; +import org.apache.kafka.streams.processor.api.ProcessorContext; +import org.apache.kafka.streams.processor.api.ProcessorSupplier; +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.processor.internals.StoreFactory; +import org.apache.kafka.streams.processor.internals.StoreFactory.FactoryWrappingStoreBuilder; +import org.apache.kafka.streams.state.ReadOnlyWindowStore; +import org.apache.kafka.streams.state.StoreBuilder; + +import java.util.Collections; +import java.util.Set; + +/** + * Aggregate processor for {@link org.apache.kafka.streams.kstream.RangedKStream}. + * For each incoming record, fetches the range from the buffer store, applies the aggregator, + * and forwards the result downstream. Connects to the buffer store by name without owning it. + */ +public class KStreamRangeAggregate implements ProcessorSupplier { + + private final StoreFactory storeFactory; + private final Range range; + private final RangeAggregator aggregator; + + @SuppressWarnings("unchecked") + public KStreamRangeAggregate( + final StoreFactory storeFactory, + final Range range, + final RangeAggregator aggregator + ) { + this.storeFactory = storeFactory; + this.range = (Range) range; + this.aggregator = aggregator; + } + + @Override + public Set> stores() { + // Return the same builder so the topology connects this processor to the existing store + // InternalTopologyBuilder deduplicates: if the store already exists it only adds the connection + return Collections.singleton(new FactoryWrappingStoreBuilder<>(storeFactory)); + } + + @Override + public Processor get() { + return new KStreamRangeAggregateProcessor(storeFactory.storeName()); + } + + private final class KStreamRangeAggregateProcessor extends ContextualProcessor { + + private final String storeName; + private ReadOnlyWindowStore store; + + KStreamRangeAggregateProcessor(final String storeName) { + this.storeName = storeName; + } + + @SuppressWarnings("unchecked") + @Override + public void init(final ProcessorContext context) { + super.init(context); + store = context.getStateStore(storeName); + } + + @Override + public void process(final Record record) { + final Iterable> rangeRecords = range.fetch(record, store); + final VR result = aggregator.apply(record, rangeRecords); + context().forward(record.withValue(result)); + } + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeBuffer.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeBuffer.java new file mode 100644 index 0000000000000..79041cb529c19 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeBuffer.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream.internals; + +import org.apache.kafka.common.metrics.Sensor; +import org.apache.kafka.streams.processor.api.ContextualProcessor; +import org.apache.kafka.streams.processor.api.Processor; +import org.apache.kafka.streams.processor.api.ProcessorContext; +import org.apache.kafka.streams.processor.api.ProcessorSupplier; +import org.apache.kafka.streams.processor.api.Record; +import org.apache.kafka.streams.processor.api.RecordMetadata; +import org.apache.kafka.streams.processor.internals.StoreFactory; +import org.apache.kafka.streams.processor.internals.StoreFactory.FactoryWrappingStoreBuilder; +import org.apache.kafka.streams.processor.internals.metrics.StreamsMetricsImpl; +import org.apache.kafka.streams.state.StoreBuilder; +import org.apache.kafka.streams.state.WindowStore; + +import org.apache.kafka.streams.processor.internals.InternalProcessorContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Set; + +import static org.apache.kafka.streams.processor.internals.metrics.TaskMetrics.droppedRecordsSensor; + +/** + * Buffer processor for {@link org.apache.kafka.streams.kstream.RangedKStream}. + * Writes each record to the buffer {@link WindowStore} and forwards it downstream. + * Drops records with null keys or values, and records that violate the grace period. + */ +public class KStreamRangeBuffer implements ProcessorSupplier { + + private static final Logger log = LoggerFactory.getLogger(KStreamRangeBuffer.class); + + private final StoreFactory storeFactory; + private final long gracePeriodMs; + + public KStreamRangeBuffer(final StoreFactory storeFactory, final long gracePeriodMs) { + this.storeFactory = storeFactory; + this.gracePeriodMs = gracePeriodMs; + } + + @Override + public Set> stores() { + return Collections.singleton(new FactoryWrappingStoreBuilder<>(storeFactory)); + } + + @Override + public Processor get() { + return new KStreamRangeBufferProcessor<>(storeFactory.storeName(), gracePeriodMs); + } + + private static final class KStreamRangeBufferProcessor extends ContextualProcessor { + + private final String storeName; + private final long gracePeriodMs; + + private WindowStore store; + private Sensor droppedRecordsSensor; + private long observedStreamTime = Long.MIN_VALUE; + + KStreamRangeBufferProcessor(final String storeName, final long gracePeriodMs) { + this.storeName = storeName; + this.gracePeriodMs = gracePeriodMs; + } + + @SuppressWarnings("unchecked") + @Override + public void init(final ProcessorContext context) { + super.init(context); + store = context.getStateStore(storeName); + final InternalProcessorContext internalContext = (InternalProcessorContext) context; + final StreamsMetricsImpl metrics = internalContext.metrics(); + droppedRecordsSensor = droppedRecordsSensor( + Thread.currentThread().getName(), + context.taskId().toString(), + metrics + ); + } + + @Override + public void process(final Record record) { + if (record.key() == null) { + logDropped("null key", record); + droppedRecordsSensor.record(); + return; + } + if (record.value() == null) { + logDropped("null value", record); + droppedRecordsSensor.record(); + return; + } + + final long timestamp = record.timestamp(); + if (observedStreamTime < timestamp) { + observedStreamTime = timestamp; + } + + if (gracePeriodMs >= 0 && timestamp < observedStreamTime - gracePeriodMs) { + logDropped("grace period", record); + droppedRecordsSensor.record(); + return; + } + + store.put(record.key(), record.value(), timestamp); + context().forward(record); + } + + private void logDropped(final String reason, final Record record) { + if (context().recordMetadata().isPresent()) { + final RecordMetadata meta = context().recordMetadata().get(); + log.warn("Skipping record due to {}. topic=[{}] partition=[{}] offset=[{}]", + reason, meta.topic(), meta.partition(), meta.offset()); + } else { + log.warn("Skipping record due to {}. Topic, partition, and offset not known.", reason); + } + } + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangeWindowStoreMaterializer.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangeWindowStoreMaterializer.java new file mode 100644 index 0000000000000..d82d50ba3a376 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangeWindowStoreMaterializer.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream.internals; + +import org.apache.kafka.common.utils.Bytes; +import org.apache.kafka.streams.DslStoreFormat; +import org.apache.kafka.streams.kstream.Range; +import org.apache.kafka.streams.state.StoreBuilder; +import org.apache.kafka.streams.state.Stores; +import org.apache.kafka.streams.state.WindowBytesStoreSupplier; +import org.apache.kafka.streams.state.WindowStore; + +import java.time.Duration; + +/** + * Materializes the buffer {@link WindowStore} for a {@link org.apache.kafka.streams.kstream.RangedKStream}. + * Always uses {@code retainDuplicates=true} so that multiple records at the same timestamp per key + * are preserved in the store. + */ +public class RangeWindowStoreMaterializer extends MaterializedStoreFactory> { + + private final long retentionPeriodMs; + + public RangeWindowStoreMaterializer( + final MaterializedInternal> materialized, + final Range range + ) { + super(materialized, DslStoreFormat.PLAIN); + + if (materialized.storeSupplier() instanceof WindowBytesStoreSupplier) { + final WindowBytesStoreSupplier userSupplier = (WindowBytesStoreSupplier) materialized.storeSupplier(); + if (!userSupplier.retainDuplicates()) { + throw new IllegalArgumentException( + "A custom WindowBytesStoreSupplier used with rangeOver() must have retainDuplicates=true"); + } + } + + this.retentionPeriodMs = retentionPeriod(materialized, range); + } + + private static long retentionPeriod( + final MaterializedInternal materialized, + final Range range + ) { + final long configured = materialized.retention() != null + ? materialized.retention().toMillis() + : range.retentionMs(); + + if (configured < range.retentionMs()) { + throw new IllegalArgumentException( + "The retention period of the buffer store must be at least Range.retentionMs()=" + + range.retentionMs() + "ms, but got " + configured + "ms"); + } + + return configured; + } + + @Override + public StoreBuilder builder() { + final WindowBytesStoreSupplier supplier; + if (materialized.storeSupplier() != null) { + supplier = (WindowBytesStoreSupplier) materialized.storeSupplier(); + } else { + supplier = Stores.persistentWindowStore( + materialized.storeName(), + Duration.ofMillis(retentionPeriodMs), + Duration.ofMillis(1L), + true + ); + } + + final StoreBuilder> builder = Stores.windowStoreBuilder( + supplier, + materialized.keySerde(), + materialized.valueSerde() + ); + + if (materialized.loggingEnabled()) { + builder.withLoggingEnabled(materialized.logConfig()); + } else { + builder.withLoggingDisabled(); + } + + if (materialized.cachingEnabled()) { + builder.withCachingEnabled(); + } + + return builder; + } + + @Override + public long retentionPeriod() { + return retentionPeriodMs; + } + + @Override + public long historyRetention() { + throw new IllegalStateException("historyRetention is not supported for range stores"); + } + + @Override + public boolean isWindowStore() { + return true; + } + + @Override + public boolean isVersionedStore() { + return false; + } +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImpl.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImpl.java new file mode 100644 index 0000000000000..d7828057b402b --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImpl.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream.internals; + +import org.apache.kafka.common.serialization.Serde; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Range; +import org.apache.kafka.streams.kstream.RangeAggregator; +import org.apache.kafka.streams.kstream.RangedKStream; +import org.apache.kafka.streams.kstream.internals.graph.GraphNode; +import org.apache.kafka.streams.kstream.internals.graph.ProcessorGraphNode; +import org.apache.kafka.streams.kstream.internals.graph.ProcessorParameters; +import org.apache.kafka.streams.processor.internals.StoreFactory; + +import java.util.Objects; +import java.util.Set; + +class RangedKStreamImpl extends AbstractStream implements RangedKStream { + + static final String RANGE_AGGREGATE_NAME = "KSTREAM-RANGE-AGGREGATE-"; + + private final Range range; + private final StoreFactory storeFactory; + + RangedKStreamImpl( + final Range range, + final StoreFactory storeFactory, + final String name, + final InternalStreamsBuilder builder, + final Set subTopologySourceNodes, + final Serde keySerde, + final Serde valueSerde, + final GraphNode graphNode + ) { + super(name, keySerde, valueSerde, subTopologySourceNodes, graphNode, builder); + this.range = range; + this.storeFactory = storeFactory; + } + + @Override + public KStream aggregate(final RangeAggregator aggregator) { + Objects.requireNonNull(aggregator, "aggregator can't be null"); + + final String aggName = builder.newProcessorName(RANGE_AGGREGATE_NAME); + + final KStreamRangeAggregate aggSupplier = new KStreamRangeAggregate<>(storeFactory, range, aggregator); + + final ProcessorGraphNode aggNode = new ProcessorGraphNode<>( + aggName, + new ProcessorParameters<>(aggSupplier, aggName) + ); + + builder.addGraphNode(graphNode, aggNode); + + return new KStreamImpl<>(aggName, null, null, subTopologySourceNodes, false, aggNode, builder); + } + + @Override + public KStream count() { + return aggregate((anchor, rangeRecords) -> { + long count = 0L; + final java.util.Iterator it = rangeRecords.iterator(); + while (it.hasNext()) { + it.next(); + count++; + } + return count; + }); + } + +} diff --git a/streams/src/test/java/org/apache/kafka/streams/kstream/EventCountRangeTest.java b/streams/src/test/java/org/apache/kafka/streams/kstream/EventCountRangeTest.java new file mode 100644 index 0000000000000..58f21ea21628e --- /dev/null +++ b/streams/src/test/java/org/apache/kafka/streams/kstream/EventCountRangeTest.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class EventCountRangeTest { + + @Test + public void shouldReturnGracePeriodForNoGrace() { + final EventCountRange range = EventCountRange.ofCountBoundsWithNoGrace(3, 1, Duration.ofHours(1)); + assertEquals(0L, range.gracePeriodMs()); + } + + @Test + public void shouldReturnGracePeriod() { + final EventCountRange range = EventCountRange.ofCountBoundsAndGrace(3, 1, Duration.ofHours(1), Duration.ofSeconds(5)); + assertEquals(5000L, range.gracePeriodMs()); + } + + @Test + public void rangeRetentionMsShouldEqualMaxTimeBefore() { + final long maxTimeBeforeMs = Duration.ofHours(2).toMillis(); + final EventCountRange range = EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofMillis(maxTimeBeforeMs)); + assertEquals(maxTimeBeforeMs, range.rangeRetentionMs()); + } + + @Test + public void retentionMsShouldEqualMaxTimeBeforePlusGrace() { + final long maxTimeBeforeMs = Duration.ofHours(1).toMillis(); + final long gracePeriodMs = Duration.ofSeconds(5).toMillis(); + final EventCountRange range = EventCountRange.ofCountBoundsAndGrace(3, 0, Duration.ofMillis(maxTimeBeforeMs), Duration.ofMillis(gracePeriodMs)); + assertEquals(maxTimeBeforeMs, range.rangeRetentionMs()); + assertEquals(maxTimeBeforeMs + gracePeriodMs, range.retentionMs()); + } + + @Test + public void beforeMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(-1, 1, Duration.ofHours(1))); + } + + @Test + public void afterMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(3, -1, Duration.ofHours(1))); + } + + @Test + public void maxTimeBeforeMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofMillis(-1))); + } + + @Test + public void gracePeriodMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsAndGrace(3, 0, Duration.ofHours(1), Duration.ofMillis(-1))); + } + + @Test + public void shouldThrowOnOverflowingMaxTimeBeforeDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofSeconds(Long.MAX_VALUE))); + } + + @Test + public void shouldThrowOnOverflowingGraceDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsAndGrace(3, 0, Duration.ofHours(1), Duration.ofSeconds(Long.MAX_VALUE))); + } + + @Test + public void withMaxTimeAfterShouldReturnConcreteType() { + final EventCountRange range = EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofHours(1)) + .withMaxTimeAfter(Duration.ofSeconds(30)); + assertInstanceOf(EventCountRange.class, range); + } + + @Test + public void maxTimeAfterMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofHours(1)).withMaxTimeAfter(Duration.ofMillis(-1))); + } + + @Test + public void shouldThrowOnOverflowingMaxTimeAfterDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventCountRange.ofCountBoundsWithNoGrace(3, 0, Duration.ofHours(1)).withMaxTimeAfter(Duration.ofSeconds(Long.MAX_VALUE))); + } +} diff --git a/streams/src/test/java/org/apache/kafka/streams/kstream/EventTimeRangeTest.java b/streams/src/test/java/org/apache/kafka/streams/kstream/EventTimeRangeTest.java new file mode 100644 index 0000000000000..db4d628847083 --- /dev/null +++ b/streams/src/test/java/org/apache/kafka/streams/kstream/EventTimeRangeTest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class EventTimeRangeTest { + + @Test + public void shouldReturnGracePeriodForNoGrace() { + final EventTimeRange range = EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofSeconds(5)); + assertEquals(0L, range.gracePeriodMs()); + } + + @Test + public void shouldReturnGracePeriod() { + final EventTimeRange range = EventTimeRange.ofTimeBoundsAndGrace(Duration.ofSeconds(10), Duration.ofSeconds(5), Duration.ofSeconds(3)); + assertEquals(3000L, range.gracePeriodMs()); + } + + @Test + public void retentionMsShouldEqualBeforePlusGrace() { + final long beforeMs = Duration.ofSeconds(20).toMillis(); + final long gracePeriodMs = Duration.ofSeconds(5).toMillis(); + final EventTimeRange range = EventTimeRange.ofTimeBoundsAndGrace( + Duration.ofMillis(beforeMs), Duration.ofSeconds(0), Duration.ofMillis(gracePeriodMs)); + assertEquals(beforeMs, range.rangeRetentionMs()); + assertEquals(beforeMs + gracePeriodMs, range.retentionMs()); + } + + @Test + public void rangeRetentionMsShouldEqualBefore() { + final long beforeMs = Duration.ofMinutes(5).toMillis(); + final EventTimeRange range = EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofMillis(beforeMs), Duration.ofSeconds(10)); + assertEquals(beforeMs, range.rangeRetentionMs()); + } + + @Test + public void beforeMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofMillis(-1), Duration.ofSeconds(5))); + } + + @Test + public void afterMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofMillis(-1))); + } + + @Test + public void gracePeriodMustNotBeNegative() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsAndGrace(Duration.ofSeconds(10), Duration.ofSeconds(5), Duration.ofMillis(-1))); + } + + @Test + public void shouldThrowOnOverflowingBeforeDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(Long.MAX_VALUE), Duration.ofSeconds(5))); + } + + @Test + public void shouldThrowOnOverflowingAfterDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofSeconds(Long.MAX_VALUE))); + } + + @Test + public void shouldThrowOnOverflowingGraceDuration() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsAndGrace(Duration.ofSeconds(10), Duration.ofSeconds(5), Duration.ofSeconds(Long.MAX_VALUE))); + } + + @Test + public void withMaxRecordsShouldReturnConcreteType() { + final EventTimeRange range = EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofSeconds(5)) + .withMaxRecords(100); + assertInstanceOf(EventTimeRange.class, range); + } + + @Test + public void maxRecordsMustBePositive() { + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofSeconds(5)).withMaxRecords(0)); + assertThrows(IllegalArgumentException.class, + () -> EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(10), Duration.ofSeconds(5)).withMaxRecords(-1)); + } + + @Test + public void rangeAggregatorCanBeExpressedAsLambda() { + final RangeAggregator aggregator = (anchor, records) -> { + long sum = 0L; + for (final org.apache.kafka.streams.processor.api.Record r : records) { + sum += r.value(); + } + return sum; + }; + // Just verifying it compiles as a lambda + assertEquals(RangeAggregator.class, aggregator.getClass().getInterfaces()[0]); + } +} diff --git a/streams/src/test/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImplTest.java b/streams/src/test/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImplTest.java new file mode 100644 index 0000000000000..fdf21d8d1a331 --- /dev/null +++ b/streams/src/test/java/org/apache/kafka/streams/kstream/internals/RangedKStreamImplTest.java @@ -0,0 +1,374 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream.internals; + +import org.apache.kafka.common.serialization.LongDeserializer; +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.apache.kafka.common.utils.Bytes; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.TestInputTopic; +import org.apache.kafka.streams.TestOutputTopic; +import org.apache.kafka.streams.TopologyTestDriver; +import org.apache.kafka.streams.kstream.Consumed; +import org.apache.kafka.streams.kstream.EventCountRange; +import org.apache.kafka.streams.kstream.EventTimeRange; +import org.apache.kafka.streams.kstream.Grouped; +import org.apache.kafka.streams.kstream.KGroupedStream; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Materialized; +import org.apache.kafka.streams.kstream.Produced; +import org.apache.kafka.streams.kstream.RangedKStream; +import org.apache.kafka.streams.state.Stores; +import org.apache.kafka.streams.state.WindowBytesStoreSupplier; +import org.apache.kafka.streams.state.WindowStore; +import org.apache.kafka.test.StreamsTestUtils; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.Duration; +import java.util.List; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RangedKStreamImplTest { + + private static final String INPUT_TOPIC = "input"; + private static final String OUTPUT_TOPIC = "output"; + private static final Duration BEFORE = Duration.ofMillis(100); + private static final Duration AFTER = Duration.ofMillis(50); + private static final Duration GRACE = Duration.ofMillis(20); + + private final Properties props = StreamsTestUtils.getStreamsConfig(Serdes.String(), Serdes.String()); + + // ---- EventTimeRange end-to-end ---- + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void eventTimeRangeShouldProduceCorrectAggregation(final boolean cachingEnabled) { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final Materialized> mat = buildMaterialized("store-" + cachingEnabled, cachingEnabled); + + final KStream counts = grouped + .rangeOver(EventTimeRange.ofTimeBoundsWithNoGrace(BEFORE, AFTER), mat) + .count(); + + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + // t=10: range [10-100, 10+50] = [-90, 60] → only v1 + input.pipeInput("a", "v1", 10L); + // t=80: range [80-100, 80+50] = [-20, 130] → v1(t=10) and v2(t=80) + input.pipeInput("a", "v2", 80L); + // t=200: range [200-100, 200+50] = [100, 250] → v3 only + input.pipeInput("a", "v3", 200L); + + final List> results = output.readKeyValuesToList(); + assertEquals(3, results.size()); + assertEquals(1L, (long) results.get(0).value); + assertEquals(2L, (long) results.get(1).value); + assertEquals(1L, (long) results.get(2).value); + } + } + + @Test + public void eventTimeRangeShouldRespectGracePeriod() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final Materialized> mat = + Materialized.>as("grace-store") + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(Duration.ofMillis(200)); + + final KStream counts = grouped + .rangeOver(EventTimeRange.ofTimeBoundsAndGrace(BEFORE, AFTER, GRACE), mat) + .count(); + + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + // t=100: stream time = 100. Accepted. + input.pipeInput("a", "v1", 100L); + // t=50: late. streamTime=100, gracePeriodMs=20. 100-20=80 > 50 → DROPPED. + input.pipeInput("a", "late", 50L); + // t=90: late. streamTime=100, gracePeriodMs=20. 100-20=80 ≤ 90 → ACCEPTED. + input.pipeInput("a", "v2", 90L); + + final List> results = output.readKeyValuesToList(); + // Only v1 and v2 produce output (late was dropped) + assertEquals(2, results.size()); + } + } + + @Test + public void nullKeyShouldBeDropped() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final KStream counts = grouped + .rangeOver(EventTimeRange.ofTimeBoundsWithNoGrace(BEFORE, AFTER)) + .count(); + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + input.pipeInput(null, "v1", 10L); + input.pipeInput("a", "v2", 20L); + + final List> results = output.readKeyValuesToList(); + assertEquals(1, results.size()); + assertEquals("a", results.get(0).key); + } + } + + @Test + public void nullValueShouldBeDropped() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final KStream counts = grouped + .rangeOver(EventTimeRange.ofTimeBoundsWithNoGrace(BEFORE, AFTER)) + .count(); + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + input.pipeInput("a", null, 10L); + input.pipeInput("a", "v2", 20L); + + final List> results = output.readKeyValuesToList(); + assertEquals(1, results.size()); + assertEquals(1L, (long) results.get(0).value); + } + } + + @Test + public void multipleAggregationsOnSameBuffer() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final Materialized> mat = + Materialized.>as("shared-buffer") + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(BEFORE.plusMillis(1)); + + final RangedKStream ranged = grouped.rangeOver( + EventTimeRange.ofTimeBoundsWithNoGrace(BEFORE, AFTER), mat + ); + + final KStream counts = ranged.count(); + final KStream doubled = ranged.aggregate((anchor, records) -> { + long n = 0L; + final java.util.Iterator it = records.iterator(); + while (it.hasNext()) { + it.next(); + n++; + } + return n * 2; + }); + + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + final String outputTopic2 = "output2"; + doubled.to(outputTopic2, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic out1 = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + final TestOutputTopic out2 = driver.createOutputTopic(outputTopic2, new StringDeserializer(), new LongDeserializer()); + + input.pipeInput("a", "v1", 10L); + + final long count = out1.readKeyValue().value; + final long agg = out2.readKeyValue().value; + + assertEquals(1L, count); + assertEquals(2L, agg); + } + } + + @Test + public void withMaxRecordsShouldCapRange() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final Materialized> mat = + Materialized.>as("maxrec-store") + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(Duration.ofMillis(200)); + + final KStream counts = grouped + .rangeOver( + EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofMillis(150), AFTER).withMaxRecords(2), + mat + ) + .count(); + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + input.pipeInput("a", "v1", 10L); + input.pipeInput("a", "v2", 50L); + input.pipeInput("a", "v3", 100L); + input.pipeInput("a", "v4", 120L); + + final List> results = output.readKeyValuesToList(); + // At t=120: range [-30, 170], all 4 records in range but maxRecords=2 + final long lastCount = results.get(results.size() - 1).value; + assertTrue(lastCount <= 2L, "Expected count <= 2 due to maxRecords, got: " + lastCount); + } + } + + // ---- EventCountRange end-to-end ---- + + @Test + public void eventCountRangeShouldIncludeCorrectCounts() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final Materialized> mat = + Materialized.>as("count-store") + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(Duration.ofHours(1).plusSeconds(5)); + + final KStream counts = grouped + .rangeOver( + EventCountRange.ofCountBoundsWithNoGrace(1, 0, Duration.ofHours(1)), + mat + ) + .count(); + counts.to(OUTPUT_TOPIC, Produced.with(Serdes.String(), Serdes.Long())); + + try (final TopologyTestDriver driver = new TopologyTestDriver(builder.build(), props)) { + final TestInputTopic input = driver.createInputTopic(INPUT_TOPIC, new StringSerializer(), new StringSerializer()); + final TestOutputTopic output = driver.createOutputTopic(OUTPUT_TOPIC, new StringDeserializer(), new LongDeserializer()); + + input.pipeInput("a", "v1", 100L); + input.pipeInput("a", "v2", 200L); + input.pipeInput("a", "v3", 300L); + + final List> results = output.readKeyValuesToList(); + assertEquals(3, results.size()); + // At t=100: no records before → just the anchor → count=1 + assertEquals(1L, (long) results.get(0).value); + // At t=200: 1 before (v1) + anchor (v2) = 2 + assertEquals(2L, (long) results.get(1).value); + // At t=300: 1 before (v2) + anchor (v3) = 2 + assertEquals(2L, (long) results.get(2).value); + } + } + + // ---- Retention validation ---- + + @Test + public void rangeOverShouldThrowWhenRetentionTooSmall() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + // before=100ms, grace=20ms → required retention=120ms. Providing 50ms → should throw. + final Materialized> mat = + Materialized.>as("tiny-store") + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(Duration.ofMillis(50)); + + assertThrows(IllegalArgumentException.class, () -> + grouped.rangeOver( + EventTimeRange.ofTimeBoundsAndGrace(Duration.ofMillis(100), Duration.ofMillis(50), Duration.ofMillis(20)), + mat + ) + ); + } + + // ---- retainDuplicates validation ---- + + @Test + public void rangeOverShouldThrowForSupplierWithoutRetainDuplicates() { + final StreamsBuilder builder = new StreamsBuilder(); + final KGroupedStream grouped = builder + .stream(INPUT_TOPIC, Consumed.with(Serdes.String(), Serdes.String())) + .groupByKey(Grouped.with(Serdes.String(), Serdes.String())); + + final WindowBytesStoreSupplier badSupplier = + Stores.persistentWindowStore("no-dups", Duration.ofSeconds(10), Duration.ofMillis(1), false); + + final Materialized> mat = + Materialized.as(badSupplier) + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()); + + assertThrows(IllegalArgumentException.class, () -> + grouped.rangeOver(EventTimeRange.ofTimeBoundsWithNoGrace(Duration.ofSeconds(5), Duration.ofSeconds(1)), mat) + ); + } + + private static Materialized> buildMaterialized( + final String storeName, + final boolean cachingEnabled + ) { + final Materialized> mat = + Materialized.>as(storeName) + .withKeySerde(Serdes.String()) + .withValueSerde(Serdes.String()) + .withRetention(Duration.ofMillis(200)); + if (!cachingEnabled) { + mat.withCachingDisabled(); + } + return mat; + } +} From 623ca29e7819322b3dfa7272f07fc9c5e6cdbf52 Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 14:40:19 +0200 Subject: [PATCH 2/7] Add KIP-1352 diagrams from doc branch Brings over EventTimeRange, EventCountRange, and processing flow diagrams (PNG + PlantUML source) from KIP/trying_to_create_my_own_kip. Co-Authored-By: Claude Sonnet 4.6 --- streams/kips/diagrams/event_count_range.png | Bin 0 -> 19393 bytes streams/kips/diagrams/event_count_range.puml | 76 ++++++++++++++++++ streams/kips/diagrams/event_time_range.png | Bin 0 -> 19542 bytes streams/kips/diagrams/event_time_range.puml | 78 +++++++++++++++++++ streams/kips/diagrams/processing_flow.png | Bin 0 -> 26134 bytes streams/kips/diagrams/processing_flow.puml | 44 +++++++++++ 6 files changed, 198 insertions(+) create mode 100644 streams/kips/diagrams/event_count_range.png create mode 100644 streams/kips/diagrams/event_count_range.puml create mode 100644 streams/kips/diagrams/event_time_range.png create mode 100644 streams/kips/diagrams/event_time_range.puml create mode 100644 streams/kips/diagrams/processing_flow.png create mode 100644 streams/kips/diagrams/processing_flow.puml diff --git a/streams/kips/diagrams/event_count_range.png b/streams/kips/diagrams/event_count_range.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8c09dbeb000c72a475e3db292f302c53e65551 GIT binary patch literal 19393 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 VaRP*0fTmk~CrzzRP%& literal 0 HcmV?d00001 diff --git a/streams/kips/diagrams/event_time_range.puml b/streams/kips/diagrams/event_time_range.puml new file mode 100644 index 0000000000000..5fe9b3ee17dd3 --- /dev/null +++ b/streams/kips/diagrams/event_time_range.puml @@ -0,0 +1,78 @@ +@startuml +!theme plain +scale 10 as 50 pixels + +title EventTimeRange (-20s before, +30s after) + +' Define axes +concise "1. Event Time (s)" as ET +concise "2. Processing Time (s)" as PT +concise "3. State Store (Buffer)" as SS +concise "4. Emitted Range" as Out + +' Initial State +@0 +ET is Idle +PT is Idle +SS is "{ }" +Out is Idle + +' --- Arrival 1: A (t=30) --- +' Box from 25 to 35 centers exactly on 30 +@25 +PT is "A" +ET is "A" +SS is "{ A }" +Out is "{ A }" +@35 +PT is Idle +ET is Idle +Out is Idle + +@45 +ET is "B" + +@55 +ET is Idle + +' --- Arrival 2: C (t=70) --- +' Box from 65 to 75 centers exactly on 70 +@65 +PT is "C" +ET is "C" +SS is "{ A, C }" +Out is "{ C }" +@75 +PT is Idle +ET is Idle +Out is Idle + +' --- Arrival 3: D (t=90) --- +' Box from 105 to 115 centers exactly on 110 +@85 +PT is "D" +ET is "D" +SS is "{ A, C, D }" +Out is "{C,D}" +@95 +PT is Idle +ET is Idle +Out is Idle + +' --- Arrival 4: B (LATE DATA) (t=50) --- +' Arrives at PT=150. Box from 145 to 155 centers on 150. +@122 +PT is "B [LATE]" +SS is "{ A, B, C, D}" +Out is "{ A, B, C }" +note bottom of Out + The after timerange + only applies on + late arriving data +end note +@138 +PT is Idle +Out is Idle + +@145 +@enduml \ No newline at end of file diff --git a/streams/kips/diagrams/processing_flow.png b/streams/kips/diagrams/processing_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..d1b06f70c4c415738cd9658573565812ed0fac23 GIT binary patch literal 26134 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 gf79K*=a RKS : process(record) +activate RKS + +alt record is past grace period + RKS -> UP : (drop record) +else within grace period + RKS -> WS : put(key, value, timestamp) + activate WS + deactivate WS + + RKS -> R : fetch(anchor, store) + activate R + + R -> WS : fetch(key, fromTimestamp, toTimestamp) + activate WS + WS --> R : Iterator> + deactivate WS + + R --> RKS : Iterable> rangeRecords + deactivate R + + RKS -> RA : apply(anchor, rangeRecords) + activate RA + RA --> RKS : VR result + deactivate RA + + RKS -> DOWN : forward(key, result, timestamp) +end + +deactivate RKS + +@enduml From 6786a59958b4970ac6921820f1a348bd071561ca Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 14:51:49 +0200 Subject: [PATCH 3/7] Fix processing flow sequence diagram Four corrections vs. the actual implementation: - Drop arrows no longer point back to upstream (records are discarded, not returned) - Null key/value drop condition added before the grace period check - Removed incorrect RAP->WindowStore close() call (iterator consumed inside apply()) - forward() label corrected to anchor.withValue(result) Co-Authored-By: Claude Sonnet 4.6 --- streams/kips/diagrams/processing_flow.png | Bin 26134 -> 29940 bytes streams/kips/diagrams/processing_flow.puml | 43 +++++++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/streams/kips/diagrams/processing_flow.png b/streams/kips/diagrams/processing_flow.png index d1b06f70c4c415738cd9658573565812ed0fac23..c71506df6e1afe973d7ca928143a019e1a7d4d23 100644 GIT binary patch literal 29940 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 gf79K*=a RKS : process(record) -activate RKS +UP -> BP : process(record) +activate BP -alt record is past grace period - RKS -> UP : (drop record) -else within grace period - RKS -> WS : put(key, value, timestamp) +alt null key or null value + note right of BP : record dropped\n(droppedRecordsSensor) +else record.timestamp() < observedStreamTime - gracePeriodMs + note right of BP : record dropped\n(past grace period) +else record valid + BP -> BP : update observedStreamTime + + BP -> WS : put(key, value, timestamp) activate WS deactivate WS - RKS -> R : fetch(anchor, store) + BP -> AP : forward(record) + activate AP + + AP -> R : fetch(record, store) activate R R -> WS : fetch(key, fromTimestamp, toTimestamp) activate WS - WS --> R : Iterator> + WS --> R : WindowStoreIterator deactivate WS - R --> RKS : Iterable> rangeRecords + R --> AP : Iterable> deactivate R - RKS -> RA : apply(anchor, rangeRecords) + AP -> RA : apply(anchor, rangeRecords) activate RA - RA --> RKS : VR result + RA --> AP : VR result deactivate RA - RKS -> DOWN : forward(key, result, timestamp) + AP -> DOWN : forward(anchor.withValue(result)) + deactivate AP end -deactivate RKS +deactivate BP @enduml From 7c3febca2a4598a917ed532a5c0a0fd1acc37477 Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 15:28:34 +0200 Subject: [PATCH 4/7] Change Range.fetch() to return CloseableIterator and add try-with-resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Range.fetch() now returns CloseableIterator> instead of Iterable>, matching the KIP spec. The aggregate processor wraps it in a try-with-resources block, guaranteeing the underlying RocksDB cursor is always closed after aggregation — even if the user's aggregator exits early or throws. - New public interface CloseableIterator (extends Iterator + AutoCloseable) - LimitingWindowStoreIterator and ConcatenatingIterator implement it - Both expose an idempotent close() that delegates to the inner store iterator - KStreamRangeAggregate.process() closes the iterator via try-with-resources Co-Authored-By: Claude Sonnet 4.6 --- ...gregations+in+the+Kafka+Streams+DSL(7).doc | 2508 +++++++++++++++++ .../streams/kstream/CloseableIterator.java | 32 + .../streams/kstream/EventCountRange.java | 17 +- .../kafka/streams/kstream/EventTimeRange.java | 19 +- .../apache/kafka/streams/kstream/Range.java | 9 +- .../internals/KStreamRangeAggregate.java | 8 +- 6 files changed, 2575 insertions(+), 18 deletions(-) create mode 100644 streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc create mode 100644 streams/src/main/java/org/apache/kafka/streams/kstream/CloseableIterator.java diff --git a/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc b/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc new file mode 100644 index 0000000000000..7344b09faa307 --- /dev/null +++ b/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc @@ -0,0 +1,2508 @@ +Date: Mon, 1 Jun 2026 12:58:53 +0000 (UTC) +Message-ID: <1553154272.193579.1780318733416@cwiki-he-fi.apache.org> +Subject: Exported From Confluence +MIME-Version: 1.0 +Content-Type: multipart/related; + boundary="----=_Part_193578_1753426155.1780318733416" + +------=_Part_193578_1753426155.1780318733416 +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable +Content-Location: file:///C:/exported.html + + + + + KIP-1352: Ranges and Range Aggregations in the Kafka Streams DSL= + + + + + +

KIP-1352: Ranges and Range Aggregations in the Kafka Streams DSL +
+

+ +

+

St= +atus

+

Current state: Under Discussion

+

Discussion thread: link

+

JIRA:

+

Please keep the discussion on the mailing list rather than commenting on= + the wiki (wiki discussions get unwieldy fast).

+

Motivation

+

While the Kafka Streams DSL excels at temporal grouping through Tumbling= +, Hopping, and Sliding windows, these native constructs are fundamentally t= +ime-centric. They group records into absolute time buckets and output conti= +nuously updating KTable changelogs via incremental aggregation= +. Many real-world stream processing use cases require a more dynamic, event= +-centric context. Developers frequently need to evaluate a holistic 'range'= + of events relative to the arrival of a specific anchor record (e.g., 'the = +3 events before and 2 events after this specific transaction'). Furthermore= +, these use cases often require the evaluation to be an immutable, point-in= +-time calculation rather than an infinitely updating KTable th= +at triggers complex cascading updates when late data arrives.
+ Example use cases include calculating time-weighted moving averages in fin= +ancial applications, building context-aware feature vectors for machine lea= +rning anomaly detection, and threshold monitoring. This event-centric, poin= +t-in-time pattern is a standard paradigm in stream processing (similar to t= +he SQL OVER clause with ROWS/RANGE BETWEEN), and = +is natively supported by other frameworks like Apache Flink. It is a highly= + requested feature from the Kafka Streams community, e.g. (1)(2)= + and (3).
+ To bridge this gap, this KIP proposes introducing range-based query capabi= +lities to the Kafka Streams DSL. This will empower developers to define dyn= +amic, event-centric contexts and perform safe, non-incremental aggregations= + across those ranges.

+

Public Interfaces

+

The proposed changes to public interfaces include:

+ A new `Range` abstract class that both built-in and c= +ustom range definitions must extend, and two built-in implementations:

+
+
abstract Range class +
+
+
public abstra=
+ct class Range<K, V> {
+
+    private final long gracePeriodMs;
+
+    /**
+     * @param gracePeriodMs the grace period in milliseconds. Must not be n=
+egative.
+     */
+    protected Range(final long gracePeriodMs) {
+        this.gracePeriodMs =3D gracePeriodMs;
+    }
+
+=09/**
+     * Fetch the records that fall within this range for the given anchor r=
+ecord.
+     * The anchor record itself should be included in the returned iterator=
+.
+     * Records should be ordered by their timestamps in ascending order.
+     * <p>
+     * The framework guarantees that this iterator will be safely closed af=
+ter=20
+     * the aggregation completes, preventing resource leaks.
+     *
+     * @param anchor the record that triggered the range evaluation
+     * @param store  the buffer store holding records for the anchor's grou=
+p key
+     * @return a closeable iterator of records that fall within the defined=
+ range
+     */
+    public abstract CloseableIterator<Record<K, V>> fetch(Recor=
+d<K, V> anchor, ReadOnlyWindowStore<K, V> store);
+
+    /**
+     * @return the grace period in milliseconds. Records arriving after str=
+eam time has advanced
+     * beyond the range's natural boundary plus this value will be dropped.
+     */
+    public long gracePeriodMs() {
+        return gracePeriodMs;
+    }
+
+    /**
+     * The minimum retention the buffer {@link WindowStore} must be configu=
+red with, excluding
+     * the grace period. Implementations should return the oldest a record =
+can be relative to an
+     * anchor's timestamp and still fall within the range (e.g. {@code befo=
+re} for
+     * {@link EventTimeRange}, {@code maxTimeBefore} for {@link EventCountR=
+ange}).
+     *
+     * @return the range-specific retention in milliseconds, excluding grac=
+e period
+     */
+    protected abstract long rangeRetentionMs();
+
+    /**
+     * The minimum retention the buffer {@link WindowStore} must be configu=
+red with to correctly
+     * serve this range, including the grace period. This is what {@code ra=
+ngeOver()} validates
+     * against the {@link Materialized} retention.
+     *
+     * @return the total required retention in milliseconds
+     */
+    public long retentionMs() {
+        return rangeRetentionMs() + gracePeriodMs;
+    }
+}
+
+
+
+
EventTimeRange implementation +
+
+
public final =
+class EventTimeRange<K, V> extends Range<K, V> {
+
+    /**
+     * Create an {@link EventTimeRange} spanning {@code before} time prior =
+to and {@code after} time following
+     * the anchor record's timestamp. Late-arriving records =
+(those arriving after stream time has advanced beyond the anchor's upper ti=
+me boundary) are dropped.
+     * Use {@link #ofTimeBoundsAndGrace(Duration, Duration, Duration)} to t=
+olerate late arrivals.
+     * Use {@link #withMaxRecords(int)} to cap the number of records includ=
+ed.
+     *
+     * @param before the time before the anchor record's timestamp that def=
+ines the start of the range. Must not be negative.
+     * @param after  the time after the anchor record's timestamp that defi=
+nes the end of the range. Must not be negative.
+     * @return a new {@link EventTimeRange} with no grace period
+     * @throws IllegalArgumentException if either duration is negative or c=
+an't be represented as {@code long milliseconds}
+     */
+    public static <K, V> EventTimeRange<K, V> ofTimeBoundsWithN=
+oGrace(final Duration before, final Duration after) {}
+
+    /**
+     * Create an {@link EventTimeRange} spanning {@code before} time prior =
+to and {@code after} time following
+     * the anchor record's timestamp, accepting late records up to {@code g=
+race} beyond the range boundary.
+     * Use {@link #withMaxRecords(int)} to cap the number of records includ=
+ed.
+     *
+     * @param before      the time before the anchor record's timestamp tha=
+t defines the start of the range. Must not be negative.
+     * @param after       the time after the anchor record's timestamp that=
+ defines the end of the range. Must not be negative.
+     * @param grace       the grace period to tolerate late-arriving record=
+s. Must not be negative.
+     * @return a new {@link EventTimeRange} with the specified grace period
+     * @throws IllegalArgumentException if any duration is negative or can'=
+t be represented as {@code long milliseconds}
+     */
+    public static <K, V> EventTimeRange<K, V> ofTimeBoundsAndGr=
+ace(final Duration before, final Duration after, final Duration grace) {}
+
+    /**
+     * Cap the number of records included in the range. If more records fal=
+l within the time boundaries,
+     * the newest records are dropped.
+     *
+     * @param maxRecords the maximum number of records to include. Must be =
+positive.
+     * @return this {@link EventTimeRange}
+     * @throws IllegalArgumentException if {@code maxRecords} is not positi=
+ve
+     */
+    public EventTimeRange<K, V> withMaxRecords(final int maxRecords) =
+{}
+}
+
+
+

 

+
+
EventCountRange implementation +
+
+
public final =
+class EventCountRange<K, V> extends Range<K, V> {
+
+    /**
+     * Create an {@link EventCountRange} including a count of {@code before=
+} records prior to, and {@code after} records following,=20
+=09 * the anchor record in event-time order. Late-arriving records (those a=
+rriving after stream time has advanced beyond the anchor's timestamp) are d=
+ropped
+     * Use {@link #ofCountBoundsAndGrace(int, int, Duration, Duration)} to =
+tolerate late arrivals.
+     * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceil=
+ing on the forward direction.
+     *
+     * @param before        the number of records before the anchor record =
+to include. Must not be negative.
+     * @param after         the number of records after the anchor record t=
+o include. Must not be negative.
+     * @param maxTimeBefore the maximum time before the anchor's timestamp =
+to look back. Must not be negative.
+     * @return a new {@link EventCountRange} with no grace period
+     * @throws IllegalArgumentException if any count is negative or the dur=
+ation can't be represented as {@code long milliseconds}
+     */
+    public static <K, V> EventCountRange<K, V> ofCountBoundsWit=
+hNoGrace(final int before, final int after, final Duration maxTimeBefore) {=
+}
+
+    /**
+     * Create an {@link EventCountRange} including a count of {@code before=
+} records prior to, and {@code after} records following,
+     * the anchor record in event-time order, accepting late=
+ records up to {@code grace} beyond the range boundary.
+     * {@code maxTimeBefore} sets a required time floor: records older than=
+ {@code anchor.timestamp - maxTimeBefore}
+     * are excluded regardless of count.
+     * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceil=
+ing on the forward direction.
+     *
+     * @param before        the number of records before the anchor record =
+to include. Must not be negative.
+     * @param after         the number of records after the anchor record t=
+o include. Must not be negative.
+     * @param maxTimeBefore the maximum time before the anchor's timestamp =
+to look back. Must not be negative.
+     * @param grace         the grace period to tolerate late-arriving reco=
+rds. Must not be negative.
+     * @return a new {@link EventCountRange} with the specified grace perio=
+d
+     * @throws IllegalArgumentException if any count is negative or any dur=
+ation can't be represented as {@code long milliseconds}
+     */
+    public static <K, V> EventCountRange<K, V> ofCountBoundsAnd=
+Grace(final int before, final int after, final Duration maxTimeBefore, fina=
+l Duration grace) {}
+
+    /**
+     * Set an optional time ceiling on the forward direction. Records newer=
+ than
+     * {@code anchor.timestamp + maxTimeAfter} are excluded regardless of c=
+ount.
+     *
+     * @param maxTimeAfter the maximum time after the anchor's timestamp to=
+ look forward. Must not be negative.
+     * @return this {@link EventCountRange}
+     * @throws IllegalArgumentException if the duration is negative or can'=
+t be represented as {@code long milliseconds}
+     */
+    public EventCountRange<K, V> withMaxTimeAfter(final Duration maxT=
+imeAfter) {}
+}
+
+
+


Two new methods `rangeOver` in the `KGroupedStream` i= +nterface:

+
+
KGroupedStream +
+
+
public interf=
+ace KGroupedStream<K, V> {
+    // existing methods...
+=09
+=09/**
+     * Create a new {@link RangedKStream} instance with a default internal =
+buffer store.
+     * The store is auto-named, uses the Serdes of this grouped stream, and=
+ its retention is set to
+     * {@link Range#retentionMs()} =E2=80=94 the minimum required to serve =
+the range. Use
+     * {@link #rangeOver(Range, Materialized)} to name the store, override =
+Serdes, or increase retention.
+     * <p>
+     * Records with {@code null} key or {@code null} value are dropped and =
+not written to the buffer store.
+     * The {@code dropped-records-total} metric is incremented for each dro=
+pped record.
+     *
+     * @param range the range definition, determining which records are inc=
+luded for each anchor record
+     * @return an instance of {@link RangedKStream}
+     */
+    RangedKStream<K, V> rangeOver(final Range<? super K, ? super V=
+> range);
+
+    /**
+     * Create a new {@link RangedKStream} instance that can be used to perf=
+orm ranged aggregations on the grouped stream.
+     * The range of the aggregation is defined by the provided {@link Range=
+} instance.
+     * Built-in implementations are provided via {@link EventTimeRange} and=
+ {@link EventCountRange}.
+     * Custom implementations of {@link Range} can also be provided.
+     * <p>
+     * The {@code materialized} parameter configures the underlying buffer =
+store, which holds the raw records
+     * used by the range definition to fetch records on each trigger. This =
+store is materialized at this step,
+     * not at aggregation time, because the aggregation result is emitted a=
+s a {@link KStream} and not persisted.
+     * <p>
+     * Records with {@code null} key or {@code null} value are dropped and =
+not written to the buffer store.
+     * The {@code dropped-records-total} metric is incremented for each dro=
+pped record.
+     *
+     * @param range        the range definition, determining which records =
+are included for each anchor record
+     * @param materialized the configuration for the underlying buffer stat=
+e store
+     * @return an instance of {@link RangedKStream}
+     * @throws IllegalArgumentException if the retention period specified i=
+n {@code materialized} is smaller than
+     * {@link Range#retentionMs()}.
+     */
+    RangedKStream<K, V> rangeOver(
+        final Range<? super K, ? super V> range,
+        final Materialized<K, V, WindowStore<Bytes, byte[]>> ma=
+terialized
+    );
+}
+
+
+



And a RangedKStream interface:

+
+
RangedKStream +
+
+
public interf=
+ace RangedKStream<K, V> {
+    /**
+     * Perform an aggregation on the records in the range defined for this =
+stream.=20
+     * The aggregation will be triggered for each incoming record and will =
+include all records that fall within the defined range of that record.
+     *
+     * @param aggregator the aggregator function to apply to the records in=
+ the range
+     * @param <VR> the type of the aggregated value
+     * @return a {@link KStream} containing the aggregated results for each=
+ unmodified key, with the output record's timestamp inherited from the anch=
+or record.
+     */
+    <VR> KStream<K, VR> aggregate(final RangeAggregator<K, V=
+, VR> aggregator);
+
+    /**
+     * Count the number of records in this range by the grouped key and def=
+ined range.
+     *
+     * @return a {@link KStream} that contains records with unmodified keys=
+ and {@link Long} values
+     * that represent the current count of records for the defined range
+     */
+    KStream<K, Long> count();
+
+}
+
+
+


+

And a new functional interface for the range aggregator:

+
+
RangeAggregator +
+
+
@FunctionalIn=
+terface
+public interface RangeAggregator<K, V, VR> {
+    /**
+     * Apply the aggregation logic to the records in the defined range for =
+a given key and timestamp.
+     * @param anchor the record that triggered the aggregation
+     * @param rangeRecords a read-only iterable of records that fall within=
+ the defined range of the anchor record, including the anchor record itself=
+. The records are ordered by their timestamps in ascending order.
+     * @return the result of the aggregation
+     */
+    VR apply(Record<K,V> anchor, Iterable<Record<K,V>> ra=
+ngeRecords);
+}
+
+
+

Proposed Changes

+

This KIP introduces the Range<K, V> abstract class as= + the primary extension point for defining range boundaries. It provides two= + built-in implementations:

+
    +
  • EventTimeRange: Defines ranges based s= +trictly on event-time durations (e.g., N seconds before and after = +the anchor).

  • +
  • EventCountRange: Defines ranges based = +on strict record counts (e.g., N records before and after), bounde= +d by a required maximum look-back time to ensure safe state store retention= +.

  • +
+

To align with modern Kafka Streams API standards (KIP-633<= +/a>), the grace period for late-arriving records is enforced strictly via s= +tatic factory methods and constructors. Furthermore, users can pass custom = +Range subclasses into rangeOver() to implement ar= +bitrary fetching logic beyond the built-in types.

+


+

Physical topology & state sharing

+

A key architectural design of this KIP is that the buffer store is mater= +ialized at rangeOver() time, not at aggregation time.

+

In the physical topology, rangeOver() injects a dedicated <= +strong>Buffer Processor that owns the WindowStore. Ea= +ch subsequent call to .aggregate() on the resulting Rang= +edKStream introduces an independent Aggregate Processor as a child node. Because the state store is owned by the parent Buffer= + Processor, multiple .aggregate() calls on the same range seam= +lessly share a single underlying RocksDB buffer, completely eliminating dat= +a duplication.

+

Iterator Lifecycle Management: To ensure optimal O(1) memory efficiency without exposing users to resource leaks, Range.= +fetch() returns a CloseableIterator. The internal Aggre= +gate Processor wraps this cursor in a lazy Iterable for the us= +er's RangeAggregator, and mathematically guarantees the cursor= + is closed via a try-with-resources block after the aggregatio= +n completes=E2=80=94even if the user exits the loop early or an exception i= +s thrown.

+

Processing Flow

+

The sequence diagram below illustrates the lifecycle of a single incomin= +g record through this topology:

+

+
    +
  1. Buffer Phase: The Ran= +geStore Processor receives the incoming record, evaluates it against the de= +fined grace period, and drops it if it is late. Valid records are persisted= + to the shared WindowStore and immediately forwarded downstrea= +m.

  2. +
  3. Fetch Phase: The RangeAggregate Processor receives = +the forwarded record (which now acts as the "anchor"). It delegates the fet= +ch operation to the Range implementation, which queries the sh= +ared state store to build the context boundaries.

  4. +
  5. Aggregate Phase: The anchor record and the fetched = +holistic context (Iterable<Record<K, V>>) are pass= +ed to the RangeAggregator. The stateless calculation is perfor= +med, and the final result is forwarded downstream as a pure, append-only KStream record.

  6. +
  7. Cleanup = +Phase: The framework mathematically guarantees that the underlying= + RocksDB cursor is safely closed via a try-with-resources block, even if the use= +r's aggregator exits the loop early or throws an exception.
  8. +
+

Usa= +ge

+


EventTimeRange =E2=80=94 compute a rolling aggregation over a 20-second window= + around each sensor reading.

+


+
+
Computing a rolling aggregate +
+
+
KStream<St=
+ring, SensorReading> readings =3D builder.stream("sensors");
+
+RangedKStream<String, SensorReading> ranged =3D readings
+    .groupByKey()
+    .rangeOver(
+        EventTimeRange.ofTimeBoundsAndGrace(Duration.ofSeconds(20), Duratio=
+n.ofSeconds(0), Duration.ofSeconds(5)),
+        Materialized.<String, SensorReading, WindowStore<Bytes, byte[=
+]>>as("sensor-buffer")
+                    .withRetention(Duration.ofSeconds(25))
+    );
+
+KStream<String, Double> movingAverage =3D ranged.aggregate((anchor, r=
+angeRecords) -> {
+    double sum =3D 0;
+    int count =3D 0;
+    for (Record<String, SensorReading> r : rangeRecords) {
+        sum +=3D r.value().reading();
+        count++;
+    }
+    return sum / count;
+});
+
+// Note that multiple aggregations on 1 buffer are possible
+
+KStream<String, Double> median =3D ranged.aggregate((anchor, rangeRec=
+ords) -> {
+    final List<Double> values =3D new ArrayList<>();
+    for (Record<String, SensorReading> r : rangeRecords) {
+        values.add(r.value().reading());
+    }
+    Collections.sort(values);
+    final int size =3D values.size();
+    return size % 2 =3D=3D 0
+        ? (values.get(size / 2 - 1) + values.get(size / 2)) / 2.0
+        : values.get(size / 2);
+});
+
+
+
+
+


+

EventCountRange =E2=80=94 include the 3 events before and 0 events after each reco= +rd, looking back at most 1 hour:

+


+
+
EventCountRange example +
+
+
KStream<St=
+ring, Long> rangeCounts =3D readings
+    .groupByKey()
+    .rangeOver(
+        EventCountRange.ofCountBoundsAndGrace(3, 0, Duration.ofHours(1), Du=
+ration.ofSeconds(5)),
+        Materialized.<String, SensorReading, WindowStore<Bytes, byte[=
+]>>as("sensor-count-buffer")
+                    .withRetention(Duration.ofHours(1).plusSeconds(5))
+    )
+    .count();
+
+
+



Custom Range =E2=80=94 subclass `Range`= + to implement arbitrary fetch logic. This example groups all records= + that fall within the same calendar hour as the anchor, regardless of how f= +ar apart they are from the anchor itself. This kind of calendar-aligned bou= +ndary is not possible with `EventTimeRange`, which is = +always relative to the anchor's timestamp:

+


+
+
HourAligned custom range +
+
+
public class =
+HourAlignedRange extends Range<String, SensorReading> {
+    private static final long HOUR_MS =3D Duration.ofHours(1).toMillis();
+
+    public HourAlignedRange(final Duration grace) {
+        super(validateMillisecondDuration(grace, "grace"));
+    }
+
+    @Override
+    public CloseableIterator<Record<String, SensorReading>> fet=
+ch(
+            final Record<String, SensorReading> anchor,
+            final ReadOnlyWindowStore<String, SensorReading> store) {
+       =20
+        final long hourStart =3D anchor.timestamp() - (anchor.timestamp() %=
+ HOUR_MS);
+        final long hourEnd =3D hourStart + HOUR_MS;
+       =20
+        // Fetch the raw RocksDB iterator
+        final WindowStoreIterator<SensorReading> storeIterator =3D=20
+                store.fetch(anchor.key(), Instant.ofEpochMilli(hourStart), =
+Instant.ofEpochMilli(hourEnd));
+
+        // Return a lazy CloseableIterator that maps the KeyValue to a Reco=
+rd
+        return new CloseableIterator<Record<String, SensorReading>=
+>() {
+            @Override
+            public boolean hasNext() { return storeIterator.hasNext(); }
+
+            @Override
+            public Record<String, SensorReading> next() {
+                KeyValue<Long, SensorReading> kv =3D storeIterator.ne=
+xt();
+                return new Record<>(anchor.key(), kv.value, kv.key);
+            }
+
+            @Override
+            public void close() { storeIterator.close(); }
+        };
+    }
+
+    @Override
+    protected long rangeRetentionMs() { return HOUR_MS; }
+}
+
+
+
+


The following illust= +rations demonstrate how the two built-in range types behave:

+

EventTimeRange

+


3D""
<= +br>

+

The diagram above illustrates four events belonging to the same group ke= +y. The RangedKStream buffers these events in the shared state = +store. To support multiple events with the exact same timestamp, the intern= +al WindowStore is configured with retainDuplicates =3D t= +rue, which appends a sequence number to the composite key.

+

After processing the first three events (A, C, D) in order, the state st= +ore looks like this:

+


+
+ ++++ + + + + + + + + + + + + + + + + + + +
KeyValue
<group-key>-30A
<group-key>-70C
<group-key>-90D
+
+


When an out-of-order= + or late-arriving event (B) arrives at timestamp 50<= +/code>, the processor immediately writes it to the store:

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + +
KeyValue
<group-key>-30A
<group-key>-50B
<group-key>-70C
<group-key>-90D
+
+

 

+

To evaluate the range for anchor B (assuming a configur= +ation of before =3D 20 and after =3D 30), the pro= +cessor executes a single highly efficient range query: store.fetch(ke= +y, 30, 80). This returns an iterator containing A, B, and C.

+

The "Forward-Looking" Constraint & maxRecords:<= +/strong> Because aggregations are emitted immediately to a KStream upon record arrival, an in-order record will never see "future" record= +s (since they haven't arrived yet). Therefore, the after param= +eter strictly serves to capture context for out-of-order or late-arriving a= +nchors evaluating against already-buffered newer records. If the fetched ra= +nge exceeds the optional maxRecords parameter, the newest reco= +rds in the iterator are dropped. This guarantees that unneeded records are = +never deserialized, saving CPU cycles.

+

EventCountRange

+


3D"=

+

The diagram above illustrates the same late-arrival scenario, this time = +applying an EventCountRange with before =3D 1 and= + after =3D 1.

+

When the late-arriving anchor event (B at timestamp 50) arrives, it is written to the store. To resolve the count-bas= +ed boundaries, the RangedKStream executes a two-pronged fetch = +strategy:

+
    +
  1. The Backward Fetch: It executes a store.backw= +ardFetch() from the anchor down to anchor.timestamp - maxTimeB= +efore. This iterator yields records descending in time, which the pr= +ocessor limits to the before count (yielding event A).

  2. +
  3. The Forward Fetch: It executes a standard sto= +re.fetch() from the anchor up to the current stream time (or m= +axTimeAfter if configured). This iterator yields records ascending i= +n time, which the processor limits to the after count (yieldin= +g event C).

  4. +
+

To ensure the final Iterable presented to the RangeAg= +gregator remains in strict chronological ascending order, the proces= +sor reverses the bounded backward-fetch results in memory (an O(before) operation) and conc= +atenates it with the anchor and the forward-fetch iterator.

+

Boundary Non-Determinism: Just as with EventTimeR= +ange, the after count strictly applies to out-of-order = +or late-arriving records looking at newer, already-buffered data. Note = +on duplicates: Because retainDuplicates =3D true uses phy= +sical sequence numbers, if multiple records share the exact same timestamp = +at the exact cut-off boundary of the before or after count, the specific records included in the iterator are technically no= +n-deterministic, aligning with standard Kafka Streams windowing behavior. +

Retention Period

+

To guarantee that context is safely preserved for out-of-order and late-= +arriving records, the buffer WindowStore must be configured wi= +th a retention period of at least Range.retentionMs(), which i= +s computed as rangeRetentionMs() + gracePeriodMs(). The = +rangeOver() method internally validates this against the user-provid= +ed Materialized configuration and throws an IllegalArgum= +entException during topology initialization if the retention is too = +small.

+

The rangeRetentionMs() bounds for the built-in types are: +

    +
  • EventTimeRange: The before duration.

  • +
  • EventCountRange: The maxTimeBefo= +re duration.

  • +
+

Custom subclasses must implement rangeRetentionMs() to math= +ematically return the absolute maximum age a record can have relative to an= + anchor's timestamp and still legally fall within the custom range.

+

Extendability

+

The Range<K, V> abstract class serves as the primary = +extension point. Users can subclass it to implement custom range logic and = +pass the result directly to rangeOver().

+

The following concepts are explicitly out of scope for this KIP but are = +natural candidates for future follow-up work:

+
    +
  • Additional built-in range types: Other range defini= +tions beyond EventTimeRange and EventCountRange c= +an be added as further subclasses of Range in the future witho= +ut requiring any overarching API changes.

  • +
  • rangeOver on plain KStream: Ranges without prior grouping would require a completely different buffe= +ring strategy (such as a global or partition-wide state store) since there = +is no specific group key to tightly scope the physical store.

  • +
  • rangeOver on CoGroupedKStream: Co-grouped ranges would require a highly complex shared multi-stream = +buffer store and a completely revised aggregator interface to handle record= +s from heterogeneous value types. This is deferred accordingly.

  • +
+

Performance Considerations

+

Because range aggregations are dynamically evaluated upon the arrival of= + every anchor record, performance will scale relative to the density and si= +ze of the fetched ranges.

+
    +
  • Memory Footprint: The API strictly bounds memory us= +age by passing a lazy Iterable (backed by a Closeab= +leIterator) to the RangeAggregator. This ensures that p= +rocessing exceptionally large ranges does not load the entire dataset into = +the JVM heap, preventing OOM errors and Garbage Collection spikes.

  • +
  • CPU & I/O Overhead: Evaluating ranges requires = +querying the underlying state store. For an EventTimeRange, ex= +ceptionally wide time boundaries combined with a high (or omitted) ma= +xRecords cap will increase RocksDB read operations and deserializati= +on overhead per anchor record.

  • +
  • Tuning: Users operating on high-throughput streams = +are highly encouraged to tune maxRecords (for time ranges) and= + maxTimeBefore (for count ranges) to the tightest business req= +uirements possible to minimize unnecessary deserialization.

  • +
+

Compatibility, Deprecation, and Migration= + Plan

+

The proposed changes are backward compatible as they introduce new inter= +faces and methods without modifying existing ones.
+ There is, however possible confusion with the existing windowing functiona= +lity, since the method names for aggregation are the same but the semantics= + and return types are different. This distinction needs to be emphasized in= + the documentation.

+

= +Test Plan

+

Range Definition Unit Tests

+

Mirrors SessionWindowsTest and SlidingWindowsTest= +.

+
    +
  • Parameter Validation: Verify that before, after, and maxTimeBefore are not negative; maxRecords is strictly positive; and grace is not n= +egative.

  • +
  • Duration Conversion: IllegalArgumentException= + is thrown for durations that cannot be safely represented as millis= +econds.

  • +
  • State Resolution: gracePeriodMs() corr= +ectly returns the value passed during construction.

  • +
  • Retention Math: retentionMs() correctl= +y equals rangeRetentionMs() + gracePeriodMs().

  • +
  • Built-in Bounds: EventTimeRange.rangeRetentio= +nMs() equals before in milliseconds. EventCountRa= +nge.rangeRetentionMs() equals maxTimeBefore in millisec= +onds.

  • +
  • Fluent Chaining: withMaxRecords() and = +withMaxTimeAfter() correctly return their concrete subtypes to= + maintain fluent chaining.

  • +
  • Builder Validation: rangeOver() throws= + IllegalArgumentException if the Materialized ret= +ention is smaller than range.retentionMs().

  • +

  • +
  • Lambda Support: Verify that RangeAggregator can be cleanly expressed as a Java lambda expression.

  • +
+

Topology & Integration Tests

+

Mirrors TimeWindowedKStreamIntegrationTest.

+
    +
  • EventTimeRange End-to-End: Records pro= +duce the correct aggregated output per anchor; output is written to a downs= +tream Kafka topic with the unmodified key, aggregated value, and the anchor= +'s original timestamp.

  • +
  • Grace Period & Late Data: Late records arriving= + within the configured grace period produce updated output; records arrivin= +g past the grace period are correctly dropped.

  • +
  • Range Capping: EventTimeRange with withMaxRecords strictly caps the output and drops the newest reco= +rds when the range exceeds the configured limit.

  • +
  • EventCountRange End-to-End: Correct be= +fore/after counts are evaluated and included per anchor.

  • +
  • Count Time Floors/Ceilings: EventCountRange with maxTimeBefore strictly excludes records beyond the = +time floor regardless of count. EventCountRange with wit= +hMaxTimeAfter strictly excludes records newer than anchor.time= +stamp + maxTimeAfter regardless of count.

  • +
  • Iterator Lifecycle Safety: Verify that the underlyi= +ng CloseableIterator is successfully closed by the framework a= +fter a successful aggregation, and explicitly verify it is closed = +if the user's RangeAggregator throws a RuntimeException<= +/code>.

  • +
  • Null Handling: Records with a null key= + or null value are dropped, and the dropped-records-tota= +l metric is successfully incremented.

  • +
  • count(): count() operator= + end-to-end test emits the correct long value per anchor.

  • +
  • Custom Subclasses: A custom Range subc= +lass is correctly integrated, materialized, and fetched via rangeOver= +().

  • +
  • State Restoration: After a topology restart, the sh= +ared buffer store is successfully restored from its changelog topic and ran= +ge aggregations resume correctly.

  • +
  • Caching Behavior: Output is verified to be identica= +l with caching enabled vs. disabled. This ensures that Range.fetch()<= +/code> correctly reads newly written records in the exact same processing s= +tep, regardless of whether they have been flushed to the physical RocksDB s= +tore yet.

  • +
+


+

Rejected Alternatives

+
    +
  • Naming (bufferedBy vs. rangeOver):= + Using .bufferedBy() alongside EventTimeBuffer<= +/code> or EventCountBuffer was rejected. The term "buffer" is = +already heavily overloaded within Kafka and Kafka Streams internals (e.g., = +Suppress buffers, RecordCollector buffers). Furth= +ermore, the term "range" tightly aligns with industry-standard streaming SQ= +L semantics (such as Flink's RANGE OVER or standard SQL = +ROWS BETWEEN).

  • +
  • Implementation as a New Window Type: Implementing t= +his directly within the existing .windowedBy() API was rejecte= +d for two structural reasons:

    +
      +
    • Semantics: Range aggregations fundamentally emit an append-= +only KStream and do not receive retroactive updates when late = +data arrives. Standard window aggregations are incremental and result in a = +continuously updating KTable.

    • +
    • Materialization Lifecycle: Standard windows only require st= +ate store materialization at the aggregation step. Ranges require a materia= +lized buffer store immediately upon definition to physically execute the lo= +ok-back/look-forward queries on the raw records, even before an aggregation= + is applied.

    • +
  • +
  • Retroactive Updates for Past Ranges (Emitting a KTable= +): When late data arrives, we do not emit retroactive updat= +es for previously evaluated ranges. Returning an updating KTable instead of an append-only KStream was rejected because over= +lapping event-centric ranges mean a single late-arriving record mathematica= +lly alters the context of N surrounding anchors. Emitting retroact= +ive updates for all affected past anchors would cause exponential write amp= +lification and severe RocksDB read-thrashing.

  • +
+
+ + +------=_Part_193578_1753426155.1780318733416 +Content-Type: application/octet-stream +Content-Transfer-Encoding: base64 +Content-Location: file:///C:/151acf64aca303d1cf241f52fe1da23e8083a8be796a8142cc93909b0bbd38b6 + +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 +------=_Part_193578_1753426155.1780318733416 +Content-Type: application/octet-stream +Content-Transfer-Encoding: base64 +Content-Location: file:///C:/bc34eb2ecd2f26896103871cf3e4e94f033a91428b2a28ce648ef6b8d59a1b28 + +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 +------=_Part_193578_1753426155.1780318733416 +Content-Type: application/octet-stream +Content-Transfer-Encoding: base64 +Content-Location: file:///C:/ac26b66d09f1da9844ed51cee98225008008dc960ddc3371a76dcd2ac86b5de2 + +iVBORw0KGgoAAAANSUhEUgAAAyEAAAF0CAMAAAAD7MasAAAAYFBMVEUAAAAPDw8WFhYZGRkiIiIp +KSk0NDQ/Pz9AQEBLS0tRUVFbW1tjY2NtbW10dHR7e3uAgICLi4uRkZGampqgoKCurq60tLS/v7/A +wMDPz8/T09Pb29vi4uLt7e309PT///+PDsRWAAAAKnRFWHRjb3B5bGVmdABHZW5lcmF0ZWQgYnkg +aHR0cHM6Ly9wbGFudHVtbC5jb212zsofAAAEJGlUWHRwbGFudHVtbAABAAAAeJzdV1tv4kYUfvev +OOVlEymhQMJ2N1pVNpfVRkqyqKbtQ9WHwT7AlGGGzow3sBH/vWdsjO2QzS6EXlQkEHP8ne9c5psD +4xvLtE3mwvvOTnGOsBCMS89ETCA0G8AMtBuw4EsUxvMst2Tuf0JpuyqR9icmJwgnTUBnghGOlcYz +yNdsbFGfet4r6OGYSwS2RONFSkbcINSa9YwKhpwCn5jTmgvXHxaIVh0GWkVoDJeTKmxQgl3UIbTM +In1SfDjpJOMxBU5xYVjgLuuQZpw++JhYl9m15JYzkRF4fsPrD4EbuI4FeoPiaxi6r7UHWNc88tza +ieH8/BwCrfknYmleQeAMnt9qb9xrQW3D6b5teYISU+0hoIV/0S5HLOVRCehftnO+To2W7XYZ+iif +1hV003xeQbgyFudgp1zODFnJg3YcJC5ttl2e/3qbc3ebc7fIOTiDbiXpbO3/8E15VxO7uIJe1qg3 +26C9bdBeuVEU5YzA5cjO4CK/PSDy5RV04OQmGPahFwyD0017OsAcAA0o8lVjUDpGDVzColCgJQWe +wciRW7MRubO5WEoQ3vObrVZeTwd+c2F+rxbTyeopl5ObXY1SkY5Hylo1d1k4lQK9hrRV6XHa7JWz +uaBSrFyOOj2ISqZ24Y5CWo3LOWaWeShjcMyU38Wbcs+q0mqStnzCunng+dvRsHm9M3Yl8EeKoZWy +8JAG67BoNtE0DOKuEkrD/ZRTGPfkvXJTwtlGgkBb2x2jhv2COmaSpcYPqwXqG5Jljk4yAjLhYwJn +G055NJO0JdBMbbdMT6gHbVqs6R2rKJm7nckSjNjCciU3q8cMjdS6Tj/HVBU1+OvAKbL4m4DZvMxx +rviQf0YgiTzv6d5SxbnrLVvyeTL/lcd2CheNRop49/1mOzwz43LBNJs7jav7GyUEX6hFuXUF5On9 +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 +cQAAAABJRU5ErkJggg== +------=_Part_193578_1753426155.1780318733416-- diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/CloseableIterator.java b/streams/src/main/java/org/apache/kafka/streams/kstream/CloseableIterator.java new file mode 100644 index 0000000000000..c6dba0c9a34f3 --- /dev/null +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/CloseableIterator.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kafka.streams.kstream; + +import java.util.Iterator; + +/** + * An {@link Iterator} that holds resources (e.g. a RocksDB cursor) and must be closed after use. + * The {@link #close()} method does not throw a checked exception, making it safe for use in + * try-with-resources blocks without requiring a catch clause. + * + *

Implementations must be idempotent: calling {@link #close()} more than once must be safe. + * + * @param the type of elements returned by this iterator + */ +public interface CloseableIterator extends Iterator, AutoCloseable { + void close(); +} diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java index bf12619db1231..7096d742bb33b 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java @@ -113,7 +113,7 @@ public EventCountRange withMaxTimeAfter(final Duration maxTimeAfter) { } @Override - public Iterable> fetch(final Record anchor, final ReadOnlyWindowStore store) { + public CloseableIterator> fetch(final Record anchor, final ReadOnlyWindowStore store) { final long from = anchor.timestamp() - maxTimeBeforeMs; final long forwardTo = maxTimeAfterMs != null ? anchor.timestamp() + maxTimeAfterMs : Long.MAX_VALUE; @@ -138,7 +138,7 @@ public Iterable> fetch(final Record anchor, final ReadOnlyWin Instant.ofEpochMilli(forwardTo) ); - return () -> new ConcatenatingIterator<>(backwardRecords.iterator(), forwardIt, anchor.key(), after); + return new ConcatenatingIterator<>(backwardRecords.iterator(), forwardIt, anchor.key(), after); } @Override @@ -160,7 +160,7 @@ private static long validateNonNegativeMs(final Duration duration, final String return ms; } - private static final class ConcatenatingIterator implements Iterator> { + private static final class ConcatenatingIterator implements CloseableIterator> { private final Iterator> backwardPart; private final WindowStoreIterator forwardIt; @@ -186,13 +186,20 @@ public boolean hasNext() { if (backwardPart.hasNext()) return true; if (forwardDone) return false; if (forwardCount >= afterLimit || !forwardIt.hasNext()) { - forwardIt.close(); - forwardDone = true; + close(); return false; } return true; } + @Override + public void close() { + if (!forwardDone) { + forwardIt.close(); + forwardDone = true; + } + } + @Override public Record next() { if (!hasNext()) throw new NoSuchElementException(); diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java b/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java index 59e9dcca44bd8..fa65dca3253e7 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/EventTimeRange.java @@ -24,7 +24,6 @@ import java.time.Duration; import java.time.Instant; -import java.util.Iterator; import java.util.NoSuchElementException; /** @@ -104,11 +103,10 @@ public EventTimeRange withMaxRecords(final int maxRecords) { } @Override - public Iterable> fetch(final Record anchor, final ReadOnlyWindowStore store) { + public CloseableIterator> fetch(final Record anchor, final ReadOnlyWindowStore store) { final Instant from = Instant.ofEpochMilli(anchor.timestamp() - beforeMs); final Instant to = Instant.ofEpochMilli(anchor.timestamp() + afterMs); - final int limit = maxRecords; - return () -> new LimitingWindowStoreIterator<>(store.fetch(anchor.key(), from, to), anchor.key(), limit); + return new LimitingWindowStoreIterator<>(store.fetch(anchor.key(), from, to), anchor.key(), maxRecords); } @Override @@ -124,7 +122,7 @@ private static long validateNonNegativeMs(final Duration duration, final String return ms; } - private static final class LimitingWindowStoreIterator implements Iterator> { + private static final class LimitingWindowStoreIterator implements CloseableIterator> { private final WindowStoreIterator inner; private final K key; @@ -142,8 +140,7 @@ private static final class LimitingWindowStoreIterator implements Iterator public boolean hasNext() { if (done) return false; if (count >= limit || !inner.hasNext()) { - inner.close(); - done = true; + close(); return false; } return true; @@ -156,5 +153,13 @@ public Record next() { count++; return new Record<>(key, kv.value, kv.key); } + + @Override + public void close() { + if (!done) { + inner.close(); + done = true; + } + } } } diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java b/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java index dd7476cd4f50c..8ced8fcd3bf9d 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/Range.java @@ -41,17 +41,20 @@ protected Range(final long gracePeriodMs) { /** * Fetch the records that fall within this range for the given anchor record. - * The anchor record itself should be included in the returned iterable. + * The anchor record itself should be included in the returned iterator. * Records should be ordered by their timestamps in ascending order. * + *

The framework guarantees that the returned iterator will be closed after aggregation + * completes, even if the aggregator exits early or throws an exception. + * *

Note: headers are not preserved in the returned records, as they are not stored in the * underlying {@link WindowStore}. Headers are only available on the {@code anchor} record. * * @param anchor the record that triggered the range evaluation * @param store the buffer store holding records for the anchor's group key - * @return an iterable of records that fall within the defined range + * @return a closeable iterator of records that fall within the defined range */ - public abstract Iterable> fetch(Record anchor, ReadOnlyWindowStore store); + public abstract CloseableIterator> fetch(Record anchor, ReadOnlyWindowStore store); /** * @return the grace period in milliseconds. Records arriving after stream time has advanced diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java index 682b2791775be..244c5965b9f41 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java @@ -16,6 +16,7 @@ */ package org.apache.kafka.streams.kstream.internals; +import org.apache.kafka.streams.kstream.CloseableIterator; import org.apache.kafka.streams.kstream.Range; import org.apache.kafka.streams.kstream.RangeAggregator; import org.apache.kafka.streams.processor.api.ContextualProcessor; @@ -83,9 +84,10 @@ public void init(final ProcessorContext context) { @Override public void process(final Record record) { - final Iterable> rangeRecords = range.fetch(record, store); - final VR result = aggregator.apply(record, rangeRecords); - context().forward(record.withValue(result)); + try (final CloseableIterator> it = range.fetch(record, store)) { + final VR result = aggregator.apply(record, () -> it); + context().forward(record.withValue(result)); + } } } } From 4d0381fed3bef111f3ac473efe1b1ee21769a798 Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 15:30:03 +0200 Subject: [PATCH 5/7] Remove KIP working documents from repository KIP docs and diagrams belong on the Confluence wiki, not in the repo. Co-Authored-By: Claude Sonnet 4.6 --- ...gregations+in+the+Kafka+Streams+DSL(7).doc | 2508 ----------------- streams/kips/diagrams/event_count_range.png | Bin 19393 -> 0 bytes streams/kips/diagrams/event_count_range.puml | 76 - streams/kips/diagrams/event_time_range.png | Bin 19542 -> 0 bytes streams/kips/diagrams/event_time_range.puml | 78 - streams/kips/diagrams/processing_flow.png | Bin 29940 -> 0 bytes streams/kips/diagrams/processing_flow.puml | 53 - 7 files changed, 2715 deletions(-) delete mode 100644 streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc delete mode 100644 streams/kips/diagrams/event_count_range.png delete mode 100644 streams/kips/diagrams/event_count_range.puml delete mode 100644 streams/kips/diagrams/event_time_range.png delete mode 100644 streams/kips/diagrams/event_time_range.puml delete mode 100644 streams/kips/diagrams/processing_flow.png delete mode 100644 streams/kips/diagrams/processing_flow.puml diff --git a/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc b/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc deleted file mode 100644 index 7344b09faa307..0000000000000 --- a/streams/kips/KIP-1352_+Ranges+and+Range+Aggregations+in+the+Kafka+Streams+DSL(7).doc +++ /dev/null @@ -1,2508 +0,0 @@ -Date: Mon, 1 Jun 2026 12:58:53 +0000 (UTC) -Message-ID: <1553154272.193579.1780318733416@cwiki-he-fi.apache.org> -Subject: Exported From Confluence -MIME-Version: 1.0 -Content-Type: multipart/related; - boundary="----=_Part_193578_1753426155.1780318733416" - -------=_Part_193578_1753426155.1780318733416 -Content-Type: text/html; charset=UTF-8 -Content-Transfer-Encoding: quoted-printable -Content-Location: file:///C:/exported.html - - - - - KIP-1352: Ranges and Range Aggregations in the Kafka Streams DSL= - - - - - -

KIP-1352: Ranges and Range Aggregations in the Kafka Streams DSL -
-

-
-

-

St= -atus

-

Current state: Under Discussion

-

Discussion thread: link

-

JIRA:

-

Please keep the discussion on the mailing list rather than commenting on= - the wiki (wiki discussions get unwieldy fast).

-

Motivation

-

While the Kafka Streams DSL excels at temporal grouping through Tumbling= -, Hopping, and Sliding windows, these native constructs are fundamentally t= -ime-centric. They group records into absolute time buckets and output conti= -nuously updating KTable changelogs via incremental aggregation= -. Many real-world stream processing use cases require a more dynamic, event= --centric context. Developers frequently need to evaluate a holistic 'range'= - of events relative to the arrival of a specific anchor record (e.g., 'the = -3 events before and 2 events after this specific transaction'). Furthermore= -, these use cases often require the evaluation to be an immutable, point-in= --time calculation rather than an infinitely updating KTable th= -at triggers complex cascading updates when late data arrives.
- Example use cases include calculating time-weighted moving averages in fin= -ancial applications, building context-aware feature vectors for machine lea= -rning anomaly detection, and threshold monitoring. This event-centric, poin= -t-in-time pattern is a standard paradigm in stream processing (similar to t= -he SQL OVER clause with ROWS/RANGE BETWEEN), and = -is natively supported by other frameworks like Apache Flink. It is a highly= - requested feature from the Kafka Streams community, e.g. (1)(2)= - and (3).
- To bridge this gap, this KIP proposes introducing range-based query capabi= -lities to the Kafka Streams DSL. This will empower developers to define dyn= -amic, event-centric contexts and perform safe, non-incremental aggregations= - across those ranges.

-

Public Interfaces

-

The proposed changes to public interfaces include:

- A new `Range` abstract class that both built-in and c= -ustom range definitions must extend, and two built-in implementations:

-
-
abstract Range class -
-
-
public abstra=
-ct class Range<K, V> {
-
-    private final long gracePeriodMs;
-
-    /**
-     * @param gracePeriodMs the grace period in milliseconds. Must not be n=
-egative.
-     */
-    protected Range(final long gracePeriodMs) {
-        this.gracePeriodMs =3D gracePeriodMs;
-    }
-
-=09/**
-     * Fetch the records that fall within this range for the given anchor r=
-ecord.
-     * The anchor record itself should be included in the returned iterator=
-.
-     * Records should be ordered by their timestamps in ascending order.
-     * <p>
-     * The framework guarantees that this iterator will be safely closed af=
-ter=20
-     * the aggregation completes, preventing resource leaks.
-     *
-     * @param anchor the record that triggered the range evaluation
-     * @param store  the buffer store holding records for the anchor's grou=
-p key
-     * @return a closeable iterator of records that fall within the defined=
- range
-     */
-    public abstract CloseableIterator<Record<K, V>> fetch(Recor=
-d<K, V> anchor, ReadOnlyWindowStore<K, V> store);
-
-    /**
-     * @return the grace period in milliseconds. Records arriving after str=
-eam time has advanced
-     * beyond the range's natural boundary plus this value will be dropped.
-     */
-    public long gracePeriodMs() {
-        return gracePeriodMs;
-    }
-
-    /**
-     * The minimum retention the buffer {@link WindowStore} must be configu=
-red with, excluding
-     * the grace period. Implementations should return the oldest a record =
-can be relative to an
-     * anchor's timestamp and still fall within the range (e.g. {@code befo=
-re} for
-     * {@link EventTimeRange}, {@code maxTimeBefore} for {@link EventCountR=
-ange}).
-     *
-     * @return the range-specific retention in milliseconds, excluding grac=
-e period
-     */
-    protected abstract long rangeRetentionMs();
-
-    /**
-     * The minimum retention the buffer {@link WindowStore} must be configu=
-red with to correctly
-     * serve this range, including the grace period. This is what {@code ra=
-ngeOver()} validates
-     * against the {@link Materialized} retention.
-     *
-     * @return the total required retention in milliseconds
-     */
-    public long retentionMs() {
-        return rangeRetentionMs() + gracePeriodMs;
-    }
-}
-
-
-
-
EventTimeRange implementation -
-
-
public final =
-class EventTimeRange<K, V> extends Range<K, V> {
-
-    /**
-     * Create an {@link EventTimeRange} spanning {@code before} time prior =
-to and {@code after} time following
-     * the anchor record's timestamp. Late-arriving records =
-(those arriving after stream time has advanced beyond the anchor's upper ti=
-me boundary) are dropped.
-     * Use {@link #ofTimeBoundsAndGrace(Duration, Duration, Duration)} to t=
-olerate late arrivals.
-     * Use {@link #withMaxRecords(int)} to cap the number of records includ=
-ed.
-     *
-     * @param before the time before the anchor record's timestamp that def=
-ines the start of the range. Must not be negative.
-     * @param after  the time after the anchor record's timestamp that defi=
-nes the end of the range. Must not be negative.
-     * @return a new {@link EventTimeRange} with no grace period
-     * @throws IllegalArgumentException if either duration is negative or c=
-an't be represented as {@code long milliseconds}
-     */
-    public static <K, V> EventTimeRange<K, V> ofTimeBoundsWithN=
-oGrace(final Duration before, final Duration after) {}
-
-    /**
-     * Create an {@link EventTimeRange} spanning {@code before} time prior =
-to and {@code after} time following
-     * the anchor record's timestamp, accepting late records up to {@code g=
-race} beyond the range boundary.
-     * Use {@link #withMaxRecords(int)} to cap the number of records includ=
-ed.
-     *
-     * @param before      the time before the anchor record's timestamp tha=
-t defines the start of the range. Must not be negative.
-     * @param after       the time after the anchor record's timestamp that=
- defines the end of the range. Must not be negative.
-     * @param grace       the grace period to tolerate late-arriving record=
-s. Must not be negative.
-     * @return a new {@link EventTimeRange} with the specified grace period
-     * @throws IllegalArgumentException if any duration is negative or can'=
-t be represented as {@code long milliseconds}
-     */
-    public static <K, V> EventTimeRange<K, V> ofTimeBoundsAndGr=
-ace(final Duration before, final Duration after, final Duration grace) {}
-
-    /**
-     * Cap the number of records included in the range. If more records fal=
-l within the time boundaries,
-     * the newest records are dropped.
-     *
-     * @param maxRecords the maximum number of records to include. Must be =
-positive.
-     * @return this {@link EventTimeRange}
-     * @throws IllegalArgumentException if {@code maxRecords} is not positi=
-ve
-     */
-    public EventTimeRange<K, V> withMaxRecords(final int maxRecords) =
-{}
-}
-
-
-

 

-
-
EventCountRange implementation -
-
-
public final =
-class EventCountRange<K, V> extends Range<K, V> {
-
-    /**
-     * Create an {@link EventCountRange} including a count of {@code before=
-} records prior to, and {@code after} records following,=20
-=09 * the anchor record in event-time order. Late-arriving records (those a=
-rriving after stream time has advanced beyond the anchor's timestamp) are d=
-ropped
-     * Use {@link #ofCountBoundsAndGrace(int, int, Duration, Duration)} to =
-tolerate late arrivals.
-     * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceil=
-ing on the forward direction.
-     *
-     * @param before        the number of records before the anchor record =
-to include. Must not be negative.
-     * @param after         the number of records after the anchor record t=
-o include. Must not be negative.
-     * @param maxTimeBefore the maximum time before the anchor's timestamp =
-to look back. Must not be negative.
-     * @return a new {@link EventCountRange} with no grace period
-     * @throws IllegalArgumentException if any count is negative or the dur=
-ation can't be represented as {@code long milliseconds}
-     */
-    public static <K, V> EventCountRange<K, V> ofCountBoundsWit=
-hNoGrace(final int before, final int after, final Duration maxTimeBefore) {=
-}
-
-    /**
-     * Create an {@link EventCountRange} including a count of {@code before=
-} records prior to, and {@code after} records following,
-     * the anchor record in event-time order, accepting late=
- records up to {@code grace} beyond the range boundary.
-     * {@code maxTimeBefore} sets a required time floor: records older than=
- {@code anchor.timestamp - maxTimeBefore}
-     * are excluded regardless of count.
-     * Use {@link #withMaxTimeAfter(Duration)} to add an optional time ceil=
-ing on the forward direction.
-     *
-     * @param before        the number of records before the anchor record =
-to include. Must not be negative.
-     * @param after         the number of records after the anchor record t=
-o include. Must not be negative.
-     * @param maxTimeBefore the maximum time before the anchor's timestamp =
-to look back. Must not be negative.
-     * @param grace         the grace period to tolerate late-arriving reco=
-rds. Must not be negative.
-     * @return a new {@link EventCountRange} with the specified grace perio=
-d
-     * @throws IllegalArgumentException if any count is negative or any dur=
-ation can't be represented as {@code long milliseconds}
-     */
-    public static <K, V> EventCountRange<K, V> ofCountBoundsAnd=
-Grace(final int before, final int after, final Duration maxTimeBefore, fina=
-l Duration grace) {}
-
-    /**
-     * Set an optional time ceiling on the forward direction. Records newer=
- than
-     * {@code anchor.timestamp + maxTimeAfter} are excluded regardless of c=
-ount.
-     *
-     * @param maxTimeAfter the maximum time after the anchor's timestamp to=
- look forward. Must not be negative.
-     * @return this {@link EventCountRange}
-     * @throws IllegalArgumentException if the duration is negative or can'=
-t be represented as {@code long milliseconds}
-     */
-    public EventCountRange<K, V> withMaxTimeAfter(final Duration maxT=
-imeAfter) {}
-}
-
-
-


Two new methods `rangeOver` in the `KGroupedStream` i= -nterface:

-
-
KGroupedStream -
-
-
public interf=
-ace KGroupedStream<K, V> {
-    // existing methods...
-=09
-=09/**
-     * Create a new {@link RangedKStream} instance with a default internal =
-buffer store.
-     * The store is auto-named, uses the Serdes of this grouped stream, and=
- its retention is set to
-     * {@link Range#retentionMs()} =E2=80=94 the minimum required to serve =
-the range. Use
-     * {@link #rangeOver(Range, Materialized)} to name the store, override =
-Serdes, or increase retention.
-     * <p>
-     * Records with {@code null} key or {@code null} value are dropped and =
-not written to the buffer store.
-     * The {@code dropped-records-total} metric is incremented for each dro=
-pped record.
-     *
-     * @param range the range definition, determining which records are inc=
-luded for each anchor record
-     * @return an instance of {@link RangedKStream}
-     */
-    RangedKStream<K, V> rangeOver(final Range<? super K, ? super V=
-> range);
-
-    /**
-     * Create a new {@link RangedKStream} instance that can be used to perf=
-orm ranged aggregations on the grouped stream.
-     * The range of the aggregation is defined by the provided {@link Range=
-} instance.
-     * Built-in implementations are provided via {@link EventTimeRange} and=
- {@link EventCountRange}.
-     * Custom implementations of {@link Range} can also be provided.
-     * <p>
-     * The {@code materialized} parameter configures the underlying buffer =
-store, which holds the raw records
-     * used by the range definition to fetch records on each trigger. This =
-store is materialized at this step,
-     * not at aggregation time, because the aggregation result is emitted a=
-s a {@link KStream} and not persisted.
-     * <p>
-     * Records with {@code null} key or {@code null} value are dropped and =
-not written to the buffer store.
-     * The {@code dropped-records-total} metric is incremented for each dro=
-pped record.
-     *
-     * @param range        the range definition, determining which records =
-are included for each anchor record
-     * @param materialized the configuration for the underlying buffer stat=
-e store
-     * @return an instance of {@link RangedKStream}
-     * @throws IllegalArgumentException if the retention period specified i=
-n {@code materialized} is smaller than
-     * {@link Range#retentionMs()}.
-     */
-    RangedKStream<K, V> rangeOver(
-        final Range<? super K, ? super V> range,
-        final Materialized<K, V, WindowStore<Bytes, byte[]>> ma=
-terialized
-    );
-}
-
-
-



And a RangedKStream interface:

-
-
RangedKStream -
-
-
public interf=
-ace RangedKStream<K, V> {
-    /**
-     * Perform an aggregation on the records in the range defined for this =
-stream.=20
-     * The aggregation will be triggered for each incoming record and will =
-include all records that fall within the defined range of that record.
-     *
-     * @param aggregator the aggregator function to apply to the records in=
- the range
-     * @param <VR> the type of the aggregated value
-     * @return a {@link KStream} containing the aggregated results for each=
- unmodified key, with the output record's timestamp inherited from the anch=
-or record.
-     */
-    <VR> KStream<K, VR> aggregate(final RangeAggregator<K, V=
-, VR> aggregator);
-
-    /**
-     * Count the number of records in this range by the grouped key and def=
-ined range.
-     *
-     * @return a {@link KStream} that contains records with unmodified keys=
- and {@link Long} values
-     * that represent the current count of records for the defined range
-     */
-    KStream<K, Long> count();
-
-}
-
-
-


-

And a new functional interface for the range aggregator:

-
-
RangeAggregator -
-
-
@FunctionalIn=
-terface
-public interface RangeAggregator<K, V, VR> {
-    /**
-     * Apply the aggregation logic to the records in the defined range for =
-a given key and timestamp.
-     * @param anchor the record that triggered the aggregation
-     * @param rangeRecords a read-only iterable of records that fall within=
- the defined range of the anchor record, including the anchor record itself=
-. The records are ordered by their timestamps in ascending order.
-     * @return the result of the aggregation
-     */
-    VR apply(Record<K,V> anchor, Iterable<Record<K,V>> ra=
-ngeRecords);
-}
-
-
-

Proposed Changes

-

This KIP introduces the Range<K, V> abstract class as= - the primary extension point for defining range boundaries. It provides two= - built-in implementations:

-
    -
  • EventTimeRange: Defines ranges based s= -trictly on event-time durations (e.g., N seconds before and after = -the anchor).

  • -
  • EventCountRange: Defines ranges based = -on strict record counts (e.g., N records before and after), bounde= -d by a required maximum look-back time to ensure safe state store retention= -.

  • -
-

To align with modern Kafka Streams API standards (KIP-633<= -/a>), the grace period for late-arriving records is enforced strictly via s= -tatic factory methods and constructors. Furthermore, users can pass custom = -Range subclasses into rangeOver() to implement ar= -bitrary fetching logic beyond the built-in types.

-


-

Physical topology & state sharing

-

A key architectural design of this KIP is that the buffer store is mater= -ialized at rangeOver() time, not at aggregation time.

-

In the physical topology, rangeOver() injects a dedicated <= -strong>Buffer Processor that owns the WindowStore. Ea= -ch subsequent call to .aggregate() on the resulting Rang= -edKStream introduces an independent Aggregate Processor as a child node. Because the state store is owned by the parent Buffer= - Processor, multiple .aggregate() calls on the same range seam= -lessly share a single underlying RocksDB buffer, completely eliminating dat= -a duplication.

-

Iterator Lifecycle Management: To ensure optimal O(1) memory efficiency without exposing users to resource leaks, Range.= -fetch() returns a CloseableIterator. The internal Aggre= -gate Processor wraps this cursor in a lazy Iterable for the us= -er's RangeAggregator, and mathematically guarantees the cursor= - is closed via a try-with-resources block after the aggregatio= -n completes=E2=80=94even if the user exits the loop early or an exception i= -s thrown.

-

Processing Flow

-

The sequence diagram below illustrates the lifecycle of a single incomin= -g record through this topology:

-

-
    -
  1. Buffer Phase: The Ran= -geStore Processor receives the incoming record, evaluates it against the de= -fined grace period, and drops it if it is late. Valid records are persisted= - to the shared WindowStore and immediately forwarded downstrea= -m.

  2. -
  3. Fetch Phase: The RangeAggregate Processor receives = -the forwarded record (which now acts as the "anchor"). It delegates the fet= -ch operation to the Range implementation, which queries the sh= -ared state store to build the context boundaries.

  4. -
  5. Aggregate Phase: The anchor record and the fetched = -holistic context (Iterable<Record<K, V>>) are pass= -ed to the RangeAggregator. The stateless calculation is perfor= -med, and the final result is forwarded downstream as a pure, append-only KStream record.

  6. -
  7. Cleanup = -Phase: The framework mathematically guarantees that the underlying= - RocksDB cursor is safely closed via a try-with-resources block, even if the use= -r's aggregator exits the loop early or throws an exception.
  8. -
-

Usa= -ge

-


EventTimeRange =E2=80=94 compute a rolling aggregation over a 20-second window= - around each sensor reading.

-


-
-
Computing a rolling aggregate -
-
-
KStream<St=
-ring, SensorReading> readings =3D builder.stream("sensors");
-
-RangedKStream<String, SensorReading> ranged =3D readings
-    .groupByKey()
-    .rangeOver(
-        EventTimeRange.ofTimeBoundsAndGrace(Duration.ofSeconds(20), Duratio=
-n.ofSeconds(0), Duration.ofSeconds(5)),
-        Materialized.<String, SensorReading, WindowStore<Bytes, byte[=
-]>>as("sensor-buffer")
-                    .withRetention(Duration.ofSeconds(25))
-    );
-
-KStream<String, Double> movingAverage =3D ranged.aggregate((anchor, r=
-angeRecords) -> {
-    double sum =3D 0;
-    int count =3D 0;
-    for (Record<String, SensorReading> r : rangeRecords) {
-        sum +=3D r.value().reading();
-        count++;
-    }
-    return sum / count;
-});
-
-// Note that multiple aggregations on 1 buffer are possible
-
-KStream<String, Double> median =3D ranged.aggregate((anchor, rangeRec=
-ords) -> {
-    final List<Double> values =3D new ArrayList<>();
-    for (Record<String, SensorReading> r : rangeRecords) {
-        values.add(r.value().reading());
-    }
-    Collections.sort(values);
-    final int size =3D values.size();
-    return size % 2 =3D=3D 0
-        ? (values.get(size / 2 - 1) + values.get(size / 2)) / 2.0
-        : values.get(size / 2);
-});
-
-
-
-
-


-

EventCountRange =E2=80=94 include the 3 events before and 0 events after each reco= -rd, looking back at most 1 hour:

-


-
-
EventCountRange example -
-
-
KStream<St=
-ring, Long> rangeCounts =3D readings
-    .groupByKey()
-    .rangeOver(
-        EventCountRange.ofCountBoundsAndGrace(3, 0, Duration.ofHours(1), Du=
-ration.ofSeconds(5)),
-        Materialized.<String, SensorReading, WindowStore<Bytes, byte[=
-]>>as("sensor-count-buffer")
-                    .withRetention(Duration.ofHours(1).plusSeconds(5))
-    )
-    .count();
-
-
-



Custom Range =E2=80=94 subclass `Range`= - to implement arbitrary fetch logic. This example groups all records= - that fall within the same calendar hour as the anchor, regardless of how f= -ar apart they are from the anchor itself. This kind of calendar-aligned bou= -ndary is not possible with `EventTimeRange`, which is = -always relative to the anchor's timestamp:

-


-
-
HourAligned custom range -
-
-
public class =
-HourAlignedRange extends Range<String, SensorReading> {
-    private static final long HOUR_MS =3D Duration.ofHours(1).toMillis();
-
-    public HourAlignedRange(final Duration grace) {
-        super(validateMillisecondDuration(grace, "grace"));
-    }
-
-    @Override
-    public CloseableIterator<Record<String, SensorReading>> fet=
-ch(
-            final Record<String, SensorReading> anchor,
-            final ReadOnlyWindowStore<String, SensorReading> store) {
-       =20
-        final long hourStart =3D anchor.timestamp() - (anchor.timestamp() %=
- HOUR_MS);
-        final long hourEnd =3D hourStart + HOUR_MS;
-       =20
-        // Fetch the raw RocksDB iterator
-        final WindowStoreIterator<SensorReading> storeIterator =3D=20
-                store.fetch(anchor.key(), Instant.ofEpochMilli(hourStart), =
-Instant.ofEpochMilli(hourEnd));
-
-        // Return a lazy CloseableIterator that maps the KeyValue to a Reco=
-rd
-        return new CloseableIterator<Record<String, SensorReading>=
->() {
-            @Override
-            public boolean hasNext() { return storeIterator.hasNext(); }
-
-            @Override
-            public Record<String, SensorReading> next() {
-                KeyValue<Long, SensorReading> kv =3D storeIterator.ne=
-xt();
-                return new Record<>(anchor.key(), kv.value, kv.key);
-            }
-
-            @Override
-            public void close() { storeIterator.close(); }
-        };
-    }
-
-    @Override
-    protected long rangeRetentionMs() { return HOUR_MS; }
-}
-
-
-
-


The following illust= -rations demonstrate how the two built-in range types behave:

-

EventTimeRange

-


3D""
<= -br>

-

The diagram above illustrates four events belonging to the same group ke= -y. The RangedKStream buffers these events in the shared state = -store. To support multiple events with the exact same timestamp, the intern= -al WindowStore is configured with retainDuplicates =3D t= -rue, which appends a sequence number to the composite key.

-

After processing the first three events (A, C, D) in order, the state st= -ore looks like this:

-


-
- ---- - - - - - - - - - - - - - - - - - - -
KeyValue
<group-key>-30A
<group-key>-70C
<group-key>-90D
-
-


When an out-of-order= - or late-arriving event (B) arrives at timestamp 50<= -/code>, the processor immediately writes it to the store:

-
- ---- - - - - - - - - - - - - - - - - - - - - - - -
KeyValue
<group-key>-30A
<group-key>-50B
<group-key>-70C
<group-key>-90D
-
-

 

-

To evaluate the range for anchor B (assuming a configur= -ation of before =3D 20 and after =3D 30), the pro= -cessor executes a single highly efficient range query: store.fetch(ke= -y, 30, 80). This returns an iterator containing A, B, and C.

-

The "Forward-Looking" Constraint & maxRecords:<= -/strong> Because aggregations are emitted immediately to a KStream upon record arrival, an in-order record will never see "future" record= -s (since they haven't arrived yet). Therefore, the after param= -eter strictly serves to capture context for out-of-order or late-arriving a= -nchors evaluating against already-buffered newer records. If the fetched ra= -nge exceeds the optional maxRecords parameter, the newest reco= -rds in the iterator are dropped. This guarantees that unneeded records are = -never deserialized, saving CPU cycles.

-

EventCountRange

-


3D"=

-

The diagram above illustrates the same late-arrival scenario, this time = -applying an EventCountRange with before =3D 1 and= - after =3D 1.

-

When the late-arriving anchor event (B at timestamp 50) arrives, it is written to the store. To resolve the count-bas= -ed boundaries, the RangedKStream executes a two-pronged fetch = -strategy:

-
    -
  1. The Backward Fetch: It executes a store.backw= -ardFetch() from the anchor down to anchor.timestamp - maxTimeB= -efore. This iterator yields records descending in time, which the pr= -ocessor limits to the before count (yielding event A).

  2. -
  3. The Forward Fetch: It executes a standard sto= -re.fetch() from the anchor up to the current stream time (or m= -axTimeAfter if configured). This iterator yields records ascending i= -n time, which the processor limits to the after count (yieldin= -g event C).

  4. -
-

To ensure the final Iterable presented to the RangeAg= -gregator remains in strict chronological ascending order, the proces= -sor reverses the bounded backward-fetch results in memory (an O(before) operation) and conc= -atenates it with the anchor and the forward-fetch iterator.

-

Boundary Non-Determinism: Just as with EventTimeR= -ange, the after count strictly applies to out-of-order = -or late-arriving records looking at newer, already-buffered data. Note = -on duplicates: Because retainDuplicates =3D true uses phy= -sical sequence numbers, if multiple records share the exact same timestamp = -at the exact cut-off boundary of the before or after count, the specific records included in the iterator are technically no= -n-deterministic, aligning with standard Kafka Streams windowing behavior. -

Retention Period

-

To guarantee that context is safely preserved for out-of-order and late-= -arriving records, the buffer WindowStore must be configured wi= -th a retention period of at least Range.retentionMs(), which i= -s computed as rangeRetentionMs() + gracePeriodMs(). The = -rangeOver() method internally validates this against the user-provid= -ed Materialized configuration and throws an IllegalArgum= -entException during topology initialization if the retention is too = -small.

-

The rangeRetentionMs() bounds for the built-in types are: -

    -
  • EventTimeRange: The before duration.

  • -
  • EventCountRange: The maxTimeBefo= -re duration.

  • -
-

Custom subclasses must implement rangeRetentionMs() to math= -ematically return the absolute maximum age a record can have relative to an= - anchor's timestamp and still legally fall within the custom range.

-

Extendability

-

The Range<K, V> abstract class serves as the primary = -extension point. Users can subclass it to implement custom range logic and = -pass the result directly to rangeOver().

-

The following concepts are explicitly out of scope for this KIP but are = -natural candidates for future follow-up work:

-
    -
  • Additional built-in range types: Other range defini= -tions beyond EventTimeRange and EventCountRange c= -an be added as further subclasses of Range in the future witho= -ut requiring any overarching API changes.

  • -
  • rangeOver on plain KStream: Ranges without prior grouping would require a completely different buffe= -ring strategy (such as a global or partition-wide state store) since there = -is no specific group key to tightly scope the physical store.

  • -
  • rangeOver on CoGroupedKStream: Co-grouped ranges would require a highly complex shared multi-stream = -buffer store and a completely revised aggregator interface to handle record= -s from heterogeneous value types. This is deferred accordingly.

  • -
-

Performance Considerations

-

Because range aggregations are dynamically evaluated upon the arrival of= - every anchor record, performance will scale relative to the density and si= -ze of the fetched ranges.

-
    -
  • Memory Footprint: The API strictly bounds memory us= -age by passing a lazy Iterable (backed by a Closeab= -leIterator) to the RangeAggregator. This ensures that p= -rocessing exceptionally large ranges does not load the entire dataset into = -the JVM heap, preventing OOM errors and Garbage Collection spikes.

  • -
  • CPU & I/O Overhead: Evaluating ranges requires = -querying the underlying state store. For an EventTimeRange, ex= -ceptionally wide time boundaries combined with a high (or omitted) ma= -xRecords cap will increase RocksDB read operations and deserializati= -on overhead per anchor record.

  • -
  • Tuning: Users operating on high-throughput streams = -are highly encouraged to tune maxRecords (for time ranges) and= - maxTimeBefore (for count ranges) to the tightest business req= -uirements possible to minimize unnecessary deserialization.

  • -
-

Compatibility, Deprecation, and Migration= - Plan

-

The proposed changes are backward compatible as they introduce new inter= -faces and methods without modifying existing ones.
- There is, however possible confusion with the existing windowing functiona= -lity, since the method names for aggregation are the same but the semantics= - and return types are different. This distinction needs to be emphasized in= - the documentation.

-

= -Test Plan

-

Range Definition Unit Tests

-

Mirrors SessionWindowsTest and SlidingWindowsTest= -.

-
    -
  • Parameter Validation: Verify that before, after, and maxTimeBefore are not negative; maxRecords is strictly positive; and grace is not n= -egative.

  • -
  • Duration Conversion: IllegalArgumentException= - is thrown for durations that cannot be safely represented as millis= -econds.

  • -
  • State Resolution: gracePeriodMs() corr= -ectly returns the value passed during construction.

  • -
  • Retention Math: retentionMs() correctl= -y equals rangeRetentionMs() + gracePeriodMs().

  • -
  • Built-in Bounds: EventTimeRange.rangeRetentio= -nMs() equals before in milliseconds. EventCountRa= -nge.rangeRetentionMs() equals maxTimeBefore in millisec= -onds.

  • -
  • Fluent Chaining: withMaxRecords() and = -withMaxTimeAfter() correctly return their concrete subtypes to= - maintain fluent chaining.

  • -
  • Builder Validation: rangeOver() throws= - IllegalArgumentException if the Materialized ret= -ention is smaller than range.retentionMs().

  • -

  • -
  • Lambda Support: Verify that RangeAggregator can be cleanly expressed as a Java lambda expression.

  • -
-

Topology & Integration Tests

-

Mirrors TimeWindowedKStreamIntegrationTest.

-
    -
  • EventTimeRange End-to-End: Records pro= -duce the correct aggregated output per anchor; output is written to a downs= -tream Kafka topic with the unmodified key, aggregated value, and the anchor= -'s original timestamp.

  • -
  • Grace Period & Late Data: Late records arriving= - within the configured grace period produce updated output; records arrivin= -g past the grace period are correctly dropped.

  • -
  • Range Capping: EventTimeRange with withMaxRecords strictly caps the output and drops the newest reco= -rds when the range exceeds the configured limit.

  • -
  • EventCountRange End-to-End: Correct be= -fore/after counts are evaluated and included per anchor.

  • -
  • Count Time Floors/Ceilings: EventCountRange with maxTimeBefore strictly excludes records beyond the = -time floor regardless of count. EventCountRange with wit= -hMaxTimeAfter strictly excludes records newer than anchor.time= -stamp + maxTimeAfter regardless of count.

  • -
  • Iterator Lifecycle Safety: Verify that the underlyi= -ng CloseableIterator is successfully closed by the framework a= -fter a successful aggregation, and explicitly verify it is closed = -if the user's RangeAggregator throws a RuntimeException<= -/code>.

  • -
  • Null Handling: Records with a null key= - or null value are dropped, and the dropped-records-tota= -l metric is successfully incremented.

  • -
  • count(): count() operator= - end-to-end test emits the correct long value per anchor.

  • -
  • Custom Subclasses: A custom Range subc= -lass is correctly integrated, materialized, and fetched via rangeOver= -().

  • -
  • State Restoration: After a topology restart, the sh= -ared buffer store is successfully restored from its changelog topic and ran= -ge aggregations resume correctly.

  • -
  • Caching Behavior: Output is verified to be identica= -l with caching enabled vs. disabled. This ensures that Range.fetch()<= -/code> correctly reads newly written records in the exact same processing s= -tep, regardless of whether they have been flushed to the physical RocksDB s= -tore yet.

  • -
-


-

Rejected Alternatives

-
    -
  • Naming (bufferedBy vs. rangeOver):= - Using .bufferedBy() alongside EventTimeBuffer<= -/code> or EventCountBuffer was rejected. The term "buffer" is = -already heavily overloaded within Kafka and Kafka Streams internals (e.g., = -Suppress buffers, RecordCollector buffers). Furth= -ermore, the term "range" tightly aligns with industry-standard streaming SQ= -L semantics (such as Flink's RANGE OVER or standard SQL = -ROWS BETWEEN).

  • -
  • Implementation as a New Window Type: Implementing t= -his directly within the existing .windowedBy() API was rejecte= -d for two structural reasons:

    -
      -
    • Semantics: Range aggregations fundamentally emit an append-= -only KStream and do not receive retroactive updates when late = -data arrives. Standard window aggregations are incremental and result in a = -continuously updating KTable.

    • -
    • Materialization Lifecycle: Standard windows only require st= -ate store materialization at the aggregation step. Ranges require a materia= -lized buffer store immediately upon definition to physically execute the lo= -ok-back/look-forward queries on the raw records, even before an aggregation= - is applied.

    • -
  • -
  • Retroactive Updates for Past Ranges (Emitting a KTable= -): When late data arrives, we do not emit retroactive updat= -es for previously evaluated ranges. Returning an updating KTable instead of an append-only KStream was rejected because over= -lapping event-centric ranges mean a single late-arriving record mathematica= -lly alters the context of N surrounding anchors. Emitting retroact= -ive updates for all affected past anchors would cause exponential write amp= -lification and severe RocksDB read-thrashing.

  • -
-
- - -------=_Part_193578_1753426155.1780318733416 -Content-Type: application/octet-stream -Content-Transfer-Encoding: base64 -Content-Location: file:///C:/151acf64aca303d1cf241f52fe1da23e8083a8be796a8142cc93909b0bbd38b6 - -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 -------=_Part_193578_1753426155.1780318733416 -Content-Type: application/octet-stream -Content-Transfer-Encoding: base64 -Content-Location: file:///C:/bc34eb2ecd2f26896103871cf3e4e94f033a91428b2a28ce648ef6b8d59a1b28 - -iVBORw0KGgoAAAANSUhEUgAAAyEAAAF0CAMAAAAD7MasAAAAYFBMVEUAAAAPDw8WFhYYGBgjIyMp -KSk0NDQ/Pz9AQEBLS0tTU1NbW1tjY2NtbW1ycnJ5eXmAgICLi4uRkZGbm5ugoKCurq63t7e/v7/A -wMDPz8/T09Pb29vi4uLt7e309PT///8kSl/dAAAAKnRFWHRjb3B5bGVmdABHZW5lcmF0ZWQgYnkg -aHR0cHM6Ly9wbGFudHVtbC5jb212zsofAAAER2lUWHRwbGFudHVtbAABAAAAeJzdV21v4kYQ/u5f -MeVLiZpQG+LkLrqreD1dpCSHatp+qPphsQfYZtl11+sL9MR/76zNiw1c7iCcWhUJxI6fnXme2ZmB -bSaGaZNOhfOdmeAUIRaMSycJmUDwXGAJ+C7EfIYicRzDDZl7H1GaAZ/iz0yOEaoXdTeBIY6UxnP4 -oUELNjKozxzne+jiiEsENsPECZUMeYJQ8Wq5D7BOoJqcVWyc3mCDqNegr1WIScLluAzrF2CNGgSG -GaRPCg7VdjoaUeAMFwQb3CUFnHJjMIKMcwb4kBrL8FZyw5nIHTlN1+kNgCdwGwl0+puvQWC/Vj7B -ouLQzrWdPFxcXEBLa/6RvHg30IKqedtwz6ydnrbVDEZaTaHug1HQ8CEk6agTwBkLjZiDktBwnWbd -X8artCpLEvbbOnCrEHq1bDb8IskC9RLH5qW/8tiu0NL3i9AtCfUb6FgJ17sSrjIJ13slXJOEq7WE -zlpCpyjhnFyXVGTL5vVXqSjTbNxA19L0vF2enpsR9by9TGmH03y1ptpdU+1uUT2nCEW2nfOuZfv6 -CLaXN9CG6l1r0INua9A6s8z9NfEMhdQ3hsr7ree7tYKWy1yLv9FiNRDGaXr1+kpFG3633v8oS2jn -KsqFk5utMqmod4bKGIqjRllHAL0GE8xbGAx1nrYdk9mVpASyOBYcLYnMJmz7McvfdmrEDHNQRmA9 -E7/Gq2KqyjVJwpwmYe3wcZrrObR8vUnMXOBPFEMrZeBTFqzNwsexVqmMOkooDU8TbnJq75Q0uW0o -CLS2PTAaHb+ijphkmfH9PEZ9x+XjCp3mDsiE2w6sbTDh4aOkQQReZrtneswl+LRY0DtSYTq1oywn -GLLYcDqefLXtwc2si+xzRKoowV8GTpBFXwXMh/MKZ8UH/G8EKpHnd9q3VNFq6z2b8Wk6/Y1HZkJz -yc0Qb35cHoeTPHIZM82mtmjV050SgscqLqZuA9l/Xpvn9OvAUmF2DmoHca+kSmIWYrTGdlSqOeoC -9o6PUJDIwGgqyvGcVCVK8KgA6VOR8ZDHTJo+iyJbsjQMNs8D/CtFGaJ1ZfPVVpqSv19cMGGRerIu -RkwkRVm/JNhGwwKbMjCaKqyYttBQr5h5lu7PFXSb6XIx7hLZV/M7iVwUD8OGYToPvL23DJxlmFWG -/NLTDtehwKgzoVW4KuFnqKzOCeinN+JpAq/L7gSjanw2Fy+XngVpGaP5MDX4Jcaf9RCQXFSGJsgx -Lt5tOv7Ane83I+DQnXbaUU88ZpsLI68IuqX/SX1yxsZYgi0rb++x7Oy3P3PmJfspOaH9g3a0h3Qo -eHjU9gd1XFF8GP5JnPPi3SnSRWnsbLJ7gnLO//Me1jPl/as6bp3ES+ckXnon8XJ7Ei8PL/BC07/D -EsydDQ4bFqe5dv0XL1qHX6z+xQvRN77IfPvLx//oZuDV6m79qlb/B70NNZ9Zy/8WAABHKElEQVR4 -2u1dh5raPNMdudNhezZ5v//+L+stSbawNPeqX3I3GGPRFjY6T8JSfDSjMuoaof8DDg6OrRA+WwEO -josGtxAOjiZwC+HgaAK3EA6OJnAL4eBoArcQDo4mcAvh4GgCtxAOjiZwC+HgaAK3EA6OJnAL4eBo -ArcQDo4mcAvh4GgCtxAOjiZwC+HgaAK3EA6OJnAL4eBoArcQDo4mcAv5OsD4szW4JrXaQvpsBVJ4 -Uf4WqXuG4YflT6JsfJDXH4waICSKR40ZfvEAOg/r0oIgRLIiZ59D3wslRUFbg1ksAYaT7WLshU9K -4nh0VNVjLUW5U6jt+6AoDIWGQa3lglTYz8dN/CPgUixk6hfvGZ1L4Ffy8kT+L6zy1917Wne1r78K -DeTB4IgxmxMDkW6r3y2XqV7aTWIj81X8R7jXtsayOTK0NmCKbgu8Z+kpjJME8d6D+G/3DrUMIldr -SpiT5qpv5DgQvT8dMwbHwBfoZWGX4JhFw599HC8wWyft0uNazehk6jqvccv1mhgIRK/GnmLm9OXw -zDSWy6KqcrI30SzWz35JDASs31HL8HK1PJJHu0gPpLZwlwfH4ci4lDbkFOixd9dQUnSN/r49vQ2Q -rgNM6lJZjPuE4eKGlDhaFkXJI8LnvbbVcwUBLX3flIPrCd0jvdPyF4IYW4w+JC9zGrwaEjPx9Xa9 -OTa10O0LaV4HF1ZpX5KFDJJkR0A6uyDE/Q2bJK5KK2Df9QNR1uLco41/N7JdrPRIanpe/B0C6Y7m -x5SUNu0O4porSOovl5RFVSDPa5pAWhw7inmwFirFaAzRglT64BALiVw/jLAgqknPpyo1Vs7zydCB -dqIU+hHbRG9J7lXiZJOflc1OmzjqCdikTZVL/tMaWv6GXFJAIiN+2HXDUCSarZuL7QWypiTvS/Js -GooQBKKaR0pVCq0h9HB3m4YNkIddkmAfJklJjMChtnLXgzebWEycVYEdBoIoaaUWMvD8KARR7Mhl -taS4/SANPeqsqUGzWpbJ+EYlJVHtG4BX43OXu2ZckoUIWUr77+TlL1IO/Tfy5jspN/O09zGYIMD0 -13Hck188KrCMe8tTOvCgfFqmUBKQSx6UnwFmpJQObGIuuvTNpx1iWD7ReFdCzZW4oRZCC8PMzNLo -ltjImlRSFqZuxunekxf7I5koWNyV2x8a2KaB3EhEIOqTGhsIKaQBDRGoKnljkae9Dy95Dn2vdM+8 -3/H3E1qhV+RNaQGM3umEAF6kPbbejZBq/X1hAvrfNg23Ixk1o65J5y8AaHKIpFgPbaqyCtFHNk65 -7+acl3S2ZK6S3MjV6szod6QDJfy1poZBtB1oszCJ1JBkiHFhFnJJTZprxPChS7WiyU8zhVQu+HfW -PdcX6ZtF3HJHrQcMetyFDn4lXemQ9o9rQqWIA65UHMF7NklWkopf3aqAt/Sh4LU8pUZaNLRZZ8uJ -RdJoqrGRxH+BNlbkg//iZbpU+ydu8v3c3i4P3lIDAfMl++qX2aThdlADwaFDE6efaJZrST7g3/nE -SN0Aw33blhMbauh5+soKndVrpdzZcEltiJMMDScy9EjVa/YTCyF16pwU685QMklerQapxpJAi4sX -SF2BFvQBAqUxcEGi0460A0B5NHPrQgXsxdYSV4pCV5ECl+gQ2X1YkwpLampyR7CSUhtQm7vpeguP -1OLFzBWdQehsG1lENL5aaiFi+p8ESxsqcUJEG+sdeEX1KWfZWZM38EmE0ABkMOjvA80j9bW/SGtj -3KRhM6aJcXXoNHOYaghCRNU0aQJMlMg3gjJD7siCT3OSJFKuljw0CIf0vNAONXokNW15p1rnxCVZ -SIE+sRAnEvyANvKAaVflRoKRSaoXN9H4oQMOneUNpF6HWshkxwCXjDDi50ljbtGeRyjWhbpMZ1KG -1Npu4yDJ0IPkdhpKITU2XuUb0S/5jRbm/gA6tFvjFGJpfZhmuDFP/qJ8hYbWsiR6iYXQ9oQKxLGR -kKGNrPYmerWJ798m88IuRlV5Y8eiRgXJkKZ/QyycxERPLURRRRxt0zCDHjeoJDLxOAwey5KVEdUs -TLWM1YxiLQWVNCojs1Skn+kTuP+bPOxJhVqqTSxk0KlPKNSRUZjUbzSkAC4KF2UhKHuNx7/mgJbC -PkrKJy1OAeTpR3JGo3VZ22lHkgEanahS0/YhEutCTdW4ix9BgWn7SfhZXV6SShlF9zsecFtu8mQp -sKhI4mhd1XgcM8kGGrgwcY384P4SFXUw3EyfDrWBQN4iLzZJ2qvrL6nEpJgnpX0bI0WQ1QJhWI5x -DO9lVGmOEi2phBekqP1yL1JwTdfHsBFEU0IRi85A06pdF/BsuCQLGRVjtP4st5Ak1yHrnZbST2hr -HilQJc+2hZpNo4H5UZvHidQ4c7vV0HIbiPIKmIa7JYnjDsxwkD1ALYTyhaR0E6ptL8fDDVo8yA7l -LfJitWh4seH55RH5FkYzbm8goFMhy64CUpiW+igOX4unq7HrrvqTIrT5akeIzWqI0L7SOxMuyUJK -6BELcZ0gGbslvZ30l9Jog3XlIHs+sZS6UPujFeljhO+P5L03JS9iR3LtulDiEoir38rymqCkV5Lm -eHU4Er3TLkZSJ8RhBUravSL/7meJxeK5Vj+4ErfJQxW1KhK3MDIkK0BEcL+T6xTPYSm3dNDmKtko -CSKcqPk4TZsdQ84NeUUNRFElfWtXqVkNDOzZemJcqIUIXZItdLxA69i4lOzY6ICZ07UuVFG6ofNF -Dh3jUsNQn0j1addlGqJNiVWUXyVIx7Nr8YC8LyGXB6DJ/o27pH8Sl0ZbSfrlJENwt+s6Hl3FAXPD -QuK+u7RNnkjV8uW0cawMedcZKzqJUASfqLcMQc1qDd9P3mV1upRKTzXA8jefaEkFmbmF0ESju8fo -3Hpt8d+meIoAcuO8FFyShXjJxAkdvMLASrKGliGZVvpvdyTlsLGcbMydxjnhdlgkwfZQ73+Rr5dq -Jx790FKzZfJRcajxdIN00UQl+q4UGoq/8L7nT2X17hqMGS0tI0RrZ0mJq4NVR1mmg4hf2oiOgF/c -mh5HPBWkoG3yYrVWpLlaQD6nDLUaxgF1oQHeVOyrMrjx5B4xpT5pH/BsEsUayDALxuTXeEdloaWX -PIo3xhLxym13e0Jl0QNuIQ2w0/4M3bmY9HKTlRG4JR0e5z9FDGpLK6KPvquhfM8mrj5U6Y42XdNv -ErUOIxTjSrJmQDKmyw1eNryFgUGem85lukW4lKa067I5cRQkyzjJxFn3Hoa0OvidiKelyDAURfDp -mLZq97qDY3ObbJUHk990lK96fvJYCWsMqlVnx7xqmG+SkklEZI1wdD0JjMbrRVLF0K5oSWcQPmyg -M1fVRJPIDysXgh/bFE/gpGl2QbikFcMKkhWIZDm6F//xbH/7o9hhXmjaEmqXfh294T6tgW1jW7Bq -dekX3dOUDB2nWuvTTU6+Bzug5ruchHSFwDNWcYdlrZL3YwMZaFvlgULVCugEdjqg2KZhPAxqm1RC -vHn/Ji/R3SR3AnNlktCUYi6KdrewaW4OtmMC3WC6TfEYmLbIW7c3fw4u20LENLVuntI34qCmhhmP -46zL54rbjvW2hDqhnXN/Lj3QUFE841oX4OjbUFN6d/Rn+qD8Y5x2D7RywYubhJ2ajB+SGGjPVKNB -WrXLN2v9dSVeVryLC+QWeTB6Stjiw/pyXJVBDFBtrq3Vflo40Oh7rJ78nGyrFG9oa91N2cLosRTd -G/qEcKOtJ5qW7HRB2xWnMDGdlG+Xe+cCupqbPoMAi1sPN/nRngefmkMNhO1nmjwpnqj6FeYjbsA+ -3chXnbP6j2T6c4tVYuyHcl5H4yCMpDq1wkAWypwNebFMunNR3CIlZfi/4vXPHQiDCItSOajQE3IN -cEi3V651lbAXicqWwJAgNSqOf5LEfLqwXtb1WMil4WegykJANx/D94bRHF0gUC/uWBDos3hT52Vh -RgY52uPh4RwVlzRSvza46d7Fm6ZEHFsBuPNJqwDPCIdhFHIuWPSw2c3h4RwXFzsOuRpkR1S3ANE+ -+2rXSvPZ4YLU+pjImeDQScSby9q2CLyXtT8iLwgxEqWdUy909UzstgnyzwZdqxUuzWy5hXBwNIP3 -sjg4msAthIOjCdxCODiawC2Eg6MJ3EI4OJrALYSDowncQjg4msAthIOjCRdtIdd98QTHl0Cy6e7v -z1aDg+OiUGw1kYovlsybPU/MmErjC9SKM/4ARqnJuOBeludc3P5sjj8PJQthP9t1WsZ8jC5QK874 -wxilwz90G7eF5eoRytS/t1y7bT/f+I3zQ8n5AX3V1uFW2cpIQ1/CsNjv/B6gx+Jkph32axgtwBmc -cURG5Xgctqax9+TSN+/J3x1XNf6T0+aZY4+70NvpXxJ/RN3SgYDJ72heHDG7vHN5HH8iyhYSuzXf -QHxdTevhihRBiEFEIPQ12HVebB4JZXuUxjM98/MBusjsI46D4/goWwgS6mp9NT5abxhwo1APnfdi -sHADqTMWgil0PUfoD+GF9Jd8MXboRl4+DHgk5dxawZ2wcFB/Fah37tLvDYksQ/dBGactXKjDML4F -0nI8Ub6RYLAK5um1ynj5ABwcn49S4+Cof9V5v/DnBJHiugap2F0sBr/MSA70KXX7PTdDf+5g6j7T -ddd4Ib381HedqRfZP9/cSF8CzD48GbmvaU/MTbxiub+XnhjQC//IxyyUZebTueaqix3gDM44IqNk -IW79E+GKIFJkMmh3QxjAHAs/nofx6WvoPNGbXNFfpGz/7/sWCXdPIkS3TxLh+zqMv31ProEB6hE3 -9upELO/2+/9ihyEaRInH11CfNGvVAM7gjCMydnsDopc7EkMazELHonfyuRD9G9+UREq3pqozCPL7 -k+pAGKpFGgfNiGhbQx0hZ76evcSJsWrA9EMZKYk2Xjz8mA8uzL8xx5+KNS/MNZCT2rw3A9OCLqIz -u8ktf8nPLa65yY0Hx/d25kLTOeJesMLYfStdqAqek7dIFzU3zhl/HmNtPSTFuy/mru9iT/cCEnqm -EXuaVhw8UAEbUsUD/k47ocZAmgnhrnD1rMQ9NbD6I99agp3c6BcPP5LFwnWtWoIzOOOIjHIvy30j -lbxhde7A94sS7/4H8XpI3yRP04sdHXiRRA+XRYih9Yp3u95UNcf+RwmDdBFEAZ9e02VNVcnPLhKI -55bTxUIOjs9HeaEDx/dvVW6kLI0uNCm5rEB7UCBwsVpmkmG20+YK0/sBwm4gpC2ckrhFV5BreuqE -GoWRNH58sZDjYpB4lPubza8cDpC4NjIPUMuhNXUXnr3/MITv8W0SUeIH3JzGnr9169K8G3P8YSgZ -RHk9pDUfyUmJLjGkdgbigKgUT06EKL6NSUzuEwtm8X2TeDmpMFjBGZxxRMbu9ZAGHMoQbmTfLD7O -RYXaxrJyAexFzY1zxp/HSEfq8YmRBbOYIzCm0/Knf+nLD+ZQOThOhdIZQ4d5yuw0jOrFzxc1N84Z -fx6j1Mu6lFloxMw4h1ac8YcyLvgULgfHBYBbCAdHE+p3Lrqv53BVhR5rO4MNwjnjlAyOGGtrgyUL -KUbR7tvjOa7sdd8e1LpvtwvnjFMyOOogjunrkr6amYXUp+3xIWlv2kYb1iicM07J4MgRG0SCkoW4 -qYWcLxVrMnGHcM44JYMjQ72FpD2uc6biRibuFM4Zp2RwpKi3kPMbyEYmthDOGadkcCTY0oZQnDsV -K5nYSjhnnJLBEWO7hZw/FUuZ2FI4Z5ySwUGx1UL2TsXQ9hUwfQmxU/NMbC28kWF7SPScSLo0GSEW -Ti6DNR4H5NoXR8lCKushjAZi0m25YrwT15uiXjSF532W6NWHWGyt8KkJk+Fuxk96wPE2Prq78Cay -oXe1tjJWc/IidG9PKQPw3KAOMO5OKOMfTPJCGW2I3mAcKdf+GJTPh7C2IKJG66jDdSCZ6NYbCLaS -g7q7GJpM/ov7yQBQxMjQTyrjVceyiq3TxkOUQvvF2ck4Vq79KSi1IQFrF0vT/o36I9Ik6UVnIJyT -nsGE0eUuycTxok64RSpG35d3Mm71GTySR2du4YHFWAVCZyLslAHCN1IBR6eUYbkwGtMjlCeNx2gQ -vgTvf9XJmMwLxtFy7Q9B0YZga7TfGGS1CIVsrw9+MZWu/+YzBqEOF7XCDRjItY1ILQO/OhhlRV3/ -iPrImO2WAXg5xWLvlDJcEEi/Vno4pQwK8RYir0bGaL7JOEKu/RkoLAQ9LNnPMlLo0P2RXWpgBajf -FcFmDMJdTeqEhw50e2C2ZVghPH/LTvCuoKN1wNopg5SPhQnIP6WMALb2nI4YDwKZOrLclLG83WQc -Idf+DJR9Lj7sN5MVQOEt0U9uHAnZQqC9ZLlGOLENOyB2orVj+CDlHTIcUHf1gPMDi9tkkKrhCS/t -jx8nlCFuTZBjxiPOClBqZYgbjMNz7Q9BeTZxTxOR/cJVlgjoWSD5yRRAPIysE24kTrANrR1DKeUx -EqLhiDop2iWDPKqAaoeRcDoZqh6thqSzvz6Xddx4AEQzEJR2Mg7PtT8FlfWQ2u2g2+HOfAi9buA6 -vhGhEV7BQNGxEzhzkcXQ0nmWTeH+Em5HfeQFQ7SDMbMi8ERtCabrQEe1PbkXuZ4f6NmNp1tlgOtg -RzdBGe7S6gAZih06tjX3RyeUsQTPWIToQdol40i59rVRWg+p+suKZwZbIyAdV9+GgQRWli/io+Lr -OmYws2IickO4AWJfVYewPk26ybB92h9DYwj8rMc/GYK1tNVdMuJfPbG/Poo+roxHYucO9E4qA0Jf -6D5qO2UcJ9f+HJR8Lsb11F6r6kHZAyMO27pfjFEW2E54AwNHZdEhTvW6BBkhlk4ugy11D8m1r46S -z8X18yGMHa0EQrkXhASWJdpKtrUS3sRAFdGCgHYyziZDEE4vgy11D8i1L4+m8yF7mcjeWKvXWgjn -jFMyOBI0nQ85azpudBV2CueMUzI4UjScD4FzpmNNX3qHcM44JYMjQ7OFnC0dawebjcI545QMjhwl -g6i/P4T7y/oTGRwxqC2UDKJkIZfi2ZozOOOzGfU37FzUrQ2cwRmXweCz4BwcTShZyEXd2sAZnHEZ -jAu8P4QzOOOCGLyXxcHRBG4hHBxN4BbCwdGEve5TvzgGZmZcZjw44/IY5duiOTg41lG6LXo5YiVf -CmMqjRkZlxkPzrgURqnF+ArrIZ4zYmRcZjw44xIZX2E9ZD5GjIzLjAdnXCKjekeRHwidqg/Q2ImC -oO7lHdyfQn+w7UcncyqoRk2PpQjeQZvkn1Ym3BR1gB3299GOg6MNyhYyp86p5vJj6Uh/7GkMAN3s -Uwgjr8FJ2TxzDngnebt9mc08qdSTGpje7FsR0mQXm4Njb6zdTyE54K85PkNyGOIPRWEJNYHyBNtP -60gRhBhEBELjYwksG25L/UF098vTs2ZHF7lHZo7ToXx/iPqkgvuy7vmVFOCpCa7yFqkdHd3BygiQ -MiadHLwyQqQMO3hp+aI6kQCbjoOl3hAsxw4l9Tacw7BrrWBgeOQxImDhCWpIGg0a7D3AhwGPpE8X -pI/1TU++QQtHG9L7LhYelgaDdB//HDT6J7AcF0mjDsh9Y5FaCF6uu7r6/NMFnPGFGOWLIGk/Rozd -I69BMQGDG7krUKi1CJHz8qjBq0vKpyN1XjxQPMv9jt5tQvfwcDUHQfD9CXYhgNClW/Ed9y/kvAKE -ZFyzfhFB6TFinxgs7ztY70Qzf4aHsY+iKADay4teA5BC1ybG1jei9NKEpbbeurnMqcUZnLEV6/2b -BZQ8HseIzGCVDP2RJoieCd374Beef9NdkB5FPdI9eFLtt9Ds2KA8Cp4NOqAnOVzlo/thTzew3V0C -jLEw36rKsDd38KC/sANf/gDtEX57q8RXqA9Ae1J2AIMJoneK0Lk6L7aQUH9mTRsODgaUfb+T/3MT -+mvOM316q9eIVtTaQ+xsugeSZnu0MzaSYAjk51f6XCBKgfev1BmDGuBfglZMwfaUvkGaCQ/EkdNw -R0VP6TrkpWdDgCJw/iHNSZho5SUu1shbXZf7sdUQWbGe88GGq8CLmk3njGtnlCxEi68N3LjRT1CR -3MnDIxU4iv/RW5u09JsONQYZ7mekv6Q7zxMwIbKs0n0D8SibPqQ13uKCSlKkWCRGGuTbrqS7eQj+ -PLgpGJ7zfSOUi5pN54xrZ5R7WcG7B/1xSAYT7774mH0rV0bCpGvjdMjIQUKKBcYYPI/8VcgIxhZC -7yl0F74fWrc3nm6BszZAkMJwqe3eMJZYG+AbASIjsRmF2CMxMlf84bszHF8EEyYXZawtFnJwHBtl -CyEGEl/nct/1/WjL85rirbwgJL2rvh4uDdHrT/RwsZKD8Eb4WKgoAFlczDWBdIzUNbczw3c6ymmH -8SL8VwFPSMYhxBhcMhDxZrIS4aTfheMJBb5YyHFqlM+H1DhS2qyhHzrgBGgyAPGxA6GHFIH8jdxQ -kgU5tEyh9wAqts2os3GTRfdekzqddkdSRjciaZ5QutIhiEDvqpVE37TlIe0GGvReHL5YyHF67OEv -C/tCWvgdKW2DAizSco8DIR434xDX3F8bGZpkrgL0v3ZioiAWE2tlTuGJNh1RGMuB4Gd8zbpuPdYQ -L2o2nTOuknGYvyykZK2DK2XesOVkLC4nE0tIqjEQiOa//50F0HafspCIibXqaTCl/T4hkYOnIA/p -YmFtE3JR3pY449oZZzyFK3QVSejcMe/kp7iV0bL4tIpk2tXaXCzk4Dg2ymcMW4+jc7AzbHu6pwx/ -Vf72hb78qCVc1Gw6Z1w7o3TG8OqA62d6L2o2nTOunXHNvk74UgjH6XHNFsLBcXpwC+HgaEL5fEjR -Nfs6N+ycA5d5X86FpBV6xHVd/r3VqI+Wg44XrbUxefl8SB4T9+2RfXKAHfVXgjcJZ2ecA+eIx9Wm -lfvW1eq+3VeN+mg5+smiVdfLaneZ/eFQH942120ahbMzvko8rjat1AfzqGrUR0s/XbQ27lM/ZyrW -3Du5Qzg746vE42rTSlLej6rGWaLVeJ/6OVNxI7Y7hbMzvko8rjat5COrcY5oNd0Wfd5UXIttC+Hs -jK8Sj6tNq2OrcYZoNVjIuVOxEttWwtkZXyUeV5tWx1bj9NHabiHnT8VSbFsKZ2d8lXhcbVodW42T -R6veQhxpf3Gh7Stg+tIeG0Hy2LYWzs5ohO0h0XOiXV7tDtQqxAITo1arT0urA/K3hRrY8n2/xT5t -1/V9QdgZ3qHKQsVCKushjKlo0m26YrzB1puiXjSF532W6NWHWGyt8KkZH5ViYLTEz4C83MZneBfe -RDb0Lvvmt/Za4bmBAXXvdjF2arVdxj+Y5IUy2hB9QFodKX9r1Xij3gakYeIWkIQMQo9E4Sb5bHxA -5wHgV+r24//+iVcDx6OVlaXOZrSOqWwF5VBYU1HUqDEfrkM8xb2lcon9DzEw2kKTyX9xbzpjPF51 -LKvY2snYrVVDzEUptF8cFsYOHCt/69UQFBTMMtc34vdvpWdJltsRjRBJCiE+pUdeJQFuvve2hndU -ZcsotSECaypq2r9Rf0SaJL3oDIRz0jOYMHrSJbEdL+qEU+9xvi8zMNriVp/BIwl85kq5W21jFQid -yQE1zzatLBdGYwhmOxkttNoe89EgfAne/zpeWh0tf2vV0O7dl9z/Jir3JkO6JGgOSEqE/8FdLGsc -Ny5i5bqbh7fJvAjvuMqWUIjEi9F+JW61CIVsUwx+MZWu/+YzBqEO64UbMJBrG5GtDDbgVwejLJf0 -j6iPjNkh4W3RygWB9Gulh5aMZq0aYi7eUn/7x06rI+RvnRr+cg5arVoGyIO1XF+9vr4G6+GN5pvR -OpayBQoLQQ9L9tO+FDp0f2RO3qwA9bsi2IxBuKtJnfDQgW4PTAYGI6wQnr9lQ8QVdLQOWIeEt0Wr -AEQWRrNWTTGXAbx2MhhwhPytU8NfuDRlamDSXPcqBTtwHGfdQZW7vN2M1rGULVD2SvqwX8c+KHn6 -9ZMbR3beB7IWVyJYrhFuxr56wxq3FNsYjPCh8DmBg9hZGMb7T4Fs00rcmiC1jEatGmMeACjtZDDg -8PytVUObRB/O/H7zQWIbPmkGzPLdlOM+rNcyNDxxI1pHUraEcv9vTxOR/aImEAE9CyQ/mdOuVrhB -q1DyR2vNYIRSSj4kREPSjw0OM5BarVQ9Wg1Jr/iuHaNJq8aYRzMy/j16Wh2cv/VqEE2loK4HZCQ3 -nxllCxHEneEdU9kyKushNZvCGiM98yH0uoHr+EaERngFA0XHTuDMRZbcSCckNoX7S7gd9ZEXDFFL -RnvMrAg8UVuC6TrQUW1P7kWu5wc6+62qu7VS7NCxrbk/2sXYqdV2GUvwjEWINvz4HZBWR8rfWjXM -ILSXHvTjYTRexc41l+Cauo5WeHDTV21MHiQie3L2A3W+YHtdpT5ax1S2sh5S9ZdVu7V4KwLSw/Nt -GEhgZYkvPiq+rmOWvMhn7DaEGyD2VXUI69Ok2xntYfu0B4fGEPhZ9TQZgrW0926VmrR6JHbuQG8n -Y5dWjTEPfaH7qO2U0R7Hyd9takRuII3XHJ5Fvu+T8cZQVftiZfxJf4gawzuislWUfC7G9dReE+eB -WKrkcYhY1hnKAtsJZ2c0AEdlZUMs7tvJ2qVViKX2jC1afVZaHZK/bdQI/xPv27jn8aOVFa8YNoV3 -sLIUJZ+L6+dD9uq5COVihQSWFYVK/FoJZ2c0AVWUFYRjGEitVhup0sSo1+rT0uqA/G2lBl5hw2rR -u53NfaC9rMbwDlU2RtP5kIPL3P5p10o4O+OrxONq02qnGkjt9XotNJO7vZ4mnCNaTedDzpqOGy3u -TuHsjK8Sj6tNq91qIFmW2+glkueEs0Sr0ULOmI41XdIdwtkZXyUeV5tWx1bjLNFqtpCzpWPt0LFR -ODvjHDhHPK42rY6txnmiVTKI+vtDuL+sS4vH1abVdfrLKs1lrc/2MoEzOONrMupv2OHg4NhAecM9 -M5kzOOPLM0oWclG3NnAGZ1wGg/eyODiawC2Eg6MJ3EI4OJpQshCHmcwZnPHlGXvcp36BDMzMuMx4 -cMblMdIVQ2YBHBxfGcWKYem2aId5yuxSGFNpzMi4zHhwxqUwSk3GV1gP8ZwRI+My48EZl8j4CnNZ -8zG/WZ3jVCjvGcZOEILcrRY3bAdYlFU6Gl77AerKpeOHoqSRX9q5nbKWMOxF8byCsGbVnmnDqGdZ -Lrpfd0u6MuGm2DVgh/3PTkWOr4uyhfyOvRcJj2WXS9ZH7GJCfoZ/oH9b+sF5hbt15x0QpK4jf4gv -rvR9t3T8EXV74L7HH4TKxn//Nw3P+CCv6872YGB6s8IT8nwCHBynQnU9ROmKEC1LPwfTCPV68mYh -zRhVvAfQ6atrs68NjHkkJFYnqQJE87Un7/43sAGe/9pwkobuwNOzD7rYaZTRApzBGVtRvj9kSH14 -/VMp3iaGERkGuya8kPbEF+9nTogFdaR4M4AFHozwknyrTlKvXh5oDwDhQvjwIHyBe9Fe+lge9Iml -wSCyugPHKT0OoQ7DxET7o+hfaoZzV3gAU4d70v2ClSERC/lQJ2DoPihjDRYOul36j0juG4vkqgnA -y3WH0S7zsI0zOGMryr2sPriBQ/8UoA7vPE1VVexSH2AiGWcIEFr2j9CnPlJ9ePFA8Sz3O0oDc146 -qnYLHgbCwKSThMD7CMbkA/lKASMsPU5XbVJhvpMI9lxiMQFhkhEReCgi1kq+memgBO7rN8V34Vds -wH0jSi9NWGotLi/i4NgXZc/WpFWg5bRb+rkjhtiyQL2V//oX+jcAE0WMZiZ2Ow9vcCt2dA+eVPst -NOOSLnZscF2QbjpPL570DGgO0jf04i2pz0nUQbIelh8nBian/r5Mk6hSFjxBS3iW4M0RfiBfhzFt -Y1bU760i4URXL7aQUH9ej9JFnS7gjGtnlCxEowbhewYuOWBG3+n9YuC+/qC9IVLzix8OLaHxRBbq -0FbglT6XuhN+0Jek7g/evtM75BAEEXQE6HngEUMYETOZVh/3cn/eshLZwc/vZadq5B9tacgLEbJY -piz0lOodePE8wXyw4VPvombTOePaGVUPEUN6lZ5ZspBQvLnx7QUOvaQv4/8mDQUuPKoSa+nQciyn -nwaDwF36YA2zX2NLyYc21cdLE8a9EegzMOvPDhOWKm3oGsNzWsyYcXDsj1KpCz8GquCEtNS+++Jj -/N3SGXdkyXLjOa8omWHS7NRCyGfFAoUUazsZb9sf464keX72tBwPNegcWToXVn0cFDtzZY/pbTpE -sgBkfLF+7QoxToFYrV++PCZMLsrgi4UcJ0a5XraT23r69O7AbHrXfweRjJdHEoih9YrJSGQmOylx -bsljPVys5CBMF/Ci2YyUcVD7ILnRL3gYrtzfyIWumAY3qD6ugB8lxrKkvSihB10Lfm3oqGqO/Y8S -Bt1i/YUM+2k7xBcLOU6N0nqIFxdbNLop/dzRYtfj4zHAjQROoAyQn7jql8YCdiLhsQORG6Z3Jild -BFGE+vcAY5WYGXXt77nQz7ttwqT8OG0G6HV1STMg9r6J0CWjdamyvkE7aPcDhN1AKA2uDEC0Dald -LLyo2XTOuHZGxV8WDrC4MfAl36VmFFBP8zjIb3IP9En1AYIwyq4LiqLYTb0P5Zvfl6PK4x+G8H1t -Z1iEqxqkfo3CsKxZ8DO+Zl23Hmui9Pneljjj2hl/b+x+T4Bq7mUuPSGtPSMJm0EU5Tj1Sy9vDw9g -YkUfazfZbdlKWbFcPAV5WLdYyMFxbHyuvyzhRvZNJkaMVSTTzSpbFgsvajadM66dcdVnDH/sdb8Q -B8cu/F17xvDqcMC9zhwcLXHNJ6i4gXCcHtdsIRwcpwf3l8UZnNGE8vmQy79h5zJxjnhcbVqhx9qT -GBes+NqYvPZuK/ftkX36jB31F3yfSfiVxeNq08p969Z+e/GKZ6hbD9n/ano2qA9vm57vziX8yuJx -tWmlPljXqXiGGn9Z51O/JtuvKe3OGo+rTaurVTzF5lzWOdXfSL2rSrvzxuNq0+pqFU+wYSHnVX8t -9a4r7c4cj6tNq6tVPMa6hZxb/UrqXVnanTseV5tWV6s4xdp6yPnVL6XetaXd2eNxtWl1tYoTiLHX -9CV9NbX91MeOh+IthIEdSuw7QSTtTYvnnE+RdqHt16iELV88+maCFvFwXSxtDyDAQvZYtOWxY6SV -7wTy9l9DvD1hrDSfj5Y4eclpiShEteXrAMW2YFlcJlDJir3Sna793MRp7nwAPLJ7nSAVDBV7CgNZ -zQGe0yyfmvGpK4pwCjBmPnNzaDyinxF009MwwU8Q/ir/GHyQJlwYx27ydBM2DpYdLa1eHRCyFYr/ -QvhWPkCAqWMb1C08efyDSR2qjFJZsxC0x9aCditelJzNBKE5RxQt+8GN/ehod7ktFModothOlNoQ -CPdK94XXT81CGWIP99hDiCuYk7S+7/juNq0DMDHfMPXTKAwVyzu6heyKx8pWnvppHbhyASulqjz6 -5YMqhBCnXmfgBpK6l4ydcBfo2yRVwtFjj04FXi2Q5SAoUmYJohgGRlL9w6Br+b2DWpGq4kXJ2UwQ -1wEFIk8sHl8ssKiGQaFAodxBitWivg1B+6W7B72svhN6urdHCLSCGS9OYCBRWuQoLEwdVMiZotMo -PP7hkuZ4hNDJU5seGzNLi82LiLa+jhV/QGLH9faTsRMhKHmrEStR8kpguTAaQzArPz8ahC/Be1K7 -I0VxPLmdnFrFJ/OK4qWSs5EgJI++kVai8BcdLkF7QHhW7mZlyh2m2A4UjTl+G+2T7tivnNMNoj3C -AHU430v4DhQe66jvh4Ec+43INN3Llg+Jh1cklBvADVilpHJjnxlaVlybtDssrUpKYJMoEdllJQRS -dUprR5vFW1KXHyPV1FFV8XLJ2UgQesZ6isWSdxvqhxPQbdUQMuVOk50xCgtBD0v2+xKx8Q5aYSFi -B96NPWzEXd3sIXwHgtUMBtmH0IFuD4oTvwOYr4K9gt0zHtaHm/f/iR4q6W+Vzh8H1QFhV/Q+rBOk -lbvQC7fMNkZ9rVRpECVqm1UZ8uLXR8Z873xyl7clxaslZyNByAMLE5BfUq52D2Gq3EGKNaO8L6tu -688OBB+2XB4j3SvOB3vBI93T/h7Cd8Ce+4O8S00S3/Zit3UJhgN/bu0X7n7x+DDQU7lPsRDKBUKE -SqqhJ2RMT5BWq2V0l0+lGCAsMLGTkhJhHSkAyDpm6l20WsJ+IIp3S4pXS85GgpA0+PbUCT5KykFd -wUqVO0SxHSivh+xhItJdx38tfX7zOrfMHcJ4/LaPfTajeyPreaqRqnJlQVFjrnR50t0v3P3icTfA -L1nrSroT7iqkXQtzlfRyVLAJy8tuUIl+48Edu4ydGI2EaVZJkP5VSMfHJvmzwokS0Sqe6Mu+SJ6b -gZBZiPsujMaMMrcoXik5mwlCRz2qCmGU6aLQoTnguQ+rVdGyZModoNguVM6HpFNyDEC97j9OkAdC -6ug75oWGdIKDXfgOiAP5VU8bEd8HYrmmbmVn23WYdPYPeo94dDqea6U9HNKnmAC8YmP8gZNe/9jE -Lxp2M5XsSLnZQ8ZOkFH60tAyJdAjvbDF6JtzJZ4G7628uSmQIpx9QbDUA4xyh00G9A8xkLLilZKz -mSCk8L9gDxRhleoiDVfWf4ob9bw5yjqKhXL7K7YT1fK8R+WE5FLrF2Q+tNjTbr9eXjOUvNtggNhX -1SHgrGcVwLGvHdkZDyVLqMgCoozaBdPDcmIU4jcNHDe/TWubdoenVa4ESZIuUaIPLqnW0nrksY88 -B3qQf0HqPF/oFmtce6daneJFyalJEMrxxP5DoctkIoR2pIkO9LMyVih3/OzMUb0/ZJ/KSfUNMVmh -xoEOEhu5soZ09FZEkIJVJ+70TWLvkFJ2fMx3QDzyZO/ueKi61Y2lCokad3ek35AVRdInD7KF4TC0 -tp1sOzitFPBsOQ48uQiyT+pjJ7u5Rbi9Demqf/7F/yrcIHD3LIj1iuclpyZBhlkjlutCvordeNow -XFduf8VaYP18CHvlNBDMX8kQi/wVWNu6yhrS0VuREZr/8je/Dn7N0JEXDFvEoyv7v2fVr5zSdCZI -mc3Of3vSYJN/lLSSevjt91qwuJQWorT2RQkvr7i316rDFsWLklOfIBvKCXQHkdvbqD32VqwNSn57 -66LTLgEiJc7c0BNYq7V1YcdeWccu1mr2ZTlIPa4roXbx8AOxWtUFtfuJvNz19ynSKnJRdWcQXt+n -hbds3HKwslfDu13xrORsT5BNXWo22u2r2HaUDKK86yRBvsmsNSQ5aYkEmbWPtZHJ7MKbgSS5xhSQ -vMcOyyPEQ5TXMlKoHbVtPHbUtELrubRhpdu2AWb5fLzE2QhxI0E2dRE3s25PxRpQMoiaoI8/Yt6G -mlrwfMKvLB5Xm1ZXq3iKOn9Z54pAbTfhqlLvfPG42rRy38bXqXiGWn9Z6sMn+ss6k/Ari8fVphV6 -rPPddsmKt/GXBer/WoR0qptQqsI//7aVS47HNaRVrXfDxhJ2UfH43PtDOIMzLp1R4y+rPTiDM748 -g/t+5+BoArcQDo4mcAvh4GgCvz+EMzijCSULYV/D4QzO+PKMS+5lXeyaEscfhKu+LZqD40S4itui -p9KpDlZycDSj1GRcbi/Lc47vFZGDgxWXayHzMb8vnePzsb5z0cZQcZKTej6Q1096zVx60DnxHIJh -syy/RmrirSOKp9UE5jN9dthnZHBwnAAlC3E0AH0G8FepXcHvyd8NT+k+9XT3y5e+AyyW8GPjJJgX -pV+5SQjotpfJaIf5pNCKDZzBGUdkVNdD3NnmE0gi2OiM3Tw9kfahnQxRFQFPo1RGO+iZZ5yLmhvn -jD+PUellhW8gbjimVBPfkQsH9VeBeucu/d5QAtNBjx8hhC/QMQDe0KiDl5YvqhMS4MIMlbLxDEbw -4oKnebMgXIk90hy9RYpg4t5IgGDuIDWEQQ8KPlC3xg/AwXEBqPjLeotGkb7+hE9dZY4E36UL9fZP -UvR1fAu+i6hLYeyCHFLnwiG8eKB4lvsdTc1aC1UgcEGIogUegxvRB1ZoHP2O4rEOGfvkfPrwUstd -xTJHiTM444iMkoVoH15nvNnNCldAXRuRlzvpPYxu5WlgJVcDPb140jMgYQXfRaR78KTab6GpmiDf -Kv+VGhHT9QPoCqA+qeD9Bpsuc0g36A1bYz2CHjET8kXOpwP0UH/OtWKOO2dwxhEZJQsxDehaPqnS -qz5mYh9f1EBQD1QL+qAZUTKHRS+VS/8h2mrEjooD8rFfNVCfBEqvJxP1KXVDGW8mkTugOgFthkZS -7PMt59OX+eD4199wcOyDkjGQgho7o/+oTlzJk+J9w5QtKfcd+rMcwfo1FD1lDtSJMel+aaqRD3QE -yAyswge6WPj9s9OFgyNByUIUuhDiBdCR4d0X87sdMC3SQsk2ymaS9qUiERQLFGJZtkAHFt3KrkN5 -GK6i9ydk01G/Ha6Jnw/jFZOcD3yxkOOCULIQgfqZn+n0fgPfL4YR7n+w7eZYBNEveCBBvEqDgR4u -VnIQ3vTF0Pp3bV/uxPG8jzvVdqnH+zIGK2wli5I5X60uFl7U3Dhn/HmMHedDmutyWaVjjF4XQhcL -jx2I3FCS0b0AuIOqIZDvTGOsgIuqi/jit66k9qkaOb9YLNyqVTM4gzOOyFjfdXIT7xXJZ5KKTb/x -RSZ3d9kj8UfxKfZXf49DQQD5AQJMnd2rf/liYXhaHIIU36b6LdCTwv9XHqIzkPEsHn3k/HyxkIPj -87F2fwgb1NQTcdYwZIFt9VQvbZT9ZTws0dSCv7ZYeFFz45zx5zHK6yHMUo7A6LoRiJ1h6ZtisfDz -tOIMzsiQWsinHjIM3EX544/P1IWDo4rLO2OI+UwvxwXh8k5QcQPhuCRwf1mcwRlN4P6yOIMzmlB/ -f4jb8v6TRauntjHqb41ZF34Yg12ry4zH1aYVeqz9urmENchoF61D4rH9hp1Csvv2yD7BzI76y1yb -hLMzzoFzxONq08p9G9d+u68a9dESTxet0l24ubEc+8rmbai9zLVRODvjq8TjatNK0j6OqkZ9tD6O -HK3SXbibt0WfMRVrYrtDODvjq8TjatPq2GqcJVqNFnLOVNyI7U7h7IyvEo+rTatjq3GOaDVZyHlT -cS22LYSzM75KPK42rY6txhmiVW8hjnQica1j20o4O+OrxONq0+rYapw+WvUWYmqfM5LLY9tSODvj -q8TjatPq2GqcPFr1FuJq+4sLbV8B05f22DKSxzYXTgKrCQhb2bGTTcZBsD0kek4kHRjMplbYISHn -KYTTxdnADtPYNcajVqs1Ri4gwBu7h1IxR0qrA/K3Nqqui1nSG4fZZiQriXFjtA5VFioWUlkPYUxF -c0pexHgrrjdFvWgKz/ts81IfYrG58NUc8oCmJkzSrfHhND8MvM7YAz+pT5Xb+LTvwpvIht5l30C9 -Ix50EesmOSqD5wYG1KXnz8D5AHjU6uOxU6sKIxUQfDgAwniQpR2SuiOUizkgrY6Uv5uKRz+j2PlN -jP9C+FY67+BR11BIuy15A3FmPoB8EyfFLATtsS7pjqlsBeX71FlTUdSoMR+uA4mtW4rrCu7+Ss9g -YQvASJ+S/rqDVT1jD2hEgnZkl0NrWum4/9cgefuqY1nFyYF8+qVez2ihVZmRCIh+O6DKkZ09ISN/ -+V4Ss39aHSt/NxWPlO936fdOWGRxFgMZ2yW/bc6rjzTRTxwcfP8mOH5dtI6qbBmHzAlo2r9Rn9Tq -S73oDIRz0jOYMB6jJbEdLzLhUQi97AcLU29bqbkIvWkUijWMfXCrz4DURf7MlXLnK8YqEDqTA2qe -qlYe9NKwLBdGYwhmWTx0r57RRqsSIxGwiGhb4aRO+kF4Jg2JvRoWYvZOq6Pl77oaIXTyAE36/6by -5L386pQcEs5A/CbCKkkBpCiOJ6fhTeZFtI6rbAlFecBvo/1K3GoRCtmmGPxiKl3/zWdNveF8VBSs -ohI1YCCXahgJvDrG/sCvDkZZZugfUR8Zs0PCK2uF/bz6cUkniGifnS6WIIjqGO20yhmpABc6pOrU -SoVsqMY7V3MxB6bVEfJ3TQ2vqJixCTdQNIBJlOcuKk6dkmgOSYkYZv5v8kKgjmqidSxlCxQWgh6W -7Dsk4whB90eWP1aA+l0RbMYg3NVtKjxYzWCQfR060O3FtUyCAcxXwTrjEFghPOed4BUpap3swpT9 -UGiFjXfIZySDqo89sQPvRrQ9Hs1apYxcQLC5+1SOC1Eu5sC0OkL+VqJqfbhCfkeNjVFfW+tm6SsM -RbEO1rbXkvpiHsfGXdZE61jKFigJxw/7deyD0p08fnLjSMgWAu3fSYlwe05dxacgtmEHxE6y7uUw -0OcwXGMcAlIL514ncAAGySl8wBnHklbBB8j5rlZxLUHuXxxHUbbGo1GrjJELEKNgM0eUkphD0+rw -/K0mzkeEnvKK2QBhgamdlJNHspbzTpYEYuqpNoN6977yH5LwxI1oHUnZEsrjkNF+JiL7RQxEQM8C -yU/mtMsmJ7qg62JmIgbEY3Mjs5CVLve764xDoJSSDwnRcJT4Hd4TZa2kO9N+zUxE1SMyMAjn2ej0 -zet05e3xaNIqZyiZANW3XRU8c+K6QtITMZzET0Ei5uC0Ojh/1xLnztZfvqcmQvpX1HM6Nvu59vFI -fQm+bIYyHUIIUqD3BTBx+rP7Lgy6W4vAcZQto7IeUrtvsiHSMx9Crxu4jm9EaIRXMFB07ATOXGTJ -jXSGIBEuqLLpp51Qfwm3oz7ygmFaPqbRXV9YZ+yHmRWBJ2pLMF0HOqrtyb3I9fxAX+59v2hFK6R0 -l0E/LQeKHTq2NffToMMZfItvrduIx06tSoxOKkDVwXCNhdCb6XLHdbC9NKFzk4s5IK2OlL/rimsd -J5DTTqRho6d+3w+jPtU+ThwDXHMFaCK82L24GpHNSHcXRuoxCpbeYCJuJt0xla2sh5RmbtR0Cq01 -AtLD820YSGBliS8+Kr6uM60G5VNoqfCiBjVA7KvqEHDWC097D+uMfWD7tAeHxhD42RhhMgRrae/d -Kq1rheSid/BI7NzJp+jIyEGoj8curSqMVID4TQPHJYMOJ+mAepE8vs/FHJJWx8nfmsRR8pQxoKuq -ah/cINU+joGLtCfRw4nJQOdewnagZBkTF4LNaB1R2SpQfKLq7/xc1V4T54FY6prgELGsM5QFJu9/ -BpNOnU8635nFK0KbjAOAo7KyIRb37WRtavVh9EaF88kwyykcLM140ashHlu0WmMYuYCAJLn70r8t -BxGLOU5aHZK/dYoHU/lOrAaypj3BcnGXz/rHTj0TVYI3/Cw3RetgZSkKg9jY27tXz6XsGZ70nFlW -FCrxSztajq33NuMV/LLRWK1lHABUUVYQjmEgqVaS5elS/mWeKuabL9xKzfGo12qd0XczATRw07kv -s2Ix4XHS6oD8rVfc842gV3lkTXuCJb7L36Ncg1869AaNReBQZRPhRS9rvQ058w63dWHxZ+xirWZf -loNo572W8emo18qNlE1LDz1BhX3iscm4RyUBYbU7QcVcSFrVqCEEYsWz5rr2kLSLm3CwIp4hWg1t -yBGq5QPSLhGOJLmmKkeyhLYxzqQuYzxAkmtqMEGWYJ941DDee1ohYK22JGIuJK3q1Oiu763ZrOvr -a3+SpOeIVsP5kNMIbJt2O4WzM75KPK42rY6txlmitf18yIkEto7rDuHsjHPgHPG42rRy37qDjS8P -UKM+WuLHcaNVv/u9gPrA7H1oH9S7PmoSzs44B84Rj6tNK/RY591wfzXqoxUeMVpr/rJKI/WLuhuL -MzjjExmlkXr5fAirEM7gjK/PuDzf7xwclwRuIRwcBFuHMZ++lMDx5+BTbzrbhZtB/fclC/n88RFn -fHHGBV11to6/51BvIvz+EM64OMan4HGu137PxyEcHBTqFhOpng9hDZQzOOMEjM/BFhPh6yGccXGM -T0K9ifBeFgdHiloT4RbCwZGhzkT4egjHZyGyodNYQ2MnkHZ4TAydHWGwQX18XZ/05eshnHFmxu/U -Z2J3OK34tN4kvpIiG9jSTe2v0RRGKnjTzE34cbBpImV/WcySOIMz2BlC7GBP3N3B10GeINOW63/F -NvSBPAHyrnDaIV/wnymV2Tfey+I4Mx6pOxvq7cWNvVx1R6QMLs1A7I6Ts9crI8RCdyx82BAuVQuC -F/QI1tJH2kSCFxiE9kijbqYB5quBYkEXZp6CTGGkzZzOSM4DMwxhsoS7qRuC1BuB/wF9I5YWzhyk -hvAglMUWy/1/r53xLd5e5tw4Z3xlxgzAwHfwboHsr6LEH5DrIxzqwYOHIXLFCLCLQJ+RByzvO7Eq -8nXcDfKoa6Bu5EIEvuvS+2WECEx8nwcWuuBgGexIiPwFGpIn3UTaqw+JI+SK2G0oWchlzo1zxldm -DLtz1wbXgid1uTCSojqYSPjVdeDpt9+7QR+m/ERaCxiP3JeADmmQFjtBQc+/4K4jpFtapBtvAdpw -4TiVwGRJhFtNCH5HzjCXZvvQvbGIbVbFbgPvZXF8InpKz40i0hy80e3nQVwa5bkd0d3oKPYbhuiK -hI9hST04U1eNo9Q3o1B2KyZ3lAV01a4T4Tww8vs38pP47uJ0c3sijbQg49gRX1XsNnAL4fhU0EEA -MQgFpe8BfodCL6webicPSLSkis3h1AQG3gtImhOUn8r+rD25BdxCOD4dZHTd6wOYsQF4Iek9rUoW -guMHlLvCX1WGaGdgQO8aekZv5fsV6MTA0N18cgv4eghnfDqjI/sfK8kLu7Q2lxBeWMWNQhIEr/DY -M01H9f2HUnEl5Xph1zh4zgNLPioA0+olOx0xNIwNsVvBz4dwxicykr4ReuiAb4fxjREgjAXPKgp+ -XwXHhdshCi1fEqHUJ7oRQitKvyiV8VJg9FutC5YnV6Q9diW1sy52K3gvi+P8+B6/qnQNok8vzpEe -6E12aUkdDtO7XZ/pi/gUYTJen0zCiA6vS6cUB4NAEOIvqCd9YSOwUXLnyn2UXP1ZSHN742hG2qqq -2G3g6yGccRGMclVd7Tql3RxRbORs/2HDAbAZD3ImzUHUhfXZc+OcwRlnwUCOQOoqLZ/mvSyOPw3d -LsvT/HwIB0cTeBvC8flwQrF1X8z3oHfkUyGNKMlxmMmcwRlHYSynq9bBWdMP8KZTj1mPPcHXQzjj -4hg7IU8mRzoVshu8l8VxbuCFFUrdMcALdF1HHcYdLPwKvQEYBqKLG+DMw0hQRwo9+gEWGgyLN/HD -9FRIfmbENx1P1G63h30Q+HoIZ5yb8eaA4C/9e4hPbNgevQIcEHLCAaz8ZJ7J9xCElvMDxUc/YK4p -+Rv6c3wqJDszEr5ESAjSPey1YR8Evh7CGWdmuA5MhoulRVfOOyNTD7241PedwBP89JC49qTCfBX5 -5Bfl3nsHp/wmRXZmxI/grhuumsI+BLyXxXFmkDF2H/pLoLulNFXQIYhLcRdhU4B0TktaTOl2XHqq -Q5QkxbOHpTcJ8jMjpI16F9VJU9iHgFsIx5kR0S2EKLuxI98VhbqmKVLnDBRTCzqCWXDwxpvizIgy -XuLQsv9C28M+BNxCOM4Mmbo/cTeLXt8Mw8xCbBhOvMxCAi99Nn+TBpOcGXF7A9c0sdNpCPsA8PMh -nHFmRkcM37sWyOsBaWII2Z3Pimvi9FCH+0JK/KD8JoGQnRnxFh05SLc7bgv7APD1EM44MwM9KJER -qQ/x++yF/u8VBjCWQj1d8cAeoFu1/CYlZWdGZMFeedq9tDXsw8B7WRznhvItCiRaNdMTG1J2wIP6 -XhCyPYXa9yA7t6HdR2L5DT32EZ/1yM6MKN0wkreHfSj4eghnnJ8h1M0whRZtRTIUBROJ629ypGdG -KkdHhINnr6rg6yGccSEMv19zk2BHUtbenBu8l8VxIdDqTGm48ebc4BbCcW6YoLDvO6xseN+1+90N -hE6LMFuBWwjHuTGF0s5cfdvtB2uoXIOw604Ew5ALC0muUdgb/HwIZ3wqw7PbhVjZ8M60+x3bdsis -dAF+fwhnfAYj296up7cf1F2P4H/AjeE9zj1N1bWOBV3dhEeEX6Gv0t3vxf72hRmpEYwTOcGHm0xt -pdcipNcoiNl+elbwXhbHZyDb3h4ktx/UXo8QufCCAfuuh0GiG96VGdhd24XbePd7vr99ptNtKqmP -0uh3BIkP0vRahEF6jUK2n55VU74ewhmfwci2t49DevtB/fUIQLcl4thxohB3qlQpsOieEjldpk/2 -t8s6yHfoVxqwHsFoOKNburJrEZJrFPxiPz0b+HoIZ3wGI9vejuLbD+qvRyC4jwu09pDuXekt7eRy -tjTkeH87eTNQ8pGGB2ic7DXJrkVIrlEo7adnA+9lcXwGqtvbd16PkKK3jJZReeW9cttBGlS6wF69 -FmFjP31rcAvh+AyUtrfjXdcjFJAVbwna2uYTUoQNxS8+BYFEW4rytQjR2n56FnAL4fgM5Nvb49sP -HhquR6ig50G5CYkhdGz3d/6pa8BPmdpLfi1Cco1CaT89G/h6CGecn4GK7e3x7Qdbr0dApVf6h1gH -6uXfpfvb7way3M+KcmdAmgw6eimuRYivUSjtp2cDXw/hjHMz6J70fHt7cvtB7fUIarJ5Pdkan3wQ -/6/4kO9v95QBXuUe42/GyW0I+bUI6TUKxX56NvBeFsfnIC95wtpnWL8eYRfcBX0dZMOT/DaE4loE -aV3APnpe1Ww6Z3xpBiM6UYjFztG2Kq6Br4dwxsUxGKGc9OQIvx2Bg6MJ3EI4OJrALYSDowl8PYQz -Lo5xUeDrIZxxPsbfrNwLAF8P4Tgb2rqvWo5YQz4ho9TLusy5cc7gjE9llCzkMufGOYMzPpXB57I4 -OJrALYSDowncQjg4msDXQziDM5rA7w/hDM5oAu9lcXA0ga+HcAZnNIGvh3AGZzSB97I4OJrALYSD -owncQjg4mlDa23uNW5M5OPZE243GUulp5rt1/+YMzrhWRuOvpeB4L4uDowncQjg4msAthIOjCdxC -ODiagJiHOBwcfxJ4G8LB0YTCQqJoH37Q+skoZGb4mJHBrtU+jDA6uYyAmcGcuhRpnrNnPQMjYGcE -p9eqPSNbMcTvDmj37S9YCH/faQD2O8L37Zxu/wyQdKOxMH57QjQZsjAA3Jf7LgvjjV5L9KSyyFjo -uHPPIMN9oa93PQYZ5gJF4z5LPIxlBPcMqbu0n/I8b5f1MaNKbMMwZgDdOxaGNSWl8lFk0gregmcW -GR69s0p7bMXILMT0/oKfZh9aYr6K/3yMh6uPH60Y/SHMlhoLo/so6PMhCwOCN8SmFYwHtB1lYCyM -JxmzyFD/IlXVL5FFxvxOc957qD3D/3joLD++t5UR/Yfp5u80z9tkfcqoEtswhEfV/zVQWRgPGv5l -jBgYJMEciUkrQD/o5VWtCn3Wy7J7CPXa3/M2+kGJfjiAQei3YyDUcdkYAiCRiRG9TiQ2rQAJgsDC -wKuxTNKWRQaRoKsaAyMkPSYpwgwMR+rAMPDbMoTvY/onzfM2WZ8yqsQ2jK4aX3/OwNA0kr4SCwN0 -+4ZNqzhTULtCn1lISIqWFEJbCPGNVyGRgoTWLENjY7i/57dMjHd6oSqbjOXPV4eF4WP9n3+XjDEP -9AkLQ5y8vr/fCCwM0p9GQtCaIcb3NaV53irrE0aV2IpBujS+xsaY/av2WBj28lFg1Ar//DXH7Rj5 -OCR/YQAGFtbMf2JjyGNz9szAWJAKFELMImOCwHj7wcAIhXvJfVXZYj7vKiwxx9ZYXFp9BkbX+CmH -kRAxaZXlOXvWMzH817HCxugpC7PXnhFN7yDCocggQ/4mBB8wacXILEQkqRuKwAZKgqgla+o9iWwM -oaP94zMwcPgK/hJUBhkyGYksWWSIkQSqGCgs8XCt70xp5ZCqpPevw5JWD0EUvMsBi1Z5nrNnPQvD -fRsNGYuXqvpWrz0Di3OIwtdnBhlIAannttMq62V1TIwt1qvgFNEAQ2h1R1b0Ej4KmIlhYjCQyMCY -PD8/yzcDBgbEMmQGhizq4IZdFhkwH0hMaSVHLgRYYpGBpWg5EJi0yvOcPesZGObrzYC06gwMK4DI -lhgYIsn2G/mZRYbjExlKO0a2ps442zvXMZKeGeYj4/k1uO+2Z4S/Q4RumeZuCX6NWRj4J7MM5x2E -EdNMrDWNpzUYGCsdYDhgYbzbMJi0lhH9hwHd9hhme1NGldiGEU+ny88MjMUS4Q6TVjSNF+1me1PG -at5aRmnXSbTX+nrAfL1Ce0Z2H/aFyUjb5VNqxSwjwiKzDMjznD3rT8oIhJNrhcPWMvi+LA6OJvB9 -WRwcTeAWwsHRBG4hHBxN4BbCwdEEbiEcHE34f+msq5D7bgldAAAAAElFTkSuQmCC -------=_Part_193578_1753426155.1780318733416 -Content-Type: application/octet-stream -Content-Transfer-Encoding: base64 -Content-Location: file:///C:/ac26b66d09f1da9844ed51cee98225008008dc960ddc3371a76dcd2ac86b5de2 - -iVBORw0KGgoAAAANSUhEUgAAAyEAAAF0CAMAAAAD7MasAAAAYFBMVEUAAAAPDw8WFhYZGRkiIiIp -KSk0NDQ/Pz9AQEBLS0tRUVFbW1tjY2NtbW10dHR7e3uAgICLi4uRkZGampqgoKCurq60tLS/v7/A -wMDPz8/T09Pb29vi4uLt7e309PT///+PDsRWAAAAKnRFWHRjb3B5bGVmdABHZW5lcmF0ZWQgYnkg -aHR0cHM6Ly9wbGFudHVtbC5jb212zsofAAAEJGlUWHRwbGFudHVtbAABAAAAeJzdV1tv4kYUfvev -OOVlEymhQMJ2N1pVNpfVRkqyqKbtQ9WHwT7AlGGGzow3sBH/vWdsjO2QzS6EXlQkEHP8ne9c5psD -4xvLtE3mwvvOTnGOsBCMS89ETCA0G8AMtBuw4EsUxvMst2Tuf0JpuyqR9icmJwgnTUBnghGOlcYz -yNdsbFGfet4r6OGYSwS2RONFSkbcINSa9YwKhpwCn5jTmgvXHxaIVh0GWkVoDJeTKmxQgl3UIbTM -In1SfDjpJOMxBU5xYVjgLuuQZpw++JhYl9m15JYzkRF4fsPrD4EbuI4FeoPiaxi6r7UHWNc88tza -ieH8/BwCrfknYmleQeAMnt9qb9xrQW3D6b5teYISU+0hoIV/0S5HLOVRCehftnO+To2W7XYZ+iif -1hV003xeQbgyFudgp1zODFnJg3YcJC5ttl2e/3qbc3ebc7fIOTiDbiXpbO3/8E15VxO7uIJe1qg3 -26C9bdBeuVEU5YzA5cjO4CK/PSDy5RV04OQmGPahFwyD0017OsAcAA0o8lVjUDpGDVzColCgJQWe -wciRW7MRubO5WEoQ3vObrVZeTwd+c2F+rxbTyeopl5ObXY1SkY5Hylo1d1k4lQK9hrRV6XHa7JWz -uaBSrFyOOj2ISqZ24Y5CWo3LOWaWeShjcMyU38Wbcs+q0mqStnzCunng+dvRsHm9M3Yl8EeKoZWy -8JAG67BoNtE0DOKuEkrD/ZRTGPfkvXJTwtlGgkBb2x2jhv2COmaSpcYPqwXqG5Jljk4yAjLhYwJn -G055NJO0JdBMbbdMT6gHbVqs6R2rKJm7nckSjNjCciU3q8cMjdS6Tj/HVBU1+OvAKbL4m4DZvMxx -rviQf0YgiTzv6d5SxbnrLVvyeTL/lcd2CheNRop49/1mOzwz43LBNJs7jav7GyUEX6hFuXUF5On9 -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 -cQAAAABJRU5ErkJggg== -------=_Part_193578_1753426155.1780318733416-- diff --git a/streams/kips/diagrams/event_count_range.png b/streams/kips/diagrams/event_count_range.png deleted file mode 100644 index 7b8c09dbeb000c72a475e3db292f302c53e65551..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19393 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 VaRP*0fTmk~CrzzRP%& diff --git a/streams/kips/diagrams/event_time_range.puml b/streams/kips/diagrams/event_time_range.puml deleted file mode 100644 index 5fe9b3ee17dd3..0000000000000 --- a/streams/kips/diagrams/event_time_range.puml +++ /dev/null @@ -1,78 +0,0 @@ -@startuml -!theme plain -scale 10 as 50 pixels - -title EventTimeRange (-20s before, +30s after) - -' Define axes -concise "1. Event Time (s)" as ET -concise "2. Processing Time (s)" as PT -concise "3. State Store (Buffer)" as SS -concise "4. Emitted Range" as Out - -' Initial State -@0 -ET is Idle -PT is Idle -SS is "{ }" -Out is Idle - -' --- Arrival 1: A (t=30) --- -' Box from 25 to 35 centers exactly on 30 -@25 -PT is "A" -ET is "A" -SS is "{ A }" -Out is "{ A }" -@35 -PT is Idle -ET is Idle -Out is Idle - -@45 -ET is "B" - -@55 -ET is Idle - -' --- Arrival 2: C (t=70) --- -' Box from 65 to 75 centers exactly on 70 -@65 -PT is "C" -ET is "C" -SS is "{ A, C }" -Out is "{ C }" -@75 -PT is Idle -ET is Idle -Out is Idle - -' --- Arrival 3: D (t=90) --- -' Box from 105 to 115 centers exactly on 110 -@85 -PT is "D" -ET is "D" -SS is "{ A, C, D }" -Out is "{C,D}" -@95 -PT is Idle -ET is Idle -Out is Idle - -' --- Arrival 4: B (LATE DATA) (t=50) --- -' Arrives at PT=150. Box from 145 to 155 centers on 150. -@122 -PT is "B [LATE]" -SS is "{ A, B, C, D}" -Out is "{ A, B, C }" -note bottom of Out - The after timerange - only applies on - late arriving data -end note -@138 -PT is Idle -Out is Idle - -@145 -@enduml \ No newline at end of file diff --git a/streams/kips/diagrams/processing_flow.png b/streams/kips/diagrams/processing_flow.png deleted file mode 100644 index c71506df6e1afe973d7ca928143a019e1a7d4d23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29940 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 BP : process(record) -activate BP - -alt null key or null value - note right of BP : record dropped\n(droppedRecordsSensor) -else record.timestamp() < observedStreamTime - gracePeriodMs - note right of BP : record dropped\n(past grace period) -else record valid - BP -> BP : update observedStreamTime - - BP -> WS : put(key, value, timestamp) - activate WS - deactivate WS - - BP -> AP : forward(record) - activate AP - - AP -> R : fetch(record, store) - activate R - - R -> WS : fetch(key, fromTimestamp, toTimestamp) - activate WS - WS --> R : WindowStoreIterator - deactivate WS - - R --> AP : Iterable> - deactivate R - - AP -> RA : apply(anchor, rangeRecords) - activate RA - RA --> AP : VR result - deactivate RA - - AP -> DOWN : forward(anchor.withValue(result)) - deactivate AP -end - -deactivate BP - -@enduml From 8df49fb9d73fa3068a7ce2052c320f0498a21652 Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 15:41:35 +0200 Subject: [PATCH 6/7] Use ArrayDeque for backward records in EventCountRange MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ArrayList.add(0, e) is O(n) per prepend (shifts all elements), giving O(before²) total. ArrayDeque.addFirst() is O(1) amortized with no shifting; its iterator() already walks head-to-tail in the correct ascending order. Co-Authored-By: Claude Sonnet 4.6 --- .../org/apache/kafka/streams/kstream/EventCountRange.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java index 7096d742bb33b..631da2842c45a 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/EventCountRange.java @@ -24,9 +24,9 @@ import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Iterator; -import java.util.List; import java.util.NoSuchElementException; /** @@ -118,7 +118,7 @@ public CloseableIterator> fetch(final Record anchor, final Re final long forwardTo = maxTimeAfterMs != null ? anchor.timestamp() + maxTimeAfterMs : Long.MAX_VALUE; // Backward fetch: collect `before+1` records (anchor + up to `before` before it), oldest first - final List> backwardRecords = new ArrayList<>(before + 1); + final Deque> backwardRecords = new ArrayDeque<>(before + 1); try (final WindowStoreIterator backIt = store.backwardFetch( anchor.key(), Instant.ofEpochMilli(from), @@ -126,7 +126,7 @@ public CloseableIterator> fetch(final Record anchor, final Re int count = 0; while (backIt.hasNext() && count <= before) { final KeyValue kv = backIt.next(); - backwardRecords.add(0, new Record<>(anchor.key(), kv.value, kv.key)); + backwardRecords.addFirst(new Record<>(anchor.key(), kv.value, kv.key)); count++; } } From 19ec7afd3fb95436739252f06c03eecadb8e53ce Mon Sep 17 00:00:00 2001 From: Hannes Buseyne Date: Mon, 1 Jun 2026 16:17:00 +0200 Subject: [PATCH 7/7] Fail fast on double iteration of rangeRecords in RangeAggregator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lambda () -> it handed a bare CloseableIterator to the aggregator, silently returning the same exhausted cursor on a second iterator() call. Replace with SingleUseIterable, which throws IllegalStateException if iterator() is called more than once — failing fast rather than silently producing empty results. Document the single-use contract on RangeAggregator.apply(). Co-Authored-By: Claude Sonnet 4.6 --- .../streams/kstream/RangeAggregator.java | 8 ++++--- .../internals/KStreamRangeAggregate.java | 22 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java b/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java index 4fb71b72167e1..3ba7fa5102379 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/RangeAggregator.java @@ -33,9 +33,11 @@ public interface RangeAggregator { * Apply the aggregation logic to the records in the defined range for a given key. * * @param anchor the record that triggered the aggregation - * @param rangeRecords an iterable of records that fall within the defined range of the anchor - * record, including the anchor record itself. Records are ordered by - * timestamp in ascending order. + * @param rangeRecords a single-use iterable of records that fall within the + * defined range of the anchor record, including the anchor record itself. + * Records are ordered by timestamp in ascending order. + * Calling {@code iterator()} more than once will throw + * {@link IllegalStateException}. * Note: headers are not preserved in {@code rangeRecords} as they are not * stored in the underlying {@link WindowStore}. Headers are only available * on the {@code anchor} record. diff --git a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java index 244c5965b9f41..35da765ed83b3 100644 --- a/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java +++ b/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KStreamRangeAggregate.java @@ -30,6 +30,7 @@ import org.apache.kafka.streams.state.StoreBuilder; import java.util.Collections; +import java.util.Iterator; import java.util.Set; /** @@ -85,9 +86,28 @@ public void init(final ProcessorContext context) { @Override public void process(final Record record) { try (final CloseableIterator> it = range.fetch(record, store)) { - final VR result = aggregator.apply(record, () -> it); + final VR result = aggregator.apply(record, new SingleUseIterable<>(it)); context().forward(record.withValue(result)); } } } + + private static final class SingleUseIterable implements Iterable { + private final Iterator iterator; + private boolean consumed = false; + + SingleUseIterable(final Iterator iterator) { + this.iterator = iterator; + } + + @Override + public Iterator iterator() { + if (consumed) { + throw new IllegalStateException( + "rangeRecords is single-use: iterator() may only be called once per aggregation"); + } + consumed = true; + return iterator; + } + } }