Skip to content

Commit 98f7004

Browse files
nikagraclaude
andcommitted
refactor(client-routes): replace CachingDnsResolver with FallbackDnsResolver
The JVM (Java 8+) already caches DNS lookups internally (~30s TTL), making the 500ms TTL layer in CachingDnsResolver redundant — the JVM's cache always wins. The semaphore storm-prevention machinery is similarly superfluous since the JVM serializes concurrent lookups to the same hostname internally. The only genuine value-add is the last-known-good fallback: returning a stale IP when DNS temporarily fails. Remove CachingDnsResolver (TTL cache, CacheEntry, SemaphoreEntry, semaphore logic, cacheDurationMillis constructor arg). Replace with FallbackDnsResolver that delegates directly to InetAddress.getByName() and keeps a lastKnownGood map. Remove dnsCacheDurationMillis from ClientRoutesConfig (field, getter, withDnsCacheDuration() builder method, DEFAULT_DNS_CACHE_DURATION_MILLIS). Update ClientRoutesTopologyMonitor to use new FallbackDnsResolver(). Replace CachingDnsResolverTest with FallbackDnsResolverTest; delete TTL and semaphore tests, keep fallback, evict, and clearCache coverage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent a1c5c91 commit 98f7004

9 files changed

Lines changed: 282 additions & 605 deletions

File tree

core/src/main/java/com/datastax/oss/driver/api/core/config/ClientRoutesConfig.java

