Search in sources :

Example 1 with MockInternalProcessorContext

use of org.apache.kafka.test.MockInternalProcessorContext in project kafka by apache.

the class EosIntegrationTest method verifyStateIsInStoreAndOffsetsAreInCheckpoint.

private void verifyStateIsInStoreAndOffsetsAreInCheckpoint(final int partition, final Set<KeyValue<Long, Long>> expectedState) throws IOException {
    final String stateStoreDir = stateTmpDir + File.separator + "appDir" + File.separator + applicationId + File.separator + "0_" + partition + File.separator;
    // Verify that the data in the state store on disk is fully up-to-date
    final StateStoreContext context = new MockInternalProcessorContext(new Properties(), new TaskId(0, 0), new File(stateStoreDir));
    final MockKeyValueStore stateStore = new MockKeyValueStore("store", false);
    final RocksDBStore store = (RocksDBStore) new RocksDbKeyValueBytesStoreSupplier(storeName, false).get();
    store.init(context, stateStore);
    store.all().forEachRemaining(kv -> {
        final KeyValue<Long, Long> kv2 = new KeyValue<>(new BigInteger(kv.key.get()).longValue(), new BigInteger(kv.value).longValue());
        expectedState.remove(kv2);
    });
    // Verify that the checkpointed offsets match exactly with max offset of the records in the changelog
    final OffsetCheckpoint checkpoint = new OffsetCheckpoint(new File(stateStoreDir + ".checkpoint"));
    final Map<TopicPartition, Long> checkpointedOffsets = checkpoint.read();
    checkpointedOffsets.forEach(this::verifyChangelogMaxRecordOffsetMatchesCheckpointedOffset);
}
Also used : OffsetCheckpoint(org.apache.kafka.streams.state.internals.OffsetCheckpoint) TaskId(org.apache.kafka.streams.processor.TaskId) KeyValue(org.apache.kafka.streams.KeyValue) RocksDbKeyValueBytesStoreSupplier(org.apache.kafka.streams.state.internals.RocksDbKeyValueBytesStoreSupplier) Properties(java.util.Properties) MockKeyValueStore(org.apache.kafka.test.MockKeyValueStore) StateStoreContext(org.apache.kafka.streams.processor.StateStoreContext) TopicPartition(org.apache.kafka.common.TopicPartition) BigInteger(java.math.BigInteger) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) File(java.io.File) RocksDBStore(org.apache.kafka.streams.state.internals.RocksDBStore)

Example 2 with MockInternalProcessorContext

use of org.apache.kafka.test.MockInternalProcessorContext in project kafka by apache.

the class TimeOrderedKeyValueBufferTest method shouldRestoreV3Format.

