Three comparators in rocketmq-tools subtract two long values and cast the difference to int:
GroupConsumeInfo.compareTo (tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java:352): (int) (o.diffTotal - diffTotal), while diffTotal is a long (field at line 283, assigned from consumeStats.computeTotalDiff()).
TagCountBean.compareTo (tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java:253): (int) (o.getCount().get() - this.count.get()).
QueryMsgByUniqueKeySubCommand.queryById (tools/src/main/java/org/apache/rocketmq/tools/command/message/QueryMsgByUniqueKeySubCommand.java:76): list.sort((o1, o2) -> (int) (o1.getStoreTimestamp() - o2.getStoreTimestamp())).
When the real difference is larger than Integer.MAX_VALUE the cast wraps: a positive difference becomes negative and vice versa. The printout order is then wrong, and the comparator contract is broken (sign(compare(a, b)) != -sign(compare(b, a))), which the JDK TimSort used by Collections.sort/List.sort can detect and fail with Comparison method violates its general contract!.
The values are reachable in practice: a group's total consume lag can exceed 2^31 messages, a queryMsgByUniqueKey -s/-e window can span more than about 24.8 days, and a printMsgByQueue tag count can exceed 2^31.
How to reproduce
Build two GroupConsumeInfo with setCount(1) and diffTotal of 0 and (long) Integer.MAX_VALUE + 1. Both left.compareTo(right) and right.compareTo(left) return a negative value, so the comparator is not antisymmetric; sorting a list that contains those entries prints them in the wrong order.
Expected
Comparisons should use Long.compare(...) / Comparator.comparingLong(...) instead of subtracting.
Three comparators in rocketmq-tools subtract two
longvalues and cast the difference toint:GroupConsumeInfo.compareTo(tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java:352):(int) (o.diffTotal - diffTotal), whilediffTotalis along(field at line 283, assigned fromconsumeStats.computeTotalDiff()).TagCountBean.compareTo(tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java:253):(int) (o.getCount().get() - this.count.get()).QueryMsgByUniqueKeySubCommand.queryById(tools/src/main/java/org/apache/rocketmq/tools/command/message/QueryMsgByUniqueKeySubCommand.java:76):list.sort((o1, o2) -> (int) (o1.getStoreTimestamp() - o2.getStoreTimestamp())).When the real difference is larger than
Integer.MAX_VALUEthe cast wraps: a positive difference becomes negative and vice versa. The printout order is then wrong, and the comparator contract is broken (sign(compare(a, b)) != -sign(compare(b, a))), which the JDKTimSortused byCollections.sort/List.sortcan detect and fail withComparison method violates its general contract!.The values are reachable in practice: a group's total consume lag can exceed 2^31 messages, a
queryMsgByUniqueKey-s/-ewindow can span more than about 24.8 days, and aprintMsgByQueuetag count can exceed 2^31.How to reproduce
Build two
GroupConsumeInfowithsetCount(1)anddiffTotalof0and(long) Integer.MAX_VALUE + 1. Bothleft.compareTo(right)andright.compareTo(left)return a negative value, so the comparator is not antisymmetric; sorting a list that contains those entries prints them in the wrong order.Expected
Comparisons should use
Long.compare(...)/Comparator.comparingLong(...)instead of subtracting.