Lines changed: 4 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
* .addEndpoint(new ClientRoutesEndpoint(
4747
* UUID.fromString("12345678-1234-1234-1234-123456789012"),
4848
* "my-cluster-endpoint.example.com:9042"))
49-
* .withDnsCacheDuration(1000L) // Cache DNS for 1 second (default: 500ms)
5049
* .build();
5150
*
5251
* CqlSession session = CqlSession.builder()
@@ -61,23 +60,16 @@
6160
public class ClientRoutesConfig {
6261

6362
private static final String DEFAULT_TABLE_NAME = "system.client_routes";
64-
private static final long DEFAULT_DNS_CACHE_DURATION_MILLIS = 500L;
6563

6664
private final List<ClientRoutesEndpoint> endpoints;
6765
private final String tableName;
68-
private final long dnsCacheDurationMillis;
6966

70-
private ClientRoutesConfig(
71-
List<ClientRoutesEndpoint> endpoints, String tableName, long dnsCacheDurationMillis) {
67+
private ClientRoutesConfig(List<ClientRoutesEndpoint> endpoints, String tableName) {
7268
if (endpoints == null || endpoints.isEmpty()) {
7369
throw new IllegalArgumentException("At least one endpoint must be specified");
7470
}
75-
if (dnsCacheDurationMillis < 0) {
76-
throw new IllegalArgumentException("DNS cache duration must be non-negative");
77-
}
7871
this.endpoints = Collections.unmodifiableList(new ArrayList<>(endpoints));
7972
this.tableName = tableName;
80-
this.dnsCacheDurationMillis = dnsCacheDurationMillis;
8173
}
8274

8375
/**
@@ -100,19 +92,6 @@ public String getTableName() {
10092
return tableName;
10193
}
10294

103-
/**
104-
* Returns the DNS cache duration in milliseconds.
105-
*
106-
* <p>This controls how long resolved DNS entries are cached before being re-resolved. A shorter
107-
* duration is appropriate for dynamic environments where DNS mappings change frequently, while a
108-
* longer duration can reduce DNS lookup overhead in stable environments.
109-
*
110-
* @return the DNS cache duration in milliseconds (default: 500ms).
111-
*/
112-
public long getDnsCacheDurationMillis() {
113-
return dnsCacheDurationMillis;
114-
}
115-
11695
/**
11796
* Creates a new builder for constructing a {@link ClientRoutesConfig}.
11897
*
@@ -132,14 +111,12 @@ public boolean equals(Object o) {
132111
return false;
133112
}
134113
ClientRoutesConfig that = (ClientRoutesConfig) o;
135-
return dnsCacheDurationMillis == that.dnsCacheDurationMillis
136-
&& endpoints.equals(that.endpoints)
137-
&& Objects.equals(tableName, that.tableName);
114+
return endpoints.equals(that.endpoints) && Objects.equals(tableName, that.tableName);
138115
}
139116

140117
@Override
141118
public int hashCode() {
142-
return Objects.hash(endpoints, tableName, dnsCacheDurationMillis);
119+
return Objects.hash(endpoints, tableName);
143120
}
144121

145122
@Override
@@ -150,16 +127,13 @@ public String toString() {
150127
+ ", tableName='"
151128
+ tableName
152129
+ '\''
153-
+ ", dnsCacheDurationMillis="
154-
+ dnsCacheDurationMillis
155130
+ '}';
156131
}
157132

158133
/** Builder for {@link ClientRoutesConfig}. */
159134
public static class Builder {
160135
private final List<ClientRoutesEndpoint> endpoints = new ArrayList<>();
161136
private String tableName = DEFAULT_TABLE_NAME;
162-
private long dnsCacheDurationMillis = DEFAULT_DNS_CACHE_DURATION_MILLIS;
163137

164138
/**
165139
* Adds an endpoint to the configuration.
@@ -208,29 +182,6 @@ public Builder withTableName(@Nullable String tableName) {
208182
return this;
209183
}
210184

211-
/**
212-
* Sets the DNS cache duration in milliseconds.
213-
*
214-
* <p>This controls how long resolved DNS entries are cached before being re-resolved. A shorter
215-
* duration is appropriate for dynamic environments where DNS mappings change frequently (e.g.,
216-
* during rolling updates), while a longer duration can reduce DNS lookup overhead in stable
217-
* environments.
218-
*
219-
* <p>Default: 500ms
220-
*
221-
* @param durationMillis the cache duration in milliseconds (must be non-negative).
222-
* @return this builder.
223-
* @throws IllegalArgumentException if the duration is negative.
224-
*/
225-
@NonNull
226-
public Builder withDnsCacheDuration(long durationMillis) {
227-
if (durationMillis < 0) {
228-
throw new IllegalArgumentException("DNS cache duration must be non-negative");
229-
}
230-
this.dnsCacheDurationMillis = durationMillis;
231-
return this;
232-
}
233-
234185
/**
235186
* Builds the {@link ClientRoutesConfig} with the configured endpoints and table name.
236187
*
@@ -239,7 +190,7 @@ public Builder withDnsCacheDuration(long durationMillis) {
239190
*/
240191
@NonNull
241192
public ClientRoutesConfig build() {
242-
return new ClientRoutesConfig(endpoints, tableName, dnsCacheDurationMillis);
193+
return new ClientRoutesConfig(endpoints, tableName);
243194
}
244195
}
245196
}

core/src/main/java/com/datastax/oss/driver/internal/core/clientroutes/CachingDnsResolver.java

Lines changed: 0 additions & 198 deletions
This file was deleted.

core/src/main/java/com/datastax/oss/driver/internal/core/clientroutes/DnsResolver.java

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,30 @@
2222
import java.net.UnknownHostException;
2323

2424
/**
25-
* Interface for DNS resolution with caching support.
25+
* Interface for DNS resolution with last-known-good fallback support.
2626
*
27-
* <p>Implementations should provide caching to avoid DNS storms during application startup and
28-
* should handle resolution failures gracefully (e.g., by returning the last known good IP).
27+
* <p>Implementations delegate to the JVM's DNS resolver (which already provides internal caching)
28+
* and retain the last successfully resolved address per hostname so that transient DNS failures can
29+
* be handled gracefully.
2930
*
3031
* <p>This interface is part of the internal API and is not intended for public use.
3132
*/
3233
public interface DnsResolver {
3334

3435
/**
35-
* Resolves a hostname to an IP address, potentially using a cache.
36+
* Resolves a hostname to an IP address.
3637
*
3738
* <p>Implementations should:
3839
*
3940
* <ul>
40-
* <li>Cache successful resolutions for a configurable duration (default: 500ms per
41-
* Description.md)
42-
* <li>Return cached results when available and not expired
41+
* <li>On success, store the resolved address as the last-known-good for the hostname
4342
* <li>On failure, return the last known good IP if available
44-
* <li>Limit concurrency to avoid DNS storms (default: 1 concurrent resolution per hostname)
4543
* </ul>
4644
*
4745
* @param hostname the hostname to resolve (must not be null)
4846
* @return the resolved IP address
49-
* @throws UnknownHostException if the hostname cannot be resolved and no cached value is
50-
* available
47+
* @throws UnknownHostException if the hostname cannot be resolved and no last-known-good address
48+
* is available
5149
*/
5250
@NonNull
5351
InetAddress resolve(@NonNull String hostname) throws UnknownHostException;
@@ -65,15 +63,10 @@ public interface DnsResolver {
6563
void evict(@NonNull String hostname);
6664

6765
/**
68-
* Clears all cached DNS entries, but intentionally retains last-known-good addresses so that the
69-
* fallback mechanism continues to work after a cache flush.
66+
* Clears all last-known-good addresses.
7067
*
7168
* <p>This method is called exactly once, by {@code ClientRoutesHandler.close()}, when the session
72-
* is shut down. It is <strong>not</strong> called during route-map refreshes (triggered by {@code
73-
* CLIENT_ROUTES_CHANGE} events or control-connection reconnects); those refreshes re-query the
74-
* routes table but let the TTL-based DNS cache expire naturally.
75-
*
76-
* <p>This method is not intended for manual or administrative use outside of session close.
69+
* is shut down.
7770
*/
7871
void clearCache();
7972
}

0 commit comments

Comments
 (0)