Add a beforeSqlSave callback to ReplaySpecializer (#1062)

* Add a beforeSqlSave callback to ReplaySpecializer

When in the Datastore-primary and SQL-secondary stage, we will want to
save the EppResource-at-this-point-in-time field in the *History
objects so that later on we can examine the *History objects to see what
the resource looked like at that point in time.

Without this PR, the full object at that point in time would be lost
during the asynchronous replay since Datastore doesn't know about it.

In addition, we modify the HistoryEntry weight / priority so that
additions to it come after the additions to the resource off of which it
is based. As a result, we need to DEFER some foreign keys so that we can
write the billing / poll message objects before the history object that
they're referencing.
This commit is contained in:
gbrodman 2021-04-12 12:11:20 -04:00 committed by GitHub
parent 020273b184
commit 92dcacf78c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 202 additions and 93 deletions

View file

@ -125,6 +125,7 @@ public class ReplayCommitLogsToSqlActionTest {
action.diffLister.gcsBucket = GCS_BUCKET;
action.diffLister.executor = newDirectExecutorService();
RegistryConfig.overrideCloudSqlReplayCommitLogs(true);
TestObject.beforeSqlSaveCallCount = 0;
TestObject.beforeSqlDeleteCallCount = 0;
}
@ -442,6 +443,21 @@ public class ReplayCommitLogsToSqlActionTest {
.isEqualTo("Can't acquire SQL commit log replay lock, aborting.");
}
@Test
void testSuccess_beforeSqlSaveCallback() throws Exception {
DateTime now = fakeClock.nowUtc();
Key<CommitLogBucket> bucketKey = getBucketKey(1);
Key<CommitLogManifest> manifestKey = CommitLogManifest.createKey(bucketKey, now);
jpaTm().transact(() -> SqlReplayCheckpoint.set(now.minusMinutes(1).minusMillis(1)));
saveDiffFile(
gcsService,
createCheckpoint(now.minusMinutes(1)),
CommitLogManifest.create(bucketKey, now, null),
CommitLogMutation.create(manifestKey, TestObject.create("a")));
runAndAssertSuccess(now.minusMinutes(1));
assertThat(TestObject.beforeSqlSaveCallCount).isEqualTo(1);
}
@Test
void testSuccess_deleteSqlCallback() throws Exception {
DateTime now = fakeClock.nowUtc();

View file

@ -40,7 +40,7 @@ class EntityWritePrioritiesTest {
Key.create(HistoryEntry.class, 200), "fake history entry",
Key.create(Registrar.class, 300), "fake registrar");
ImmutableMap<Long, Integer> expectedValues =
ImmutableMap.of(100L, EntityWritePriorities.DELETE_RANGE + 10, 200L, -10, 300L, 0);
ImmutableMap.of(100L, EntityWritePriorities.DELETE_RANGE - 20, 200L, 20, 300L, 0);
for (ImmutableMap.Entry<Key<?>, Object> entry : actions.entrySet()) {
assertThat(

View file

@ -34,6 +34,7 @@ import javax.persistence.Transient;
@EntityForTesting
public class TestObject extends ImmutableObject implements DatastoreAndSqlEntity {
public static int beforeSqlSaveCallCount;
public static int beforeSqlDeleteCallCount;
@Parent @Transient Key<EntityGroupRoot> parent;
@ -74,6 +75,10 @@ public class TestObject extends ImmutableObject implements DatastoreAndSqlEntity
beforeSqlDeleteCallCount++;
}
public static void beforeSqlSave(TestObject testObject) {
beforeSqlSaveCallCount++;
}
/** A test @VirtualEntity model object, which should not be persisted. */
@Entity
@VirtualEntity