DefaultEndPoint.equals resolves the unresolved side before comparing:
if (thisAddress.isUnresolved() && !thatAddress.isUnresolved()) {
thisAddress = new InetSocketAddress(thisAddress.getHostName(), thisAddress.getPort());
} // ...
Three problems with that branch:
- It blocks.
new InetSocketAddress(String, int) performs a DNS lookup inline on the calling
thread. equals() is called from metadata refresh paths and from event handling on the admin
event loop, so a slow or unreachable resolver stalls a driver thread inside what reads like a
field comparison.
- The answer is arbitrary. That constructor keeps only the first address the name maps to,
so for a multi-record name the result is "equal iff this node happens to be the one the resolver
listed first" — it flips as DNS ordering changes.
- It is inconsistent with
hashCode(), which is address.hashCode() and ignores resolution
entirely. So a hostname and one of its IPs can be equals while hashing differently, and
hash-based collections never treat them as the same entry — including the contact-point
Set<EndPoint> (SessionBuilder.programmaticContactPoints, ContactPoints.merge), where a
mixed pair for the same host is silently kept twice.
The lenient comparison therefore only ever takes effect on linear scans, and where it does take
effect it is neither cheap nor deterministic.
Proposal
Compare address as-is and drop the resolving branch, making equals/hashCode consistent for
the first time. The only remaining consumer of the lenient behaviour is the public
Metadata.findNode(EndPoint), so this needs an upgrade-guide entry: a caller holding an unresolved
hostname endpoint would no longer find a node registered under its resolved IP (which today it
finds only when that IP is the name's first record anyway).
Signal to watch first
DRIVER-201 (#890) removed every driver-internal mixed comparison and added a one-shot WARN on
this branch. If that warning does not show up in the field, nothing outside findNode relies on
it and the branch can go.
DefaultEndPoint.equalsresolves the unresolved side before comparing:Three problems with that branch:
new InetSocketAddress(String, int)performs a DNS lookup inline on the callingthread.
equals()is called from metadata refresh paths and from event handling on the adminevent loop, so a slow or unreachable resolver stalls a driver thread inside what reads like a
field comparison.
so for a multi-record name the result is "equal iff this node happens to be the one the resolver
listed first" — it flips as DNS ordering changes.
hashCode(), which isaddress.hashCode()and ignores resolutionentirely. So a hostname and one of its IPs can be
equalswhile hashing differently, andhash-based collections never treat them as the same entry — including the contact-point
Set<EndPoint>(SessionBuilder.programmaticContactPoints,ContactPoints.merge), where amixed pair for the same host is silently kept twice.
The lenient comparison therefore only ever takes effect on linear scans, and where it does take
effect it is neither cheap nor deterministic.
Proposal
Compare
addressas-is and drop the resolving branch, makingequals/hashCodeconsistent forthe first time. The only remaining consumer of the lenient behaviour is the public
Metadata.findNode(EndPoint), so this needs an upgrade-guide entry: a caller holding an unresolvedhostname endpoint would no longer find a node registered under its resolved IP (which today it
finds only when that IP is the name's first record anyway).
Signal to watch first
DRIVER-201 (#890) removed every driver-internal mixed comparison and added a one-shot
WARNonthis branch. If that warning does not show up in the field, nothing outside
findNoderelies onit and the branch can go.