You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iggy.apache.org by ra...@apache.org on 2026/10/03 23:47:28 UTC
(iggy) branch feat/gateways-3546-delete-topics-only updated: Updating after quick review
This is an automated email from the ASF dual-hosted git repository.
ryerraguntla pushed a commit to branch feat/gateways-3546-delete-topics-only
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/feat/gateways-3546-delete-topics-only by this push:
new 1a0acc49b Updating after quick review
1a0acc49b is described below
commit 1a0acc49b1c370384243df0b697c9989a9c0ad2a
Author: ryerraguntla <ra...@gmail.com>
AuthorDate: Sat Oct 3 19:44:01 2026 -0400
Updating after quick review
---
.../kafka/src/protocol/handlers/delete_topics.rs | 42 ++++++++++++++--------
1 file changed, 28 insertions(+), 14 deletions(-)
diff --git a/gateways/kafka/src/protocol/handlers/delete_topics.rs b/gateways/kafka/src/protocol/handlers/delete_topics.rs
index 58f427614..0a23f95f7 100644
--- a/gateways/kafka/src/protocol/handlers/delete_topics.rs
+++ b/gateways/kafka/src/protocol/handlers/delete_topics.rs
@@ -21,12 +21,19 @@
//! stream - see [`IggyBridge::delete_kafka_topic`]'s own doc comment for why: the shared
//! `default_stream` can hold other Kafka topics' data, and this bridge has no way to tell
//! whether the stream it just emptied is actually abandoned or just temporarily topic-less.
+//!
+//! `DeletableTopicResult.error_message` is only encoded on the wire at v5+ (`kafka_protocol`'s
+//! own gate) - a client negotiating v1-v4 gets `error_code` only, with any text this module sets
+//! silently dropped. Unlike `CreateTopics`, whose equivalent field is encoded at every version it
+//! supports.
use std::time::Duration;
use bytes::Bytes;
+use iggy::prelude::IggyError;
use kafka_protocol::messages::delete_topics_response::DeletableTopicResult;
use kafka_protocol::messages::{DeleteTopicsRequest, DeleteTopicsResponse, TopicName};
+use kafka_protocol::protocol::StrBytes;
use tokio::time::Instant;
@@ -53,10 +60,12 @@ pub const RANGE: ApiVersionRange = ApiVersionRange {
max_version: 5,
};
-/// Cap on distinct topic names one `DeleteTopics` request may address through the bridge.
+/// Cap on topic names one `DeleteTopics` request may address through the bridge.
///
-/// Same rationale as `create_topics::MAX_BRIDGE_BACKED_TOPICS`: each name costs a bridge round
-/// trip against the single lockstep `IggyClient` every Kafka connection on this gateway shares.
+/// Same rationale as `create_topics::MAX_BRIDGE_BACKED_TOPICS`, but counted differently: every
+/// name here costs its own bridge round trip against the single lockstep `IggyClient` every
+/// Kafka connection on this gateway shares, duplicates included, so this charges the raw count
+/// rather than the distinct one `CreateTopics` charges.
const MAX_BRIDGE_BACKED_TOPICS: usize = 100;
/// Same bounds as `create_topics::clamp_request_timeout` - this request carries the identical
@@ -111,12 +120,12 @@ pub async fn handle(state: &GatewayState, api_version: i16, body: Bytes) -> Hand
// the only populated field at any version this bridge advertises.
if req.topic_names.len() > MAX_BRIDGE_BACKED_TOPICS {
tracing::warn!(
- distinct_topics = req.topic_names.len(),
+ requested_topics = req.topic_names.len(),
max = MAX_BRIDGE_BACKED_TOPICS,
"DeleteTopics request addresses too many topics; rejecting"
);
- let message = kafka_protocol::protocol::StrBytes::from(format!(
- "this gateway addresses at most {MAX_BRIDGE_BACKED_TOPICS} distinct topics per DeleteTopics request"
+ let message = StrBytes::from(format!(
+ "this gateway addresses at most {MAX_BRIDGE_BACKED_TOPICS} topic names per DeleteTopics request"
));
let results = req
.topic_names
@@ -181,7 +190,12 @@ async fn delete_one_topic(bridge: &IggyBridge, name: &TopicName) -> DeletableTop
.with_name(Some(name.clone()))
.with_error_message(None);
match bridge.delete_kafka_topic(name.as_str()).await {
- Ok(()) => result.with_error_code(ERROR_NONE),
+ // The second arm: the write committed on its first attempt, the SDK's own reconnect path
+ // replayed it, and the server's client-table dedup caught the replay - not a fault. Same
+ // reasoning as `create_topics::create_one_topic`'s identical arm.
+ Ok(()) | Err(BridgeError::Iggy(IggyError::RequestAlreadyApplied)) => {
+ result.with_error_code(ERROR_NONE)
+ }
Err(err) => bridge_error_result(result, name.as_str(), &err),
}
}
@@ -204,17 +218,17 @@ fn bridge_error_result(
reason,
"DeleteTopics rejected an invalid topic name"
);
- result.with_error_code(error_code).with_error_message(Some(
- kafka_protocol::protocol::StrBytes::from(reason.clone()),
- ))
+ result
+ .with_error_code(error_code)
+ .with_error_message(Some(StrBytes::from(reason.clone())))
}
other => {
tracing::error!(kafka_topic, %other, "DeleteTopics failed against the Iggy bridge");
- result.with_error_code(error_code).with_error_message(Some(
- kafka_protocol::protocol::StrBytes::from(
+ result
+ .with_error_code(error_code)
+ .with_error_message(Some(StrBytes::from(
"internal error deleting this topic".to_string(),
- ),
- ))
+ )))
}
}
}