Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2179f0c
change to topicIdPartition
jolshan Sep 8, 2021
28acda9
Handle unknown topic IDs for full/sessionless cases.
jolshan Sep 9, 2021
8be7a96
Handling some incremental session things. Still need to handle partit…
jolshan Sep 9, 2021
79319f3
fix inconsistent topic ID handling for sessionless fetch contexts
jolshan Sep 9, 2021
9dcfa3f
finish up first draft of handling incremental partitions
jolshan Sep 10, 2021
643d7ff
Remove unnecessary error handling
jolshan Sep 16, 2021
eb8a6ed
cleanups
jolshan Sep 20, 2021
11deaa8
Merge branch 'trunk' of github.com:apache/kafka into KAFKA-13111
jolshan Sep 20, 2021
938d35e
Change equality checks based on which version we are using
jolshan Sep 21, 2021
8ea8653
Merge branch 'trunk' of github.com:apache/kafka into KAFKA-13111
jolshan Sep 28, 2021
815e8c0
try to transform fetch session handler
jolshan Sep 27, 2021
4caa2dd
Change FetchSessionHandler again to handle creating a new session rig…
jolshan Sep 28, 2021
5e7b628
Move topic ID error to partition level, remove extra topic ID map par…
jolshan Oct 6, 2021
32c6297
check version using nodeApiVersions
jolshan Oct 6, 2021
a1de391
KAFKA-13111; FetchSessionHandler WIP
dajac Oct 12, 2021
2708655
more refactor
dajac Oct 13, 2021
4cdc41c
Merge remote-tracking branch 'dajac/KAFKA-13111' into KAFKA-13111-test
jolshan Oct 22, 2021
83a91e6
Merge branch 'trunk' of github.com:apache/kafka into KAFKA-13111
jolshan Oct 22, 2021
50c9db6
Merge branch 'KAFKA-13111' of github.com:jolshan/kafka into KAFKA-13111
jolshan Oct 22, 2021
9f349f2
remove inconsistent topic ID from top level, put toForget after fetch…
jolshan Oct 26, 2021
c0a278f
Add some testing for edge cases
jolshan Oct 28, 2021
fbbf522
Respond to review comments
jolshan Nov 4, 2021
ea75200
Respond to comments on tests
jolshan Nov 5, 2021
9174fdb
FetchRequestTests, CachedPartition, FetchSessionHandler, and other cl…
jolshan Nov 8, 2021
43d69a1
PartitionData should take into account topicId in both equals and has…
dajac Nov 8, 2021
594b549
Add more tests to FetcherTest; Update logic in FetchSessionHandler; F…
dajac Nov 8, 2021
321ea1d
Fix tests, remove outdated error comments from FetchRequest/Response
jolshan Nov 8, 2021
f84b6f9
Add tests for AbstractFetcherThread and ReplicaFetcherThread
jolshan Nov 9, 2021
63bc476
Add testResolveUnknownPartitions test
dajac Nov 9, 2021
1a5fa71
More cleanups and test fixes
jolshan Nov 10, 2021
165a106
Merge branch 'trunk' of github.com:apache/kafka into KAFKA-13111
jolshan Nov 10, 2021
f8b1d14
Small fix in testResolveUnknownPartitions
dajac Nov 10, 2021
09fad0a
Further test fixes
jolshan Nov 10, 2021
eab5380
prepare for topicIdPartition refactor
jolshan Nov 11, 2021
5048d03
Merge branch 'trunk' of github.com:apache/kafka into KAFKA-13111
jolshan Nov 11, 2021
ae81d04
fix build
jolshan Nov 11, 2021
d458fd1
fix build
dajac Nov 11, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.kafka.clients;

import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.TopicIdPartition;
import org.apache.kafka.common.Uuid;
import org.apache.kafka.common.protocol.Errors;
import org.apache.kafka.common.requests.FetchMetadata;
Expand All @@ -39,6 +40,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.kafka.common.requests.FetchMetadata.INVALID_SESSION_ID;

