use of org.apache.kafka.common.Uuid in project kafka by apache.
the class FetchSessionHandlerTest method testVerifyFullFetchResponsePartitionsWithTopicIds.
@Test
public void testVerifyFullFetchResponsePartitionsWithTopicIds() {
Map<String, Uuid> topicIds = new HashMap<>();
Map<Uuid, String> topicNames = new HashMap<>();
FetchSessionHandler handler = new FetchSessionHandler(LOG_CONTEXT, 1);
addTopicId(topicIds, topicNames, "foo", ApiKeys.FETCH.latestVersion());
addTopicId(topicIds, topicNames, "bar", ApiKeys.FETCH.latestVersion());
addTopicId(topicIds, topicNames, "extra2", ApiKeys.FETCH.latestVersion());
FetchResponse resp1 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, topicIds.get("foo"), 10, 20), new RespEntry("extra2", 1, topicIds.get("extra2"), 10, 20), new RespEntry("bar", 0, topicIds.get("bar"), 10, 20)));
String issue = handler.verifyFullFetchResponsePartitions(resp1.responseData(topicNames, ApiKeys.FETCH.latestVersion()).keySet(), resp1.topicIds(), ApiKeys.FETCH.latestVersion());
assertTrue(issue.contains("extraPartitions="));
assertFalse(issue.contains("omittedPartitions="));
FetchSessionHandler.Builder builder = handler.newBuilder();
builder.add(new TopicPartition("foo", 0), new FetchRequest.PartitionData(topicIds.get("foo"), 0, 100, 200, Optional.empty()));
builder.add(new TopicPartition("bar", 0), new FetchRequest.PartitionData(topicIds.get("bar"), 20, 120, 220, Optional.empty()));
builder.build();
FetchResponse resp2 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, topicIds.get("foo"), 10, 20), new RespEntry("extra2", 1, topicIds.get("extra2"), 10, 20), new RespEntry("bar", 0, topicIds.get("bar"), 10, 20)));
String issue2 = handler.verifyFullFetchResponsePartitions(resp2.responseData(topicNames, ApiKeys.FETCH.latestVersion()).keySet(), resp2.topicIds(), ApiKeys.FETCH.latestVersion());
assertTrue(issue2.contains("extraPartitions="));
assertFalse(issue2.contains("omittedPartitions="));
FetchResponse resp3 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, topicIds.get("foo"), 10, 20), new RespEntry("bar", 0, topicIds.get("bar"), 10, 20)));
String issue3 = handler.verifyFullFetchResponsePartitions(resp3.responseData(topicNames, ApiKeys.FETCH.latestVersion()).keySet(), resp3.topicIds(), ApiKeys.FETCH.latestVersion());
assertNull(issue3);
}
use of org.apache.kafka.common.Uuid in project kafka by apache.
the class FetchSessionHandlerTest method testVerifyFullFetchResponsePartitions.
@Test
public void testVerifyFullFetchResponsePartitions() {
Map<String, Uuid> topicIds = new HashMap<>();
Map<Uuid, String> topicNames = new HashMap<>();
// We want to test both on older versions that do not use topic IDs and on newer versions that do.
List<Short> versions = Arrays.asList((short) 12, ApiKeys.FETCH.latestVersion());
versions.forEach(version -> {
FetchSessionHandler handler = new FetchSessionHandler(LOG_CONTEXT, 1);
addTopicId(topicIds, topicNames, "foo", version);
addTopicId(topicIds, topicNames, "bar", version);
Uuid fooId = topicIds.getOrDefault("foo", Uuid.ZERO_UUID);
Uuid barId = topicIds.getOrDefault("bar", Uuid.ZERO_UUID);
TopicPartition foo0 = new TopicPartition("foo", 0);
TopicPartition foo1 = new TopicPartition("foo", 1);
TopicPartition bar0 = new TopicPartition("bar", 0);
FetchResponse resp1 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, fooId, 10, 20), new RespEntry("foo", 1, fooId, 10, 20), new RespEntry("bar", 0, barId, 10, 20)));
String issue = handler.verifyFullFetchResponsePartitions(resp1.responseData(topicNames, version).keySet(), resp1.topicIds(), version);
assertTrue(issue.contains("extraPartitions="));
assertFalse(issue.contains("omittedPartitions="));
FetchSessionHandler.Builder builder = handler.newBuilder();
builder.add(foo0, new FetchRequest.PartitionData(fooId, 0, 100, 200, Optional.empty()));
builder.add(foo1, new FetchRequest.PartitionData(fooId, 10, 110, 210, Optional.empty()));
builder.add(bar0, new FetchRequest.PartitionData(barId, 20, 120, 220, Optional.empty()));
builder.build();
FetchResponse resp2 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, fooId, 10, 20), new RespEntry("foo", 1, fooId, 10, 20), new RespEntry("bar", 0, barId, 10, 20)));
String issue2 = handler.verifyFullFetchResponsePartitions(resp2.responseData(topicNames, version).keySet(), resp2.topicIds(), version);
assertNull(issue2);
FetchResponse resp3 = FetchResponse.of(Errors.NONE, 0, INVALID_SESSION_ID, respMap(new RespEntry("foo", 0, fooId, 10, 20), new RespEntry("foo", 1, fooId, 10, 20)));
String issue3 = handler.verifyFullFetchResponsePartitions(resp3.responseData(topicNames, version).keySet(), resp3.topicIds(), version);
assertFalse(issue3.contains("extraPartitions="));
assertTrue(issue3.contains("omittedPartitions="));
});
}
use of org.apache.kafka.common.Uuid in project kafka by apache.
the class FetchSessionHandlerTest method testOkToAddNewIdAfterTopicRemovedFromSession.
@Test
public void testOkToAddNewIdAfterTopicRemovedFromSession() {
Uuid topicId = Uuid.randomUuid();
FetchSessionHandler handler = new FetchSessionHandler(LOG_CONTEXT, 1);
FetchSessionHandler.Builder builder = handler.newBuilder();
builder.add(new TopicPartition("foo", 0), new FetchRequest.PartitionData(topicId, 0, 100, 200, Optional.empty()));
FetchSessionHandler.FetchRequestData data = builder.build();
assertMapsEqual(reqMap(new ReqEntry("foo", topicId, 0, 0, 100, 200)), data.toSend(), data.sessionPartitions());
assertTrue(data.metadata().isFull());
assertTrue(data.canUseTopicIds());
FetchResponse resp = FetchResponse.of(Errors.NONE, 0, 123, respMap(new RespEntry("foo", 0, topicId, 10, 20)));
handler.handleResponse(resp, ApiKeys.FETCH.latestVersion());
// Remove the partition from the session. Return a session ID as though the session is still open.
FetchSessionHandler.Builder builder2 = handler.newBuilder();
FetchSessionHandler.FetchRequestData data2 = builder2.build();
assertMapsEqual(new LinkedHashMap<>(), data2.toSend(), data2.sessionPartitions());
FetchResponse resp2 = FetchResponse.of(Errors.NONE, 0, 123, new LinkedHashMap<>());
handler.handleResponse(resp2, ApiKeys.FETCH.latestVersion());
// After the topic is removed, add a recreated topic with a new ID.
FetchSessionHandler.Builder builder3 = handler.newBuilder();
builder3.add(new TopicPartition("foo", 0), new FetchRequest.PartitionData(Uuid.randomUuid(), 0, 100, 200, Optional.empty()));
FetchSessionHandler.FetchRequestData data3 = builder3.build();
// Should have the same session ID and epoch 2.
assertEquals(123, data3.metadata().sessionId(), "Did not use same session");
assertEquals(2, data3.metadata().epoch(), "Did not have the correct session epoch");
assertTrue(data.canUseTopicIds());
}
use of org.apache.kafka.common.Uuid in project kafka by apache.
the class KafkaAdminClient method handleDeleteTopicsUsingIds.
private Map<Uuid, KafkaFuture<Void>> handleDeleteTopicsUsingIds(final Collection<Uuid> topicIds, final DeleteTopicsOptions options) {
final Map<Uuid, KafkaFutureImpl<Void>> topicFutures = new HashMap<>(topicIds.size());
final List<Uuid> validTopicIds = new ArrayList<>(topicIds.size());
for (Uuid topicId : topicIds) {
if (topicId.equals(Uuid.ZERO_UUID)) {
KafkaFutureImpl<Void> future = new KafkaFutureImpl<>();
future.completeExceptionally(new InvalidTopicException("The given topic ID '" + topicId + "' cannot be represented in a request."));
topicFutures.put(topicId, future);
} else if (!topicFutures.containsKey(topicId)) {
topicFutures.put(topicId, new KafkaFutureImpl<>());
validTopicIds.add(topicId);
}
}
if (!validTopicIds.isEmpty()) {
final long now = time.milliseconds();
final long deadline = calcDeadlineMs(now, options.timeoutMs());
final Call call = getDeleteTopicsWithIdsCall(options, topicFutures, validTopicIds, Collections.emptyMap(), now, deadline);
runnable.call(call, now);
}
return new HashMap<>(topicFutures);
}
use of org.apache.kafka.common.Uuid in project kafka by apache.
the class KafkaAdminClient method getDeleteTopicsWithIdsCall.
private Call getDeleteTopicsWithIdsCall(final DeleteTopicsOptions options, final Map<Uuid, KafkaFutureImpl<Void>> futures, final List<Uuid> topicIds, final Map<Uuid, ThrottlingQuotaExceededException> quotaExceededExceptions, final long now, final long deadline) {
return new Call("deleteTopics", deadline, new ControllerNodeProvider()) {
@Override
DeleteTopicsRequest.Builder createRequest(int timeoutMs) {
return new DeleteTopicsRequest.Builder(new DeleteTopicsRequestData().setTopics(topicIds.stream().map(topic -> new DeleteTopicState().setTopicId(topic)).collect(Collectors.toList())).setTimeoutMs(timeoutMs));
}
@Override
void handleResponse(AbstractResponse abstractResponse) {
// Check for controller change
handleNotControllerError(abstractResponse);
// Handle server responses for particular topics.
final DeleteTopicsResponse response = (DeleteTopicsResponse) abstractResponse;
final List<Uuid> retryTopics = new ArrayList<>();
final Map<Uuid, ThrottlingQuotaExceededException> retryTopicQuotaExceededExceptions = new HashMap<>();
for (DeletableTopicResult result : response.data().responses()) {
KafkaFutureImpl<Void> future = futures.get(result.topicId());
if (future == null) {
log.warn("Server response mentioned unknown topic ID {}", result.topicId());
} else {
ApiError error = new ApiError(result.errorCode(), result.errorMessage());
if (error.isFailure()) {
if (error.is(Errors.THROTTLING_QUOTA_EXCEEDED)) {
ThrottlingQuotaExceededException quotaExceededException = new ThrottlingQuotaExceededException(response.throttleTimeMs(), error.messageWithFallback());
if (options.shouldRetryOnQuotaViolation()) {
retryTopics.add(result.topicId());
retryTopicQuotaExceededExceptions.put(result.topicId(), quotaExceededException);
} else {
future.completeExceptionally(quotaExceededException);
}
} else {
future.completeExceptionally(error.exception());
}
} else {
future.complete(null);
}
}
}
// If there are topics to retry, retry them; complete unrealized futures otherwise.
if (retryTopics.isEmpty()) {
// The server should send back a response for every topic. But do a sanity check anyway.
completeUnrealizedFutures(futures.entrySet().stream(), topic -> "The controller response did not contain a result for topic " + topic);
} else {
final long now = time.milliseconds();
final Call call = getDeleteTopicsWithIdsCall(options, futures, retryTopics, retryTopicQuotaExceededExceptions, now, deadline);
runnable.call(call, now);
}
}
@Override
void handleFailure(Throwable throwable) {
// If there were any topics retries due to a quota exceeded exception, we propagate
// the initial error back to the caller if the request timed out.
maybeCompleteQuotaExceededException(options.shouldRetryOnQuotaViolation(), throwable, futures, quotaExceededExceptions, (int) (time.milliseconds() - now));
// Fail all the other remaining futures
completeAllExceptionally(futures.values(), throwable);
}
};
}
Aggregations