Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private KTable<K, VOut> doAggregate(final Initializer<VOut> initializer,
groupPatterns,
initializer,
named,
new TimestampedKeyValueStoreMaterializer<>(materializedInternal).materialize(),
new KeyValueStoreMaterializer<>(materializedInternal).materialize(),
materializedInternal.keySerde(),
materializedInternal.valueSerde(),
materializedInternal.queryableStoreName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ private <T> KTable<K, T> doAggregate(final KStreamAggProcessorSupplier<K, V, K,
final MaterializedInternal<K, T, KeyValueStore<Bytes, byte[]>> materializedInternal) {
return aggregateBuilder.build(
new NamedInternal(functionName),
new TimestampedKeyValueStoreMaterializer<>(materializedInternal).materialize(),
new KeyValueStoreMaterializer<>(materializedInternal).materialize(),
aggregateSupplier,
materializedInternal.queryableStoreName(),
materializedInternal.keySerde(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private <VAgg> KTable<K, VAgg> doAggregate(final ProcessorSupplier<K, Change<V>,
final StatefulProcessorNode statefulProcessorNode = new StatefulProcessorNode<>(
funcName,
new ProcessorParameters<>(aggregateSupplier, funcName),
new TimestampedKeyValueStoreMaterializer<>(materialized).materialize()
new KeyValueStoreMaterializer<>(materialized).materialize()
);

// now the repartition node must be the parent of the StateProcessorNode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ private KTable<K, V> doFilter(final Predicate<? super K, ? super V> predicate,
valueSerde = materializedInternal.valueSerde() != null ? materializedInternal.valueSerde() : this.valueSerde;
queryableStoreName = materializedInternal.queryableStoreName();
// only materialize if materialized is specified and it has queryable name
storeBuilder = queryableStoreName != null ? (new TimestampedKeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
storeBuilder = queryableStoreName != null ? (new KeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
} else {
keySerde = this.keySerde;
valueSerde = this.valueSerde;
Expand Down Expand Up @@ -302,7 +302,7 @@ private <VR> KTable<K, VR> doMapValues(final ValueMapperWithKey<? super K, ? sup
valueSerde = materializedInternal.valueSerde();
queryableStoreName = materializedInternal.queryableStoreName();
// only materialize if materialized is specified and it has queryable name
storeBuilder = queryableStoreName != null ? (new TimestampedKeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
storeBuilder = queryableStoreName != null ? (new KeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
} else {
keySerde = this.keySerde;
valueSerde = null;
Expand Down Expand Up @@ -455,7 +455,7 @@ private <VR> KTable<K, VR> doTransformValues(final ValueTransformerWithKeySuppli
valueSerde = materializedInternal.valueSerde();
queryableStoreName = materializedInternal.queryableStoreName();
// only materialize if materialized is specified and it has queryable name
storeBuilder = queryableStoreName != null ? (new TimestampedKeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
storeBuilder = queryableStoreName != null ? (new KeyValueStoreMaterializer<>(materializedInternal)).materialize() : null;
} else {
keySerde = this.keySerde;
valueSerde = null;
Expand Down Expand Up @@ -759,7 +759,7 @@ private <VO, VR> KTable<K, VR> doJoin(final KTable<K, VO> other,
keySerde = materializedInternal.keySerde();
valueSerde = materializedInternal.valueSerde();
queryableStoreName = materializedInternal.storeName();
storeBuilder = new TimestampedKeyValueStoreMaterializer<>(materializedInternal).materialize();
storeBuilder = new KeyValueStoreMaterializer<>(materializedInternal).materialize();
} else {
keySerde = this.keySerde;
valueSerde = null;
Expand Down Expand Up @@ -1271,7 +1271,7 @@ private <VR, KO, VO> KTable<K, VR> doJoinOnForeignKey(final KTable<KO, VO> forei
);

final StoreBuilder<?> resultStore =
new TimestampedKeyValueStoreMaterializer<>(materializedInternal).materialize();
new KeyValueStoreMaterializer<>(materializedInternal).materialize();

final TableProcessorNode<K, VR> resultNode = new TableProcessorNode<>(
resultProcessorName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,34 @@
package org.apache.kafka.streams.kstream.internals;

import org.apache.kafka.common.utils.Bytes;
import org.apache.kafka.common.utils.Time;
import org.apache.kafka.streams.state.KeyValueBytesStoreSupplier;
import org.apache.kafka.streams.state.KeyValueStore;
import org.apache.kafka.streams.state.StoreBuilder;
import org.apache.kafka.streams.state.Stores;
import org.apache.kafka.streams.state.TimestampedKeyValueStore;
import org.apache.kafka.streams.state.VersionedBytesStoreSupplier;
import org.apache.kafka.streams.state.internals.TimestampedKeyValueStoreBuilder;
import org.apache.kafka.streams.state.internals.VersionedKeyValueStoreBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Materializes a key-value store as either a {@link TimestampedKeyValueStoreBuilder} or a
* {@link VersionedKeyValueStoreBuilder} depending on whether the store is versioned or not.
*/
public class KeyValueStoreMaterializer<K, V> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While renaming this class in IntelliJ, I got a warning that a class with this name existed in a previous version of Kafka Streams. I think this is fine since it's an internal class, but wanted to call it out in case there are compatibility concerns I'm not aware of.

private static final Logger LOG = LoggerFactory.getLogger(KeyValueStoreMaterializer.class);

public class TimestampedKeyValueStoreMaterializer<K, V> {
private final MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>> materialized;

public TimestampedKeyValueStoreMaterializer(final MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>> materialized) {
public KeyValueStoreMaterializer(final MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>> materialized) {
this.materialized = materialized;
}

/**
* @return StoreBuilder
*/
public StoreBuilder<TimestampedKeyValueStore<K, V>> materialize() {
public StoreBuilder<?> materialize() {
KeyValueBytesStoreSupplier supplier = (KeyValueBytesStoreSupplier) materialized.storeSupplier();
if (supplier == null) {
switch (materialized.storeType()) {
Expand All @@ -48,10 +59,19 @@ public StoreBuilder<TimestampedKeyValueStore<K, V>> materialize() {
}
}

final StoreBuilder<TimestampedKeyValueStore<K, V>> builder = Stores.timestampedKeyValueStoreBuilder(
supplier,
materialized.keySerde(),
materialized.valueSerde());
final StoreBuilder<?> builder;
if (supplier instanceof VersionedBytesStoreSupplier) {
builder = new VersionedKeyValueStoreBuilder<>(
(VersionedBytesStoreSupplier) supplier,
materialized.keySerde(),
materialized.valueSerde(),
Time.SYSTEM);
} else {
builder = Stores.timestampedKeyValueStoreBuilder(
supplier,
materialized.keySerde(),
materialized.valueSerde());
}

if (materialized.loggingEnabled()) {
builder.withLoggingEnabled(materialized.logConfig());
Expand All @@ -60,8 +80,12 @@ public StoreBuilder<TimestampedKeyValueStore<K, V>> materialize() {
}

if (materialized.cachingEnabled()) {
builder.withCachingEnabled();
if (!(builder instanceof VersionedKeyValueStoreBuilder)) {
builder.withCachingEnabled();
} else {
LOG.info("Not enabling caching for store '{}' as versioned stores do not support caching.", supplier.name());
}
}
return builder;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import org.apache.kafka.common.utils.Bytes;
import org.apache.kafka.streams.kstream.internals.KTableSource;
import org.apache.kafka.streams.kstream.internals.MaterializedInternal;
import org.apache.kafka.streams.kstream.internals.TimestampedKeyValueStoreMaterializer;
import org.apache.kafka.streams.kstream.internals.KeyValueStoreMaterializer;
import org.apache.kafka.streams.processor.internals.InternalTopologyBuilder;
import org.apache.kafka.streams.state.KeyValueStore;
import org.apache.kafka.streams.state.StoreBuilder;
Expand Down Expand Up @@ -53,7 +53,7 @@ public String toString() {
@Override
public void writeToTopology(final InternalTopologyBuilder topologyBuilder) {
final StoreBuilder<?> storeBuilder =
new TimestampedKeyValueStoreMaterializer<>((MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>>) materializedInternal).materialize();
new KeyValueStoreMaterializer<>((MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>>) materializedInternal).materialize();

final String processorName = processorParameters.processorName();
final KTableSource<K, V> tableSource = processorParameters.processorSupplier() instanceof KTableSource ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.apache.kafka.streams.kstream.internals.ConsumedInternal;
import org.apache.kafka.streams.kstream.internals.KTableSource;
import org.apache.kafka.streams.kstream.internals.MaterializedInternal;
import org.apache.kafka.streams.kstream.internals.TimestampedKeyValueStoreMaterializer;
import org.apache.kafka.streams.kstream.internals.KeyValueStoreMaterializer;
import org.apache.kafka.streams.processor.api.ProcessorSupplier;
import org.apache.kafka.streams.processor.internals.InternalTopologyBuilder;
import org.apache.kafka.streams.state.KeyValueStore;
Expand Down Expand Up @@ -94,7 +94,7 @@ public void writeToTopology(final InternalTopologyBuilder topologyBuilder) {
}

final StoreBuilder<?> storeBuilder =
new TimestampedKeyValueStoreMaterializer<>((MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>>) materializedInternal).materialize();
new KeyValueStoreMaterializer<>((MaterializedInternal<K, V, KeyValueStore<Bytes, byte[]>>) materializedInternal).materialize();

if (isGlobalKTable) {
topologyBuilder.addGlobalStore(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.apache.kafka.streams.state.TimestampedKeyValueStore;
import org.apache.kafka.streams.state.TimestampedWindowStore;
import org.apache.kafka.streams.state.ValueAndTimestamp;
import org.apache.kafka.streams.state.VersionedKeyValueStore;
import org.apache.kafka.streams.state.VersionedRecord;
import org.apache.kafka.streams.state.WindowStore;
import org.apache.kafka.streams.state.WindowStoreIterator;
import org.apache.kafka.streams.state.internals.WrappedStateStore;
Expand Down Expand Up @@ -68,6 +70,8 @@ public void close() {
static StateStore getReadOnlyStore(final StateStore global) {
if (global instanceof TimestampedKeyValueStore) {
return new TimestampedKeyValueStoreReadOnlyDecorator<>((TimestampedKeyValueStore<?, ?>) global);
} else if (global instanceof VersionedKeyValueStore) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addition, and the analogous one in AbstractReadWriteDecorator, is necessary so that ProcessorContextImpl#getStateStore() can properly return versioned stores.

return new VersionedKeyValueStoreReadOnlyDecorator<>((VersionedKeyValueStore<?, ?>) global);
} else if (global instanceof KeyValueStore) {
return new KeyValueStoreReadOnlyDecorator<>((KeyValueStore<?, ?>) global);
} else if (global instanceof TimestampedWindowStore) {
Expand Down Expand Up @@ -159,6 +163,35 @@ private TimestampedKeyValueStoreReadOnlyDecorator(final TimestampedKeyValueStore
}
}

static class VersionedKeyValueStoreReadOnlyDecorator<K, V>
extends AbstractReadOnlyDecorator<VersionedKeyValueStore<K, V>, K, V>
implements VersionedKeyValueStore<K, V> {

private VersionedKeyValueStoreReadOnlyDecorator(final VersionedKeyValueStore<K, V> inner) {
super(inner);
}

@Override
public void put(final K key, final V value, final long timestamp) {
throw new UnsupportedOperationException(ERROR_MESSAGE);
}

@Override
public VersionedRecord<V> delete(final K key, final long timestamp) {
throw new UnsupportedOperationException(ERROR_MESSAGE);
}

@Override
public VersionedRecord<V> get(final K key) {
return wrapped().get(key);
}

@Override
public VersionedRecord<V> get(final K key, final long asOfTimestamp) {
return wrapped().get(key, asOfTimestamp);
}
}

static class WindowStoreReadOnlyDecorator<K, V>
extends AbstractReadOnlyDecorator<WindowStore<K, V>, K, V>
implements WindowStore<K, V> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.apache.kafka.streams.state.TimestampedKeyValueStore;
import org.apache.kafka.streams.state.TimestampedWindowStore;
import org.apache.kafka.streams.state.ValueAndTimestamp;
import org.apache.kafka.streams.state.VersionedKeyValueStore;
import org.apache.kafka.streams.state.VersionedRecord;
import org.apache.kafka.streams.state.WindowStore;
import org.apache.kafka.streams.state.WindowStoreIterator;
import org.apache.kafka.streams.state.internals.WrappedStateStore;
Expand Down Expand Up @@ -62,6 +64,8 @@ public void close() {
static StateStore getReadWriteStore(final StateStore store) {
if (store instanceof TimestampedKeyValueStore) {
return new TimestampedKeyValueStoreReadWriteDecorator<>((TimestampedKeyValueStore<?, ?>) store);
} else if (store instanceof VersionedKeyValueStore) {
return new VersionedKeyValueStoreReadWriteDecorator<>((VersionedKeyValueStore<?, ?>) store);
} else if (store instanceof KeyValueStore) {
return new KeyValueStoreReadWriteDecorator<>((KeyValueStore<?, ?>) store);
} else if (store instanceof TimestampedWindowStore) {
Expand Down Expand Up @@ -153,6 +157,35 @@ static class TimestampedKeyValueStoreReadWriteDecorator<K, V>
}
}

static class VersionedKeyValueStoreReadWriteDecorator<K, V>
extends AbstractReadWriteDecorator<VersionedKeyValueStore<K, V>, K, V>
implements VersionedKeyValueStore<K, V> {

VersionedKeyValueStoreReadWriteDecorator(final VersionedKeyValueStore<K, V> inner) {
super(inner);
}

@Override
public void put(final K key, final V value, final long timestamp) {
wrapped().put(key, value, timestamp);
}

@Override
public VersionedRecord<V> delete(final K key, final long timestamp) {
return wrapped().delete(key, timestamp);
}

@Override
public VersionedRecord<V> get(final K key) {
return wrapped().get(key);
}

@Override
public VersionedRecord<V> get(final K key, final long asOfTimestamp) {
return wrapped().get(key, asOfTimestamp);
}
}

static class WindowStoreReadWriteDecorator<K, V>
extends AbstractReadWriteDecorator<WindowStore<K, V>, K, V>
implements WindowStore<K, V> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.state.internals;

import org.apache.kafka.common.serialization.Serde;
import org.apache.kafka.common.utils.Bytes;
import org.apache.kafka.common.utils.Time;
import org.apache.kafka.streams.state.KeyValueStore;

import java.util.Objects;
import org.apache.kafka.streams.state.StoreBuilder;
import org.apache.kafka.streams.state.ValueAndTimestamp;
import org.apache.kafka.streams.state.VersionedBytesStore;
import org.apache.kafka.streams.state.VersionedBytesStoreSupplier;
import org.apache.kafka.streams.state.VersionedKeyValueStore;

public class VersionedKeyValueStoreBuilder<K, V>
extends AbstractStoreBuilder<K, V, VersionedKeyValueStore<K, V>> {

private final VersionedBytesStoreSupplier storeSupplier;

public VersionedKeyValueStoreBuilder(final VersionedBytesStoreSupplier storeSupplier,
final Serde<K> keySerde,
final Serde<V> valueSerde,
final Time time) {
super(
storeSupplier.name(),
keySerde,
valueSerde,
time);
Objects.requireNonNull(storeSupplier, "storeSupplier can't be null");
Objects.requireNonNull(storeSupplier.metricsScope(), "storeSupplier's metricsScope can't be null");
this.storeSupplier = storeSupplier;
}

@Override
public VersionedKeyValueStore<K, V> build() {
final KeyValueStore<Bytes, byte[]> store = storeSupplier.get();
if (!(store instanceof VersionedBytesStore)) {
throw new IllegalStateException("VersionedBytesStoreSupplier.get() must return an instance of VersionedBytesStore");
}

final Serde<ValueAndTimestamp<V>> valueAndTimestampSerde = valueSerde == null
? null
: new NullableValueAndTimestampSerde<>(valueSerde);

return new MeteredVersionedKeyValueStore<>(
maybeWrapLogging((VersionedBytesStore) store), // no caching layer for versioned stores
storeSupplier.metricsScope(),
time,
keySerde,
valueAndTimestampSerde);
}

@Override
public StoreBuilder<VersionedKeyValueStore<K, V>> withCachingEnabled() {
throw new IllegalStateException("Versioned stores do not support caching");
}

private VersionedBytesStore maybeWrapLogging(final VersionedBytesStore inner) {
if (!enableLogging) {
return inner;
}
return new ChangeLoggingVersionedKeyValueBytesStore(inner);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.apache.kafka.streams.kstream.Materialized;
import org.apache.kafka.streams.kstream.internals.InternalNameProvider;
import org.apache.kafka.streams.kstream.internals.MaterializedInternal;
import org.apache.kafka.streams.kstream.internals.TimestampedKeyValueStoreMaterializer;
import org.apache.kafka.streams.kstream.internals.KeyValueStoreMaterializer;
import org.apache.kafka.streams.processor.StateStore;
import org.apache.kafka.streams.processor.api.ContextualProcessor;
import org.apache.kafka.streams.processor.api.ProcessorSupplier;
Expand Down Expand Up @@ -100,7 +100,7 @@ public void process(final Record<Object, Object> record) {
};

builder.addGlobalStore(
new TimestampedKeyValueStoreMaterializer<>(materialized).materialize().withLoggingDisabled(),
new KeyValueStoreMaterializer<>(materialized).materialize().withLoggingDisabled(),
"sourceName",
null,
null,
Expand Down
Loading