Load DatabaseMigrationStateSchedule in a more performant way (#1273)

This performs a direct load-by-key (the most efficient Datastore operation),
rather than attempting to load all entities by type using an ancestor query. The
existing implementation is possibly more error-prone as well, and might be
responsible for the "cross-group transaction need to be explicitly specified"
error we're seeing.
This commit is contained in:
Ben McIlwain 2021-08-10 14:47:59 -04:00 committed by GitHub
parent f82fe3b182
commit f9184a37d5
2 changed files with 19 additions and 8 deletions

View file

@ -15,6 +15,8 @@
package google.registry.model.common; package google.registry.model.common;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm; import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
@ -24,6 +26,7 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Embed;
import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Mapify; import com.googlecode.objectify.annotation.Mapify;
@ -32,6 +35,7 @@ import google.registry.model.common.TimedTransitionProperty.TimeMapper;
import google.registry.model.common.TimedTransitionProperty.TimedTransition; import google.registry.model.common.TimedTransitionProperty.TimedTransition;
import google.registry.schema.replay.DatastoreOnlyEntity; import google.registry.schema.replay.DatastoreOnlyEntity;
import java.time.Duration; import java.time.Duration;
import java.util.Optional;
import org.joda.time.DateTime; import org.joda.time.DateTime;
/** /**
@ -224,13 +228,20 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton
/** Loads the currently-set migration schedule from Datastore, or the default if none exists. */ /** Loads the currently-set migration schedule from Datastore, or the default if none exists. */
@VisibleForTesting @VisibleForTesting
static TimedTransitionProperty<MigrationState, MigrationStateTransition> getUncached() { static TimedTransitionProperty<MigrationState, MigrationStateTransition> getUncached() {
return ofyTm() return Optional.ofNullable(
.transactNew( auditedOfy()
.doTransactionless(
() -> () ->
ofyTm() auditedOfy()
.loadSingleton(DatabaseMigrationStateSchedule.class) .load()
.key(
Key.create(
getCrossTldKey(),
DatabaseMigrationStateSchedule.class,
CrossTldSingleton.SINGLETON_ID))
.now()))
.map(s -> s.migrationTransitions) .map(s -> s.migrationTransitions)
.orElse(DEFAULT_TRANSITION_MAP)); .orElse(DEFAULT_TRANSITION_MAP);
} }
/** /**

View file

@ -325,7 +325,7 @@ public class Ofy {
} }
/** Execute some work in a transactionless context. */ /** Execute some work in a transactionless context. */
<R> R doTransactionless(Supplier<R> work) { public <R> R doTransactionless(Supplier<R> work) {
try { try {
com.googlecode.objectify.ObjectifyService.push( com.googlecode.objectify.ObjectifyService.push(
com.googlecode.objectify.ObjectifyService.ofy().transactionless()); com.googlecode.objectify.ObjectifyService.ofy().transactionless());