2121import static com .google .firebase .firestore .util .Util .repeatSequence ;
2222
2323import android .database .Cursor ;
24+ import androidx .annotation .NonNull ;
2425import androidx .annotation .VisibleForTesting ;
2526import com .google .firebase .Timestamp ;
2627import com .google .firebase .database .collection .ImmutableSortedMap ;
@@ -147,30 +148,40 @@ public MutableDocument get(DocumentKey documentKey) {
147148 public Map <DocumentKey , MutableDocument > getAll (Iterable <DocumentKey > documentKeys ) {
148149 Map <DocumentKey , MutableDocument > results = new HashMap <>();
149150 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 ()));
152154
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+ }
156159 }
157160
158161 SQLitePersistence .LongQuery longQuery =
159162 new SQLitePersistence .LongQuery (
160163 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 "
162166 + "WHERE path IN (" ,
163167 bindVars ,
164168 ") ORDER BY path" );
165169
166170 BackgroundQueue backgroundQueue = new BackgroundQueue ();
171+ ArrayList <DocumentTypeUpdateInfo > documentTypeBackfills = new ArrayList <>();
167172 while (longQuery .hasMoreSubqueries ()) {
168173 longQuery
169174 .performNextSubquery ()
170- .forEach (row -> processRowInBackground (backgroundQueue , results , row , /*filter*/ null ));
175+ .forEach (
176+ row ->
177+ processRowInBackground (
178+ backgroundQueue , results , row , documentTypeBackfills , /*filter*/ null ));
171179 }
172180 backgroundQueue .drain ();
173- return results ;
181+
182+ synchronized (results ) {
183+ return results ;
184+ }
174185 }
175186
176187 @ Override
@@ -217,7 +228,7 @@ private Map<DocumentKey, MutableDocument> getAll(
217228
218229 StringBuilder sql =
219230 repeatSequence (
220- "SELECT contents, read_time_seconds, read_time_nanos, path "
231+ "SELECT contents, read_time_seconds, read_time_nanos, document_type, path "
221232 + "FROM remote_documents "
222233 + "WHERE path >= ? AND path < ? AND path_length = ? "
223234 + (tryFilterDocumentType == null
@@ -254,17 +265,21 @@ private Map<DocumentKey, MutableDocument> getAll(
254265
255266 BackgroundQueue backgroundQueue = new BackgroundQueue ();
256267 Map <DocumentKey , MutableDocument > results = new HashMap <>();
268+ ArrayList <DocumentTypeUpdateInfo > documentTypeBackfills = new ArrayList <>();
257269 db .query (sql .toString ())
258270 .binding (bindVars )
259271 .forEach (
260272 row -> {
261- processRowInBackground (backgroundQueue , results , row , filter );
273+ processRowInBackground (backgroundQueue , results , row , documentTypeBackfills , filter );
262274 if (context != null ) {
263275 context .incrementDocumentReadCount ();
264276 }
265277 });
266278 backgroundQueue .drain ();
267- return results ;
279+
280+ synchronized (results ) {
281+ return results ;
282+ }
268283 }
269284
270285 private Map <DocumentKey , MutableDocument > getAll (
@@ -280,10 +295,13 @@ private void processRowInBackground(
280295 BackgroundQueue backgroundQueue ,
281296 Map <DocumentKey , MutableDocument > results ,
282297 Cursor row ,
298+ List <DocumentTypeUpdateInfo > documentTypeBackfills ,
283299 @ Nullable Function <MutableDocument , Boolean > filter ) {
284300 byte [] rawDocument = row .getBlob (0 );
285301 int readTimeSeconds = row .getInt (1 );
286302 int readTimeNanos = row .getInt (2 );
303+ boolean documentTypeIsNull = row .isNull (3 );
304+ String path = row .getString (4 );
287305
288306 // Since scheduling background tasks incurs overhead, we only dispatch to a
289307 // background thread if there are still some documents remaining.
@@ -292,6 +310,17 @@ private void processRowInBackground(
292310 () -> {
293311 MutableDocument document =
294312 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+ }
295324 if (filter == null || filter .apply (document )) {
296325 synchronized (results ) {
297326 results .put (document .getKey (), document );
@@ -334,4 +363,33 @@ private MutableDocument decodeMaybeDocument(
334363 throw fail ("MaybeDocument failed to parse: %s" , e );
335364 }
336365 }
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+ }
337395}
0 commit comments