-
Notifications
You must be signed in to change notification settings - Fork 13.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KAFKA-14190: Update Zk TopicId from locally stored cache in controller #13111
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1664,11 +1664,21 @@ class KafkaController(val config: KafkaConfig, | |
} | ||
|
||
private def processTopicIds(topicIdAssignments: Set[TopicIdReplicaAssignment]): Unit = { | ||
// Create topic IDs for topics missing them if we are using topic IDs | ||
// Create topic IDs or update with locally stored topicIDs for topics missing them if we are using topic IDs | ||
// Otherwise, maintain what we have in the topicZNode | ||
val updatedTopicIdAssignments = if (config.usesTopicId) { | ||
val (withTopicIds, withoutTopicIds) = topicIdAssignments.partition(_.topicId.isDefined) | ||
withTopicIds ++ zkClient.setTopicIds(withoutTopicIds, controllerContext.epochZkVersion) | ||
val (withTopicIds, withoutTopicIds, withLocalTopicIds) = topicIdAssignments.foldLeft((Set.empty[TopicIdReplicaAssignment], Set.empty[TopicIdReplicaAssignment], Set.empty[TopicIdReplicaAssignment])) { | ||
case ((wt, wo, wl), t) => | ||
if (t.topicId.isDefined) (wt union Set(t), wo, wl) | ||
else if (controllerContext.topicIds.contains(t.topic)) (wt, wo, wl union Set(t)) | ||
else (wt, wo union Set(t), wl) | ||
} | ||
|
||
val topicIdsForZkUpdate = withoutTopicIds ++ withLocalTopicIds.map { t => | ||
TopicIdReplicaAssignment(t.topic, controllerContext.topicIds.get(t.topic), t.assignment) | ||
} | ||
|
||
withTopicIds ++ zkClient.setTopicIds(topicIdsForZkUpdate, controllerContext.epochZkVersion) | ||
} else { | ||
topicIdAssignments | ||
} | ||
|
@@ -1698,7 +1708,7 @@ class KafkaController(val config: KafkaConfig, | |
private def processPartitionModifications(topic: String): Unit = { | ||
def restorePartitionReplicaAssignment( | ||
topic: String, | ||
newPartitionReplicaAssignment: Map[TopicPartition, ReplicaAssignment] | ||
newPartitionReplicaAssignment: Set[(TopicPartition, ReplicaAssignment)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did we make this a set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we changed the call to Zk from We can work on improving the readibility as you suggested once we have a consensus on whether we even want to make this change at all. |
||
): Unit = { | ||
info("Restoring the partition replica assignment for topic %s".format(topic)) | ||
|
||
|
@@ -1716,27 +1726,25 @@ class KafkaController(val config: KafkaConfig, | |
} | ||
|
||
if (!isActive) return | ||
val partitionReplicaAssignment = zkClient.getFullReplicaAssignmentForTopics(immutable.Set(topic)) | ||
val partitionsToBeAdded = partitionReplicaAssignment.filter { case (topicPartition, _) => | ||
controllerContext.partitionReplicaAssignment(topicPartition).isEmpty | ||
} | ||
val partitions = zkClient.getReplicaAssignmentAndTopicIdForTopics(immutable.Set(topic)) | ||
val partitionsToBeAdded = partitions.flatMap(_.assignment).filter(t => controllerContext.partitionReplicaAssignment(t._1).isEmpty) | ||
|
||
if (topicDeletionManager.isTopicQueuedUpForDeletion(topic)) { | ||
if (partitionsToBeAdded.nonEmpty) { | ||
warn("Skipping adding partitions %s for topic %s since it is currently being deleted" | ||
.format(partitionsToBeAdded.map(_._1.partition).mkString(","), topic)) | ||
|
||
restorePartitionReplicaAssignment(topic, partitionReplicaAssignment) | ||
restorePartitionReplicaAssignment(topic, partitions.flatMap(_.assignment)) | ||
} else { | ||
// This can happen if existing partition replica assignment are restored to prevent increasing partition count during topic deletion | ||
info("Ignoring partition change during topic deletion as no new partitions are added") | ||
} | ||
} else if (partitionsToBeAdded.nonEmpty) { | ||
info(s"New partitions to be added $partitionsToBeAdded") | ||
partitionsToBeAdded.forKeyValue { (topicPartition, assignedReplicas) => | ||
controllerContext.updatePartitionFullReplicaAssignment(topicPartition, assignedReplicas) | ||
} | ||
onNewPartitionCreation(partitionsToBeAdded.keySet) | ||
processTopicIds(partitions) | ||
partitionsToBeAdded.foreach(tuple => controllerContext.updatePartitionFullReplicaAssignment(tuple._1, tuple._2)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think switching this to "tuple" makes it harder to read and less clear what the variables are. |
||
|
||
onNewPartitionCreation(partitionsToBeAdded.map(_._1)) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -602,14 +602,13 @@ class KafkaZkClient private[zk] (zooKeeperClient: ZooKeeperClient, isSecure: Boo | |
val updatedAssignments = topicIdReplicaAssignments.map { | ||
case TopicIdReplicaAssignment(topic, None, assignments) => | ||
TopicIdReplicaAssignment(topic, Some(Uuid.randomUuid()), assignments) | ||
case TopicIdReplicaAssignment(topic, Some(_), _) => | ||
throw new IllegalArgumentException("TopicIdReplicaAssignment for " + topic + " already contains a topic ID.") | ||
case t => t | ||
divijvaidya marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}.toSet | ||
|
||
val setDataRequests = updatedAssignments.map { case TopicIdReplicaAssignment(topic, topicIdOpt, assignments) => | ||
SetDataRequest(TopicZNode.path(topic), TopicZNode.encode(topicIdOpt, assignments), ZkVersion.MatchAnyVersion) | ||
}.toSeq | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: spacing |
||
retryRequestsUntilConnected(setDataRequests, expectedControllerEpochZkVersion) | ||
updatedAssignments | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readability is a bit tricky here. I'm also wondering if there was an operation you could have done besides making singleton sets and unioning them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we go through all the partitions again to check the topic ID and add to the replica assignment I wonder if we could have kept the partition and then a separate part for the ones with local IDs. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose this approach because this was the only one where we are able to 3-way partition the
topicIdAssignments
in a single iterations. All other approaches require multiple iterations.We can work on improving this and favouring readibility once we have a consensus on whether we will proceed with this change or not.