Skip to content

DefaultEndPoint.equals blocks on DNS and is inconsistent with hashCode for unresolved vs resolved addresses #1006

Description

@nikagra

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:

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions