-
Notifications
You must be signed in to change notification settings - Fork 627
Initial base classes for index backfill #2950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Coverage ReportAffected SDKs
Test Logs
NotesHTML coverage reports can be produced locally with Head commit (10c3770c) is created by Prow via merging commits: e41b233 db08413. |
Binary Size ReportAffected SDKs
Test Logs
NotesHead commit (10c3770c) is created by Prow via merging commits: e41b233 db08413. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, but it could be simplified by making it a bit less generic. We should also figure out how to run this optionally when the indexing flag is enabled.
@@ -143,6 +145,10 @@ public FirestoreClient( | |||
if (gcScheduler != null) { | |||
gcScheduler.stop(); | |||
} | |||
|
|||
if (indexScheduler != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this scheduler always run? We may also need to backfill indices that were configured after client startup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my mind, the scheduler should always run, but whether the scheduler schedules anything is another question. We can change this as necessary as we build more functionality out.
/** How long we wait to try running LRU GC after SDK initialization. */ | ||
private static final long INITIAL_GC_DELAY_MS = TimeUnit.MINUTES.toMillis(1); | ||
/** Minimum amount of time between GC checks, after the first one. */ | ||
private static final long REGULAR_GC_DELAY_MS = TimeUnit.MINUTES.toMillis(5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I think we should be much more aggressive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to 30 seconds and every minute. We can tune this number once we can run benchmarks.
} | ||
} | ||
|
||
public class Scheduler implements StartStopScheduler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am trying to figure out what functionality a StartStopSchedule offers over a Scheduler, but I am not convinced I will ever find out :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed the base class to Scheduler. To be honest, I'm not sure why the LruGarbageCollector's Scheduler used the abstract base class to begin with since it's not shared with any other class.
firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexBackfiller.java
Outdated
Show resolved
Hide resolved
firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexBackfiller.java
Outdated
Show resolved
Hide resolved
* Persistence layers intending to perform index backfills should implement this interface. This | ||
* interface defines the operations that the Index Backfiller needs from the persistence layer. | ||
*/ | ||
public interface IndexBackfillerDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the indirection with the delegate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the delegate. Initially, I thought we would need to support MemoryPersistence in case the user disables persistence in their app, but I realize we can work around that.
|
||
@Override | ||
@Nullable | ||
public IndexEntry getIndexEntry(int indexId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this belongs here. You should only be writing. We also need to figure out how to index partial document updates, but even for those I don't think we should have a public API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take this back if you want to use this for testing - but then this should be marked as such.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave this here for the base prototype, and add more features to it as we build it out.
|
||
@RunWith(RobolectricTestRunner.class) | ||
@Config(manifest = Config.NONE) | ||
public class MemoryIndexBackfillerTest extends IndexBackfillerTestCase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test will not test anything, will it? We can probably just have a single SQLLite backfill test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the early stage review!
/** How long we wait to try running LRU GC after SDK initialization. */ | ||
private static final long INITIAL_GC_DELAY_MS = TimeUnit.MINUTES.toMillis(1); | ||
/** Minimum amount of time between GC checks, after the first one. */ | ||
private static final long REGULAR_GC_DELAY_MS = TimeUnit.MINUTES.toMillis(5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to 30 seconds and every minute. We can tune this number once we can run benchmarks.
@@ -143,6 +145,10 @@ public FirestoreClient( | |||
if (gcScheduler != null) { | |||
gcScheduler.stop(); | |||
} | |||
|
|||
if (indexScheduler != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my mind, the scheduler should always run, but whether the scheduler schedules anything is another question. We can change this as necessary as we build more functionality out.
} | ||
} | ||
|
||
public class Scheduler implements StartStopScheduler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed the base class to Scheduler. To be honest, I'm not sure why the LruGarbageCollector's Scheduler used the abstract base class to begin with since it's not shared with any other class.
firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexBackfiller.java
Outdated
Show resolved
Hide resolved
firebase-firestore/src/main/java/com/google/firebase/firestore/local/IndexBackfiller.java
Outdated
Show resolved
Hide resolved
* Persistence layers intending to perform index backfills should implement this interface. This | ||
* interface defines the operations that the Index Backfiller needs from the persistence layer. | ||
*/ | ||
public interface IndexBackfillerDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the delegate. Initially, I thought we would need to support MemoryPersistence in case the user disables persistence in their app, but I realize we can work around that.
|
||
@Override | ||
@Nullable | ||
public IndexEntry getIndexEntry(int indexId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave this here for the base prototype, and add more features to it as we build it out.
|
||
@RunWith(RobolectricTestRunner.class) | ||
@Config(manifest = Config.NONE) | ||
public class MemoryIndexBackfillerTest extends IndexBackfillerTestCase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
f595b7b
to
c660690
Compare
@@ -143,6 +145,10 @@ public FirestoreClient( | |||
if (gcScheduler != null) { | |||
gcScheduler.stop(); | |||
} | |||
|
|||
if (indexScheduler != null && Persistence.INDEXING_SUPPORT_ENABLED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check the flag here? The scheduler would not be available if the flag is off.
The name is also a bit generic. I wonder if we should include "backfill" in the scheduler name, which reduces the mental scope from "all of indexing" to "backfill index data".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the flag and renamed to indexBackfillScheduler
.
@@ -264,6 +271,10 @@ private void initialize(Context context, User user, FirebaseFirestoreSettings se | |||
if (gcScheduler != null) { | |||
gcScheduler.start(); | |||
} | |||
|
|||
if (indexScheduler != null && Persistence.INDEXING_SUPPORT_ENABLED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should guard the scheduler assignment based on this flag (line 265). Ideally, if indexing is off, none of the logic should even be loaded. It otherwise becomes hard to reason about the system - e.g. the constructor code of the scheduler needs to be aware that indexing might be on or off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guarded based on the flag and persistence being enabled.
|
||
/** | ||
* Represents an index entry saved by the SDK in the local storage. Temporary placeholder, since | ||
* we'll probably serialize the indexValue right away rather than store it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add "TODO(indexing)".
Note that we already committed FieldIndex
. In #2963, FieldIndex also gets an indexId
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return new BackfillScheduler(asyncQueue, localStore); | ||
} | ||
|
||
// TODO: Figure out which index entries to backfill. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO(indexing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@Before | ||
public void setUp() { | ||
persistence = PersistenceTestHelpers.createSQLitePersistence(); | ||
; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tzzzz.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😨
return new Results(/* hasRun= */ true, numIndexesWritten, numIndexesRemoved); | ||
} | ||
|
||
public void addIndexEntry(IndexEntry entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These methods would probably also be private if it was not for your tests. They should also be marked @VisibleForTesting
if that is true.
All of the test-only methods should also be package-private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
public void addAndRemoveIndexEntry() { | ||
IndexEntry testEntry = | ||
new IndexEntry(1, "TEST_BLOB".getBytes(), "sample-uid", "sample-documentId"); | ||
backfiller.addIndexEntry(testEntry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addIndex
and related methods should be scoped to a SQLite transaction and not be run without it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
No description provided.