@@ -155,48 +155,59 @@ public ImmutableSortedMap<DocumentKey, Document> getAllDocumentsMatchingQuery(
155
155
(ImmutableSortedMap <DocumentKey , Document >[])
156
156
new ImmutableSortedMap [] {DocumentCollections .emptyDocumentMap ()};
157
157
158
+ SQLitePersistence .Query sqlQuery ;
159
+ if (sinceReadTime .equals (SnapshotVersion .NONE )) {
160
+ sqlQuery =
161
+ db .query ("SELECT path, contents FROM remote_documents WHERE path >= ? AND path < ?" )
162
+ .binding (prefixPath , prefixSuccessorPath );
163
+ } else {
164
+ // Execute an index-free query and filter by read time. This is safe since all document
165
+ // changes to queries that have a lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read
166
+ // time set.
167
+ sqlQuery =
168
+ db .query (
169
+ "SELECT path, contents FROM remote_documents WHERE path >= ? AND path < ?"
170
+ + "AND (read_time_seconds > ? OR (read_time_seconds = ? AND read_time_nanos > ?))" )
171
+ .binding (
172
+ prefixPath ,
173
+ prefixSuccessorPath ,
174
+ readTime .getSeconds (),
175
+ readTime .getSeconds (),
176
+ readTime .getNanoseconds ());
177
+ }
178
+
158
179
int rowsProcessed =
159
- db .query (
160
- "SELECT path, contents FROM remote_documents WHERE path >= ? AND path < ? "
161
- + "AND (read_time_seconds IS NULL OR read_time_seconds > ? "
162
- + "OR (read_time_seconds = ? AND read_time_nanos > ?))" )
163
- .binding (
164
- prefixPath ,
165
- prefixSuccessorPath ,
166
- readTime .getSeconds (),
167
- readTime .getSeconds (),
168
- readTime .getNanoseconds ())
169
- .forEach (
170
- row -> {
171
- // TODO: Actually implement a single-collection query
172
- //
173
- // The query is actually returning any path that starts with the query path prefix
174
- // which may include documents in subcollections. For example, a query on 'rooms'
175
- // will return rooms/abc/messages/xyx but we shouldn't match it. Fix this by
176
- // discarding rows with document keys more than one segment longer than the query
177
- // path.
178
- ResourcePath path = EncodedPath .decodeResourcePath (row .getString (0 ));
179
- if (path .length () != immediateChildrenPathLength ) {
180
- return ;
181
- }
182
-
183
- byte [] rawDocument = row .getBlob (1 );
184
-
185
- // Since scheduling background tasks incurs overhead, we only dispatch to a
186
- // background thread if there are still some documents remaining.
187
- Executor executor = row .isLast () ? Executors .DIRECT_EXECUTOR : backgroundQueue ;
188
- executor .execute (
189
- () -> {
190
- MaybeDocument maybeDoc = decodeMaybeDocument (rawDocument );
191
-
192
- if (maybeDoc instanceof Document && query .matches ((Document ) maybeDoc )) {
193
- synchronized (SQLiteRemoteDocumentCache .this ) {
194
- matchingDocuments [0 ] =
195
- matchingDocuments [0 ].insert (maybeDoc .getKey (), (Document ) maybeDoc );
196
- }
197
- }
198
- });
199
- });
180
+ sqlQuery .forEach (
181
+ row -> {
182
+ // TODO: Actually implement a single-collection query
183
+ //
184
+ // The query is actually returning any path that starts with the query path prefix
185
+ // which may include documents in subcollections. For example, a query on 'rooms'
186
+ // will return rooms/abc/messages/xyx but we shouldn't match it. Fix this by
187
+ // discarding rows with document keys more than one segment longer than the query
188
+ // path.
189
+ ResourcePath path = EncodedPath .decodeResourcePath (row .getString (0 ));
190
+ if (path .length () != immediateChildrenPathLength ) {
191
+ return ;
192
+ }
193
+
194
+ byte [] rawDocument = row .getBlob (1 );
195
+
196
+ // Since scheduling background tasks incurs overhead, we only dispatch to a
197
+ // background thread if there are still some documents remaining.
198
+ Executor executor = row .isLast () ? Executors .DIRECT_EXECUTOR : backgroundQueue ;
199
+ executor .execute (
200
+ () -> {
201
+ MaybeDocument maybeDoc = decodeMaybeDocument (rawDocument );
202
+
203
+ if (maybeDoc instanceof Document && query .matches ((Document ) maybeDoc )) {
204
+ synchronized (SQLiteRemoteDocumentCache .this ) {
205
+ matchingDocuments [0 ] =
206
+ matchingDocuments [0 ].insert (maybeDoc .getKey (), (Document ) maybeDoc );
207
+ }
208
+ }
209
+ });
210
+ });
200
211
201
212
statsCollector .recordRowsRead (STATS_TAG , rowsProcessed );
202
213
0 commit comments