Skip to content

Commit 05ba8a0

Browse files
Add BundleCache
1 parent 2a3f7dc commit 05ba8a0

16 files changed

+656
-15
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.local;
16+
17+
import androidx.annotation.Nullable;
18+
19+
/** Provides methods to save and read Firestore bundles. */
20+
public interface BundleCache {
21+
/**
22+
* Gets the saved BundleMetadata for a given bundle id. Returns {@code null} if no bundles are
23+
* found under the given id.
24+
*/
25+
@Nullable
26+
BundleMetadata getBundleMetadata(String bundleId);
27+
28+
/**
29+
* Saves the BundleMetadata from a bundle into local storage, using its id as the persistent key.
30+
*/
31+
void saveBundleMetadata(BundleMetadata metadata);
32+
33+
/**
34+
* Gets a saved NamedQuery for the given query name. Returns {@code null} if no queries are found
35+
* under the given name.
36+
*/
37+
@Nullable
38+
NamedQuery getNamedQuery(String queryName);
39+
40+
/** Saves a NamedQuery from a bundle, using its name as the persistent key. */
41+
void saveNamedQuery(NamedQuery query);
42+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.local;
16+
17+
import com.google.firebase.firestore.model.SnapshotVersion;
18+
19+
/** Represents a Firestore bundle saved by the SDK in its local storage. */
20+
/* package */ class BundleMetadata {
21+
private final String bundleId;
22+
private final int schemaVersion;
23+
private final SnapshotVersion createTime;
24+
25+
public BundleMetadata(String bundleId, int schemaVersion, SnapshotVersion createTime) {
26+
this.bundleId = bundleId;
27+
this.schemaVersion = schemaVersion;
28+
this.createTime = createTime;
29+
}
30+
31+
/**
32+
* @return Id of the bundle. It is used together with `createTime` to determine if a bundle has
33+
* been loaded by the SDK.
34+
*/
35+
public String getBundleId() {
36+
return bundleId;
37+
}
38+
39+
/** @return Schema version of the bundle. */
40+
public int getSchemaVersion() {
41+
return schemaVersion;
42+
}
43+
44+
/**
45+
* @return Snapshot version of the bundle if created by the Server SDKs, or else
46+
* SnapshotVersion.MIN.
47+
*/
48+
public SnapshotVersion getCreateTime() {
49+
return createTime;
50+
}
51+
52+
@Override
53+
public boolean equals(Object o) {
54+
if (this == o) return true;
55+
if (o == null || getClass() != o.getClass()) return false;
56+
57+
BundleMetadata that = (BundleMetadata) o;
58+
59+
if (schemaVersion != that.schemaVersion) return false;
60+
if (!bundleId.equals(that.bundleId)) return false;
61+
return createTime.equals(that.createTime);
62+
}
63+
64+
@Override
65+
public int hashCode() {
66+
int result = bundleId.hashCode();
67+
result = 31 * result + schemaVersion;
68+
result = 31 * result + createTime.hashCode();
69+
return result;
70+
}
71+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import static com.google.firebase.firestore.util.Assert.hardAssert;
1919

2020
import com.google.firebase.Timestamp;
21+
import com.google.firebase.firestore.core.Query;
22+
import com.google.firebase.firestore.core.Query.LimitType;
2123
import com.google.firebase.firestore.core.Target;
2224
import com.google.firebase.firestore.model.Document;
2325
import com.google.firebase.firestore.model.DocumentKey;
@@ -29,6 +31,7 @@
2931
import com.google.firebase.firestore.model.mutation.Mutation;
3032
import com.google.firebase.firestore.model.mutation.MutationBatch;
3133
import com.google.firebase.firestore.remote.RemoteSerializer;
34+
import com.google.firestore.proto.BundledQuery;
3235
import com.google.firestore.v1.DocumentTransform.FieldTransform;
3336
import com.google.firestore.v1.Write;
3437
import com.google.firestore.v1.Write.Builder;
@@ -266,4 +269,32 @@ TargetData decodeTargetData(com.google.firebase.firestore.proto.Target targetPro
266269
lastLimboFreeSnapshotVersion,
267270
resumeToken);
268271
}
272+
273+
public com.google.firestore.proto.BundledQuery encodeQuery(Query query) {
274+
// We store LimitToLast as metadata information below. We remove it from the query itself as
275+
// `toTarget()` flips the order by constraints otherwise.
276+
Query queryWithoutLimitToLast =
277+
query.hasLimitToLast() ? query.limitToFirst(query.getLimitToLast()) : query;
278+
com.google.firestore.v1.Target.QueryTarget queryTarget =
279+
rpcSerializer.encodeQueryTarget(queryWithoutLimitToLast.toTarget());
280+
281+
com.google.firestore.proto.BundledQuery.Builder result =
282+
com.google.firestore.proto.BundledQuery.newBuilder();
283+
result.setLimitType(
284+
query.hasLimitToLast() ? BundledQuery.LimitType.LAST : BundledQuery.LimitType.FIRST);
285+
result.setParent(queryTarget.getParent());
286+
result.setStructuredQuery(queryTarget.getStructuredQuery());
287+
288+
return result.build();
289+
}
290+
291+
public Query decodeQuery(com.google.firestore.proto.BundledQuery bundledQuery) {
292+
LimitType limitType =
293+
bundledQuery.getLimitType().equals(BundledQuery.LimitType.FIRST)
294+
? LimitType.LIMIT_TO_FIRST
295+
: LimitType.LIMIT_TO_LAST;
296+
297+
return rpcSerializer.decodeQuery(
298+
bundledQuery.getParent(), bundledQuery.getStructuredQuery(), limitType);
299+
}
269300
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.local;
16+
17+
import androidx.annotation.Nullable;
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
/** A memory-backed implementation of the bundle cache. */
22+
/* package */ class MemoryBundleCache implements BundleCache {
23+
private final Map<String, BundleMetadata> bundles = new HashMap<>();
24+
private final Map<String, NamedQuery> namedQueries = new HashMap<>();
25+
26+
@Nullable
27+
@Override
28+
public BundleMetadata getBundleMetadata(String bundleId) {
29+
return bundles.get(bundleId);
30+
}
31+
32+
@Override
33+
public void saveBundleMetadata(BundleMetadata metadata) {
34+
bundles.put(metadata.getBundleId(), metadata);
35+
}
36+
37+
@Override
38+
@Nullable
39+
public NamedQuery getNamedQuery(String queryName) {
40+
return namedQueries.get(queryName);
41+
}
42+
43+
@Override
44+
public void saveNamedQuery(NamedQuery query) {
45+
namedQueries.put(query.getName(), query);
46+
}
47+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryPersistence.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public final class MemoryPersistence extends Persistence {
3434
private final Map<User, MemoryMutationQueue> mutationQueues;
3535
private final MemoryIndexManager indexManager;
3636
private final MemoryTargetCache targetCache;
37+
private final MemoryBundleCache bundleCache;
3738
private final MemoryRemoteDocumentCache remoteDocumentCache;
3839
private ReferenceDelegate referenceDelegate;
3940

@@ -58,6 +59,7 @@ private MemoryPersistence() {
5859
mutationQueues = new HashMap<>();
5960
indexManager = new MemoryIndexManager();
6061
targetCache = new MemoryTargetCache(this);
62+
bundleCache = new MemoryBundleCache();
6163
remoteDocumentCache = new MemoryRemoteDocumentCache(this);
6264
}
6365

@@ -118,6 +120,11 @@ IndexManager getIndexManager() {
118120
return indexManager;
119121
}
120122

123+
@Override
124+
BundleCache getBundleCache() {
125+
return bundleCache;
126+
}
127+
121128
@Override
122129
void runTransaction(String action, Runnable operation) {
123130
referenceDelegate.onTransactionStarted();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.firestore.local;
16+
17+
import com.google.firebase.firestore.core.Query;
18+
import com.google.firebase.firestore.model.SnapshotVersion;
19+
20+
/** Represents a named query saved by the SDK in its local storage. */
21+
/* package */ class NamedQuery {
22+
private final String name;
23+
private final Query query;
24+
private final SnapshotVersion readTime;
25+
26+
public NamedQuery(String name, Query query, SnapshotVersion readTime) {
27+
this.name = name;
28+
this.query = query;
29+
this.readTime = readTime;
30+
}
31+
32+
/** @return The name of the query. */
33+
public String getName() {
34+
return name;
35+
}
36+
37+
/** @return The underlying query associated with the given name. */
38+
public Query getQuery() {
39+
return query;
40+
}
41+
42+
/** @return The time at which the results for this query were read. */
43+
public SnapshotVersion getReadTime() {
44+
return readTime;
45+
}
46+
47+
@Override
48+
public boolean equals(Object o) {
49+
if (this == o) return true;
50+
if (o == null || getClass() != o.getClass()) return false;
51+
52+
NamedQuery that = (NamedQuery) o;
53+
54+
if (!name.equals(that.name)) return false;
55+
if (!query.equals(that.query)) return false;
56+
return readTime.equals(that.readTime);
57+
}
58+
}

firebase-firestore/src/main/java/com/google/firebase/firestore/local/Persistence.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ public abstract class Persistence {
8989
/** Creates an IndexManager that manages our persisted query indexes. */
9090
abstract IndexManager getIndexManager();
9191

92+
/** Returns a BundleCache representing the persisted cache of loaded bundles. */
93+
abstract BundleCache getBundleCache();
94+
9295
/**
9396
* Performs an operation inside a persistence transaction. Any reads or writes against persistence
9497
* must be performed within a transaction. Writes will be committed atomically once the

0 commit comments

Comments
 (0)