use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class SQLiteMutationQueue method getAllMutationBatchesAffectingQuery.
@Override
public List<MutationBatch> getAllMutationBatchesAffectingQuery(Query query) {
hardAssert(!query.isCollectionGroupQuery(), "CollectionGroup queries should be handled in LocalDocumentsView");
// Use the query path as a prefix for testing if a document matches the query.
ResourcePath prefix = query.getPath();
int immediateChildrenPathLength = prefix.length() + 1;
// Scan the document_mutations table looking for documents whose path has a prefix that matches
// the query path.
//
// The most obvious way to do this would be with a LIKE query with a trailing wildcard (e.g.
// path LIKE 'foo/%'). Unfortunately SQLite does not convert a trailing wildcard like that into
// the equivalent range scan so a LIKE query ends up being a table scan. The query below is
// equivalent but hits the index on both uid and path, so it's much faster.
// TODO: Actually implement a single-collection query
//
// This is actually executing an ancestor query, traversing the whole subtree below the
// collection which can be horrifically inefficient for some structures. The right way to
// solve this is to implement the full value index, but that's not in the cards in the near
// future so this is the best we can do for the moment.
String prefixPath = EncodedPath.encode(prefix);
String prefixSuccessorPath = EncodedPath.prefixSuccessor(prefixPath);
List<MutationBatch> result = new ArrayList<>();
db.query("SELECT dm.batch_id, dm.path, SUBSTR(m.mutations, 1, ?) " + "FROM document_mutations dm, mutations m " + "WHERE dm.uid = ? " + "AND dm.path >= ? " + "AND dm.path < ? " + "AND dm.uid = m.uid " + "AND dm.batch_id = m.batch_id " + "ORDER BY dm.batch_id").binding(BLOB_MAX_INLINE_LENGTH, uid, prefixPath, prefixSuccessorPath).forEach(row -> {
// Ensure unique batches only. This works because the batches come out in order so
// we only need to ensure that the batchId of this row is different from the
// preceding one.
int batchId = row.getInt(0);
int size = result.size();
if (size > 0 && batchId == result.get(size - 1).getBatchId()) {
return;
}
// The query is actually returning any path that starts with the query path prefix
// which may include documents in subcollections. For example, a query on 'rooms'
// will return rooms/abc/messages/xyx but we shouldn't match it. Fix this by
// discarding rows with document keys more than one segment longer than the query
// path.
ResourcePath path = EncodedPath.decodeResourcePath(row.getString(1));
if (path.length() != immediateChildrenPathLength) {
return;
}
result.add(decodeInlineMutationBatch(batchId, row.getBlob(2)));
});
return result;
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class SQLiteOverlayMigrationManager method buildOverlays.
private void buildOverlays() {
db.runTransaction("build overlays", () -> {
if (!hasPendingOverlayMigration()) {
return;
}
Set<String> userIds = getAllUserIds();
RemoteDocumentCache remoteDocumentCache = db.getRemoteDocumentCache();
for (String uid : userIds) {
User user = new User(uid);
MutationQueue mutationQueue = db.getMutationQueue(user, db.getIndexManager(user));
// Get all document keys that have local mutations
Set<DocumentKey> allDocumentKeys = new HashSet<>();
List<MutationBatch> batches = mutationQueue.getAllMutationBatches();
for (MutationBatch batch : batches) {
allDocumentKeys.addAll(batch.getKeys());
}
// Recalculate and save overlays
DocumentOverlayCache documentOverlayCache = db.getDocumentOverlayCache(user);
LocalDocumentsView localView = new LocalDocumentsView(remoteDocumentCache, mutationQueue, documentOverlayCache, db.getIndexManager(user));
localView.recalculateAndSaveOverlays(allDocumentKeys);
}
removePendingOverlayMigrations();
});
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalStore method rejectBatch.
/**
* Removes mutations from the MutationQueue for the specified batch. LocalDocuments will be
* recalculated.
*
* @return The resulting (modified) documents.
*/
public ImmutableSortedMap<DocumentKey, Document> rejectBatch(int batchId) {
return persistence.runTransaction("Reject batch", () -> {
MutationBatch toReject = mutationQueue.lookupMutationBatch(batchId);
hardAssert(toReject != null, "Attempt to reject nonexistent batch!");
mutationQueue.removeMutationBatch(toReject);
mutationQueue.performConsistencyCheck();
documentOverlayCache.removeOverlaysForBatchId(batchId);
localDocuments.recalculateAndSaveOverlays(toReject.getKeys());
return localDocuments.getDocuments(toReject.getKeys());
});
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class MemoryMutationQueue method lookupMutationBatch.
@Nullable
@Override
public MutationBatch lookupMutationBatch(int batchId) {
int index = indexOfBatchId(batchId);
if (index < 0 || index >= queue.size()) {
return null;
}
MutationBatch batch = queue.get(index);
hardAssert(batch.getBatchId() == batchId, "If found batch must match");
return batch;
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class MemoryMutationQueue method addMutationBatch.
@Override
public MutationBatch addMutationBatch(Timestamp localWriteTime, List<Mutation> baseMutations, List<Mutation> mutations) {
hardAssert(!mutations.isEmpty(), "Mutation batches should not be empty");
int batchId = nextBatchId;
nextBatchId += 1;
int size = queue.size();
if (size > 0) {
MutationBatch prior = queue.get(size - 1);
hardAssert(prior.getBatchId() < batchId, "Mutation batchIds must be monotonically increasing order");
}
MutationBatch batch = new MutationBatch(batchId, localWriteTime, baseMutations, mutations);
queue.add(batch);
// Track references by document key and index collection parents.
for (Mutation mutation : mutations) {
batchesByDocumentKey = batchesByDocumentKey.insert(new DocumentReference(mutation.getKey(), batchId));
indexManager.addToCollectionParentIndex(mutation.getKey().getCollectionPath());
}
return batch;
}
Aggregations