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
47 changes: 32 additions & 15 deletions core/src/main/scala/kafka/admin/ReassignPartitionsCommand.scala
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,26 @@ object ReassignPartitionsCommand extends Logging {
proposedAssignments
}

private def describeTopics(adminClient: Admin,
topics: Set[String])
: Map[String, TopicDescription] = {
adminClient.describeTopics(topics.asJava).values.asScala.map {
case (topicName, topicDescriptionFuture) =>
try {
topicName -> topicDescriptionFuture.get
}
catch {
case t: ExecutionException =>
if (classOf[UnknownTopicOrPartitionException].isInstance(t.getCause)) {

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.

Hmm. why not write this as t.getCause.isInstanceOf[UnknownTopicOrPartitionException]?

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.

Also, you can have the if in the case t line and then a second case for the rethrow case.

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 initially used t.getCause != null && t.getCause.isInstanceOf[UnknownTopicOrPartitionException]. @chia7712 suggested to use classOf[UnknownTopicOrPartitionException].isInstance(t.getCause) to avoid having to do the null check as isInstance does it. That seemed reasonable to me so I went with it. Is there a reason not to use it?

I do agree with your second comment.

@ijuma ijuma Mar 8, 2021

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.

Hmm, I think this is an example of code that is less readable. If cause may be nullable, it's better to write code that makes that clear rather than a non obvious alternative that could have been used for many other reasons (using Option to handle nullables is fine as a counter example since it's common usage to do that to handle nulls).

What do you think?

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.

Oh, one more thing, did you check that the null check is actually needed? I think isInstanceOf is defined for null too.

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 isInstanceOf is defined for null too.

you are right. Scala does define it. https://scala-lang.org/files/archive/spec/2.13/spec.pdf

‘’’

isInstanceOf[T] always returns false.
‘’’

Good to know that :)

+1 to use ‘t.getCause.isInstanceOf[UnknownTopicOrPartitionException]‘ as it can deal with null check.

Sorry for my imprecise comment :(

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.

@ijuma Yeah, I do agree with you. For the null check, I was not aware that isInstanceOf handles it. That's good to know, thanks.

I will open a small PR to fix this.

throw new ExecutionException(
new UnknownTopicOrPartitionException(s"Topic $topicName not found."))
} else {
throw t
}
}
}
}

/**
* Get the current replica assignments for some topics.
*
Expand All @@ -823,12 +843,10 @@ object ReassignPartitionsCommand extends Logging {
def getReplicaAssignmentForTopics(adminClient: Admin,
topics: Seq[String])
: Map[TopicPartition, Seq[Int]] = {
adminClient.describeTopics(topics.asJava).all().get().asScala.flatMap {
case (topicName, topicDescription) =>
topicDescription.partitions.asScala.map {
info => (new TopicPartition(topicName, info.partition),
info.replicas.asScala.map(_.id))
}
describeTopics(adminClient, topics.toSet).flatMap {
case (topicName, topicDescription) => topicDescription.partitions.asScala.map { info =>
(new TopicPartition(topicName, info.partition), info.replicas.asScala.map(_.id))
}
}
}

Expand All @@ -843,15 +861,14 @@ object ReassignPartitionsCommand extends Logging {
def getReplicaAssignmentForPartitions(adminClient: Admin,
partitions: Set[TopicPartition])
: Map[TopicPartition, Seq[Int]] = {
adminClient.describeTopics(partitions.map(_.topic).asJava).all().get().asScala.flatMap {
case (topicName, topicDescription) =>
topicDescription.partitions.asScala.flatMap {
info => if (partitions.contains(new TopicPartition(topicName, info.partition))) {
Some(new TopicPartition(topicName, info.partition()),
info.replicas.asScala.map(_.id))
} else {
None
}
describeTopics(adminClient, partitions.map(_.topic)).flatMap {
case (topicName, topicDescription) => topicDescription.partitions.asScala.flatMap { info =>
val tp = new TopicPartition(topicName, info.partition)
if (partitions.contains(tp)) {
Some(tp, info.replicas.asScala.map(_.id))
} else {
None
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,20 @@ class ReassignPartitionsUnitTest {
}
}

@Test
def testGenerateAssignmentWithInvalidPartitionsFails(): Unit = {
val adminClient = new MockAdminClient.Builder().numBrokers(5).build()
try {
addTopics(adminClient)
assertStartsWith("Topic quux not found",
assertThrows(classOf[ExecutionException],
() => generateAssignment(adminClient, """{"topics":[{"topic":"foo"},{"topic":"quux"}]}""", "0,1", false),
() => "Expected generateAssignment to fail").getCause.getMessage)
} finally {
adminClient.close()
}
}

@Test
def testGenerateAssignmentWithInconsistentRacks(): Unit = {
val adminClient = new MockAdminClient.Builder().
Expand Down