PDGGK opened a new pull request, #9405:
URL: https://github.com/apache/paimon/pull/9405
### Purpose
`IcebergRef.equals` compares `maxRefAgeMs` with `==`, and that field is a
boxed
`Long`:
```java
// IcebergRef.java:50
@Nullable private final Long maxRefAgeMs;
// :85-87
return snapshotId == that.snapshotId
&& type.equals(that.type)
&& maxRefAgeMs == that.maxRefAgeMs;
```
So the comparison is on references, not values. It would still work if the
two
boxes happened to be the same object, but the constructor guarantees they are
not:
```java
// :53-60
public IcebergRef(@JsonProperty(FIELD_SNAPSHOT_ID) long snapshotId) {
this.snapshotId = snapshotId;
this.type = "tag";
this.maxRefAgeMs = Long.MAX_VALUE;
}
```
`Long.MAX_VALUE` is far outside the `Long` cache, so every `new
IcebergRef(..)`
autoboxes a fresh object and
```java
new IcebergRef(1L).equals(new IcebergRef(1L)) // false
```
`hashCode` was already written the other way:
```java
// :91-93
return Objects.hash(snapshotId, type, maxRefAgeMs);
```
which is value-based. The two therefore disagree: refs that hash to the same
bucket compare unequal, so a `HashSet<IcebergRef>` keeps both copies rather
than
deduplicating.
It does not stop there. `IcebergMetadata.equals` compares its refs map:
```java
// IcebergMetadata.java:371
&& Objects.equals(refs, that.refs);
```
`Map.equals` compares values with `equals`, so two `IcebergMetadata` carrying
identical tags are reported as different.
### What changes
```java
return snapshotId == that.snapshotId
&& Objects.equals(type, that.type)
&& Objects.equals(maxRefAgeMs, that.maxRefAgeMs);
```
`Objects` is already imported. `type` is switched over at the same time — it
is
non-null in practice, but there is no reason for one field in the expression
to
be able to throw while the others cannot.
### Test
`IcebergRefTest`, three cases, one per layer the defect reaches:
* `testEqualsIsByValue` — two refs built with the same snapshot id are
equal, and
refs with different ids are not
* `testEqualObjectsShareAHashCode` — the hashCodes match, and a `HashSet`
holding
both ends up with one element
* `testMetadataComparesItsRefsByValue` — two `Map<String, IcebergRef>` with
the
same content compare equal, which is the shape `IcebergMetadata.equals`
relies
on
Reverting only the `equals` body, on a forced clean rebuild of `paimon-core`,
fails all three — at three different levels rather than all on the same
assertion.
Wider run: `*Iceberg*` across `paimon-core` — 167 tests, 0 failures.
### API and Format
No change to any option, on-disk format or public signature.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]