@Test
public void shouldRestoreV3Format() {
    final TimeOrderedKeyValueBuffer<String, String> buffer = bufferSupplier.apply(testName);
    final MockInternalProcessorContext context = makeContext();
    buffer.init((StateStoreContext) context, buffer);
    final RecordBatchingStateRestoreCallback stateRestoreCallback = (RecordBatchingStateRestoreCallback) context.stateRestoreCallback(testName);
    context.setRecordContext(new ProcessorRecordContext(0, 0, 0, "", new RecordHeaders()));
    final RecordHeaders headers = new RecordHeaders(new Header[] { new RecordHeader("v", new byte[] { (byte) 3 }) });
    // These serialized formats were captured by running version 2.4 code.
    // They verify that an upgrade from 2.4 will work.
    // Do not change them.
    final String toDeleteBinary = "0000000000000000000000000000000000000005746F70696300000000FFFFFFFFFFFFFFFFFFFFFFFF00000006646F6F6D65640000000000000000";
    final String asdfBinary = "0000000000000001000000000000000000000005746F70696300000000FFFFFFFFFFFFFFFFFFFFFFFF00000004717765720000000000000002";
    final String zxcvBinary1 = "0000000000000002000000000000000000000005746F70696300000000FFFFFFFF0000000870726576696F75730000000749474E4F52454400000005336F34696D0000000000000001";
    final String zxcvBinary2 = "0000000000000003000000000000000000000005746F70696300000000FFFFFFFF0000000870726576696F757300000005336F34696D000000046E6578740000000000000001";
    stateRestoreCallback.restoreBatch(asList(new ConsumerRecord<>("changelog-topic", 0, 0, 999, TimestampType.CREATE_TIME, -1, -1, "todelete".getBytes(UTF_8), hexStringToByteArray(toDeleteBinary), headers, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 1, 9999, TimestampType.CREATE_TIME, -1, -1, "asdf".getBytes(UTF_8), hexStringToByteArray(asdfBinary), headers, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 2, 99, TimestampType.CREATE_TIME, -1, -1, "zxcv".getBytes(UTF_8), hexStringToByteArray(zxcvBinary1), headers, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 2, 100, TimestampType.CREATE_TIME, -1, -1, "zxcv".getBytes(UTF_8), hexStringToByteArray(zxcvBinary2), headers, Optional.empty())));
    assertThat(buffer.numRecords(), is(3));
    assertThat(buffer.minTimestamp(), is(0L));
    assertThat(buffer.bufferSize(), is(142L));
    stateRestoreCallback.restoreBatch(singletonList(new ConsumerRecord<>("changelog-topic", 0, 3, 3, TimestampType.CREATE_TIME, -1, -1, "todelete".getBytes(UTF_8), null, new RecordHeaders(), Optional.empty())));
    assertThat(buffer.numRecords(), is(2));
    assertThat(buffer.minTimestamp(), is(1L));
    assertThat(buffer.bufferSize(), is(95L));
    assertThat(buffer.priorValueForBuffered("todelete"), is(Maybe.undefined()));
    assertThat(buffer.priorValueForBuffered("asdf"), is(Maybe.defined(null)));
    assertThat(buffer.priorValueForBuffered("zxcv"), is(Maybe.defined(ValueAndTimestamp.make("previous", -1))));
    // flush the buffer into a list in buffer order so we can make assertions about the contents.
    final List<Eviction<String, String>> evicted = new LinkedList<>();
    buffer.evictWhile(() -> true, evicted::add);
    // Several things to note:
    // * The buffered records are ordered according to their buffer time (serialized in the value of the changelog)
    // * The record timestamps are properly restored, and not conflated with the record's buffer time.
    // * The keys and values are properly restored
    // * The record topic is set to the original input topic, *not* the changelog topic
    // * The record offset preserves the original input record's offset, *not* the offset of the changelog record
    assertThat(evicted, is(asList(new Eviction<>("zxcv", new Change<>("next", "3o4im"), getContext(3L)), new Eviction<>("asdf", new Change<>("qwer", null), getContext(1L)))));
    cleanup(context, buffer);
}
Also used : Change(org.apache.kafka.streams.kstream.internals.Change) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) LinkedList(java.util.LinkedList) RecordBatchingStateRestoreCallback(org.apache.kafka.streams.processor.internals.RecordBatchingStateRestoreCallback) RecordHeaders(org.apache.kafka.common.header.internals.RecordHeaders) ProcessorRecordContext(org.apache.kafka.streams.processor.internals.ProcessorRecordContext) Eviction(org.apache.kafka.streams.state.internals.TimeOrderedKeyValueBuffer.Eviction) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) RecordHeader(org.apache.kafka.common.header.internals.RecordHeader) Test(org.junit.Test)

Example 3 with MockInternalProcessorContext

use of org.apache.kafka.test.MockInternalProcessorContext in project kafka by apache.

the class TimeOrderedKeyValueBufferTest method shouldFlush.