Expand Down Expand Up @@ -536,7 +538,8 @@ public boolean handleResponse(FetchResponse response, short version) {
}
return false;
}
Set<TopicPartition> topicPartitions = response.responseData(sessionTopicNames, version).keySet();
Set<TopicPartition> topicPartitions = response.responseData(sessionTopicNames, version).keySet().stream().map(
TopicIdPartition::topicPartition).collect(Collectors.toSet());
if (nextMetadata.isFull()) {
if (topicPartitions.isEmpty() && response.throttleTimeMs() > 0) {
// Normally, an empty full fetch response would be invalid. However, KIP-219
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.kafka.common.Node;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.TopicIdPartition;
import org.apache.kafka.common.Uuid;
import org.apache.kafka.common.errors.CorruptRecordException;
import org.apache.kafka.common.errors.InvalidTopicException;
Expand Down Expand Up @@ -299,12 +300,12 @@ public void onSuccess(ClientResponse resp) {
return;
}

Map<TopicPartition, FetchResponseData.PartitionData> responseData = response.responseData(data.topicNames(), resp.requestHeader().apiVersion());
Set<TopicPartition> partitions = new HashSet<>(responseData.keySet());
Map<TopicIdPartition, FetchResponseData.PartitionData> responseData = response.responseData(data.topicNames(), resp.requestHeader().apiVersion());
Set<TopicPartition> partitions = new HashSet<>(responseData.keySet().stream().map(TopicIdPartition::topicPartition).collect(Collectors.toSet()));
FetchResponseMetricAggregator metricAggregator = new FetchResponseMetricAggregator(sensors, partitions);

for (Map.Entry<TopicPartition, FetchResponseData.PartitionData> entry : responseData.entrySet()) {
TopicPartition partition = entry.getKey();
for (Map.Entry<TopicIdPartition, FetchResponseData.PartitionData> entry : responseData.entrySet()) {
TopicPartition partition = entry.getKey().topicPartition();
FetchRequest.PartitionData requestData = data.sessionPartitions().get(partition);
if (requestData == null) {
String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.kafka.common.IsolationLevel;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.TopicIdPartition;
import org.apache.kafka.common.Uuid;
import org.apache.kafka.common.errors.UnknownTopicIdException;
import org.apache.kafka.common.message.FetchRequestData;
Expand Down Expand Up @@ -47,8 +48,8 @@ public class FetchRequest extends AbstractRequest {
public static final long INVALID_LOG_START_OFFSET = -1L;

private final FetchRequestData data;
private volatile LinkedHashMap<TopicPartition, PartitionData> fetchData = null;
private volatile List<TopicPartition> toForget = null;
private volatile LinkedHashMap<TopicIdPartition, PartitionData> fetchData = null;
private volatile List<TopicIdPartition> toForget = null;

// This is an immutable read-only structures derived from FetchRequestData
private final FetchMetadata metadata;
Expand Down Expand Up @@ -315,7 +316,7 @@ public int maxBytes() {
// For versions < 13, builds the partitionData map using only the FetchRequestData.
// For versions 13+, builds the partitionData map using both the FetchRequestData and a mapping of topic IDs to names.
// Throws UnknownTopicIdException for versions 13+ if the topic ID was unknown to the server.
public Map<TopicPartition, PartitionData> fetchData(Map<Uuid, String> topicNames) throws UnknownTopicIdException {
public Map<TopicIdPartition, PartitionData> fetchData(Map<Uuid, String> topicNames) throws UnknownTopicIdException {
Comment thread
jolshan marked this conversation as resolved.
Outdated
if (fetchData == null) {
synchronized (this) {
if (fetchData == null) {
Expand All @@ -328,22 +329,18 @@ public Map<TopicPartition, PartitionData> fetchData(Map<Uuid, String> topicNames
} else {
name = topicNames.get(fetchTopic.topicId());
}
if (name != null) {
// If topic name is resolved, simply add to fetchData map
fetchTopic.partitions().forEach(fetchPartition ->
fetchData.put(new TopicPartition(name, fetchPartition.partition()),
new PartitionData(
fetchPartition.fetchOffset(),
fetchPartition.logStartOffset(),
fetchPartition.partitionMaxBytes(),
optionalEpoch(fetchPartition.currentLeaderEpoch()),
optionalEpoch(fetchPartition.lastFetchedEpoch())
)
)
);
} else {
throw new UnknownTopicIdException(String.format("Topic Id %s in FetchRequest was unknown to the server", fetchTopic.topicId()));
}
// If topic name is resolved, simply add to fetchData map
Comment thread
jolshan marked this conversation as resolved.
Outdated
fetchTopic.partitions().forEach(fetchPartition ->
fetchData.put(new TopicIdPartition(fetchTopic.topicId(), new TopicPartition(name, fetchPartition.partition())),
Comment thread
jolshan marked this conversation as resolved.
new PartitionData(
fetchPartition.fetchOffset(),
fetchPartition.logStartOffset(),
fetchPartition.partitionMaxBytes(),
optionalEpoch(fetchPartition.currentLeaderEpoch()),
optionalEpoch(fetchPartition.lastFetchedEpoch())
)
)
);
});
}
}
Expand All @@ -352,7 +349,7 @@ public Map<TopicPartition, PartitionData> fetchData(Map<Uuid, String> topicNames
}

// For versions 13+, throws UnknownTopicIdException if the topic ID was unknown to the server.
public List<TopicPartition> forgottenTopics(Map<Uuid, String> topicNames) throws UnknownTopicIdException {
public List<TopicIdPartition> forgottenTopics(Map<Uuid, String> topicNames) throws UnknownTopicIdException {
if (toForget == null) {
synchronized (this) {
if (toForget == null) {
Expand All @@ -367,7 +364,7 @@ public List<TopicPartition> forgottenTopics(Map<Uuid, String> topicNames) throws
if (name == null) {
throw new UnknownTopicIdException(String.format("Topic Id %s in FetchRequest was unknown to the server", forgottenTopic.topicId()));
}
forgottenTopic.partitions().forEach(partitionId -> toForget.add(new TopicPartition(name, partitionId)));
forgottenTopic.partitions().forEach(partitionId -> toForget.add(new TopicIdPartition(forgottenTopic.topicId(), new TopicPartition(name, partitionId))));
Comment thread
jolshan marked this conversation as resolved.
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.kafka.common.requests;

import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.TopicIdPartition;
import org.apache.kafka.common.Uuid;
import org.apache.kafka.common.message.FetchResponseData;
import org.apache.kafka.common.protocol.ApiKeys;
Expand Down Expand Up @@ -72,7 +73,7 @@ public class FetchResponse extends AbstractResponse {

private final FetchResponseData data;
// we build responseData when needed.
private volatile LinkedHashMap<TopicPartition, FetchResponseData.PartitionData> responseData = null;
private volatile LinkedHashMap<TopicIdPartition, FetchResponseData.PartitionData> responseData = null;

@Override
public FetchResponseData data() {
Expand All @@ -96,7 +97,7 @@ public Errors error() {
return Errors.forCode(data.errorCode());
}

public LinkedHashMap<TopicPartition, FetchResponseData.PartitionData> responseData(Map<Uuid, String> topicNames, short version) {
public LinkedHashMap<TopicIdPartition, FetchResponseData.PartitionData> responseData(Map<Uuid, String> topicNames, short version) {
if (responseData == null) {
synchronized (this) {
if (responseData == null) {
Expand All @@ -110,7 +111,7 @@ public LinkedHashMap<TopicPartition, FetchResponseData.PartitionData> responseDa
}
if (name != null) {
topicResponse.partitions().forEach(partition ->
responseData.put(new TopicPartition(name, partition.partitionIndex()), partition));
responseData.put(new TopicIdPartition(topicResponse.topicId(), new TopicPartition(name, partition.partitionIndex())), partition));
}
});
}
Expand Down Expand Up @@ -154,16 +155,14 @@ public Set<Uuid> topicIds() {
*
* @param version The version of the response to use.
* @param partIterator The partition iterator.
* @param topicIds The mapping from topic name to topic ID.
* @return The response size in bytes.
*/
public static int sizeOf(short version,
Iterator<Map.Entry<TopicPartition,
FetchResponseData.PartitionData>> partIterator,
Map<String, Uuid> topicIds) {
Iterator<Map.Entry<TopicIdPartition,
FetchResponseData.PartitionData>> partIterator) {
// Since the throttleTimeMs and metadata field sizes are constant and fixed, we can
// use arbitrary values here without affecting the result.
FetchResponseData data = toMessage(Errors.NONE, 0, INVALID_SESSION_ID, partIterator, topicIds);
FetchResponseData data = toMessage(Errors.NONE, 0, INVALID_SESSION_ID, partIterator);
ObjectSerializationCache cache = new ObjectSerializationCache();
return 4 + data.size(cache, version);
}
Expand Down Expand Up @@ -226,40 +225,55 @@ public static int recordsSize(FetchResponseData.PartitionData partition) {
public static FetchResponse of(Errors error,
int throttleTimeMs,
int sessionId,
LinkedHashMap<TopicPartition, FetchResponseData.PartitionData> responseData,
Map<String, Uuid> topicIds) {
return new FetchResponse(toMessage(error, throttleTimeMs, sessionId, responseData.entrySet().iterator(), topicIds));
LinkedHashMap<TopicIdPartition, FetchResponseData.PartitionData> responseData) {
return new FetchResponse(toMessage(error, throttleTimeMs, sessionId, responseData.entrySet().iterator()));
}

private static boolean matchingTopic(FetchResponseData.FetchableTopicResponse previousTopic, TopicIdPartition currentTopic) {
if (previousTopic == null)
return false;
if (!previousTopic.topicId().equals(Uuid.ZERO_UUID))
return previousTopic.topicId().equals(currentTopic.topicId());
else
return previousTopic.topic().equals(currentTopic.topicPartition().topic());

}

private static FetchResponseData toMessage(Errors error,
int throttleTimeMs,
int sessionId,
Iterator<Map.Entry<TopicPartition, FetchResponseData.PartitionData>> partIterator,
Map<String, Uuid> topicIds) {
Iterator<Map.Entry<TopicIdPartition, FetchResponseData.PartitionData>> partIterator) {
List<FetchResponseData.FetchableTopicResponse> topicResponseList = new ArrayList<>();
partIterator.forEachRemaining(entry -> {
boolean hasInconsistentTopicId = false;
while (partIterator.hasNext()) {
Map.Entry<TopicIdPartition, FetchResponseData.PartitionData> entry = partIterator.next();
FetchResponseData.PartitionData partitionData = entry.getValue();
// Since PartitionData alone doesn't know the partition ID, we set it here
partitionData.setPartitionIndex(entry.getKey().partition());
partitionData.setPartitionIndex(entry.getKey().topicPartition().partition());
// We have to keep the order of input topic-partition. Hence, we batch the partitions only if the last
// batch is in the same topic group.
if (partitionData.errorCode() == Errors.INCONSISTENT_TOPIC_ID.code()) {
hasInconsistentTopicId = true;
}
FetchResponseData.FetchableTopicResponse previousTopic = topicResponseList.isEmpty() ? null
: topicResponseList.get(topicResponseList.size() - 1);
if (previousTopic != null && previousTopic.topic().equals(entry.getKey().topic()))
: topicResponseList.get(topicResponseList.size() - 1);
if (matchingTopic(previousTopic, entry.getKey()))
previousTopic.partitions().add(partitionData);
else {
List<FetchResponseData.PartitionData> partitionResponses = new ArrayList<>();
partitionResponses.add(partitionData);
topicResponseList.add(new FetchResponseData.FetchableTopicResponse()
.setTopic(entry.getKey().topic())
.setTopicId(topicIds.getOrDefault(entry.getKey().topic(), Uuid.ZERO_UUID))
.setPartitions(partitionResponses));
.setTopic(entry.getKey().topicPartition().topic())
.setTopicId(entry.getKey().topicId())
.setPartitions(partitionResponses));
}
});
}

short errorCode = hasInconsistentTopicId ? Errors.INCONSISTENT_TOPIC_ID.code() : error.code();

return new FetchResponseData()
.setThrottleTimeMs(throttleTimeMs)
.setErrorCode(error.code())
.setErrorCode(errorCode)
.setSessionId(sessionId)
.setResponses(topicResponseList);
}
Expand Down
Loading