diff --git a/java/google/registry/flows/ResourceFlowUtils.java b/java/google/registry/flows/ResourceFlowUtils.java index 943e24c94..eec25ae51 100644 --- a/java/google/registry/flows/ResourceFlowUtils.java +++ b/java/google/registry/flows/ResourceFlowUtils.java @@ -20,7 +20,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.tryFind; import static com.google.common.collect.Sets.intersection; import static google.registry.model.EppResourceUtils.loadByForeignKey; -import static google.registry.model.EppResourceUtils.queryDomainsUsingResource; +import static google.registry.model.EppResourceUtils.queryForLinkedDomains; import static google.registry.model.domain.DomainResource.extendRegistrationWithCap; import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey; import static google.registry.model.ofy.ObjectifyService.ofy; @@ -189,8 +189,8 @@ public final class ResourceFlowUtils { // eventually consistent and so might be very stale, but the direct load will not be stale, // just non-transactional. If we find at least one actual reference then we can reliably // fail. If we don't find any, we can't trust the query and need to do the full mapreduce. - List> keys = queryDomainsUsingResource( - resourceClass, fki.getResourceKey(), now, FAILFAST_CHECK_COUNT); + Iterable> keys = + queryForLinkedDomains(fki.getResourceKey(), now).limit(FAILFAST_CHECK_COUNT).keys(); Predicate predicate = new Predicate() { @Override public boolean apply(DomainBase domain) { diff --git a/java/google/registry/model/EppResourceUtils.java b/java/google/registry/model/EppResourceUtils.java index 022c50f6a..45ebb5749 100644 --- a/java/google/registry/model/EppResourceUtils.java +++ b/java/google/registry/model/EppResourceUtils.java @@ -25,6 +25,7 @@ import static google.registry.util.DateTimeUtils.latestOf; import com.google.common.base.Function; import com.googlecode.objectify.Key; import com.googlecode.objectify.Result; +import com.googlecode.objectify.cmd.Query; import com.googlecode.objectify.util.ResultNow; import google.registry.model.EppResource.Builder; import google.registry.model.EppResource.BuilderWithTransferData; @@ -34,7 +35,6 @@ import google.registry.model.contact.ContactResource; import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainBase; import google.registry.model.eppcommon.StatusValue; -import google.registry.model.host.HostResource; import google.registry.model.index.ForeignKeyIndex; import google.registry.model.ofy.CommitLogManifest; import google.registry.model.ofy.CommitLogMutation; @@ -331,35 +331,42 @@ public final class EppResourceUtils { } /** - * Find keys of domains or applications that reference a specified contact or host. + * Returns a query for domains or applications that reference a specified contact or host. * *

This is an eventually consistent query. * - * @param clazz the referent type (contact or host) * @param key the referent key * @param now the logical time of the check - * @param limit max number of keys to return */ - public static List> queryDomainsUsingResource( - Class clazz, Key key, DateTime now, int limit) { - checkArgument(ContactResource.class.equals(clazz) || HostResource.class.equals(clazz)); + public static Query queryForLinkedDomains( + Key key, DateTime now) { + boolean isContactKey = key.getKind().equals(Key.getKind(ContactResource.class)); return ofy() .load() .type(DomainBase.class) - .filter(clazz.equals(ContactResource.class) ? "allContacts.contact" : "nsHosts", key) - .filter("deletionTime >", now) - .limit(limit) - .keys() - .list(); + .filter(isContactKey ? "allContacts.contact" : "nsHosts", key) + .filter("deletionTime >", now); + } + + /** + * Returns whether the given contact or host is linked to (that is, referenced by) a domain. + * + *

This is an eventually consistent query. + * + * @param key the referent key + * @param now the logical time of the check + */ + public static boolean isLinked(Key key, DateTime now) { + return queryForLinkedDomains(key, now).limit(1).count() > 0; } /** Clone a contact or host with an eventually-consistent notion of LINKED. */ public static EppResource cloneResourceWithLinkedStatus(EppResource resource, DateTime now) { Builder builder = resource.asBuilder(); - if (queryDomainsUsingResource(resource.getClass(), Key.create(resource), now, 1).isEmpty()) { - builder.removeStatusValue(StatusValue.LINKED); - } else { + if (isLinked(Key.create(resource), now)) { builder.addStatusValue(StatusValue.LINKED); + } else { + builder.removeStatusValue(StatusValue.LINKED); } return builder.build(); }