Skip to content

Merge the Index Engines #3208

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
Dec 9, 2021
Merged

Merge the Index Engines #3208

merged 5 commits into from
Dec 9, 2021

Conversation

schmidt-sebastian
Copy link
Contributor

This PR removes all Index Engines in favor one of single index engine that does Indexed queries by default, then falls back to index-free if no index is available and then falls back to collection scans.

Comment on lines 137 to 224
if (lastLimboFreeSnapshotVersion.equals(SnapshotVersion.NONE)) {
// Queries that have never seen a snapshot without limbo free documents should be run as a
// full collection scan.
return null;
}

ImmutableSortedMap<DocumentKey, Document> documents =
localDocumentsView.getDocuments(remoteKeys);
ImmutableSortedSet<Document> previousResults = applyQuery(query, documents);

if ((query.hasLimitToFirst() || query.hasLimitToLast())
&& needsRefill(
query.getLimitType(), previousResults, remoteKeys, lastLimboFreeSnapshotVersion)) {
return null;
}

if (Logger.isDebugEnabled()) {
Logger.debug(
LOG_TAG,
"Re-using previous result from %s to execute query: %s",
lastLimboFreeSnapshotVersion.toString(),
query.toString());
}

return mergeResults(previousResults, query, IndexOffset.create(lastLimboFreeSnapshotVersion));
}

/** Applies the query filter and sorting to the provided documents. */
private ImmutableSortedSet<Document> applyQuery(
Query query, ImmutableSortedMap<DocumentKey, Document> documents) {
// Sort the documents and re-apply the query filter since previously matching documents do not
// necessarily still match the query.
ImmutableSortedSet<Document> queryResults =
new ImmutableSortedSet<>(Collections.emptyList(), query.comparator());
for (Map.Entry<DocumentKey, Document> entry : documents) {
Document document = entry.getValue();
if (query.matches(document)) {
queryResults = queryResults.insert(document);
}
}
return queryResults;
}

/**
* Determines if a limit query needs to be refilled from cache, making it ineligible for
* index-free execution.
*
* @param limitType The type of limit query for refill calculation.
* @param sortedPreviousResults The documents that matched the query when it was last
* synchronized, sorted by the query's comparator.
* @param remoteKeys The document keys that matched the query at the last snapshot.
* @param limboFreeSnapshotVersion The version of the snapshot when the query was last
* synchronized.
*/
private boolean needsRefill(
Query.LimitType limitType,
ImmutableSortedSet<Document> sortedPreviousResults,
ImmutableSortedSet<DocumentKey> remoteKeys,
SnapshotVersion limboFreeSnapshotVersion) {
// The query needs to be refilled if a previously matching document no longer matches.
if (remoteKeys.size() != sortedPreviousResults.size()) {
return true;
}

// Limit queries are not eligible for index-free query execution if there is a potential that an
// older document from cache now sorts before a document that was previously part of the limit.
// This, however, can only happen if the document at the edge of the limit goes out of limit. If
// a document that is not the limit boundary sorts differently, the boundary of the limit itself
// did not change and documents from cache will continue to be "rejected" by this boundary.
// Therefore, we can ignore any modifications that don't affect the last document.
Document documentAtLimitEdge =
limitType == Query.LimitType.LIMIT_TO_FIRST
? sortedPreviousResults.getMaxEntry()
: sortedPreviousResults.getMinEntry();
if (documentAtLimitEdge == null) {
// We don't need to refill the query if there were already no documents.
return false;
}
return documentAtLimitEdge.hasPendingWrites()
|| documentAtLimitEdge.getVersion().compareTo(limboFreeSnapshotVersion) > 0;
}

private ImmutableSortedMap<DocumentKey, Document> executeFullCollectionScan(Query query) {
if (Logger.isDebugEnabled()) {
Logger.debug(LOG_TAG, "Using full collection scan to execute query: %s", query.toString());
}
return localDocumentsView.getDocumentsMatchingQuery(query, IndexOffset.NONE);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of this code is moved from DefaultQueryEngine.

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Dec 6, 2021

Coverage Report

Affected SDKs

  • firebase-firestore

    SDK overall coverage changed from 45.21% (dfa2231) to 45.23% (4f8b6e54) by +0.03%.

    Filename Base (dfa2231) Head (4f8b6e54) Diff
    LocalStore.java 99.37% 99.37% -0.01%
    MemoryIndexManager.java 66.67% 70.37% +3.70%
    QueryEngine.java 0.00% 98.51% +98.51%
    SQLiteIndexManager.java 99.37% 99.06% -0.31%
    SetMutation.java 94.29% 97.14% +2.86%
    Util.java 63.70% 65.00% +1.30%

Test Logs

Notes

HTML coverage reports can be produced locally with ./gradlew <product>:checkCoverage.
Report files are located at <product-build-dir>/reports/jacoco/.

Head commit (4f8b6e54) is created by Prow via merging commits: dfa2231 7d109b8.

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Dec 6, 2021

Binary Size Report

Affected SDKs

  • firebase-firestore

    Type Base (dfa2231) Head (4f8b6e54) Diff
    aar 1.23 MB 1.23 MB -893 B (-0.1%)
    apk (release) 3.33 MB 3.33 MB +172 B (+0.0%)

Test Logs

Notes

Head commit (4f8b6e54) is created by Prow via merging commits: dfa2231 7d109b8.

@schmidt-sebastian
Copy link
Contributor Author

/test device-check-changed

@thebrianchen
Copy link

/test device-check-changed

Checking if canBeRemovedTwice and testObservesExistingDocument still fail.

@schmidt-sebastian
Copy link
Contributor Author

Checking if canBeRemovedTwice and testObservesExistingDocument still fail.

Doing the lords work.

(These two tests have been failing a lot since the GRPC update)

Copy link

@thebrianchen thebrianchen left a comment

Choose a reason for hiding this comment

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

lgtm


public ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingQuery(
Query query,
ImmutableSortedSet<DocumentKey> remoteKeys,

Choose a reason for hiding this comment

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

Any reason you switched remoteKeys and lastLimboFreeSnapshotVersion around? Would prefer having the signature the same to reduce merge conflicts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At some point during my iterations on this PR, it felt like the right thing to do. I don't think this is needed anymore and reducing merge conflicts is a good reason to revert this.

@@ -504,6 +504,10 @@ private void deleteIndexEntry(Document document, IndexEntry indexEntry) {
public FieldIndex getFieldIndex(Target target) {

Choose a reason for hiding this comment

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

Optional: add @Nullable annotation.

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 already has one :)

return localDocumentsView.getDocumentsMatchingQuery(query, IndexOffset.NONE);
}

private ImmutableSortedMap<DocumentKey, Document> mergeResults(

Choose a reason for hiding this comment

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

nit: Either add comment or change method name to include the fact that we're merging results with LDV's new documents since the offset

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 (did both)

@schmidt-sebastian
Copy link
Contributor Author

/test device-check-changed

@schmidt-sebastian schmidt-sebastian merged commit 072ee4c into master Dec 9, 2021
@schmidt-sebastian schmidt-sebastian deleted the mrschmidt/onequeryengine branch December 9, 2021 01:08
@firebase firebase locked and limited conversation to collaborators Jan 8, 2022
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.

3 participants