@Test
public void shouldFlush() {
    final TimeOrderedKeyValueBuffer<String, String> buffer = bufferSupplier.apply(testName);
    final MockInternalProcessorContext context = makeContext();
    buffer.init((StateStoreContext) context, buffer);
    putRecord(buffer, context, 2L, 0L, "asdf", "2093j");
    putRecord(buffer, context, 1L, 1L, "zxcv", "3gon4i");
    putRecord(buffer, context, 0L, 2L, "deleteme", "deadbeef");
    // replace "deleteme" with a tombstone
    buffer.evictWhile(() -> buffer.minTimestamp() < 1, kv -> {
    });
    // flush everything to the changelog
    buffer.flush();
    // the buffer should serialize the buffer time and the value as byte[],
    // which we can't compare for equality using ProducerRecord.
    // As a workaround, I'm deserializing them and shoving them in a KeyValue, just for ease of testing.
    final List<ProducerRecord<String, KeyValue<Long, BufferValue>>> collected = ((MockRecordCollector) context.recordCollector()).collected().stream().map(pr -> {
        final KeyValue<Long, BufferValue> niceValue;
        if (pr.value() == null) {
            niceValue = null;
        } else {
            final byte[] serializedValue = (byte[]) pr.value();
            final ByteBuffer valueBuffer = ByteBuffer.wrap(serializedValue);
            final BufferValue contextualRecord = BufferValue.deserialize(valueBuffer);
            final long timestamp = valueBuffer.getLong();
            niceValue = new KeyValue<>(timestamp, contextualRecord);
        }
        return new ProducerRecord<>(pr.topic(), pr.partition(), pr.timestamp(), pr.key().toString(), niceValue, pr.headers());
    }).collect(Collectors.toList());
    assertThat(collected, is(asList(new ProducerRecord<>(APP_ID + "-" + testName + "-changelog", // Producer will assign
    0, null, "deleteme", null, new RecordHeaders()), new ProducerRecord<>(APP_ID + "-" + testName + "-changelog", 0, null, "zxcv", new KeyValue<>(1L, getBufferValue("3gon4i", 1)), CHANGELOG_HEADERS), new ProducerRecord<>(APP_ID + "-" + testName + "-changelog", 0, null, "asdf", new KeyValue<>(2L, getBufferValue("2093j", 0)), CHANGELOG_HEADERS))));
    cleanup(context, buffer);
}
Also used : StreamsConfig(org.apache.kafka.streams.StreamsConfig) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) TaskId(org.apache.kafka.streams.processor.TaskId) ProcessorRecordContext(org.apache.kafka.streams.processor.internals.ProcessorRecordContext) RunWith(org.junit.runner.RunWith) Random(java.util.Random) Eviction(org.apache.kafka.streams.state.internals.TimeOrderedKeyValueBuffer.Eviction) RecordHeader(org.apache.kafka.common.header.internals.RecordHeader) ValueAndTimestamp(org.apache.kafka.streams.state.ValueAndTimestamp) Function(java.util.function.Function) RecordBatchingStateRestoreCallback(org.apache.kafka.streams.processor.internals.RecordBatchingStateRestoreCallback) ByteBuffer(java.nio.ByteBuffer) Collections.singletonList(java.util.Collections.singletonList) RecordHeaders(org.apache.kafka.common.header.internals.RecordHeaders) StringDeserializer(org.apache.kafka.common.serialization.StringDeserializer) StateStoreContext(org.apache.kafka.streams.processor.StateStoreContext) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Arrays.asList(java.util.Arrays.asList) Serdes(org.apache.kafka.common.serialization.Serdes) StringSerializer(org.apache.kafka.common.serialization.StringSerializer) Record(org.apache.kafka.streams.processor.api.Record) Assert.fail(org.junit.Assert.fail) MockRecordCollector(org.apache.kafka.test.MockRecordCollector) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) LinkedList(java.util.LinkedList) TimestampType(org.apache.kafka.common.record.TimestampType) Parameterized(org.junit.runners.Parameterized) Utils(org.apache.kafka.common.utils.Utils) Properties(java.util.Properties) TestUtils(org.apache.kafka.test.TestUtils) UTF_8(java.nio.charset.StandardCharsets.UTF_8) Collection(java.util.Collection) KeyValue(org.apache.kafka.streams.KeyValue) CHANGELOG_HEADERS(org.apache.kafka.streams.state.internals.InMemoryTimeOrderedKeyValueBuffer.CHANGELOG_HEADERS) Test(org.junit.Test) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) List(java.util.List) Header(org.apache.kafka.common.header.Header) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) Optional(java.util.Optional) Matchers.is(org.hamcrest.Matchers.is) Change(org.apache.kafka.streams.kstream.internals.Change) KeyValue(org.apache.kafka.streams.KeyValue) RecordHeaders(org.apache.kafka.common.header.internals.RecordHeaders) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) ByteBuffer(java.nio.ByteBuffer) Test(org.junit.Test)

