-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-14402: Update AddPartitionsToTxn protocol to batch and handle verifyOnly requests #13231
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
Changes from all commits
4f760d6
70d11ba
a8d6c00
47f0fff
4c4d99e
4ad3df0
3f0c89c
791d56b
f8dbaa1
2c7d25c
4aa0417
19dbfe6
42486de
32ca9bb
a7abdae
fd1f92b
4589d36
ac16b13
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 |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
|
|
||
| import org.apache.kafka.common.TopicPartition; | ||
| import org.apache.kafka.common.message.AddPartitionsToTxnResponseData; | ||
| import org.apache.kafka.common.message.AddPartitionsToTxnResponseData.AddPartitionsToTxnResult; | ||
| import org.apache.kafka.common.message.AddPartitionsToTxnResponseData.AddPartitionsToTxnPartitionResult; | ||
| import org.apache.kafka.common.message.AddPartitionsToTxnResponseData.AddPartitionsToTxnPartitionResultCollection; | ||
| import org.apache.kafka.common.message.AddPartitionsToTxnResponseData.AddPartitionsToTxnTopicResult; | ||
|
|
@@ -27,7 +28,9 @@ | |
| import org.apache.kafka.common.protocol.Errors; | ||
|
|
||
| import java.nio.ByteBuffer; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
|
|
@@ -48,29 +51,51 @@ public class AddPartitionsToTxnResponse extends AbstractResponse { | |
|
|
||
| private final AddPartitionsToTxnResponseData data; | ||
|
|
||
| private Map<TopicPartition, Errors> cachedErrorsMap = null; | ||
| public static final String V3_AND_BELOW_TXN_ID = ""; | ||
|
|
||
| public AddPartitionsToTxnResponse(AddPartitionsToTxnResponseData data) { | ||
| super(ApiKeys.ADD_PARTITIONS_TO_TXN); | ||
| this.data = data; | ||
| } | ||
|
|
||
| public AddPartitionsToTxnResponse(int throttleTimeMs, Map<TopicPartition, Errors> errors) { | ||
| super(ApiKeys.ADD_PARTITIONS_TO_TXN); | ||
| @Override | ||
| public int throttleTimeMs() { | ||
| return data.throttleTimeMs(); | ||
| } | ||
|
|
||
| @Override | ||
| public void maybeSetThrottleTimeMs(int throttleTimeMs) { | ||
| data.setThrottleTimeMs(throttleTimeMs); | ||
| } | ||
|
|
||
| public Map<String, Map<TopicPartition, Errors>> errors() { | ||
| Map<String, Map<TopicPartition, Errors>> errorsMap = new HashMap<>(); | ||
|
|
||
| if (!this.data.resultsByTopicV3AndBelow().isEmpty()) { | ||
| errorsMap.put(V3_AND_BELOW_TXN_ID, errorsForTransaction(this.data.resultsByTopicV3AndBelow())); | ||
| } | ||
|
|
||
| for (AddPartitionsToTxnResult result : this.data.resultsByTransaction()) { | ||
| errorsMap.put(result.transactionalId(), errorsForTransaction(result.topicResults())); | ||
| } | ||
|
|
||
| return errorsMap; | ||
| } | ||
|
|
||
| private static AddPartitionsToTxnTopicResultCollection topicCollectionForErrors(Map<TopicPartition, Errors> errors) { | ||
| Map<String, AddPartitionsToTxnPartitionResultCollection> resultMap = new HashMap<>(); | ||
|
|
||
| for (Map.Entry<TopicPartition, Errors> entry : errors.entrySet()) { | ||
| TopicPartition topicPartition = entry.getKey(); | ||
| String topicName = topicPartition.topic(); | ||
|
|
||
| AddPartitionsToTxnPartitionResult partitionResult = | ||
| new AddPartitionsToTxnPartitionResult() | ||
| .setErrorCode(entry.getValue().code()) | ||
| .setPartitionIndex(topicPartition.partition()); | ||
| new AddPartitionsToTxnPartitionResult() | ||
| .setPartitionErrorCode(entry.getValue().code()) | ||
| .setPartitionIndex(topicPartition.partition()); | ||
|
|
||
| AddPartitionsToTxnPartitionResultCollection partitionResultCollection = resultMap.getOrDefault( | ||
| topicName, new AddPartitionsToTxnPartitionResultCollection() | ||
| topicName, new AddPartitionsToTxnPartitionResultCollection() | ||
| ); | ||
|
|
||
| partitionResultCollection.add(partitionResult); | ||
|
|
@@ -80,45 +105,44 @@ topicName, new AddPartitionsToTxnPartitionResultCollection() | |
| AddPartitionsToTxnTopicResultCollection topicCollection = new AddPartitionsToTxnTopicResultCollection(); | ||
| for (Map.Entry<String, AddPartitionsToTxnPartitionResultCollection> entry : resultMap.entrySet()) { | ||
| topicCollection.add(new AddPartitionsToTxnTopicResult() | ||
| .setName(entry.getKey()) | ||
| .setResults(entry.getValue())); | ||
| .setName(entry.getKey()) | ||
| .setResultsByPartition(entry.getValue())); | ||
| } | ||
|
|
||
| this.data = new AddPartitionsToTxnResponseData() | ||
| .setThrottleTimeMs(throttleTimeMs) | ||
| .setResults(topicCollection); | ||
| return topicCollection; | ||
| } | ||
|
|
||
| @Override | ||
| public int throttleTimeMs() { | ||
| return data.throttleTimeMs(); | ||
| public static AddPartitionsToTxnResult resultForTransaction(String transactionalId, Map<TopicPartition, Errors> errors) { | ||
| return new AddPartitionsToTxnResult().setTransactionalId(transactionalId).setTopicResults(topicCollectionForErrors(errors)); | ||
| } | ||
|
|
||
| @Override | ||
| public void maybeSetThrottleTimeMs(int throttleTimeMs) { | ||
| data.setThrottleTimeMs(throttleTimeMs); | ||
| public AddPartitionsToTxnTopicResultCollection getTransactionTopicResults(String transactionalId) { | ||
| return data.resultsByTransaction().find(transactionalId).topicResults(); | ||
| } | ||
|
|
||
| public Map<TopicPartition, Errors> errors() { | ||
| if (cachedErrorsMap != null) { | ||
| return cachedErrorsMap; | ||
| } | ||
|
|
||
| cachedErrorsMap = new HashMap<>(); | ||
|
|
||
| for (AddPartitionsToTxnTopicResult topicResult : this.data.results()) { | ||
| for (AddPartitionsToTxnPartitionResult partitionResult : topicResult.results()) { | ||
| cachedErrorsMap.put(new TopicPartition( | ||
| topicResult.name(), partitionResult.partitionIndex()), | ||
| Errors.forCode(partitionResult.errorCode())); | ||
| public static Map<TopicPartition, Errors> errorsForTransaction(AddPartitionsToTxnTopicResultCollection topicCollection) { | ||
| Map<TopicPartition, Errors> topicResults = new HashMap<>(); | ||
| for (AddPartitionsToTxnTopicResult topicResult : topicCollection) { | ||
| for (AddPartitionsToTxnPartitionResult partitionResult : topicResult.resultsByPartition()) { | ||
| topicResults.put( | ||
| new TopicPartition(topicResult.name(), partitionResult.partitionIndex()), Errors.forCode(partitionResult.partitionErrorCode())); | ||
| } | ||
| } | ||
| return cachedErrorsMap; | ||
| return topicResults; | ||
| } | ||
|
|
||
| @Override | ||
| public Map<Errors, Integer> errorCounts() { | ||
| return errorCounts(errors().values()); | ||
| List<Errors> allErrors = new ArrayList<>(); | ||
|
|
||
| // If we are not using this field, we have request 4 or later | ||
| if (this.data.resultsByTopicV3AndBelow().isEmpty()) { | ||
| allErrors.add(Errors.forCode(data.errorCode())); | ||
|
Member
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: Should we use
Member
Author
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 create allErrors because I use addAll for the individual transactions. I can place this code after I create error counts, but it doesn't really seem to accomplish much. |
||
| } | ||
|
|
||
| errors().forEach((txnId, errors) -> | ||
| allErrors.addAll(errors.values()) | ||
| ); | ||
| return errorCounts(allErrors); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
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.
nit: I suppose that
errorsshould never benullhere. I wonder if we should still check it. What do you think?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.
What should we do if the check fails? Just have a better error message thrown?
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.
Yeah, the check is probably not necessary. By the way, I find the idea of having
V3_AND_BELOW_TXN_IDfor old version a bit confusing. I was wondering if usingaddPartitionsToTxnResponse.data().resultsByTopicV3AndBelow()would be a better alternative here. We only iterate over the Map so the Map is not strictly required here. Have you considered something like this?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 was told not to have v3 and below specific methods from Jason because the v3 case should generalize to a single version of the v4 case and that should make it easy to use methods for both.
However, if we really think this is an issue. I guess we can change the approach again. I'm just not sure the experience of errors only applying to v4+. Any ideas there besides changing the method name to express it should only be used in v4+?
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.
Understood. Let's keep it as it is then.
I agree that v3 case should generalized to a single item of the v4 case. It is just unfortunate that we don't have the transaction id in v3 response so we have to use an empty string for it. I suppose that it is the way it is.
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.
Yeah. It really is unfortunate. 😞