diff --git a/java/google/registry/model/EntityClasses.java b/java/google/registry/model/EntityClasses.java
index 6100d2866..896ddc2cd 100644
--- a/java/google/registry/model/EntityClasses.java
+++ b/java/google/registry/model/EntityClasses.java
@@ -46,7 +46,6 @@ import google.registry.model.rde.RdeRevision;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.model.registry.Registry;
-import google.registry.model.registry.RegistryCursor;
import google.registry.model.registry.label.PremiumList;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.reporting.HistoryEntry;
@@ -107,7 +106,6 @@ public final class EntityClasses {
RegistrarCredit.class,
RegistrarCreditBalance.class,
Registry.class,
- RegistryCursor.class,
ReservedList.class,
ServerSecret.class,
SignedMarkRevocationList.class,
diff --git a/java/google/registry/model/registry/RegistryCursor.java b/java/google/registry/model/registry/RegistryCursor.java
deleted file mode 100644
index bb09e3fd5..000000000
--- a/java/google/registry/model/registry/RegistryCursor.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package google.registry.model.registry;
-
-import static google.registry.model.ofy.ObjectifyService.ofy;
-
-import com.google.common.base.Optional;
-
-import com.googlecode.objectify.Key;
-import com.googlecode.objectify.annotation.Entity;
-import com.googlecode.objectify.annotation.Id;
-import com.googlecode.objectify.annotation.Parent;
-
-import google.registry.model.ImmutableObject;
-import google.registry.model.common.Cursor;
-
-import org.joda.time.DateTime;
-
-/** Shared entity for per-TLD date cursors. */
-@Entity
-public class RegistryCursor extends ImmutableObject {
-
- // TODO(b/28386088): Drop this class once all registry cursors have been saved in parallel as
- // new-style Cursors (either through business-as-usual operations or UpdateCursorsCommand).
-
- /** The types of cursors, used as the string id field for each cursor in datastore. */
- public enum CursorType {
- /** Cursor for ensuring rolling transactional isolation of BRDA staging operation. */
- BRDA,
-
- /** Cursor for ensuring rolling transactional isolation of RDE report operation. */
- RDE_REPORT,
-
- /** Cursor for ensuring rolling transactional isolation of RDE staging operation. */
- RDE_STAGING,
-
- /** Cursor for ensuring rolling transactional isolation of RDE upload operation. */
- RDE_UPLOAD,
-
- /**
- * Cursor that tracks the last time we talked to the escrow provider's SFTP server for a given
- * TLD.
- *
- *
Our escrow provider has an odd feature where separate deposits uploaded within two hours
- * of each other will be merged into a single deposit. This is problematic in situations where
- * the cursor might be a few days behind and is trying to catch up.
- *
- *
The way we solve this problem is by having {@code RdeUploadAction} check this cursor
- * before performing an upload for a given TLD. If the cursor is less than two hours old, the
- * action will fail with a status code above 300 and App Engine will keep retrying the action
- * until it's ready.
- */
- RDE_UPLOAD_SFTP;
- }
-
- @Parent
- Key registry;
-
- @Id
- String cursorType;
-
- DateTime date;
-
- /**
- * Convenience shortcut to load a cursor (as an {@link Optional}) for a given registry and cursor
- * type. Note that this currently reads the new cursor style first, then fails back to the old
- * RegistryCursor if the corresponding new style cursor does not exist.
- */
- public static Optional load(Registry registry, CursorType cursorType) {
- Cursor newStyleCursor =
- ofy()
- .load()
- .key(Cursor.createKey(Cursor.CursorType.valueOf(cursorType.name()), registry))
- .now();
- if (newStyleCursor != null) {
- return Optional.of(newStyleCursor.getCursorTime());
- }
- // New cursor style wasn't found for this TLD and cursor type, so load the old style.
- Key key =
- Key.create(Key.create(registry), RegistryCursor.class, cursorType.name());
- RegistryCursor cursor = ofy().load().key(key).now();
- return Optional.fromNullable(cursor == null ? null : cursor.date);
- }
-
- /** Convenience shortcut to save a cursor. */
- public static void save(Registry registry, CursorType cursorType, DateTime value) {
- ofy().save().entity(create(registry, cursorType, value));
- // In parallel, save the new cursor type alongside the old.
- ofy()
- .save()
- .entity(Cursor.create(Cursor.CursorType.valueOf(cursorType.name()), value, registry));
- }
-
- /** Creates a new cursor instance. */
- public static RegistryCursor create(Registry registry, CursorType cursorType, DateTime date) {
- RegistryCursor instance = new RegistryCursor();
- instance.registry = Key.create(registry);
- instance.cursorType = cursorType.name();
- instance.date = date;
- return instance;
- }
-}
diff --git a/javatests/google/registry/export/backup_kinds.txt b/javatests/google/registry/export/backup_kinds.txt
index bd5f652bc..a9a2d7aa6 100644
--- a/javatests/google/registry/export/backup_kinds.txt
+++ b/javatests/google/registry/export/backup_kinds.txt
@@ -25,5 +25,4 @@ RegistrarContact
RegistrarCredit
RegistrarCreditBalance
Registry
-RegistryCursor
ReservedList
diff --git a/javatests/google/registry/model/registry/RegistryCursorTest.java b/javatests/google/registry/model/registry/RegistryCursorTest.java
deleted file mode 100644
index a6f19041f..000000000
--- a/javatests/google/registry/model/registry/RegistryCursorTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package google.registry.model.registry;
-
-import static com.google.common.truth.Truth.assertThat;
-import static google.registry.model.ofy.ObjectifyService.ofy;
-import static google.registry.model.registry.RegistryCursor.CursorType.BRDA;
-import static google.registry.model.registry.RegistryCursor.CursorType.RDE_UPLOAD;
-import static google.registry.testing.DatastoreHelper.createTld;
-
-import com.googlecode.objectify.VoidWork;
-
-import google.registry.model.EntityTestCase;
-import google.registry.model.common.Cursor;
-
-import org.joda.time.DateTime;
-import org.junit.Test;
-
-/** Unit tests for {@link RegistryCursor}. */
-public class RegistryCursorTest extends EntityTestCase {
-
- @Test
- public void testPersistence() {
- createTld("tld");
- clock.advanceOneMilli();
- final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
- ofy().transact(new VoidWork() {
- @Override
- public void vrun() {
- RegistryCursor.save(Registry.get("tld"), RDE_UPLOAD, time);
- }});
- assertThat(RegistryCursor.load(Registry.get("tld"), BRDA)).isAbsent();
- assertThat(RegistryCursor.load(Registry.get("tld"), RDE_UPLOAD)).hasValue(time);
- }
-
- @Test
- public void testSuccess_dualRead_newOverOld() {
- createTld("tld");
- final DateTime newCursorTime = DateTime.parse("2012-07-12T03:30:00.000Z");
- final DateTime oldCursorTime = DateTime.parse("2012-07-11T03:30:00.000Z");
- ofy().transact(
- new VoidWork() {
- @Override
- public void vrun() {
- ofy()
- .save()
- .entities(
- // We can't use RegistryCursor.save() since dual-writing happens there.
- RegistryCursor.create(Registry.get("tld"), RDE_UPLOAD, oldCursorTime),
- Cursor.create(
- Cursor.CursorType.RDE_UPLOAD, newCursorTime, Registry.get("tld")))
- .now();
- }
- });
- assertThat(RegistryCursor.load(Registry.get("tld"), RDE_UPLOAD)).hasValue(newCursorTime);
- }
-
- @Test
- public void testSuccess_dualRead_onlyOld() {
- createTld("tld");
- final DateTime oldCursorTime = DateTime.parse("2012-07-11T03:30:00.000Z");
- ofy().transact(
- new VoidWork() {
- @Override
- public void vrun() {
- ofy()
- .save()
- .entity(RegistryCursor.create(Registry.get("tld"), RDE_UPLOAD, oldCursorTime))
- .now();
- }
- });
- assertThat(RegistryCursor.load(Registry.get("tld"), RDE_UPLOAD)).hasValue(oldCursorTime);
- }
-}