Example 4 with MockInternalProcessorContext

use of org.apache.kafka.test.MockInternalProcessorContext in project kafka by apache.

the class TimeOrderedKeyValueBufferTest method shouldReturnPriorValueForBufferedKey.

@Test
public void shouldReturnPriorValueForBufferedKey() {
    final TimeOrderedKeyValueBuffer<String, String> buffer = bufferSupplier.apply(testName);
    final MockInternalProcessorContext context = makeContext();
    buffer.init((StateStoreContext) context, buffer);
    final ProcessorRecordContext recordContext = getContext(0L);
    context.setRecordContext(recordContext);
    buffer.put(1L, new Record<>("A", new Change<>("new-value", "old-value"), 0L), recordContext);
    buffer.put(1L, new Record<>("B", new Change<>("new-value", null), 0L), recordContext);
    assertThat(buffer.priorValueForBuffered("A"), is(Maybe.defined(ValueAndTimestamp.make("old-value", -1))));
    assertThat(buffer.priorValueForBuffered("B"), is(Maybe.defined(null)));
}
Also used : ProcessorRecordContext(org.apache.kafka.streams.processor.internals.ProcessorRecordContext) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) Change(org.apache.kafka.streams.kstream.internals.Change) Test(org.junit.Test)

Example 5 with MockInternalProcessorContext

use of org.apache.kafka.test.MockInternalProcessorContext in project kafka by apache.

the class TimeOrderedKeyValueBufferTest method shouldRestoreV1Format.

