21
21
import static com .google .firebase .firestore .util .Util .repeatSequence ;
22
22
23
23
import android .database .Cursor ;
24
+ import androidx .annotation .NonNull ;
24
25
import androidx .annotation .VisibleForTesting ;
25
26
import com .google .firebase .Timestamp ;
26
27
import com .google .firebase .database .collection .ImmutableSortedMap ;
@@ -147,30 +148,40 @@ public MutableDocument get(DocumentKey documentKey) {
147
148
public Map <DocumentKey , MutableDocument > getAll (Iterable <DocumentKey > documentKeys ) {
148
149
Map <DocumentKey , MutableDocument > results = new HashMap <>();
149
150
List <Object > bindVars = new ArrayList <>();
150
- for (DocumentKey key : documentKeys ) {
151
- bindVars .add (EncodedPath .encode (key .getPath ()));
151
+ synchronized (results ) {
152
+ for (DocumentKey key : documentKeys ) {
153
+ bindVars .add (EncodedPath .encode (key .getPath ()));
152
154
153
- // Make sure each key has a corresponding entry, which is null in case the document is not
154
- // found.
155
- results .put (key , MutableDocument .newInvalidDocument (key ));
155
+ // Make sure each key has a corresponding entry, which is null in case the document is not
156
+ // found.
157
+ results .put (key , MutableDocument .newInvalidDocument (key ));
158
+ }
156
159
}
157
160
158
161
SQLitePersistence .LongQuery longQuery =
159
162
new SQLitePersistence .LongQuery (
160
163
db ,
161
- "SELECT contents, read_time_seconds, read_time_nanos FROM remote_documents "
164
+ "SELECT contents, read_time_seconds, read_time_nanos, document_type, path "
165
+ + "FROM remote_documents "
162
166
+ "WHERE path IN (" ,
163
167
bindVars ,
164
168
") ORDER BY path" );
165
169
166
170
BackgroundQueue backgroundQueue = new BackgroundQueue ();
171
+ ArrayList <DocumentTypeUpdateInfo > documentTypeBackfills = new ArrayList <>();
167
172
while (longQuery .hasMoreSubqueries ()) {
168
173
longQuery
169
174
.performNextSubquery ()
170
- .forEach (row -> processRowInBackground (backgroundQueue , results , row , /*filter*/ null ));
175
+ .forEach (
176
+ row ->
177
+ processRowInBackground (
178
+ backgroundQueue , results , row , documentTypeBackfills , /*filter*/ null ));
171
179
}
172
180
backgroundQueue .drain ();
173
- return results ;
181
+
182
+ synchronized (results ) {
183
+ return results ;
184
+ }
174
185
}
175
186
176
187
@ Override
@@ -217,7 +228,7 @@ private Map<DocumentKey, MutableDocument> getAll(
217
228
218
229
StringBuilder sql =
219
230
repeatSequence (
220
- "SELECT contents, read_time_seconds, read_time_nanos, path "
231
+ "SELECT contents, read_time_seconds, read_time_nanos, document_type, path "
221
232
+ "FROM remote_documents "
222
233
+ "WHERE path >= ? AND path < ? AND path_length = ? "
223
234
+ (tryFilterDocumentType == null
@@ -254,17 +265,21 @@ private Map<DocumentKey, MutableDocument> getAll(
254
265
255
266
BackgroundQueue backgroundQueue = new BackgroundQueue ();
256
267
Map <DocumentKey , MutableDocument > results = new HashMap <>();
268
+ ArrayList <DocumentTypeUpdateInfo > documentTypeBackfills = new ArrayList <>();
257
269
db .query (sql .toString ())
258
270
.binding (bindVars )
259
271
.forEach (
260
272
row -> {
261
- processRowInBackground (backgroundQueue , results , row , filter );
273
+ processRowInBackground (backgroundQueue , results , row , documentTypeBackfills , filter );
262
274
if (context != null ) {
263
275
context .incrementDocumentReadCount ();
264
276
}
265
277
});
266
278
backgroundQueue .drain ();
267
- return results ;
279
+
280
+ synchronized (results ) {
281
+ return results ;
282
+ }
268
283
}
269
284
270
285
private Map <DocumentKey , MutableDocument > getAll (
@@ -280,10 +295,13 @@ private void processRowInBackground(
280
295
BackgroundQueue backgroundQueue ,
281
296
Map <DocumentKey , MutableDocument > results ,
282
297
Cursor row ,
298
+ List <DocumentTypeUpdateInfo > documentTypeBackfills ,
283
299
@ Nullable Function <MutableDocument , Boolean > filter ) {
284
300
byte [] rawDocument = row .getBlob (0 );
285
301
int readTimeSeconds = row .getInt (1 );
286
302
int readTimeNanos = row .getInt (2 );
303
+ boolean documentTypeIsNull = row .isNull (3 );
304
+ String path = row .getString (4 );
287
305
288
306
// Since scheduling background tasks incurs overhead, we only dispatch to a
289
307
// background thread if there are still some documents remaining.
@@ -292,6 +310,17 @@ private void processRowInBackground(
292
310
() -> {
293
311
MutableDocument document =
294
312
decodeMaybeDocument (rawDocument , readTimeSeconds , readTimeNanos );
313
+ if (documentTypeIsNull ) {
314
+ DocumentTypeUpdateInfo updateInfo =
315
+ new DocumentTypeUpdateInfo (
316
+ path ,
317
+ readTimeSeconds ,
318
+ readTimeNanos ,
319
+ DocumentType .forMutableDocument (document ));
320
+ synchronized (documentTypeBackfills ) {
321
+ documentTypeBackfills .add (updateInfo );
322
+ }
323
+ }
295
324
if (filter == null || filter .apply (document )) {
296
325
synchronized (results ) {
297
326
results .put (document .getKey (), document );
@@ -334,4 +363,33 @@ private MutableDocument decodeMaybeDocument(
334
363
throw fail ("MaybeDocument failed to parse: %s" , e );
335
364
}
336
365
}
366
+
367
+ private static class DocumentTypeUpdateInfo {
368
+ final String path ;
369
+ final int readTimeSeconds ;
370
+ final int readTimeNanos ;
371
+ final DocumentType documentType ;
372
+
373
+ DocumentTypeUpdateInfo (
374
+ String path , int readTimeSeconds , int readTimeNanos , DocumentType documentType ) {
375
+ this .path = path ;
376
+ this .readTimeSeconds = readTimeSeconds ;
377
+ this .readTimeNanos = readTimeNanos ;
378
+ this .documentType = documentType ;
379
+ }
380
+
381
+ @ NonNull
382
+ @ Override
383
+ public String toString () {
384
+ return "DocumentTypeUpdateInfo(path="
385
+ + path
386
+ + ", readTimeSeconds="
387
+ + readTimeSeconds
388
+ + ", readTimeNanos="
389
+ + readTimeNanos
390
+ + ", documentType="
391
+ + documentType
392
+ + ")" ;
393
+ }
394
+ }
337
395
}
0 commit comments