Skip to content

KAFKA-8705: Remove parent node after leaving loop to prevent NPE - #7117

Merged
bbejeck merged 1 commit into
apache:trunkfrom
bbejeck:KAFKA-8705_npe_optimization_two_merge_nodes_common_key_changing_node
Dec 12, 2019
Merged

KAFKA-8705: Remove parent node after leaving loop to prevent NPE#7117
bbejeck merged 1 commit into
apache:trunkfrom
bbejeck:KAFKA-8705_npe_optimization_two_merge_nodes_common_key_changing_node

Conversation

@bbejeck

@bbejeck bbejeck commented Jul 25, 2019

Copy link
Copy Markdown
Member

Fixes case where multiple children merged from a key-changing node causes an NPE.

I've updated the tests.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@bbejeck

bbejeck commented Jul 25, 2019

Copy link
Copy Markdown
Member Author

@abbccdda abbccdda left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the PR. Have we verified that the NPE will recur without this fix in unit test?

final Set<StreamsGraphNode> mergeNodeKeyChangingParentsToRemove = new HashSet<>();
for (final StreamsGraphNode mergeNode : mergeNodes) {
mergeNodesToKeyChangers.put(mergeNode, new LinkedHashSet<>());
final Collection<StreamsGraphNode> keys = keyChangingOperationsToOptimizableRepartitionNodes.keySet();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The maps' names involved are very lengthy such as keyChangingOperationsToOptimizableRepartitionNodes, mergeNodeKeyChangingParentsToRemove, , shall we comment on their individual functionalities?

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.

ack

keyChangingOperationsToOptimizableRepartitionNodes.put(mergeKey, repartitionNodes);
}

for (final StreamsGraphNode mergeNodeKeyChangingParent : mergeNodeKeyChangingParentsToRemove) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same here, add a comment on why we need to remove these nodes

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.

ack

@abbccdda

Copy link
Copy Markdown

Marking that we have already got 3/3 green check. Future flaky tests shall be ignored for comment-only changes.

childStream1
.merge(childStream2)
.merge(childStream3)
.to("output_topic");

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.

Seems I don't understand the root cause of the bug. Don't we need to add a "key dependent" operation (like aggregation) to trigger a repartition and to merge the nodes to only create one repartition topic?

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.

Going back to my comment above, when users specify OPTIMIZE the code eagerly makes changes for adjusting the graph for any merge nodes that may require repartitioning. But in this case, we should do nothing as there is nothing to trigger a repartition. I'll look to fix this, but I don't see this being a quick fix, so my preference is to do this in a follow-up PR.

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 think we can remove the to() operator to verify if we don't fail with a NPE.

@@ -395,11 +397,14 @@ private void maybeUpdateKeyChangingRepartitionNodeMap() {
final LinkedHashSet<OptimizableRepartitionNode> repartitionNodes = new LinkedHashSet<>();
for (final StreamsGraphNode keyChangingParent : keyChangingParents) {
repartitionNodes.addAll(keyChangingOperationsToOptimizableRepartitionNodes.get(keyChangingParent));

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.

The stack trace on the ticket indicate that the NPE is thrown in this line, because keyChangingOperationsToOptimizableRepartitionNodes.get(keyChangingParent) returns null -- can you elaborate why it becomes null?

From my current understanding, keyChangingParents should be a Set and hence we should get each item once and remove it once from keyChangingOperationsToOptimizableRepartitionNodes (in the old code). Why would we get() the same item twice? Seems I am missing 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.

This is due to a single key changing node having multiple merge child nodes. We build a map where the keys are merge nodes and point to a collection of key changing parents, hence we need to wait to remove from the map until we've dropped out of the loop. cf https://github.com/apache/kafka/blob/trunk/streams/src/main/java/org/apache/kafka/streams/kstream/internals/InternalStreamsBuilder.java#L380-L389

I'm not completely sure of this design now, I'm revisiting it at the moment, but IMHO it's beyond the scope of this PR.

@bbejeck

bbejeck commented Jul 31, 2019

Copy link
Copy Markdown
Member Author

Thanks for the PR. Have we verified that the NPE will recur without this fix in unit test?

Yes the test fails without the fix.

@bbejeck

bbejeck commented Sep 4, 2019

Copy link
Copy Markdown
Member Author

ping @mjsax


final KStream<Integer, Integer> childStream1 = parentStream.mapValues(v -> v + 1);
final KStream<Integer, Integer> childStream2 = parentStream.mapValues(v -> v + 2);
final KStream<Integer, Integer> childStream3 = parentStream.mapValues(v -> v + 3);

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.

While this is the example from the ticket, the issue is not related to branching out as done here. Should we rewrite/simplify the test and just create 3 KStream sX = streams.builder() and later add one single key-changing operation? -> s1.selectKey().merge(s2).merge(s3).

@mjsax mjsax left a 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.

Sync with @bbejeck in person. Overall LGTM.

@mjsax

mjsax commented Oct 22, 2019

Copy link
Copy Markdown
Member

@abbccdda Call for second review.

@bbejeck
bbejeck merged commit 7a84d93 into apache:trunk Dec 12, 2019
@bbejeck

bbejeck commented Dec 12, 2019

Copy link
Copy Markdown
Member Author

Merged #7117 into trunk

@bbejeck
bbejeck deleted the KAFKA-8705_npe_optimization_two_merge_nodes_common_key_changing_node branch December 12, 2019 21:24
@bbejeck

bbejeck commented Dec 12, 2019

Copy link
Copy Markdown
Member Author

will cherry-pick to 2.4 once next release is out

bbejeck added a commit that referenced this pull request Dec 12, 2019
Fixes case where multiple children merged from a key-changing node causes an NPE.

Reviewers:  Matthias J. Sax <mjsax@apache.org>, Boyang Chen <boyang@confluent.io>
bbejeck added a commit that referenced this pull request Dec 12, 2019
Fixes case where multiple children merged from a key-changing node causes an NPE.

Reviewers:  Matthias J. Sax <mjsax@apache.org>, Boyang Chen <boyang@confluent.io>
@bbejeck

bbejeck commented Dec 12, 2019

Copy link
Copy Markdown
Member Author

cherry-picked to 2.3 and 2.2

bbejeck added a commit that referenced this pull request Dec 16, 2019
Fixes case where multiple children merged from a key-changing node causes an NPE.

Reviewers:  Matthias J. Sax <mjsax@apache.org>, Boyang Chen <boyang@confluent.io>
@bbejeck

bbejeck commented Dec 16, 2019

Copy link
Copy Markdown
Member Author

cherry-picked to 2.4

qq619618919 pushed a commit to qq619618919/kafka that referenced this pull request May 12, 2020
…che#7117)

Fixes case where multiple children merged from a key-changing node causes an NPE.

Reviewers:  Matthias J. Sax <mjsax@apache.org>, Boyang Chen <boyang@confluent.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants