-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-10427: Fetch snapshot #9553
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 4 commits
277e6a5
e648377
4ea3c9b
4609922
a96d16a
79fed61
33be3a4
2393cf7
61de910
cad8284
22133d1
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 |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.kafka.common.errors; | ||
|
|
||
| public class SnapshotNotFoundException extends ApiException { | ||
|
|
||
| private static final long serialVersionUID = 1; | ||
|
|
||
| public SnapshotNotFoundException(String s) { | ||
| super(s); | ||
| } | ||
|
|
||
| public SnapshotNotFoundException(String message, Throwable cause) { | ||
| super(message, cause); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.kafka.common.requests; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.Optional; | ||
| import java.util.function.UnaryOperator; | ||
| import org.apache.kafka.common.TopicPartition; | ||
| import org.apache.kafka.common.message.FetchSnapshotRequestData; | ||
| import org.apache.kafka.common.message.FetchSnapshotResponseData; | ||
| import org.apache.kafka.common.protocol.ApiKeys; | ||
| import org.apache.kafka.common.protocol.Errors; | ||
| import org.apache.kafka.common.protocol.Message; | ||
|
|
||
| final public class FetchSnapshotRequest extends AbstractRequest { | ||
| public final FetchSnapshotRequestData data; | ||
|
|
||
| public FetchSnapshotRequest(FetchSnapshotRequestData data) { | ||
| super(ApiKeys.FETCH_SNAPSHOT, (short) (FetchSnapshotRequestData.SCHEMAS.length - 1)); | ||
| this.data = data; | ||
| } | ||
|
|
||
| @Override | ||
| public FetchSnapshotResponse getErrorResponse(int throttleTimeMs, Throwable e) { | ||
| // TODO: we need to handle throttleTimeMs | ||
| return new FetchSnapshotResponse(new FetchSnapshotResponseData().setErrorCode(Errors.forException(e).code())); | ||
| } | ||
|
|
||
| @Override | ||
| protected Message data() { | ||
| return data; | ||
| } | ||
|
|
||
| public static FetchSnapshotRequestData singleton( | ||
| TopicPartition topicPartition, | ||
| UnaryOperator<FetchSnapshotRequestData.PartitionSnapshot> operator | ||
| ) { | ||
| FetchSnapshotRequestData.PartitionSnapshot partitionSnapshot = operator.apply( | ||
| new FetchSnapshotRequestData.PartitionSnapshot().setPartition(topicPartition.partition()) | ||
| ); | ||
|
|
||
| return new FetchSnapshotRequestData() | ||
| .setTopics( | ||
| Collections.singletonList( | ||
| new FetchSnapshotRequestData.TopicSnapshot() | ||
| .setName(topicPartition.topic()) | ||
| .setPartitions(Collections.singletonList(partitionSnapshot)) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| // TODO: write documentation. This function assumes that topic partitions are unique in `data` | ||
| public static Optional<FetchSnapshotRequestData.PartitionSnapshot> forTopicPartition( | ||
| FetchSnapshotRequestData data, | ||
| TopicPartition topicPartition | ||
| ) { | ||
| return data | ||
| .topics() | ||
| .stream() | ||
| .filter(topic -> topic.name().equals(topicPartition.topic())) | ||
| .flatMap(topic -> topic.partitions().stream()) | ||
| .filter(partition -> partition.partition() == topicPartition.partition()) | ||
| .findAny(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.kafka.common.requests; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.function.UnaryOperator; | ||
| import org.apache.kafka.common.TopicPartition; | ||
| import org.apache.kafka.common.message.FetchSnapshotResponseData; | ||
| import org.apache.kafka.common.protocol.ApiKeys; | ||
| import org.apache.kafka.common.protocol.Errors; | ||
| import org.apache.kafka.common.protocol.Message; | ||
|
|
||
| final public class FetchSnapshotResponse extends AbstractResponse { | ||
| public final FetchSnapshotResponseData data; | ||
|
|
||
| public FetchSnapshotResponse(FetchSnapshotResponseData data) { | ||
| super(ApiKeys.FETCH_SNAPSHOT); | ||
|
|
||
| this.data = data; | ||
| } | ||
|
|
||
| @Override | ||
| public Map<Errors, Integer> errorCounts() { | ||
| Map<Errors, Integer> errors = new HashMap<>(); | ||
|
|
||
| Errors topLevelError = Errors.forCode(data.errorCode()); | ||
| if (topLevelError != Errors.NONE) { | ||
| errors.put(topLevelError, 1); | ||
| } | ||
|
|
||
| for (FetchSnapshotResponseData.TopicSnapshot topicResponse : data.topics()) { | ||
| for (FetchSnapshotResponseData.PartitionSnapshot partitionResponse : topicResponse.partitions()) { | ||
| errors.compute(Errors.forCode(partitionResponse.errorCode()), | ||
| (error, count) -> count == null ? 1 : count + 1); | ||
| } | ||
| } | ||
|
|
||
| return errors; | ||
| } | ||
|
|
||
| @Override | ||
| public int throttleTimeMs() { | ||
| return data.throttleTimeMs(); | ||
| } | ||
|
|
||
| @Override | ||
| protected Message data() { | ||
| return data; | ||
| } | ||
|
|
||
| public static FetchSnapshotResponseData withTopError(Errors error) { | ||
| return new FetchSnapshotResponseData().setErrorCode(error.code()); | ||
| } | ||
|
|
||
| public static FetchSnapshotResponseData singleton( | ||
| TopicPartition topicPartition, | ||
| UnaryOperator<FetchSnapshotResponseData.PartitionSnapshot> operator | ||
| ) { | ||
| FetchSnapshotResponseData.PartitionSnapshot partitionSnapshot = operator.apply( | ||
| new FetchSnapshotResponseData.PartitionSnapshot().setIndex(topicPartition.partition()) | ||
| ); | ||
|
|
||
| return new FetchSnapshotResponseData() | ||
| .setTopics( | ||
| Collections.singletonList( | ||
| new FetchSnapshotResponseData.TopicSnapshot() | ||
| .setName(topicPartition.topic()) | ||
| .setPartitions(Collections.singletonList(partitionSnapshot)) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| // TODO: write documentation. This function assumes that topic partitions are unique in `data` | ||
| public static Optional<FetchSnapshotResponseData.PartitionSnapshot> forTopicPartition( | ||
| FetchSnapshotResponseData data, | ||
| TopicPartition topicPartition | ||
| ) { | ||
| return data | ||
| .topics() | ||
| .stream() | ||
| .filter(topic -> topic.name().equals(topicPartition.topic())) | ||
| .flatMap(topic -> topic.partitions().stream()) | ||
| .filter(parition -> parition.index() == topicPartition.partition()) | ||
| .findAny(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one or more | ||
| // contributor license agreements. See the NOTICE file distributed with | ||
| // this work for additional information regarding copyright ownership. | ||
| // The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| // (the "License"); you may not use this file except in compliance with | ||
| // the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| { | ||
| "apiKey": 59, | ||
| "type": "request", | ||
| "name": "FetchSnapshotRequest", | ||
| "validVersions": "0", | ||
| "flexibleVersions": "0+", | ||
| "fields": [ | ||
| { "name": "ClusterId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null", "taggedVersions": "0+", "tag": 0, | ||
| "about": "The clusterId if known, this is used to validate metadata fetches prior to broker registration" }, | ||
| { "name": "ReplicaId", "type": "int32", "versions": "0+", "default": "-1", | ||
| "about": "The broker ID of the follower" }, | ||
| { "name": "MaxBytes", "type": "int32", "versions": "0+", "default": "0x7fffffff", | ||
| "about": "The maximum bytes to fetch from all of the snapshots" }, | ||
| { "name": "Topics", "type": "[]TopicSnapshot", "versions": "0+", | ||
| "about": "The topics to fetch", "fields": [ | ||
| { "name": "Name", "type": "string", "versions": "0+", "entityType": "topicName", | ||
| "about": "The name of the topic to fetch" }, | ||
| { "name": "Partitions", "type": "[]PartitionSnapshot", "versions": "0+", | ||
| "about": "The partitions to fetch", "fields": [ | ||
| { "name": "Partition", "type": "int32", "versions": "0+", | ||
| "about": "The partition index" }, | ||
| { "name": "CurrentLeaderEpoch", "type": "int32", "versions": "0+", | ||
| "about": "The current leader epoch of the partition, -1 for unknown leader epoch" }, | ||
| { "name": "SnapshotId", "type": "SnapshotId", "versions": "0+", | ||
| "about": "The snapshot endOffset and epoch to fetch", | ||
| "fields": [ | ||
| { "name": "EndOffset", "type": "int64", "versions": "0+" }, | ||
| { "name": "Epoch", "type": "int32", "versions": "0+" } | ||
| ]}, | ||
| { "name": "Position", "type": "int64", "versions": "0+", | ||
| "about": "The byte position within the snapshot to start fetching from" } | ||
| ]} | ||
| ]} | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one or more | ||
| // contributor license agreements. See the NOTICE file distributed with | ||
| // this work for additional information regarding copyright ownership. | ||
| // The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| // (the "License"); you may not use this file except in compliance with | ||
| // the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| { | ||
| "apiKey": 59, | ||
| "type": "response", | ||
| "name": "FetchSnapshotResponse", | ||
| "validVersions": "0", | ||
| "flexibleVersions": "0+", | ||
| "fields": [ | ||
| { "name": "ThrottleTimeMs", "type": "int32", "versions": "0+", "ignorable": true, | ||
| "about": "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota." }, | ||
| { "name": "ErrorCode", "type": "int16", "versions": "0+", "ignorable": false, | ||
| "about": "The top level response error code." }, | ||
| { "name": "Topics", "type": "[]TopicSnapshot", "versions": "0+", | ||
| "about": "The topics to fetch.", "fields": [ | ||
| { "name": "Name", "type": "string", "versions": "0+", "entityType": "topicName", | ||
| "about": "The name of the topic to fetch." }, | ||
| { "name": "Partitions", "type": "[]PartitionSnapshot", "versions": "0+", | ||
| "about": "The partitions to fetch.", "fields": [ | ||
| { "name": "Index", "type": "int32", "versions": "0+", | ||
| "about": "The partition index." }, | ||
| { "name": "ErrorCode", "type": "int16", "versions": "0+", | ||
| "about": "The error code, or 0 if there was no fetch error." }, | ||
| { "name": "SnapshotId", "type": "SnapshotId", "versions": "0+", | ||
| "about": "The snapshot endOffset and epoch fetched", | ||
| "fields": [ | ||
| { "name": "EndOffset", "type": "int64", "versions": "0+" }, | ||
| { "name": "Epoch", "type": "int32", "versions": "0+" } | ||
| ]}, | ||
| { "name": "CurrentLeader", "type": "LeaderIdAndEpoch", | ||
| "versions": "0+", "taggedVersions": "0+", "tag": 0, "fields": [ | ||
| { "name": "LeaderId", "type": "int32", "versions": "0+", | ||
| "about": "The ID of the current leader or -1 if the leader is unknown."}, | ||
| { "name": "LeaderEpoch", "type": "int32", "versions": "0+", | ||
| "about": "The latest known leader epoch"} | ||
| ]}, | ||
| { "name": "Size", "type": "int64", "versions": "0+", | ||
| "about": "The total size of the snapshot." }, | ||
| { "name": "Position", "type": "int64", "versions": "0+", | ||
| "about": "The starting byte position within the snapshot included in the Bytes field." }, | ||
| { "name": "Bytes", "type": "bytes", "versions": "0+", "zeroCopy": true, | ||
|
Contributor
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. Can you remind me if we are planning to change the type to "records"? I don't think we will get the benefit of
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. Yeah. I created this issue: https://issues.apache.org/jira/browse/KAFKA-10694 I think we have two options:
I want to play around with this soon and restart the conversation on that issue and PR.
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. @jsancio Can we add an index file to the snapshot file so that the
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. @dengziming, Thanks for the comment. The If we implement option 1 in my comment above, we can still use
This guarantees that the Having said that, I think we should try and implement option 2. Unfortunately, the Jira https://issues.apache.org/jira/browse/KAFKA-10694 doesn't document option 2. |
||
| "about": "Snapshot data." } | ||
| ]} | ||
| ]} | ||
| ] | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.