@Test
public void shouldRestoreV1Format() {
    final TimeOrderedKeyValueBuffer<String, String> buffer = bufferSupplier.apply(testName);
    final MockInternalProcessorContext context = makeContext();
    buffer.init((StateStoreContext) context, buffer);
    final RecordBatchingStateRestoreCallback stateRestoreCallback = (RecordBatchingStateRestoreCallback) context.stateRestoreCallback(testName);
    context.setRecordContext(new ProcessorRecordContext(0, 0, 0, "", new RecordHeaders()));
    final RecordHeaders v1FlagHeaders = new RecordHeaders(new Header[] { new RecordHeader("v", new byte[] { (byte) 1 }) });
    // These serialized formats were captured by running version 2.2 code.
    // They verify that an upgrade from 2.2 will work.
    // Do not change them.
    final String toDeleteBinary = "00000000000000000000000000000000000000000000000000000005746F70696300000000FFFFFFFF0000000EFFFFFFFF00000006646F6F6D6564";
    final String asdfBinary = "00000000000000020000000000000001000000000000000000000005746F70696300000000FFFFFFFF0000000CFFFFFFFF0000000471776572";
    final String zxcvBinary1 = "00000000000000010000000000000002000000000000000000000005746F70696300000000FFFFFFFF000000150000000870726576696F757300000005336F34696D";
    final String zxcvBinary2 = "00000000000000010000000000000003000000000000000000000005746F70696300000000FFFFFFFF0000001100000005336F34696D000000046E657874";
    stateRestoreCallback.restoreBatch(asList(new ConsumerRecord<>("changelog-topic", 0, 0, 999, TimestampType.CREATE_TIME, -1, -1, "todelete".getBytes(UTF_8), hexStringToByteArray(toDeleteBinary), v1FlagHeaders, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 1, 9999, TimestampType.CREATE_TIME, -1, -1, "asdf".getBytes(UTF_8), hexStringToByteArray(asdfBinary), v1FlagHeaders, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 2, 99, TimestampType.CREATE_TIME, -1, -1, "zxcv".getBytes(UTF_8), hexStringToByteArray(zxcvBinary1), v1FlagHeaders, Optional.empty()), new ConsumerRecord<>("changelog-topic", 0, 3, 100, TimestampType.CREATE_TIME, -1, -1, "zxcv".getBytes(UTF_8), hexStringToByteArray(zxcvBinary2), v1FlagHeaders, Optional.empty())));
    assertThat(buffer.numRecords(), is(3));
    assertThat(buffer.minTimestamp(), is(0L));
    assertThat(buffer.bufferSize(), is(142L));
    stateRestoreCallback.restoreBatch(singletonList(new ConsumerRecord<>("changelog-topic", 0, 3, 3, TimestampType.CREATE_TIME, -1, -1, "todelete".getBytes(UTF_8), null, new RecordHeaders(), Optional.empty())));
    assertThat(buffer.numRecords(), is(2));
    assertThat(buffer.minTimestamp(), is(1L));
    assertThat(buffer.bufferSize(), is(95L));
    assertThat(buffer.priorValueForBuffered("todelete"), is(Maybe.undefined()));
    assertThat(buffer.priorValueForBuffered("asdf"), is(Maybe.defined(null)));
    assertThat(buffer.priorValueForBuffered("zxcv"), is(Maybe.defined(ValueAndTimestamp.make("previous", -1))));
    // flush the buffer into a list in buffer order so we can make assertions about the contents.
    final List<Eviction<String, String>> evicted = new LinkedList<>();
    buffer.evictWhile(() -> true, evicted::add);
    // Several things to note:
    // * The buffered records are ordered according to their buffer time (serialized in the value of the changelog)
    // * The record timestamps are properly restored, and not conflated with the record's buffer time.
    // * The keys and values are properly restored
    // * The record topic is set to the original input topic, *not* the changelog topic
    // * The record offset preserves the original input record's offset, *not* the offset of the changelog record
    assertThat(evicted, is(asList(new Eviction<>("zxcv", new Change<>("next", "3o4im"), getContext(3L)), new Eviction<>("asdf", new Change<>("qwer", null), getContext(1L)))));
    cleanup(context, buffer);
}
Also used : Change(org.apache.kafka.streams.kstream.internals.Change) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) LinkedList(java.util.LinkedList) RecordBatchingStateRestoreCallback(org.apache.kafka.streams.processor.internals.RecordBatchingStateRestoreCallback) RecordHeaders(org.apache.kafka.common.header.internals.RecordHeaders) ProcessorRecordContext(org.apache.kafka.streams.processor.internals.ProcessorRecordContext) Eviction(org.apache.kafka.streams.state.internals.TimeOrderedKeyValueBuffer.Eviction) MockInternalProcessorContext(org.apache.kafka.test.MockInternalProcessorContext) RecordHeader(org.apache.kafka.common.header.internals.RecordHeader) Test(org.junit.Test)

Aggregations

MockInternalProcessorContext (org.apache.kafka.test.MockInternalProcessorContext)20 Test (org.junit.Test)18 Change (org.apache.kafka.streams.kstream.internals.Change)8 ProcessorRecordContext (org.apache.kafka.streams.processor.internals.ProcessorRecordContext)8 LinkedList (java.util.LinkedList)7 ConsumerRecord (org.apache.kafka.clients.consumer.ConsumerRecord)7 RecordHeaders (org.apache.kafka.common.header.internals.RecordHeaders)7 RecordBatchingStateRestoreCallback (org.apache.kafka.streams.processor.internals.RecordBatchingStateRestoreCallback)7 Eviction (org.apache.kafka.streams.state.internals.TimeOrderedKeyValueBuffer.Eviction)7 RecordHeader (org.apache.kafka.common.header.internals.RecordHeader)6 Properties (java.util.Properties)3 TaskId (org.apache.kafka.streams.processor.TaskId)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 KeyValue (org.apache.kafka.streams.KeyValue)2 StateStoreContext (org.apache.kafka.streams.processor.StateStoreContext)2 File (java.io.File)1 IOException (java.io.IOException)1 BigInteger (java.math.BigInteger)1 ByteBuffer (java.nio.ByteBuffer)1 UTF_8 (java.nio.charset.StandardCharsets.UTF_8)1