Skip to content

Commit 8047d1e

Browse files
authored
Use remote caches in RDAP queries (#3034)
Note that this primarily affects domain lookups. We choose to use the remote cache for hosts based on repo ID (not host name), so the remote caches are not particularly useful for host lookups. We chose this because the number of domain queries is orders of magnitude higher than the number of host queries.
1 parent 5854ccf commit 8047d1e

7 files changed

Lines changed: 32 additions & 31 deletions

File tree

core/src/main/java/google/registry/rdap/RdapActionBase.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.google.gson.JsonArray;
3333
import com.google.gson.JsonElement;
3434
import com.google.gson.JsonObject;
35+
import google.registry.cache.DomainCache;
3536
import google.registry.config.RegistryConfig.Config;
3637
import google.registry.model.EppResource;
3738
import google.registry.model.registrar.Registrar;
@@ -88,6 +89,7 @@ protected enum DeletedItemHandling {
8889
@Inject @Parameter("formatOutput") Optional<Boolean> formatOutputParam;
8990
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
9091
@Inject RdapMetrics rdapMetrics;
92+
@Inject DomainCache domainCache;
9193
@Inject Clock clock;
9294

9395
/** Builder for metric recording. */
@@ -117,14 +119,14 @@ final String getActionPath() {
117119
/**
118120
* Does the actual search and returns an RDAP JSON object.
119121
*
120-
* RFC7480 4.1 - we have to support GET and HEAD.
122+
* <p>RFC7480 4.1 - we have to support GET and HEAD.
121123
*
122124
* @param pathSearchString the search string in the URL path
123125
* @param isHeadRequest whether the returned map will actually be used. HTTP HEAD requests don't
124-
* actually return anything. However, we usually still want to go through the process of
125-
* building a map, to make sure that the request would return a 500 status if it were
126-
* invoked using GET. So this field should usually be ignored, unless there's some
127-
* expensive task required to create the map which will never result in a request failure.
126+
* actually return anything. However, we usually still want to go through the process of
127+
* building a map, to make sure that the request would return a 500 status if it were invoked
128+
* using GET. So this field should usually be ignored, unless there's some expensive task
129+
* required to create the map which will never result in a request failure.
128130
* @return A map (probably containing nested maps and lists) with the final JSON response data.
129131
*/
130132
abstract ReplyPayloadBase getJsonObjectForResource(

core/src/main/java/google/registry/rdap/RdapDomainAction.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ public RdapDomain getJsonObjectForResource(String pathSearchString, boolean isHe
6767
}
6868
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
6969
Optional<Domain> domain =
70-
ForeignKeyUtils.loadResourceByCache(
71-
Domain.class,
72-
pathSearchString,
73-
shouldIncludeDeleted() ? START_INSTANT : getRequestTime());
70+
shouldIncludeDeleted() // the remote domain cache cannot handle times in the past
71+
? ForeignKeyUtils.loadResourceByCache(Domain.class, pathSearchString, START_INSTANT)
72+
: domainCache.loadByDomainName(pathSearchString);
7473
if (domain.isEmpty() || !isAuthorized(domain.get())) {
7574
handlePossibleBsaBlock(domainName);
7675
// RFC7480 5.3 - if the server wishes to respond that it doesn't have data satisfying the

core/src/main/java/google/registry/rdap/RdapDomainSearchAction.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,10 @@ private DomainSearchResponse searchByDomainName(final RdapSearchPattern partialS
181181
/** Searches for domains by domain name without a wildcard or interest in deleted entries. */
182182
private DomainSearchResponse searchByDomainNameWithoutWildcard(
183183
final RdapSearchPattern partialStringQuery) {
184-
Optional<Domain> domain =
185-
ForeignKeyUtils.loadResourceByCache(
186-
Domain.class, partialStringQuery.getInitialString(), getRequestTime());
187184
return makeSearchResults(
188-
shouldBeVisible(domain) ? ImmutableList.of(domain.get()) : ImmutableList.of());
185+
domainCache.loadByDomainName(partialStringQuery.getInitialString()).stream()
186+
.filter(this::shouldBeVisible)
187+
.toList());
189188
}
190189

191190
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
@@ -359,8 +358,8 @@ private ImmutableList<VKey<Host>> getNameserverRefsByLdhNameWithSuffix(
359358
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
360359
// with no initial string.
361360
Domain domain =
362-
ForeignKeyUtils.loadResourceByCache(
363-
Domain.class, partialStringQuery.getSuffix(), timeToQuery)
361+
domainCache
362+
.loadByDomainName(partialStringQuery.getSuffix())
364363
.orElseThrow(
365364
() ->
366365
new UnprocessableEntityException(

core/src/main/java/google/registry/rdap/RdapJsonFormatter.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.google.common.flogger.FluentLogger;
3333
import com.google.common.net.InetAddresses;
3434
import com.google.gson.JsonArray;
35+
import google.registry.cache.HostCache;
3536
import google.registry.config.RegistryConfig;
3637
import google.registry.config.RegistryConfig.Config;
3738
import google.registry.model.CacheUtils;
@@ -122,6 +123,7 @@ record HistoryTimeAndRegistrar(Instant modificationTime, String registrarId) {}
122123
@Inject @RequestServerName String serverName;
123124
@Inject RdapAuthorization rdapAuthorization;
124125
@Inject Clock clock;
126+
@Inject HostCache hostCache;
125127

126128
@Inject
127129
RdapJsonFormatter() {}
@@ -393,20 +395,11 @@ RdapDomain createRdapDomain(Domain domain, OutputDataType outputDataType) {
393395
domain.getDomainName(), domain.getRepoId());
394396
}
395397

396-
// We're just trying to load the hosts by cache here, but the generics and casting require
397-
// a lot of boilerplate to make the compiler happy
398-
Iterable<VKey<? extends EppResource>> nameservers =
399-
ImmutableSet.copyOf(domain.getNameservers());
400398
ImmutableSet<Host> loadedHosts =
401-
replicaTm()
402-
.transact(
403-
() -> {
404-
ImmutableSet.Builder<Host> hostBuilder = new ImmutableSet.Builder<>();
405-
for (EppResource host : EppResource.loadByCacheIfEnabled(nameservers).values()) {
406-
hostBuilder.add((Host) host);
407-
}
408-
return hostBuilder.build();
409-
});
399+
domain.getNameservers().stream()
400+
.map(key -> hostCache.loadByRepoId((String) key.getKey()))
401+
.flatMap(Optional::stream)
402+
.collect(toImmutableSet());
410403

411404
// Add the nameservers to the data; the load was kicked off above for efficiency.
412405
// RDAP Response Profile 2.8: we MUST have the nameservers

core/src/main/java/google/registry/rdap/RdapNameserverSearchAction.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,7 @@ private NameserverSearchResponse searchByNameUsingForeignKey(
175175
/** Searches for nameservers by name using the superordinate domain as a suffix. */
176176
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
177177
RdapSearchPattern partialStringQuery) {
178-
Optional<Domain> domain =
179-
ForeignKeyUtils.loadResourceByCache(
180-
Domain.class, partialStringQuery.getSuffix(), getRequestTime());
178+
Optional<Domain> domain = domainCache.loadByDomainName(partialStringQuery.getSuffix());
181179
if (domain.isEmpty()) {
182180
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
183181
// table scan in many easily foreseeable cases. The user might ask for ns*.zombo.com,

core/src/test/java/google/registry/rdap/RdapActionBaseTestCase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import com.google.gson.JsonElement;
2929
import com.google.gson.JsonObject;
3030
import com.google.gson.JsonParser;
31+
import google.registry.model.ForeignKeyUtils;
3132
import google.registry.model.console.User;
3233
import google.registry.model.console.UserRoles;
34+
import google.registry.model.domain.Domain;
3335
import google.registry.persistence.transaction.JpaTestExtensions;
3436
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
3537
import google.registry.request.Actions;
@@ -92,6 +94,8 @@ public void beforeEachRdapActionBaseTestCase() {
9294
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
9395
action.rdapMetrics = rdapMetrics;
9496
action.requestMethod = GET;
97+
action.domainCache =
98+
(domainName) -> ForeignKeyUtils.loadResourceByCache(Domain.class, domainName, clock.now());
9599
action.clock = new FakeClock(DateTime.parse("2025-01-01T00:00:00.000Z"));
96100
logout();
97101
}

core/src/test/java/google/registry/rdap/RdapTestHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
import com.google.gson.JsonArray;
2828
import com.google.gson.JsonElement;
2929
import com.google.gson.JsonObject;
30+
import google.registry.model.EppResource;
31+
import google.registry.model.host.Host;
32+
import google.registry.persistence.VKey;
3033
import google.registry.util.Clock;
3134
import java.util.Map;
35+
import java.util.Optional;
3236

3337
/** Test helper methods for RDAP tests. */
3438
class RdapTestHelper {
@@ -68,6 +72,8 @@ static RdapJsonFormatter getTestRdapJsonFormatter(Clock clock) {
6872
+ " suspect that you have failed to comply with these terms.",
6973
"We reserve the right to modify this agreement at any time.");
7074
rdapJsonFormatter.rdapTosStaticUrl = "https://www.example.tld/about/rdap/tos.html";
75+
rdapJsonFormatter.hostCache =
76+
(repoId) -> Optional.ofNullable(EppResource.loadByCache(VKey.create(Host.class, repoId)));
7177
return rdapJsonFormatter;
7278
}
7379

0 commit comments

Comments
 (0)