Skip to content

Expose operation counts from Persistence layer #595

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

Merged
merged 5 commits into from
Jul 11, 2019

Conversation

schmidt-sebastian
Copy link
Contributor

This PR adds a pretty-bare bones way to export document read counts from the RemoteDocumentCache and the MutationQueue. I will use this in more thorough tests once we start optimizing our query execution.

The different ways to construct the Persistence layer are getting a little out of hand. I think a good follow up would be to add Builders for some of the classes here and address the overload overload.

return batch;
}

@Nullable
@Override
public MutationBatch lookupMutationBatch(int batchId) {
statsCollector.recordRowsRead(MemoryMutationQueue.TAG, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this just be TAG? Also even if you don't want to name it just that, it's actually MutationQueue.TAG.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it should just be TAG. In an effort to keep it legible I renamed it to STATS_TAG.

@@ -25,6 +25,9 @@

/** A queue of mutations to apply to the remote store. */
interface MutationQueue {
/** The tag used by the StatsCollector. */
String TAG = "Mutations";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if these tags matched the table names we're reading from. This one would be mutations and the other one remote_documents.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Done.

List<MutationBatch> result = new ArrayList<>();
Set<Integer> uniqueBatchIds = new HashSet<>();
while (longQuery.hasMoreSubqueries()) {
longQuery
.performNextSubquery()
.forEach(
row -> {
++rowsRead[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to just make this a part of forEach and similar methods (and the return value of the method)?

Just spitballing. Feel free to ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea and it's actually pretty simple. I'm just a little worried that this might cause the counts from Memory Persistence and SQLLite Persistence to differ (as we might have to skip rows in one implementation but not in the other), but we can cross that bridge when we get there.

public SQLitePersistence(
Context context,
String persistenceKey,
DatabaseId databaseId,
LocalSerializer serializer,
StatsCollector statsProvider,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your class is StatsCollector but the variable is statsProvider. Elsewhere you called it statsCollector too. Make these consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed all statsProvider in this PR to statsCollector.


SQLiteRemoteDocumentCache(SQLitePersistence persistence, LocalSerializer serializer) {
SQLiteRemoteDocumentCache(
SQLitePersistence persistence, LocalSerializer serializer, StatsCollector statsProvider) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/statsProvider/statsCollector/ as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

*/
abstract class StatsCollector {
/** A stats collector that discards all operation counts. */
static class NoOpStatsCollector extends StatsCollector {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be private static if newNoOpStatsCollector() had the return type of StatsCollector.

Alternatively, just consider making StatsCollector non-abstract and new StatsCollector() would be enough to get you a no-op instance. That would cut the line count here and reduce the number of classes in production by one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are your really gonna make me change this PR from a "sophisticated stats framework" to a dumb counter? Okay then. It's done.

@@ -849,17 +873,28 @@ public void testCanExecuteMixedCollectionQueries() {
allocateQuery(query);
assertTargetId(2);

localStore.executeQuery(query);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't awful but please consider making a separate test that specifically exercises interesting cases rather than making additional assertions as a side-effect of some other scenario. In the current configuration it becomes difficult to understand what part of the test is essential to verifying mixed collection queries vs what's essential to verifying the stats.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically wanted to write the exact same test that we have here. I did remove the checks in 877 and 888, which should improve the readability of this test.

I can create a separate test but it would likely contain most lines from this test. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The worry I essentially have is that we end up wanting to change this test to verify some additional case and then get tripped up around the interaction with the counts and then it's not clear if changing the counts is the right thing to do.

I couldn't find a reference to it quickly, but some hardline testing guru types advocate for only having one assertion per test case essentially on these grounds.

Most of these tests are copies of each other in some way so I don't think that's much of an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR to add a separate test.

@wilhuff wilhuff assigned schmidt-sebastian and unassigned wilhuff Jul 10, 2019
Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@schmidt-sebastian
Copy link
Contributor Author

/retest

1 similar comment
@schmidt-sebastian
Copy link
Contributor Author

/retest

@schmidt-sebastian schmidt-sebastian merged commit a7761a4 into master Jul 11, 2019
@schmidt-sebastian schmidt-sebastian deleted the mrschmidt/localstorecounter branch July 15, 2019 23:14
@firebase firebase locked and limited conversation to collaborators Oct 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants