[ISSUE #10446] Support batch deletion of topics and subscription groups in broker#10448
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds broker/admin support for batch deletion of topics and subscription groups via new remoting request codes and request bodies, plus client APIs and broker-side handling.
Changes:
- Introduce new request bodies and request codes for batch-delete operations.
- Implement broker processor logic to delete topic/group lists (including dedup + optional cleanup behaviors).
- Add persistence helpers for batch config deletion and tests covering the new admin paths.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/DeleteTopicListRequestBody.java | Adds request body for batch topic deletion. |
| remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/DeleteSubscriptionGroupListRequestBody.java | Adds request body for batch subscription-group deletion (with cleanOffset flag). |
| remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RequestCode.java | Adds new request codes for batch delete operations. |
| client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java | Adds client APIs to invoke the new batch delete broker requests. |
| broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java | Adds unit tests for batch deletion request handling and persistence behavior. |
| broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java | Adds batch topic-config deletion with single persist/update. |
| broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java | Adds batch subscription-group deletion with single persist/update. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java | Routes new request codes and implements batch delete handlers; refactors pop retry topic collection. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
oss-sentinel-ai
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
This PR addresses two related performance issues in AdminBrokerProcessor:
- Removes
synchronizedfromdeleteTopicsincetopicConfigTableis already aConcurrentHashMap - Adds batch deletion APIs (
DELETE_TOPIC_IN_BROKER_LISTandDELETE_SUBSCRIPTIONGROUP_LIST) to reduce network round-trips
Findings
- [Good] AdminBrokerProcessor.java:769 — Removed
synchronizedfromdeleteTopic. The underlyingtopicConfigTableis aConcurrentHashMap, so per-keyremoveis atomic. This eliminates unnecessary serialization of concurrent admin delete requests. - [Good] AdminBrokerProcessor.java — Added
deleteTopicList()anddeleteSubscriptionGroupList()handlers following the existing*_LISTconvention (consistent withUPDATE_AND_CREATE_TOPIC_LIST). - [Good] DeleteTopicListRequestBody.java / DeleteSubscriptionGroupListRequestBody.java — Clean request body classes extending
RemotingSerializable, following existing patterns. - [Good] MQClientAPIImpl.java:2202-2220 / 2281-2301 — Client-side batch deletion methods properly implemented with timeout handling.
- [Good] RequestCode.java — Added
DELETE_TOPIC_IN_BROKER_LISTandDELETE_SUBSCRIPTIONGROUP_LISTrequest codes. - [Good] TopicConfigManager.java / SubscriptionGroupManager.java — Added
deleteTopicList()anddeleteSubscriptionGroupList()batch methods. - [Good] AdminBrokerProcessorTest.java — Comprehensive test coverage including:
- Empty list validation (returns INVALID_PARAMETER)
- System topic rejection in batch
- Happy path with multiple topics
- Duplicate handling in batch
- Batch persist verification
Analysis
The implementation is well-structured:
- Backward compatibility: Existing single-item deletion APIs remain unchanged
- Consistent patterns: Follows the
*_LISTconvention established byCreateTopicListRequestBody - Proper validation: Empty lists and system topics are rejected
- Test coverage: Edge cases are well covered
Suggestions
- Consider adding a maximum batch size limit to prevent excessive memory usage or long-running operations.
- The batch persist test verifies deduplication — good attention to edge cases.
Verdict
✅ Approved — Well-designed performance optimization with proper validation and comprehensive test coverage.
Automated review by github-manager-bot
b3e851d to
75ae0ef
Compare
75ae0ef to
53cda76
Compare
2ac8039 to
9afd46f
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #10448 +/- ##
=============================================
- Coverage 48.19% 48.18% -0.02%
- Complexity 13398 13435 +37
=============================================
Files 1377 1380 +3
Lines 100730 100998 +268
Branches 13012 13072 +60
=============================================
+ Hits 48548 48661 +113
- Misses 46252 46353 +101
- Partials 5930 5984 +54 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Adds batch deletion APIs for topics (DELETE_TOPIC_IN_BROKER_LIST) and subscription groups (DELETE_SUBSCRIPTIONGROUP_LIST), with proper per-resource authorization, input validation, and atomic-all-or-nothing semantics.
Findings
- [Info] Authorization — Correctly emits one
DELETEcontext per resource in the batch, preventing bypass when the body carries the target list instead of the header. This is a security-critical detail handled well. - [Info] Error handling — Returns a structured error response with the list of failed items and the first exception. Good for debugging partial failures.
- [Info] Dedup — Uses
LinkedHashSetto preserve insertion order while deduplicating. Reasonable choice. - [Info] Refactoring — Extracts
collectPopRetryTopics()from inline code indeleteTopic(). Good cleanup that avoids duplication. - [Info] Cleanup order — Deletes client config and subscription first, then topic config last. Allows retry after partial failure.
- [Warning]
AdminBrokerProcessor.deleteTopicInBrokerList()— TheRemotingCommand responseis created once at the top and reused. IfdeleteTopicInBrokerinternally sets response fields, ensure there's no state leakage between the success and error paths. - [Warning]
MQClientAPIImpl.deleteTopicInBrokerList()— The method creates the request body and sends it. Consider adding a timeout or batch size limit to prevent excessively large requests.
Suggestions
- Consider adding a max batch size constant (e.g., 100) to prevent abuse or accidental large requests.
- The
DeleteTopicListRequestBodyandDeleteSubscriptionGroupListRequestBodyclasses are clean. Consider adding@AllArgsConstructorfor convenience if not already present. - Cross-repo: If batch deletion is exposed in the dashboard or CLI, ensure those clients are updated to use the new APIs.
Overall: Well-structured feature with proper authorization and error handling. A few minor suggestions but nothing blocking.
Automated review by github-manager-bot
9afd46f to
267bec0
Compare
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Adds two new batch admin APIs — DELETE_TOPIC_IN_BROKER_LIST and DELETE_SUBSCRIPTIONGROUP_LIST — to AdminBrokerProcessor, following the existing *_LIST convention (e.g. UPDATE_AND_CREATE_TOPIC_LIST). Includes proper authorization context building for body-driven batch requests, new request body DTOs, and test coverage.
Findings
- [Info] Authorization handling for body-driven batch APIs is correctly implemented — the
DefaultAuthorizationContextBuilderdecodes the request body and emits oneDELETEcontext per item, preventing the annotation-based path from producing an empty context list (which would bypass permission checks). - [Info] Good test coverage in
DefaultAuthorizationContextBuilderTest— verifies blank entries are filtered, correct resource types, and per-item DELETE action. - [Warning] The batch deletion is not atomic — if one topic/group fails to delete (e.g. still in use), the remaining items in the list may still be deleted. Consider documenting this partial-failure behavior in the API response, or adding a
failFastflag. - [Info]
LinkedHashSetfor deduplication while preserving insertion order is a good choice for predictable behavior. - [Info] New
DeleteTopicListRequestBodyandDeleteSubscriptionGroupListRequestBodyfollow the existing pattern ofCreateTopicListRequestBody.
Suggestions
- Consider adding a response summary that reports per-item success/failure status (similar to how batch operations in other systems report partial results). This would help callers understand which items succeeded when partial failure occurs.
- Add a brief comment in
AdminBrokerProcessordocumenting the non-atomic semantics of batch deletion.
No blocking issues. Well-structured addition that follows existing conventions.
Automated review by github-manager-bot
Server Benchmark Results (2026-06-22)Environment: 8C30G broker, Dragonwell JDK 21, 1KB msg, 128 queues, sync mode, 256 threads, 20s warmup + 30s collect Producer-only (steady state, lines 3-5)
This is a feature PR (batch delete Topic/SubscriptionGroup), not a performance optimization. Benchmark confirms no regression. |
|
For That keeps the batch API aligned with the current single-delete semantics and avoids a large batch request creating a sudden cleanup burst on the broker. It would also be good to add a regression test covering the throttled batch path and invalid-entry handling before the loop starts. |
267bec0 to
4f0ab43
Compare
Review by github-manager-bot (Re-review after new commit
|
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Updated review for the latest push (4f0ab43). This PR adds batch deletion APIs (DELETE_TOPIC_IN_BROKER_LIST, DELETE_SUBSCRIPTIONGROUP_LIST) to AdminBrokerProcessor, following the existing *_LIST convention. Includes per-resource authorization context building, new request body DTOs, client helpers, and test coverage.
What Changed Since Last Review
- Single commit (4f0ab43) rebased/updated on 2026-06-24.
- A new reviewer suggestion from @fuyou001 proposes reusing the single-topic delete path with a
RateLimiterinstead of a separate batch cleanup sequence.
Findings
- [Info] Authorization —
DefaultAuthorizationContextBuildercorrectly decodes the request body and emits oneDELETEcontext per resource. This prevents the annotation-based path from producing an empty context list (which would bypass permission checks). Well handled. - [Info] Dedup + ordering —
LinkedHashSetpreserves insertion order while deduplicating inputs. Good choice for predictable behavior. - [Info] Refactoring —
collectPopRetryTopics(...)is extracted from inline code indeleteTopic(), now shared by both single and batch paths. Reduces duplication. - [Info] Batch persist —
TopicConfigManager.deleteTopicConfigList()andSubscriptionGroupManager.deleteSubscriptionGroupConfigList()aggregatepersist()once per batch instead of N times. Significant efficiency gain for large batches. - [Info] Error reporting — Returns structured error with the list of failed items and the first exception. Good for debugging partial failures.
- [Warning] No batch size limit — Neither
deleteTopicListnordeleteSubscriptionGroupListcaps the input list size. A caller could send thousands of items in a single RPC, causing a long-running synchronized block and a largemessageStore.deleteTopics(...)call. Consider adding a max batch size constant (e.g., 100 or 200) and returningREQUEST_CODE_NOT_SUPPORTEDor a validation error when exceeded. - [Warning] Rate limiting concern (raised by @fuyou001) — The current batch path does a burst of all deletes in one shot. If the reviewer suggestion is adopted (iterate +
RateLimiter), it would smooth out the cleanup burst. If not adopted, at minimum document why a burst is acceptable for the expected use cases (tenant decommissioning, retention purge). - [Warning]
synchronizedscope — BothdeleteTopicListanddeleteSubscriptionGroupListaresynchronized, consistent with existing single-item methods. However, the batch path holds the lock for the entire batch duration. For large batches this could block other admin operations. This is acknowledged as out-of-scope (#9997/#9998) but worth noting for reviewers. - [Info] Client null-check —
MQClientAPIImpl.deleteTopicInBrokerList()anddeleteSubscriptionGroupList()use explicit null checks on the response (instead ofassert), producing a deterministicMQClientException(SYSTEM_ERROR, ...). Good defensive coding. - [Info] Backward compatibility — New
*_LISTrequest codes are additive; older brokers will returnREQUEST_CODE_NOT_SUPPORTEDviagetUnknownCmdResponse. No breaking changes.
Suggestions
- Add a max batch size guard — e.g.,
if (topicList.size() > MAX_BATCH_SIZE) { return error response; }. This is a low-cost safety measure. - Address @fuyou001 feedback — Either adopt the RateLimiter approach or explain why the current burst behavior is acceptable for the target use cases.
- Consider adding a timeout parameter — The client methods accept
timeoutMillisbut the broker-side processing has no internal timeout. For very large batches, the broker could log a warning if processing exceeds a threshold.
Overall: Solid implementation with proper authorization, error handling, and test coverage. The main concern is the lack of batch size limits and the reviewer suggestion about rate limiting. Nothing blocking, but worth addressing before merge.
Automated review by github-manager-bot
4f0ab43 to
930d6e6
Compare
|
@fuyou001 Thanks for the suggestion!
We ran a broker-side A/B experiment comparing both approaches with the same batch RPC (only the broker JAR differs):
Server benchmark results (50 topics/groups, Producer+Consumer running at ~180k TPS):
The key bottleneck is Both variants have zero impact on concurrent Producer/Consumer TPS and P99 RT because the delete operation completes in under 1 second either way. The difference is in the delete operation latency itself — important for admin tools that wait for the response. Regarding code reuse concern: The batch path only diverges at the Would appreciate your feedback! |
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot (Re-review)
Summary
Re-review after rebase. PR adds batch deletion APIs (DELETE_TOPIC_IN_BROKER_LIST, DELETE_SUBSCRIPTIONGROUP_LIST) following the existing *_LIST convention. The rebase preserves the previous design: body-driven batch requests, per-item authorization contexts, single-persist batching, and structured partial-failure responses.
Findings
- [Info] Authorization — Body-driven batch APIs correctly emit one
DELETEcontext per resource inDefaultAuthorizationContextBuilder, preventing the annotation-based path from producing an empty context list. Verified for both topic and subscription group batch codes. - [Info] Batch persist —
TopicConfigManager#deleteTopicConfigListandSubscriptionGroupManager#deleteSubscriptionGroupConfigListaggregate into a singlepersist()call per batch, avoiding N writes. Good. - [Info] Dedup —
LinkedHashSetpreserves insertion order while deduplicating input. Consistent with existing*_LISTpatterns. - [Info] Refactoring —
collectPopRetryTopics()extraction is clean and shared between single and batch delete paths, reducing duplication. - [Info] Client null-check —
MQClientAPIImplmethods use explicitresponse == nullcheck (instead ofassert) and throwMQClientException(SYSTEM_ERROR, ...). Deterministic behavior. - [Info] Request codes —
5002/5003are additive; older brokers returngetUnknownCmdResponsefor unknown codes. No backward compatibility risk. - [Warning]
AdminBrokerProcessor#deleteTopicList— TheRemotingCommand responseis created once at the top. On the success path,response.setCode(ResponseCode.SUCCESS)andresponse.setRemark(null)are set explicitly. On the error path, aDeleteTopicListResponseBodyis serialized into the response body. This is correct, but verify that no intermediate code path mutatesresponsefields between the two branches (e.g., a logging interceptor that callsresponse.setRemark()). - [Warning] No max batch size — Neither the server-side handler nor the client method enforces a maximum batch size. A caller could send thousands of topics in a single RPC, causing a long
synchronizedhold on the broker. Consider adding a server-side guard (e.g., reject iftopicList.size() > 1000) to prevent accidental or malicious abuse.
Suggestions
- Consider adding a
MAX_BATCH_SIZEconstant (e.g., 1000) and rejecting oversized requests early indeleteTopicList()/deleteSubscriptionGroupList()with a clear error message. - The
DeleteSubscriptionGroupListRequestBodyhas a 2-arg constructor(groupNameList, cleanOffset)and a 1-arg constructor(groupNameList). The 1-arg constructor could delegate to the 2-arg one (this(groupNameList, false)) to reduce duplication.
Verdict
Rebase looks clean — previous findings still hold. No new issues introduced. The two warnings above are non-blocking suggestions for future hardening.
Automated review by github-manager-bot
930d6e6 to
e9c0d3e
Compare
…n groups in broker - Add DELETE_TOPIC_IN_BROKER_LIST and DELETE_SUBSCRIPTIONGROUP_LIST request codes with corresponding RequestBody types - Implement deleteTopicList / deleteSubscriptionGroupList in AdminBrokerProcessor with deduplication and one-shot persist - Add deleteTopicConfigList / deleteSubscriptionGroupConfigList in TopicConfigManager / SubscriptionGroupManager (single persist per batch) - Add MQClientAPIImpl#deleteTopicInBrokerList / deleteSubscriptionGroupList client APIs - Cover changes with unit tests in AdminBrokerProcessorTest
e9c0d3e to
42a2df2
Compare
Which Issue(s) This PR Fixes
Fixes #10446
Brief Description
Adds two new batch admin APIs to
AdminBrokerProcessorwhose names follow the existing*_LISTconvention (e.g.UPDATE_AND_CREATE_TOPIC_LIST,UPDATE_AND_CREATE_SUBSCRIPTIONGROUP_LIST):DELETE_TOPIC_IN_BROKER_LISTDELETE_SUBSCRIPTIONGROUP_LISTBulk metadata cleanup (e.g. tenant decommissioning, retention purge, cluster migration) currently requires N round-trips to delete N items and triggers N
persist()calls on the broker config files. These new APIs allow doing the same in 1 RPC + 1 persist + 1messageStore.deleteTopics(Set)call.Changes
RequestCode: addDELETE_TOPIC_IN_BROKER_LISTandDELETE_SUBSCRIPTIONGROUP_LIST.DeleteTopicListRequestBody { List<String> topicList }DeleteSubscriptionGroupListRequestBody { List<String> groupNameList; boolean cleanOffset }TopicConfigManager#deleteTopicConfigList(List<String>)andSubscriptionGroupManager#deleteSubscriptionGroupConfigList(List<String>): aggregatepersist()once per batch.AdminBrokerProcessor:collectPopRetryTopics(...)shared helper used by both single and batch paths.deleteTopicList(...)anddeleteSubscriptionGroupList(...)(bothsynchronized, consistent with existing single APIs) with input dedup (preserving order), system-topic / blank validation, one-shot persist, and one-shotmessageStore.deleteTopics(...)call.MQClientAPIImpl: adddeleteTopicInBrokerList(...)anddeleteSubscriptionGroupList(...)client helpers; both use an explicit null check (instead ofassert) so callers get a deterministicMQClientException(SYSTEM_ERROR, ...)wheninvokeSyncreturns null.Compatibility
DELETE_TOPIC_IN_BROKER/DELETE_SUBSCRIPTIONGROUPrequest codes and methods are unchanged; existing clients are not affected.*_LISTrequest codes are additive; older brokers will fall through togetUnknownCmdResponse, so older clients/brokers continue to work as today.How Did You Test This Change?
New unit tests added in
AdminBrokerProcessorTest:testDeleteTopicListInBroker— covers empty input, system-topic rejection, and the success path.testDeleteTopicListBatchPersist— verifies that:deleteTopicConfigListis invoked once (sopersist()runs once for the whole batch),deleteTopicConfigis not called on the batch path,messageStore.deleteTopics(...)is invoked once with the batched set,testDeleteSubscriptionGroupList— covers empty input and the success path withcleanOffset=true.Local verification: