Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion checkstyle/suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
files="(Utils|Topic|KafkaLZ4BlockOutputStream|AclData|JoinGroupRequest).java"/>

<suppress checks="CyclomaticComplexity"
files="(ConsumerCoordinator|Fetcher|KafkaProducer|ConfigDef|KerberosLogin|AbstractRequest|AbstractResponse|Selector|SslFactory|SslTransportLayer|SaslClientAuthenticator|SaslClientCallbackHandler|SaslServerAuthenticator|AbstractCoordinator|TransactionManager|AbstractStickyAssignor|DefaultSslEngineFactory|Authorizer|RecordAccumulator|MemoryRecords).java"/>
files="(ConsumerCoordinator|Fetcher|KafkaProducer|ConfigDef|KerberosLogin|AbstractRequest|AbstractResponse|Selector|SslFactory|SslTransportLayer|SaslClientAuthenticator|SaslClientCallbackHandler|SaslServerAuthenticator|AbstractCoordinator|TransactionManager|AbstractStickyAssignor|DefaultSslEngineFactory|Authorizer|RecordAccumulator|MemoryRecords|FetchSessionHandler).java"/>

<suppress checks="JavaNCSS"
files="(AbstractRequest|AbstractResponse|KerberosLogin|WorkerSinkTaskTest|TransactionManagerTest|SenderTest|KafkaAdminClient|ConsumerCoordinatorTest|KafkaAdminClientTest|KafkaRaftClientTest).java"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.kafka.clients;

