Skip to content

resolver: cache all resolved addresses, not just the first#142

Open
zytakeshi wants to merge 1 commit into
cfal:masterfrom
zytakeshi:fix/resolver-cache-all-addresses
Open

resolver: cache all resolved addresses, not just the first#142
zytakeshi wants to merge 1 commit into
cfal:masterfrom
zytakeshi:fix/resolver-cache-all-addresses

Conversation

@zytakeshi

Copy link
Copy Markdown

CachingNativeResolver (the default resolver when no DNS config is set) caches resolution results in CachedResolveResult, which stored only a single SocketAddr per entry.

The two cache paths were asymmetric:

  • Cache miss: lookup_host returns the full Vec, and that full list is returned to the caller -- but only addrs[0] was stored in the cache.
  • Cache hit: only the stored single address was returned (vec![cached.addr]).

So the first lookup of a host returned every resolved record, while every subsequent lookup within the TTL (default 1h) returned just one address.

This matters because the consumer SocketConnectorImpl::connect iterates the full address list with a real per-address connect fallback (both the TCP and QUIC transports try each address in turn until one succeeds). With a cache hit returning a single address, that fallback has nothing left to try. The practical failure: a dual-stack host whose first record is unreachable connects on the first attempt (miss -> full list -> fallback works) but fails on every subsequent attempt for the rest of the TTL (hit -> single dead address).

Fix: store the full Vec in the cache and clone it on a hit, so the hit path is symmetric with the miss path. TTL/expiry semantics are unchanged.

Single-address callers are unaffected: resolve_single_address and the separate ResolverCache still take addrs[0], and the head of the list is identical to the previously-cached single address. A focused regression test asserts that a cache hit returns the same full list as the initial miss.

CachingNativeResolver stored only a single SocketAddr per cache entry.
A cache miss returned the full Vec<SocketAddr> from lookup_host, but a
cache hit returned only the first address. SocketConnectorImpl::connect
iterates the full list with a per-address connect fallback, so within the
cache TTL every connection after the first to a multi-address host could
only ever try one address -- if that address was unreachable (e.g. a
dual-stack host whose first record is down) the connection failed even
though a working address was cached. Store and return the full list on
both paths so the hit path is symmetric with the miss path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant