KIP-557: Add Emit On Change Support#8254
Conversation
|
test this please |
|
Thanks for this PR @ConcurrencyPractitioner ! I'll take a look at this asap. Just wanted to acknowledge that it's on my plate. |
|
Just FYI, it looks like the tests couldn't build. |
|
@vvcephei Acknowledged. My intention wasn't really to get a working model of the code. I was intending this to be a draft of what the code might look like. I just want approval on this approach first before I dive in. |
|
@vvcephei It looks like casting the store to MeteredTimestampedKeyValueStore doesn't work, as in some cases, the TimestampedKeyValueStore is in fact TimestampedKeyValueStoreReadWriteDecorator. So we will have to abandon this approach. In this case, we will probably need to consider passing in null serdes instead. |
|
@vvcephei @mjsax @guozhangwang Pinging for initial review. |
vvcephei
left a comment
There was a problem hiding this comment.
Hey @ConcurrencyPractitioner , thanks for the PR! I think this looks really close. I'm recommending a few tweaks.
I think you can convert this WIP PR to an actual PR by addressing my comments and adding some additional test cases.
Thanks again!
-John
…ls/KTableSourceTest.java Co-Authored-By: John Roesler <vvcephei@users.noreply.github.com>
…ls/KTableSource.java Co-Authored-By: John Roesler <vvcephei@users.noreply.github.com>
…/MeteredTimestampedKeyValueStore.java Co-Authored-By: John Roesler <vvcephei@users.noreply.github.com>
| final byte[] serializedValue = wrapped().get(keyBytes(key)); | ||
| return new RawAndDeserializedValue<V>(serializedValue, | ||
| maybeMeasureLatency(() -> outerValue(serializedValue), time, getSensor)); |
There was a problem hiding this comment.
Ah, missed this the last time though. We should also perform the wrapped().get inside the lambda, so that the time to perform the get is included in the latency.
There was a problem hiding this comment.
Cool, I will make the change.
|
test this please |
|
test this please |
1 similar comment
|
test this please |
|
test this please |
2 similar comments
|
test this please |
|
test this please |
|
retest this please |
|
@vvcephei Looks like I forgot to push. You can retrigger the tests after this one. |
|
@vvcephei Alright, all tests passed (looks like there were some flakies) and all comments addressed. |
|
@vvcephei Just pinging. I looked into the flakies, and it turns out they were different test failures for each build. So its the equivalent of an all green. |
|
Retest this please |
|
Sorry, for the delay @ConcurrencyPractitioner . I have been insanely busy. I really appreciate your patience. I'm giving it a final pass now. |
vvcephei
left a comment
There was a problem hiding this comment.
Hey, @ConcurrencyPractitioner ,
Again, I'm really sorry there have been so many delays. I have just a few very quick remarks. If you don't have time to address them (or don't care to wait on me anymore ;) ), I can also do it while merging.
Thanks again!
| assertFalse(metered.putIfDifferentValues(key, | ||
| newValueAndTimestamp, | ||
| encodedOldValue)); |
There was a problem hiding this comment.
Ah, sorry to say, one more thing slipped by me before. We should verify(inner) at the end of both of these tests. It should actually fail for shouldNotPutIfSameValuesAndGreaterTimestamp because we should not call inner.put in this case. To fix that, we would just delete L202, where we set up the mock for inner.put. Then, the mock would be initialized to expect no calls, and the verification would fail if we did call it.
| final byte[] encodedOldValue = stringSerde.serializer().serialize("TOPIC", valueAndTimestamp); | ||
|
|
||
| final ValueAndTimestamp<String> outOfOrderValueAndTimestamp = ValueAndTimestamp.make("value", 95L); | ||
| assertTrue(metered.putIfDifferentValues(key, outOfOrderValueAndTimestamp, encodedOldValue)); |
There was a problem hiding this comment.
As I mentioned in the earlier comment, we're missing a verify(inner) call at the end of this test.
| * if the timestamp of right is less than left (indicating out of order record) | ||
| * false otherwise | ||
| */ | ||
| public static boolean maskTimestampAndCompareValues(final byte[] left, final byte[] right) { |
There was a problem hiding this comment.
Ah, upon reading that last test, I realized that I previously overlooked when you added the timestamp comparison to this method. We should change the method name for maintainability. It no longer just "masks the timestamp and compares the values". Can we instead call it "compareValuesAndCheckForIncreasingTimestamp" or something? I can almost guarantee that one or more people will be badly misled by the current method name.
|
@vvcephei Alright, cool. Got those last comments addressed. |
|
Unrelated test failures: kafka.api.SslConsumerTest.testCoordinatorFailover org.apache.kafka.streams.integration.EosBetaUpgradeIntegrationTest.shouldUpgradeFromEosAlphaToEosBeta[true] kafka.api.ConsumerBounceTest.testClose org.apache.kafka.connect.mirror.MirrorConnectorsIntegrationTest.testReplication |
|
Hey @ConcurrencyPractitioner , I just pushed a very minor test fix. I'm verifying it locally before merging. |
|
Thanks for the awesome contribution, @ConcurrencyPractitioner ! |
* 'trunk' of github.com:apache/kafka: MINOR: add option to rebuild source for system tests (apache#6656) KAFKA-9850 Move KStream#repartition operator validation during Topolo… (apache#8550) MINOR: Add a duplicate() method to Message classes (apache#8556) KAFKA-9966: add internal assignment listener to stabilize eos-beta upgrade test (apache#8648) MINOR: Replace null with an actual value for timestamp field in InsertField SMT unit tests (apache#8649) MINOR: Fix ProcessorContext JavaDocs and stream-time computation (apache#8603) MINOR: improve tests for TopologyTestDriver (apache#8631) KAFKA-9821: consolidate Streams rebalance triggering mechanisms (apache#8596) KAFKA-9669; Loosen validation of inner offsets for older message formats (apache#8647) KAFKA-8770: KIP-557: Drop idempotent KTable source updates (apache#8254) MINOR: Remove allow concurrent test (apache#8641)
| if (ValueAndTimestampSerializer.compareValuesAndCheckForIncreasingTimestamp(oldSerializedValue, newSerializedValue)) { | ||
| return false; | ||
| } else { | ||
| wrapped().put(keyBytes(key), newSerializedValue); |
There was a problem hiding this comment.
@ConcurrencyPractitioner @vvcephei I'm trying to understand this to debug some broken tests in ksql. Couple questions:
When the timestamp of the newer value is lower (ignoring the value), why do we want to put the new value into the store? Surely the store should have the value with the newer timestamp? Otherwise we could wind up with a corrupt store.
Don't we still want to put the value in the store (even if we don't forward it on to the next context) if the values are the same but the timestamp is newer? Otherwise if we get an out-of-order update with a different value, but a timestamp in between the rows with the same value, we'd incorrectly put that value into the store, e.g. the following updates:
TS: 1, K: X, V: A
TS: 3, K: X, V: A
TS: 2, K: X, V: B
would result in the table containing K: X, V: B, which is wrong.
There was a problem hiding this comment.
Why when the timestamp of the newer value is lower, do we want to put the new value into the store? Surely the store should have the value with the newer timestamp? Otherwise we could wind up with a corrupt store.
This behavior was there also before this PR. If a out-of-order record is encountered, a log message was written, but the record was nevertheless put into the state store (cf.
Could you elaborate on why a store should get corrupted because of this?
would result in the table containing K: X, V: B, which is wrong.
As said above, this behavior should not have been changed.
There was a problem hiding this comment.
Don't we still want to put the value in the store (even if we don't forward it on to the next context) if the values are the same but the timestamp is newer?
If we just put the value in the store but did not forward it, then the store would actually be corrupted, because the local state would not be consistent with downstream anymore.
Not putting a record with the same value but a newer timestamp in the store and not forwarding it was the main point of this KIP.
Drops idempotent updates from KTable source operators. Specifically, drop updates in which the value is unchanged, and the timestamp is the same or larger. Implements: KIP-557 Reviewers: Bruno Cadonna <bruno@confluent.io>, John Roesler <vvcephei@apache.org>
The latest commit #8254 on this test deleted all topics after each test, but the topic was actually shared among tests before. And after that we are relying on the less-reliable auto-topic generation to get the topic which makes the test flaky. I'm now using different topics for different tests, also setting the app.id for tests differently. Reviewers: Boyang Chen <boyang@confluent.io>, A. Sophie Blee-Goldman <sophie@confluent.io>, Matthias J. Sax <matthias@confluent.io>
The latest commit #8254 on this test deleted all topics after each test, but the topic was actually shared among tests before. And after that we are relying on the less-reliable auto-topic generation to get the topic which makes the test flaky. I'm now using different topics for different tests, also setting the app.id for tests differently. Reviewers: Boyang Chen <boyang@confluent.io>, A. Sophie Blee-Goldman <sophie@confluent.io>, Matthias J. Sax <matthias@confluent.io>
Drops idempotent updates from KTable source operators. Specifically, drop updates in which the value is unchanged, and the timestamp is the same or larger. Implements: KIP-557 Reviewers: Bruno Cadonna <bruno@confluent.io>, John Roesler <vvcephei@apache.org>
This is the initial draft PR for adding emit on change. For reference of the design document, please see here.
https://cwiki.apache.org/confluence/display/KAFKA/KIP-557%3A+Add+emit+on+change+support+for+Kafka+Streams
Committer Checklist (excluded from commit message)