Fix create/update timestamp replay problems (#1515)

* Fix create/update timestamp replay problems

When CreateAutoTimestamp and UpdateAutoTimestamp are inserted into a
Transaction, their values are not populated in the same way as when they are
stored in the course of an SQL commit.  This results in different timestamp
values between SQL and datastore during the SQL -> DS replay.

Fix this by providing these values from the JPA transaction time when we're
doing transaction serialization.

This change also removes the initialization of the Ofy clock in
ExpandRecurringBillingEventsActionTest.  It's not necessary as the
ReplayExtension already takes care of this and doing it after the
ReplayExtension as we were breaks a test now that the update timestamps are
correct.
This commit is contained in:
Michael Muller
2022-02-09 08:48:51 -05:00
committed by GitHub
parent 2ccae00dae
commit c9da36be9f
6 changed files with 81 additions and 21 deletions
@@ -14,12 +14,10 @@
package google.registry.model.translators;
import static com.google.common.base.MoreObjects.firstNonNull;
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static org.joda.time.DateTimeZone.UTC;
import google.registry.model.CreateAutoTimestamp;
import google.registry.persistence.transaction.Transaction;
import java.util.Date;
import org.joda.time.DateTime;
@@ -47,13 +45,13 @@ public class CreateAutoTimestampTranslatorFactory
/** Save a timestamp, setting it to the current time if it did not have a previous value. */
@Override
public Date saveValue(CreateAutoTimestamp pojoValue) {
// Don't do this if we're in the course of transaction serialization.
if (Transaction.inSerializationMode()) {
return pojoValue.getTimestamp() == null ? null : pojoValue.getTimestamp().toDate();
}
return firstNonNull(pojoValue.getTimestamp(), ofyTm().getTransactionTime()).toDate();
// Note that we use the current transaction manager -- we need to do this under JPA when we
// serialize the entity from a Transaction object, but we need to use the JPA transaction
// manager in that case.
return (pojoValue.getTimestamp() == null
? tm().getTransactionTime()
: pojoValue.getTimestamp())
.toDate();
}
};
}
@@ -14,6 +14,8 @@
package google.registry.model.translators;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
import static org.joda.time.DateTimeZone.UTC;
@@ -48,9 +50,16 @@ public class UpdateAutoTimestampTranslatorFactory
@Override
public Date saveValue(UpdateAutoTimestamp pojoValue) {
// Don't do this if we're in the course of transaction serialization.
// If we're in the course of Transaction serialization, we have to use the transaction time
// here and the JPA transaction manager which is what will ultimately be saved during the
// commit.
// Note that this branch doesn't respect "auto update disabled", as this state is
// specifically to address replay, so we add a runtime check for this.
if (Transaction.inSerializationMode()) {
return pojoValue.getTimestamp() == null ? null : pojoValue.getTimestamp().toDate();
checkState(
UpdateAutoTimestamp.autoUpdateEnabled(),
"Auto-update disabled during transaction serialization.");
return jpaTm().getTransactionTime().toDate();
}
return UpdateAutoTimestamp.autoUpdateEnabled()