Skip to content

[Bug] Master election may choose lower-offset broker due to maxOffset comparator overflow #10578

Description

@Aias00

Before Creating the Bug Report

  • I found a bug, not just asking a question, which should be created in GitHub Discussions.

  • I have searched the GitHub Issues and GitHub Discussions of this repository and believe that this is not a duplicate.

  • I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.

Runtime platform environment

OS: Ubuntu 20.04

RocketMQ version

branch: develop

JDK Version

No response

Describe the Bug

DefaultElectPolicy may elect the wrong broker as master when two broker candidates have the same epoch but their maxOffset values differ by more than Integer.MAX_VALUE.

The comparator currently subtracts two long offsets and casts the result to int:

(int) (o2.getMaxOffset() - o1.getMaxOffset())

This can overflow and reverse the intended ordering, causing a lower-offset broker to be ranked before a higher-offset broker.

Steps to Reproduce

  1. Create two BrokerLiveInfo candidates with the same epoch and same election priority.
  2. Set broker 1 maxOffset to 0.
  3. Set broker 2 maxOffset to Integer.MAX_VALUE + 1L.
  4. Call DefaultElectPolicy.elect(...) with both brokers as valid candidates.
  5. Observe which broker is elected.

What Did You Expect to See?

The broker with the higher maxOffset should be elected when epoch values are equal.

What Did You See Instead?

The comparator can overflow and rank the lower-offset broker first, so the controller may elect a stale replica as master.

Additional Context

Affected file:

controller/src/main/java/org/apache/rocketmq/controller/elect/impl/DefaultElectPolicy.java

Suggested fix: replace subtraction-based comparison with safe comparator methods:

int epochCompare = Integer.compare(o2.getEpoch(), o1.getEpoch());
if (epochCompare != 0) {
return epochCompare;
}

int offsetCompare = Long.compare(o2.getMaxOffset(), o1.getMaxOffset());
if (offsetCompare != 0) {
return offsetCompare;
}

return Integer.compare(o1.getElectionPriority(), o2.getElectionPriority());

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions