Skip to content

KAFKA-3522: Add TimestampedWindowStore builder/runtime classes#6173

Merged
bbejeck merged 3 commits intoapache:trunkfrom
mjsax:kafka-3522-rocksdb-format-windowstore-runtime
Mar 8, 2019
Merged

KAFKA-3522: Add TimestampedWindowStore builder/runtime classes#6173
bbejeck merged 3 commits intoapache:trunkfrom
mjsax:kafka-3522-rocksdb-format-windowstore-runtime

Conversation

@mjsax
Copy link
Copy Markdown
Member

@mjsax mjsax commented Jan 19, 2019

Part of KIP-258.

This PR adds

  • TimestampedWindowStore
  • MeteredTimestampedWindowStore
  • ChangeLoggingTimestampedWindowByteStore
  • TimestampedWindowStoreBuilder

@mjsax mjsax added the streams label Jan 19, 2019
@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Jan 19, 2019

Call for review @guozhangwang @bbejeck @vvcephei @ableegoldman

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from 06c3ace to 7f58b88 Compare January 29, 2019 22:18
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the same refactoring as in #6152

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Refactoring as-in #6152

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Refactoring as-in #6152

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Refactoring as-in #6152

Copy link
Copy Markdown
Member

@bbejeck bbejeck left a comment

Choose a reason for hiding this comment

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

