apache / apache/rocketmq

[Bug] Static topic routing may use stale epoch due to comparator overflow

Open
#10,580 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.