import org.apache.kafka.common.TopicIdPartition;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.Uuid;
import org.apache.kafka.common.protocol.Errors;
Expand Down Expand Up @@ -76,11 +77,6 @@ public FetchSessionHandler(LogContext logContext, int node) {
private LinkedHashMap<TopicPartition, PartitionData> sessionPartitions =
new LinkedHashMap<>(0);

/**
* All of the topic ids mapped to topic names for topics which exist in the fetch request session.
*/
private Map<String, Uuid> sessionTopicIds = new HashMap<>(0);

/**
* All of the topic names mapped to topic ids for topics which exist in the fetch request session.
*/
Expand All @@ -99,22 +95,18 @@ public static class FetchRequestData {
/**
* The partitions to send in the request's "forget" list.
*/
private final List<TopicPartition> toForget;

/**
* All of the partitions which exist in the fetch request session.
*/
private final Map<TopicPartition, PartitionData> sessionPartitions;
private final List<TopicIdPartition> toForget;

/**
* All of the topic IDs for topics which exist in the fetch request session.
* The partitions to send in the request's "forget" list if
* the version is >= 13.
*/
private final Map<String, Uuid> topicIds;
private final List<TopicIdPartition> toReplace;

/**
* All of the topic IDs for topics which exist in the fetch request session
* All of the partitions which exist in the fetch request session.
*/
private final Map<Uuid, String> topicNames;
private final Map<TopicPartition, PartitionData> sessionPartitions;

/**
* The metadata to use in this fetch request.
Expand All @@ -128,17 +120,15 @@ public static class FetchRequestData {
private final boolean canUseTopicIds;

FetchRequestData(Map<TopicPartition, PartitionData> toSend,
List<TopicPartition> toForget,
List<TopicIdPartition> toForget,
List<TopicIdPartition> toReplace,
Map<TopicPartition, PartitionData> sessionPartitions,
Map<String, Uuid> topicIds,
Map<Uuid, String> topicNames,
FetchMetadata metadata,
boolean canUseTopicIds) {
this.toSend = toSend;
this.toForget = toForget;
this.toReplace = toReplace;
this.sessionPartitions = sessionPartitions;
this.topicIds = topicIds;
this.topicNames = topicNames;
this.metadata = metadata;
this.canUseTopicIds = canUseTopicIds;
}
Expand All @@ -153,25 +143,24 @@ public Map<TopicPartition, PartitionData> toSend() {
/**
* Get a list of partitions to forget in this fetch request.
*/
public List<TopicPartition> toForget() {
public List<TopicIdPartition> toForget() {
return toForget;
}

/**
* Get a list of partitions to forget in this fetch request.
*/
public List<TopicIdPartition> toReplace() {
return toReplace;
}

/**
* Get the full set of partitions involved in this fetch request.
*/
public Map<TopicPartition, PartitionData> sessionPartitions() {
return sessionPartitions;
}

public Map<String, Uuid> topicIds() {
return topicIds;
}

public Map<Uuid, String> topicNames() {
return topicNames;
}

public FetchMetadata metadata() {
return metadata;
}
Expand Down Expand Up @@ -201,7 +190,14 @@ public String toString() {
}
bld.append("), toForget=(");
prefix = "";
for (TopicPartition partition : toForget) {
for (TopicIdPartition partition : toForget) {
bld.append(prefix);
bld.append(partition);
prefix = ", ";
}
bld.append("), toReplace=(");
prefix = "";
for (TopicIdPartition partition : toReplace) {
bld.append(prefix);
bld.append(partition);
prefix = ", ";
Expand All @@ -216,15 +212,6 @@ public String toString() {
}
}
}
bld.append("), topicIds=(");
String prefix = "";
for (Map.Entry<String, Uuid> entry : topicIds.entrySet()) {
bld.append(prefix);
bld.append(entry.getKey());
bld.append(": ");
bld.append(entry.getValue());
prefix = ", ";
}
if (canUseTopicIds) {
bld.append("), canUseTopicIds=True");
} else {
Expand All @@ -250,32 +237,32 @@ public class Builder {
* incremental fetch requests (see below).
*/
private LinkedHashMap<TopicPartition, PartitionData> next;
private Map<String, Uuid> topicIds;
private Map<Uuid, String> topicNames;
private final boolean copySessionPartitions;
private int partitionsWithoutTopicIds = 0;

Builder() {
this.next = new LinkedHashMap<>();
this.topicIds = new HashMap<>();
this.topicNames = new HashMap<>();
Comment thread
jolshan marked this conversation as resolved.
this.copySessionPartitions = true;
}

Builder(int initialSize, boolean copySessionPartitions) {
this.next = new LinkedHashMap<>(initialSize);
this.topicIds = new HashMap<>(initialSize);
this.topicNames = new HashMap<>();
this.copySessionPartitions = copySessionPartitions;
}

/**
* Mark that we want data from this partition in the upcoming fetch.
*/
public void add(TopicPartition topicPartition, Uuid topicId, PartitionData data) {
public void add(TopicPartition topicPartition, PartitionData data) {
next.put(topicPartition, data);
// topicIds should not change between adding partitions and building, so we can use putIfAbsent
if (!topicId.equals(Uuid.ZERO_UUID)) {
topicIds.putIfAbsent(topicPartition.topic(), topicId);
} else {
if (data.topicId.equals(Uuid.ZERO_UUID)) {
partitionsWithoutTopicIds++;
} else {
topicNames.putIfAbsent(data.topicId, topicPartition.topic());
}
}

Expand All @@ -285,52 +272,55 @@ public FetchRequestData build() {
if (nextMetadata.isFull()) {
if (log.isDebugEnabled()) {
log.debug("Built full fetch {} for node {} with {}.",
nextMetadata, node, partitionsToLogString(next.keySet()));
nextMetadata, node, topicPartitionsToLogString(next.keySet()));
}
sessionPartitions = next;
next = null;
// Only add topic IDs to the session if we are using topic IDs.
if (canUseTopicIds) {
sessionTopicIds = topicIds;
sessionTopicNames = new HashMap<>(topicIds.size());
topicIds.forEach((name, id) -> sessionTopicNames.put(id, name));
sessionTopicNames = topicNames;
} else {
sessionTopicIds = new HashMap<>();
sessionTopicNames = new HashMap<>();
sessionTopicNames = Collections.emptyMap();
}
topicIds = null;
Map<TopicPartition, PartitionData> toSend =
Collections.unmodifiableMap(new LinkedHashMap<>(sessionPartitions));
Map<String, Uuid> toSendTopicIds =
Collections.unmodifiableMap(new HashMap<>(sessionTopicIds));
Map<Uuid, String> toSendTopicNames =
Collections.unmodifiableMap(new HashMap<>(sessionTopicNames));
return new FetchRequestData(toSend, Collections.emptyList(), toSend, toSendTopicIds, toSendTopicNames, nextMetadata, canUseTopicIds);
Collections.unmodifiableMap(new LinkedHashMap<>(sessionPartitions));
return new FetchRequestData(toSend, Collections.emptyList(), Collections.emptyList(), toSend, nextMetadata, canUseTopicIds);
}

List<TopicPartition> added = new ArrayList<>();
List<TopicPartition> removed = new ArrayList<>();
List<TopicPartition> altered = new ArrayList<>();
List<TopicIdPartition> added = new ArrayList<>();
List<TopicIdPartition> removed = new ArrayList<>();
List<TopicIdPartition> altered = new ArrayList<>();
List<TopicIdPartition> replaced = new ArrayList<>();
for (Iterator<Entry<TopicPartition, PartitionData>> iter =
sessionPartitions.entrySet().iterator(); iter.hasNext(); ) {
sessionPartitions.entrySet().iterator(); iter.hasNext(); ) {
Entry<TopicPartition, PartitionData> entry = iter.next();
TopicPartition topicPartition = entry.getKey();
PartitionData prevData = entry.getValue();
PartitionData nextData = next.remove(topicPartition);
if (nextData != null) {
if (!prevData.equals(nextData)) {
// We basically check if the new partition had the same topic ID. If not,
// we add it to the "replaced" set. If the request is version 13 or higher, the replaced
// partition will be forgotten. In any case, we will send the new partition in the request.
if (!prevData.topicId.equals(nextData.topicId)
&& !prevData.topicId.equals(Uuid.ZERO_UUID)
&& !nextData.topicId.equals(Uuid.ZERO_UUID)) {
Comment thread
dajac marked this conversation as resolved.
// Re-add the replaced partition to the end of 'next'
next.put(topicPartition, nextData);
entry.setValue(nextData);
replaced.add(new TopicIdPartition(prevData.topicId, topicPartition));
} else if (!prevData.equals(nextData)) {
// Re-add the altered partition to the end of 'next'
next.put(topicPartition, nextData);
entry.setValue(nextData);
altered.add(topicPartition);
altered.add(new TopicIdPartition(nextData.topicId, topicPartition));
}
} else {
// Remove this partition from the session.
iter.remove();
// Indicate that we no longer want to listen to this partition.
removed.add(topicPartition);
removed.add(new TopicIdPartition(prevData.topicId, topicPartition));
// If we do not have this topic ID in the builder or the session, we can not use topic IDs.
if (canUseTopicIds && !topicIds.containsKey(topicPartition.topic()) && !sessionTopicIds.containsKey(topicPartition.topic()))
if (canUseTopicIds && prevData.topicId.equals(Uuid.ZERO_UUID))
canUseTopicIds = false;
}
}
Expand All @@ -346,38 +336,34 @@ public FetchRequestData build() {
break;
}
sessionPartitions.put(topicPartition, nextData);
added.add(topicPartition);
added.add(new TopicIdPartition(nextData.topicId, topicPartition));
}

// Add topic IDs to session if we can use them. If an ID is inconsistent, we will handle in the receiving broker.
// If we switched from using topic IDs to not using them (or vice versa), that error will also be handled in the receiving broker.
if (canUseTopicIds) {
for (Map.Entry<String, Uuid> topic : topicIds.entrySet()) {
String topicName = topic.getKey();
Uuid addedId = topic.getValue();
sessionTopicIds.put(topicName, addedId);
sessionTopicNames.put(addedId, topicName);
}
sessionTopicNames = topicNames;
} else {
sessionTopicNames = Collections.emptyMap();
Comment thread
dajac marked this conversation as resolved.
}

if (log.isDebugEnabled()) {
log.debug("Built incremental fetch {} for node {}. Added {}, altered {}, removed {} " +
"out of {}", nextMetadata, node, partitionsToLogString(added),
partitionsToLogString(altered), partitionsToLogString(removed),
partitionsToLogString(sessionPartitions.keySet()));
log.debug("Built incremental fetch {} for node {}. Added {}, altered {}, removed {}, " +
"replaced {} out of {}", nextMetadata, node, topicIdPartitionsToLogString(added),
topicIdPartitionsToLogString(altered), topicIdPartitionsToLogString(removed),
topicIdPartitionsToLogString(replaced), topicPartitionsToLogString(sessionPartitions.keySet()));
}
Map<TopicPartition, PartitionData> toSend = Collections.unmodifiableMap(next);
Map<TopicPartition, PartitionData> curSessionPartitions = copySessionPartitions
? Collections.unmodifiableMap(new LinkedHashMap<>(sessionPartitions))
: Collections.unmodifiableMap(sessionPartitions);
Map<String, Uuid> toSendTopicIds =
Collections.unmodifiableMap(new HashMap<>(sessionTopicIds));
Map<Uuid, String> toSendTopicNames =
Collections.unmodifiableMap(new HashMap<>(sessionTopicNames));
next = null;
topicIds = null;
return new FetchRequestData(toSend, Collections.unmodifiableList(removed), curSessionPartitions,
toSendTopicIds, toSendTopicNames, nextMetadata, canUseTopicIds);
return new FetchRequestData(toSend,
Collections.unmodifiableList(removed),
Collections.unmodifiableList(replaced),
curSessionPartitions,
nextMetadata,
canUseTopicIds);
}
}

Expand All @@ -397,7 +383,14 @@ public Builder newBuilder(int size, boolean copySessionPartitions) {
return new Builder(size, copySessionPartitions);
}

private String partitionsToLogString(Collection<TopicPartition> partitions) {
private String topicPartitionsToLogString(Collection<TopicPartition> partitions) {
if (!log.isTraceEnabled()) {
return String.format("%d partition(s)", partitions.size());
}
return "(" + Utils.join(partitions, ", ") + ")";
}

private String topicIdPartitionsToLogString(Collection<TopicIdPartition> partitions) {
if (!log.isTraceEnabled()) {
return String.format("%d partition(s)", partitions.size());
}
Expand Down
Loading