From 0fba6bc14e95291dfa0f2bcd3142d1c3e8dab830 Mon Sep 17 00:00:00 2001 From: enkilee Date: Thu, 2 Jul 2026 15:08:42 +0800 Subject: [PATCH 1/2] Signed-off-by: enkilee MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix equal bug in some files. equals/hashCode 基于当前字段值。若对象在集合中时字段被修改,可能导致定位失败——这是这些类本就存在的可变性问题,本次修复仅保证契约一致性,未改变可变性。 --- .../rocketmq/client/trace/TraceContext.java | 17 +++++++++++++ .../grpc/v2/channel/GrpcClientChannel.java | 17 +++++++++++++ .../processor/channel/RemoteChannel.java | 17 +++++++++++++ .../rocketmq/store/pop/PopCheckPoint.java | 17 +++++++++++++ .../tieredstore/provider/FileSegment.java | 17 +++++++++++++ .../consumer/ConsumerProgressSubCommand.java | 19 +++++++++++++++ .../message/PrintMessageByQueueCommand.java | 24 +++++++++++++++++++ 7 files changed, 128 insertions(+) diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java b/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java index a1f632e024c..13b06c17d38 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/TraceContext.java @@ -131,6 +131,23 @@ public int compareTo(TraceContext o) { return Long.compare(this.timeStamp, o.getTimeStamp()); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TraceContext)) { + return false; + } + TraceContext that = (TraceContext) o; + return this.timeStamp == that.timeStamp; + } + + @Override + public int hashCode() { + return Long.hashCode(timeStamp); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(1024); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 0135818fb3b..f77dde6d6db 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -155,6 +155,23 @@ public int compareTo(ChannelId o) { return asLongText().compareTo(o.asLongText()); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof GrpcChannelId)) { + return false; + } + GrpcChannelId that = (GrpcChannelId) o; + return this.clientId == null ? that.clientId == null : this.clientId.equals(that.clientId); + } + + @Override + public int hashCode() { + return this.clientId == null ? 0 : this.clientId.hashCode(); + } } public void setClientObserver(StreamObserver future) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannel.java index fb9666afcc3..a3887ce0e15 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannel.java @@ -59,6 +59,23 @@ public int compareTo(ChannelId o) { return this.id.compareTo(o.asLongText()); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RemoteChannelId)) { + return false; + } + RemoteChannelId that = (RemoteChannelId) o; + return this.id.equals(that.id); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java index 803ebc68957..b38d4005b0f 100644 --- a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java +++ b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java @@ -214,4 +214,21 @@ public String toString() { public int compareTo(PopCheckPoint o) { return (int) (this.getStartOffset() - o.getStartOffset()); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PopCheckPoint)) { + return false; + } + PopCheckPoint that = (PopCheckPoint) o; + return this.getStartOffset() == that.getStartOffset(); + } + + @Override + public int hashCode() { + return Long.hashCode(getStartOffset()); + } } diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/provider/FileSegment.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/provider/FileSegment.java index 0d4e39b74f1..60d6b43f006 100644 --- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/provider/FileSegment.java +++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/provider/FileSegment.java @@ -77,6 +77,23 @@ public int compareTo(FileSegment o) { return Long.compare(this.baseOffset, o.baseOffset); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FileSegment)) { + return false; + } + FileSegment that = (FileSegment) o; + return this.baseOffset == that.baseOffset; + } + + @Override + public int hashCode() { + return Long.hashCode(baseOffset); + } + public long getBaseOffset() { return baseOffset; } diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java index b638dcf61f3..04976192575 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerProgressSubCommand.java @@ -352,6 +352,25 @@ public int compareTo(GroupConsumeInfo o) { return (int) (o.diffTotal - diffTotal); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof GroupConsumeInfo)) { + return false; + } + GroupConsumeInfo that = (GroupConsumeInfo) o; + return this.count == that.count && this.diffTotal == that.diffTotal; + } + + @Override + public int hashCode() { + int result = Integer.hashCode(count); + result = 31 * result + Long.hashCode(diffTotal); + return result; + } + public int getConsumeTps() { return consumeTps; } diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java index 0418e88a706..c1a22ac9b8d 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java @@ -252,5 +252,29 @@ public void setCount(final AtomicLong count) { public int compareTo(final TagCountBean o) { return (int) (o.getCount().get() - this.count.get()); } + + // Note: compareTo orders by count for display sorting, but the identity of a + // TagCountBean is its tag. equals/hashCode are intentionally based on tag so that + // two beans with the same tag but different counts are treated as equal, and beans + // with different tags are never collapsed even if their counts happen to match. + // This means compareTo is inconsistent with equals by design (allowed by the + // Comparable contract when the ordering is "not consistent with equals"); the class + // is only used with Collections.sort on a List, never in a sorted set/map. + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TagCountBean)) { + return false; + } + TagCountBean that = (TagCountBean) o; + return this.tag == null ? that.tag == null : this.tag.equals(that.tag); + } + + @Override + public int hashCode() { + return tag == null ? 0 : tag.hashCode(); + } } } From 769919ddf70f3a71d92d6c4cf6ee6dbce9f8ae3f Mon Sep 17 00:00:00 2001 From: enkilee Date: Thu, 2 Jul 2026 15:11:50 +0800 Subject: [PATCH 2/2] del comment --- .../tools/command/message/PrintMessageByQueueCommand.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java index c1a22ac9b8d..4a5b21d0ff1 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/command/message/PrintMessageByQueueCommand.java @@ -253,13 +253,6 @@ public int compareTo(final TagCountBean o) { return (int) (o.getCount().get() - this.count.get()); } - // Note: compareTo orders by count for display sorting, but the identity of a - // TagCountBean is its tag. equals/hashCode are intentionally based on tag so that - // two beans with the same tag but different counts are treated as equal, and beans - // with different tags are never collapsed even if their counts happen to match. - // This means compareTo is inconsistent with equals by design (allowed by the - // Comparable contract when the ordering is "not consistent with equals"); the class - // is only used with Collections.sort on a List, never in a sorted set/map. @Override public boolean equals(Object o) { if (this == o) {