[Bug] Static topic routing may use stale epoch due to comparator overflow
- Dominant language
- Java
- Stars
- 22.6k
- Forks
- 12k
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 27
Description
### Before Creating the Bug Report
- [x] I found a bug, not just asking a question, which should be created in [GitHub Discussions](https://github.com/apache/rocketmq/discussions).
- [x] I have searched the [GitHub Issues](https://github.com/apache/rocketmq/issues) and [GitHub Discussions](https://github.com/apache/rocketmq/discussions) of this repository and believe that this is not a duplicate.
- [x] I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.
### Runtime platform environment
Ubuntu 20.04
### RocketMQ version
branch: develop
### JDK Version
_No response_
### Describe the Bug
Static topic routing and mapping validation may use the wrong mapping version when comparing mapping epochs with a large difference.
Two places sort static topic mapping metadata by epoch using subtraction and casting the result to `int`:
```java
(int) (o2.getValue().getEpoch() - o1.getValue().getEpoch())
```
and:
```java
(int) (o2.getEpoch() - o1.getEpoch())
```
If the epoch difference is greater than Integer.MAX_VALUE, the cast can overflow and return the wrong ordering. This can cause older static topic mapping metadata to be processed before newer metadata.
Affected files:
- remoting/src/main/java/org/apache/rocketmq/remoting/rpc/ClientMetadata.java
- remoting/src/main/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingUtils.java
### Steps to Reproduce
1. Create old static topic mapping metadata with epoch 0.
2. Create new static topic mapping metadata with epoch Integer.MAX_VALUE + 1L.
3. Use both mappings for the same logical queue/global queue.
4. Build routing/mapping result through:
- ClientMetadata.topicRouteData2EndpointsForStaticTopic(...)
- TopicQueueMappingUtils.checkAndBuildMappingItems(..., replace=true, ...)
5. Verify which mapping is selected.
### What Did You Expect to See?
The newer mapping with the higher epoch should always be selected, even when the epoch difference is greater than Integer.MAX_VALUE.
### What Did You See Instead?
The subtraction-based comparator can overflow and process stale lower-epoch metadata before newer metadata, which may cause static topic routing or mapping replacement to use stale broker mapping information.
### Additional Context
Suggested fix: use Long.compare(...) instead of subtraction-based comparison:
mappingInfos.sort((o1, o2) -> Long.compare(o2.getValue().getEpoch(), o1.getValue().getEpoch()));
and:
mappingDetailList.sort((o1, o2) -> Long.compare(o2.getEpoch(), o1.getEpoch()));
Contributor guide
Research direction
Start with remoting/src/main/java/org/apache/rocketmq/remoting/rpc/ClientMetadata.java and remoting/src/main/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingUtils.java, focusing on the sorting in topicRouteData2EndpointsForStaticTopic(...) and checkAndBuildMappingItems(...). Reproduce the case with epochs 0 and Integer.MAX_VALUE + 1L, then verify both routing and replacement paths consistently select the newer mapping.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100