@mjsax made an initial pass, overall looks good to me, just one minor comment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the new classes are static maybe they could go in their own package along with the other pre-existing decorators? Probably not on this PR but in a follow-up.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am open to add new packages -- @vvcephei was suggestion this too (for example for RocksDB classes). I would prefer to do this a follow up PRs (it's internal anyway).

@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Jan 30, 2019

Retest this please

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm sorry; getting a little cross-eyed here...

It looks like we're putting newValue and oldRawValue in a new FlushEntry instance here for the sole purpose of extracting them back out and discarding the FlushEntry object immediately following.

What am I missing here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

discarding the FlushEntry object immediately following.

We don't discard it. It's use the in next lines:

if (flushEntry.value != null || flushEntry.oldValue != null) {
flushListener.apply(
                        key,
                        flushEntry.value,
                        flushEntry.oldValue,
                        entry.entry().context().timestamp());
}

Maybe I miss-understand your question?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, that's what I meant. We put the new and old value in, and then immediately take them back out again, and never do anything else with the flushEntry. It just seems like we could skip the middle-man and directly deserialize the values and pass them to the flushListener.

But it's also no big deal... I was just curious if I missed something.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Well. As you mentioned, we pass in objects into flushEntry() and it creates a FlushEntry with serialized data. To share code, and to apply the same patter for all stores, it makes sense IMHO to push the serialization work into flushEntry() method -- the caller should be agnostic if flushEntry modified the data or not.

Copy link
Copy Markdown
Contributor

@vvcephei vvcephei left a comment

Choose a reason for hiding this comment

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

One minor question, but overall, I'm happy with this PR.

Thanks, @mjsax !
-John

Copy link
Copy Markdown
Member

@bbejeck bbejeck left a comment

Choose a reason for hiding this comment

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

Thanks for the update @mjsax LGTM

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from 2095f23 to 9d028c4 Compare March 2, 2019 01:43
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

init() is just moved from below.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

need to access this in sub-class when overwriting new intiStoreSerde() method

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

note: we can reuse exiting CachingWindowStore (thanks to our refactoring)

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from 9d028c4 to c24cc3f Compare March 2, 2019 02:20
@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Mar 2, 2019

Rebased this. Call for review @guozhangwang @bbejeck @vvcephei @ableegoldman

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from c24cc3f to b03a811 Compare March 7, 2019 01:25
Copy link
Copy Markdown
Contributor

@guozhangwang guozhangwang left a comment

Choose a reason for hiding this comment

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

Made a pass.

if (valueAndTimestamp != null) {
changeLogger.logChange(key, rawValue(valueAndTimestamp), timestamp(valueAndTimestamp));
} else {
changeLogger.logChange(key, null);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not specifically related to this line of code but when I read about this, I was thinking about some correlated topic: when we call kvStore.delete and sessionStore.remove, we will pass null as ValueAndTimestamp and hence the timestamp field will also be null. Whereas in windowStore we do not have a delete api, but users can call put(k, null) or put(k, null, timestamp) in which case the timestamp field will not be null actually. Hence there's a discrepancy between the first two and the latter one, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

WindowStore#put(k, null, timestamp) is more or less the same as put(k, null) (the later actually calls the former and used context.timestamp() as third parameter) -- note that the timestamp that is passed is the windowStartTimestamp (not the timestamp that is associated with the value for the timestamped store).

In fact, we plan to deprecate and remove put(k, null), because it does not make sense semantically, to put something into a window store without specifying the window start timestamp (and context.timestamp() is not a good default value). Thus, for put(k, null, timestamp) the provided timestamp would be ignored anyway.

Also note, that for timestamped-store, the call would be put(key, valueAndTimestamp, windowStartTimestamp) and the timestamp in the value is not related to the window-start-timestamp (that will be part of the key in the store).

I agree that calling put(key, null, timestamp) to delete a window would be weird. However, in the DSL we would never delete a window anyway and don't need this. Not sure if PAPI uses would want a proper remove(key) method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am just adding my 2 cents here. I understand what you are saying @mjsax, but I think if we should have a follow-up PR to update the docs to fully explain the semantic operations and differences between (kvStore, sessionStore) and the windowStore.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We have many gaps in store documentation, and I agree it would be worth to do a follow up for this.

I also think I understand now why WindowStore#put(k, v) was added in the first place. For stream-steam join, we use windowed stores (with "allow duplicates" enabled) to store each individual record and thus there is not really a notion of a window (we use it more like a key-value store that allows for time-range queried plus retention time), and we use the record timestamp as "window start timestamp" (ie, we can use this shortcut method). Still think, we should remove it though.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation @mjsax , yes we were trying to "reuse" the window store for stream-stream windowed join, which, as an after-thought is not a very good design.

I think we do not need to make any code changes atm (as for doc changes maybe we can track those as a separate ticket / PR).


verifyWindowedKeyValue(a.next(), new Windowed<>(keyA, new SessionWindow(0, 0)), "1");
verifyWindowedKeyValue(b.next(), new Windowed<>(keyB, new SessionWindow(0, 0)), "1");
verifyWindowedKeyValue(a.next(), new Windowed<>(keyA, new SessionWindow(0, 0)), "1".getBytes());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm.. why move the getBytes() from internal function to all its callers?

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from 4279841 to 458935f Compare March 7, 2019 01:58
@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Mar 7, 2019

Pushed one more commit to cleanup the code.

@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Mar 7, 2019

Copy link
Copy Markdown
Member

@bbejeck bbejeck left a comment

Choose a reason for hiding this comment

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

Thanks, @mjsax I've made a pass over the updates this still looks good to me, I have only minor comments.

Do we need a test for TimestampedWindowStoreBuilder?


checkThrowsUnsupportedOperation(store::flush, "flush()");
checkThrowsUnsupportedOperation(() -> store.put("1", ValueAndTimestamp.make(1L, 1L), 1L), "put()");
checkThrowsUnsupportedOperation(() -> store.put("1", ValueAndTimestamp.make(1L, 1L)), "put()");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Super nit: maybe add a comment here this is for put(key, value) as it took a few seconds for me to realize the diff between this line and the one above. This comment is subjective though so feel free to ignore.

if (valueAndTimestamp != null) {
changeLogger.logChange(key, rawValue(valueAndTimestamp), timestamp(valueAndTimestamp));
} else {
changeLogger.logChange(key, null);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am just adding my 2 cents here. I understand what you are saying @mjsax, but I think if we should have a follow-up PR to update the docs to fully explain the semantic operations and differences between (kvStore, sessionStore) and the windowStore.

private final List<KeyValueIterator<Windowed<String>, Long>> iters = new ArrayList<>(7);
private final List<KeyValueIterator<Windowed<String>, ValueAndTimestamp<Long>>> timestampedIters = new ArrayList<>(7);
private WindowStoreIterator<Long> windowStoreIter;
private WindowStoreIterator<ValueAndTimestamp<Long>> timestampedWindowStoreIter;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: this only used in one line for an assertion, could we use something else?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I merged it with windowStoreIter -- we "loose" generics and need to add a suppress warning, but with mocking we don't really have type safety anyway so I think that is fine.

@mjsax mjsax force-pushed the kafka-3522-rocksdb-format-windowstore-runtime branch from dc73092 to 5a3613b Compare March 7, 2019 22:13
@guozhangwang
Copy link
Copy Markdown
Contributor

@mjsax Thanks for the updates! LGTM.

@mjsax
Copy link
Copy Markdown
Member Author

mjsax commented Mar 8, 2019

Known flaky test failed: https://issues.apache.org/jira/browse/KAFKA-8059

Retest this please.

@bbejeck bbejeck merged commit 04e2061 into apache:trunk Mar 8, 2019
@bbejeck
Copy link
Copy Markdown
Member

bbejeck commented Mar 8, 2019

Merged #6173 into trunk

@mjsax mjsax deleted the kafka-3522-rocksdb-format-windowstore-runtime branch March 9, 2019 03:43
jarekr pushed a commit to confluentinc/kafka that referenced this pull request Apr 18, 2019
* warn-apache-kafka/trunk: (41 commits)
  MINOR: Avoid double null check in KStream#transform() (apache#6429)
  KAFKA-7944: Improve Suppress test coverage (apache#6382)
  KAFKA-3522: add missing guards for TimestampedXxxStore (apache#6356)
  MINOR: Change Trogdor agent's cleanup executor to a cached thread pool (apache#6309)
  KAFKA-7976; Update config before notifying controller of unclean leader update (apache#6426)
  KAFKA-7801: TopicCommand should not be able to alter transaction topic partition count
  KAFKA-8091; Wait for processor shutdown before testing removed listeners (apache#6425)
  MINOR: Update delete topics zk path in assertion error messages
  KAFKA-7939: Fix timing issue in KafkaAdminClientTest.testCreateTopicsRetryBackoff
  KAFKA-7922: Return authorized operations in Metadata request response (KIP-430 Part-2)
  MINOR: Print usage when parse fails during console producer
  MINOR: fix Scala compiler warning (apache#6417)
  KAFKA-7288; Fix check in SelectorTest to wait for no buffered bytes (apache#6415)
  KAFKA-8065: restore original input record timestamp in forward() (apache#6393)
  MINOR: cleanup deprectaion annotations (apache#6290)
  KAFKA-3522: Add TimestampedWindowStore builder/runtime classes (apache#6173)
  KAFKA-8069; Fix early expiration of offsets due to invalid loading of expire timestamp (apache#6401)
  KAFKA-8070: Increase consumer startup timeout in system tests (apache#6405)
  KAFKA-8040: Streams handle initTransactions timeout (apache#6372)
  KAFKA-7980 - Fix timing issue in SocketServerTest.testConnectionRateLimit (apache#6391)
  ...
pengxiaolong pushed a commit to pengxiaolong/kafka that referenced this pull request Jun 14, 2019
…e#6173)

Add TimestampedWindowStore builder/runtime classes

Reviewers: Guozhang Wang <wangguoz@gmail.com>, Matthias J. Sax <mjsax@apache.org>,  John Roesler <john@confluent.io>,  Bill Bejeck <bbejeck@gmail.com>
@mjsax mjsax added the kip Requires or implements a KIP label Jun 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kip Requires or implements a KIP streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants