Skip to content

Don't persist documents that we already have #720

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 4 commits into from
Aug 21, 2019

Conversation

schmidt-sebastian
Copy link
Contributor

Port of firebase/firebase-js-sdk#2099.

Also pulls in spec test changes from firebase/firebase-js-sdk#2098

@@ -395,8 +396,16 @@ public static RemoteEvent noChangeEvent(int targetId, int version, ByteString re

public static RemoteEvent addedRemoteEvent(
MaybeDocument doc, List<Integer> updatedInTargets, List<Integer> removedFromTargets) {
DocumentChange change =
new DocumentChange(updatedInTargets, removedFromTargets, doc.getKey(), doc);
return addedRemoteEvent(Collections.singletonList(doc), updatedInTargets, removedFromTargets);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -329,50 +329,35 @@ public SnapshotVersion getLastRemoteSnapshotVersion() {
return persistence.runTransaction(
"Apply remote event",
() -> {
SnapshotVersion remoteVersion = remoteEvent.getSnapshotVersion();
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: this variable is now much further from its first point of use, and I didn't notice any references to it in-between. Perhaps move it back to the end of this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's used in line 354. I moved it to the top of the function body - let me know if you think that's better. I can otherwise also inline the usage in line 354.

if (shouldPersistQueryData(oldQueryData, queryData, change)) {
queryCache.updateQueryData(queryData);
QueryData oldQueryData = targetIds.get(targetId);
if (oldQueryData != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional: I personally liked the continue approach that was in place before (this function is long, and I feel the increased nestedness hurts readability).

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. Reverted.

queryCache.removeMatchingKeys(change.getRemovedDocuments(), targetId);
queryCache.addMatchingKeys(change.getAddedDocuments(), targetId);

// Update the resume token if the change includes one. Don't clear any preexisting
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: which code is responsible for Don't clear any preexisting value -- is it shouldPersistQueryData?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I removed that part of the comment since it is a bit confusing.

for (Map.Entry<Integer, TargetChange> entry : targetChanges.entrySet()) {
Integer boxedTargetId = entry.getKey();
int targetId = boxedTargetId;
TargetChange change = entry.getValue();

// Do not ref/unref unassigned targetIds - it may lead to leaks.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this comment no longer apply?

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 rewrote it below since I didn't quite understand it at first.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, cool. I also found the original comment confusing.

// version to the remote cache.
|| doc.getVersion().compareTo(existingDoc.getVersion()) > 0
|| (doc.getVersion().compareTo(existingDoc.getVersion()) == 0
&& existingDoc.hasPendingWrites())) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, why do we overwrite the existing doc when it has pending writes?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is the only important question, the rest are nitpicks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When the write stream sends us an acknowledgment, we persist a document with hasCommittedMutations. We then pretend we know the state of the document, but that is not always true (another client may have changed a field we didn't write to, or we supplied an ArrayUnion/ArrayRemove transform that was applied to a set of elements that the client didn't yet know about). By allowing the server to send us the state of a committed document, we overwrite the hasCommittedMutations version with the actual version from the backend.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation!

Preconditions.checkArgument(!docs.isEmpty(), "Cannot pass empty docs array");

ResourcePath collectionPath = docs.get(0).getKey().getPath().popLast();
SnapshotVersion version = docs.get(0).getVersion();
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional: move this declaration to the point right before it's used?

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.

@@ -407,11 +416,16 @@ public static RemoteEvent addedRemoteEvent(

@Override
public QueryData getQueryDataForTarget(int targetId) {
return queryData(targetId, QueryPurpose.LISTEN, doc.getKey().toString());
return queryData(targetId, QueryPurpose.LISTEN, collectionPath.toString());
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: what's the reason for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The new test passes multiple docs to addedRemoteEvent. The test helper now uses the collection path of the first doc to represent the query.

FWIW I also believe the original implementation should have returned a collection path here.

@google-oss-bot
Copy link
Contributor

The public api surface has changed for the subproject firebase-firestore:
error: Removed class com.google.firebase.firestore.FirebaseFirestore.InstanceRegistry [RemovedInterface]

Please update the api.txt files for the subprojects being affected by this change by running ./gradlew ${subproject}:generateApiTxtFile. Also perform a major/minor bump accordingly.

for (Map.Entry<Integer, TargetChange> entry : targetChanges.entrySet()) {
Integer boxedTargetId = entry.getKey();
int targetId = boxedTargetId;
TargetChange change = entry.getValue();

// Do not ref/unref unassigned targetIds - it may lead to leaks.
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, cool. I also found the original comment confusing.

@schmidt-sebastian schmidt-sebastian merged commit a1d363b into master Aug 21, 2019
@schmidt-sebastian schmidt-sebastian deleted the mrschmidt/noupdate branch August 21, 2019 22:38
@firebase firebase locked and limited conversation to collaborators Oct 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes Override cla size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants