use of org.apache.kafka.common.message.FetchRequestData in project kafka by apache.
the class RaftClientTestContext method assertFetchRequestData.
void assertFetchRequestData(RaftMessage message, int epoch, long fetchOffset, int lastFetchedEpoch) {
assertTrue(message.data() instanceof FetchRequestData, "Unexpected request type " + message.data());
FetchRequestData request = (FetchRequestData) message.data();
assertEquals(KafkaRaftClient.MAX_FETCH_SIZE_BYTES, request.maxBytes());
assertEquals(fetchMaxWaitMs, request.maxWaitMs());
assertEquals(1, request.topics().size());
assertEquals(metadataPartition.topic(), request.topics().get(0).topic());
assertEquals(1, request.topics().get(0).partitions().size());
FetchRequestData.FetchPartition fetchPartition = request.topics().get(0).partitions().get(0);
assertEquals(epoch, fetchPartition.currentLeaderEpoch());
assertEquals(fetchOffset, fetchPartition.fetchOffset());
assertEquals(lastFetchedEpoch, fetchPartition.lastFetchedEpoch());
assertEquals(localId.orElse(-1), request.replicaId());
}
use of org.apache.kafka.common.message.FetchRequestData in project kafka by apache.
the class RaftUtil method singletonFetchRequest.
public static FetchRequestData singletonFetchRequest(TopicPartition topicPartition, Uuid topicId, Consumer<FetchRequestData.FetchPartition> partitionConsumer) {
FetchRequestData.FetchPartition fetchPartition = new FetchRequestData.FetchPartition().setPartition(topicPartition.partition());
partitionConsumer.accept(fetchPartition);
FetchRequestData.FetchTopic fetchTopic = new FetchRequestData.FetchTopic().setTopic(topicPartition.topic()).setTopicId(topicId).setPartitions(singletonList(fetchPartition));
return new FetchRequestData().setTopics(singletonList(fetchTopic));
}
use of org.apache.kafka.common.message.FetchRequestData in project kafka by apache.
the class KafkaRaftClient method handleFetchRequest.
/**
* Handle a Fetch request. The fetch offset and last fetched epoch are always
* validated against the current log. In the case that they do not match, the response will
* indicate the diverging offset/epoch. A follower is expected to truncate its log in this
* case and resend the fetch.
*
* This API may return the following errors:
*
* - {@link Errors#INCONSISTENT_CLUSTER_ID} if the cluster id is presented in request
* but different from this node
* - {@link Errors#BROKER_NOT_AVAILABLE} if this node is currently shutting down
* - {@link Errors#FENCED_LEADER_EPOCH} if the epoch is smaller than this node's epoch
* - {@link Errors#INVALID_REQUEST} if the request epoch is larger than the leader's current epoch
* or if either the fetch offset or the last fetched epoch is invalid
*/
private CompletableFuture<FetchResponseData> handleFetchRequest(RaftRequest.Inbound requestMetadata, long currentTimeMs) {
FetchRequestData request = (FetchRequestData) requestMetadata.data;
if (!hasValidClusterId(request.clusterId())) {
return completedFuture(new FetchResponseData().setErrorCode(Errors.INCONSISTENT_CLUSTER_ID.code()));
}
if (!hasValidTopicPartition(request, log.topicPartition(), log.topicId())) {
// Until we support multi-raft, we treat topic partition mismatches as invalid requests
return completedFuture(new FetchResponseData().setErrorCode(Errors.INVALID_REQUEST.code()));
}
// If the ID is valid, we can set the topic name.
request.topics().get(0).setTopic(log.topicPartition().topic());
FetchRequestData.FetchPartition fetchPartition = request.topics().get(0).partitions().get(0);
if (request.maxWaitMs() < 0 || fetchPartition.fetchOffset() < 0 || fetchPartition.lastFetchedEpoch() < 0 || fetchPartition.lastFetchedEpoch() > fetchPartition.currentLeaderEpoch()) {
return completedFuture(buildEmptyFetchResponse(Errors.INVALID_REQUEST, Optional.empty()));
}
FetchResponseData response = tryCompleteFetchRequest(request.replicaId(), fetchPartition, currentTimeMs);
FetchResponseData.PartitionData partitionResponse = response.responses().get(0).partitions().get(0);
if (partitionResponse.errorCode() != Errors.NONE.code() || FetchResponse.recordsSize(partitionResponse) > 0 || request.maxWaitMs() == 0) {
return completedFuture(response);
}
CompletableFuture<Long> future = fetchPurgatory.await(fetchPartition.fetchOffset(), request.maxWaitMs());
return future.handle((completionTimeMs, exception) -> {
if (exception != null) {
Throwable cause = exception instanceof ExecutionException ? exception.getCause() : exception;
// If the fetch timed out in purgatory, it means no new data is available,
// and we will complete the fetch successfully. Otherwise, if there was
// any other error, we need to return it.
Errors error = Errors.forException(cause);
if (error != Errors.REQUEST_TIMED_OUT) {
logger.debug("Failed to handle fetch from {} at {} due to {}", request.replicaId(), fetchPartition.fetchOffset(), error);
return buildEmptyFetchResponse(error, Optional.empty());
}
}
// FIXME: `completionTimeMs`, which can be null
logger.trace("Completing delayed fetch from {} starting at offset {} at {}", request.replicaId(), fetchPartition.fetchOffset(), completionTimeMs);
return tryCompleteFetchRequest(request.replicaId(), fetchPartition, time.milliseconds());
});
}
use of org.apache.kafka.common.message.FetchRequestData in project kafka by apache.
the class RequestResponseTest method testFetchRequestCompat.
@Test
public void testFetchRequestCompat() {
Map<TopicPartition, FetchRequest.PartitionData> fetchData = new HashMap<>();
fetchData.put(new TopicPartition("test", 0), new FetchRequest.PartitionData(Uuid.ZERO_UUID, 100, 2, 100, Optional.of(42)));
FetchRequest req = FetchRequest.Builder.forConsumer((short) 2, 100, 100, fetchData).metadata(new FetchMetadata(10, 20)).isolationLevel(IsolationLevel.READ_COMMITTED).build((short) 2);
FetchRequestData data = req.data();
ObjectSerializationCache cache = new ObjectSerializationCache();
int size = data.size(cache, (short) 2);
ByteBufferAccessor writer = new ByteBufferAccessor(ByteBuffer.allocate(size));
data.write(writer, cache, (short) 2);
}
Aggregations