use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalDocumentsView method recalculateAndSaveOverlays.
private void recalculateAndSaveOverlays(Map<DocumentKey, MutableDocument> docs) {
List<MutationBatch> batches = mutationQueue.getAllMutationBatchesAffectingDocumentKeys(docs.keySet());
Map<DocumentKey, FieldMask> masks = new HashMap<>();
// A reverse lookup map from batch id to the documents within that batch.
TreeMap<Integer, Set<DocumentKey>> documentsByBatchId = new TreeMap<>();
// along the way.
for (MutationBatch batch : batches) {
for (DocumentKey key : batch.getKeys()) {
MutableDocument baseDoc = docs.get(key);
if (baseDoc == null) {
// If this batch has documents not included in passed in `docs`, skip them.
continue;
}
FieldMask mask = masks.containsKey(key) ? masks.get(key) : FieldMask.EMPTY;
mask = batch.applyToLocalView(baseDoc, mask);
masks.put(key, mask);
int batchId = batch.getBatchId();
if (!documentsByBatchId.containsKey(batchId)) {
documentsByBatchId.put(batchId, new HashSet<>());
}
documentsByBatchId.get(batchId).add(key);
}
}
Set<DocumentKey> processed = new HashSet<>();
// Iterate in descending order of batch ids, skip documents that are already saved.
for (Map.Entry<Integer, Set<DocumentKey>> entry : documentsByBatchId.descendingMap().entrySet()) {
Map<DocumentKey, Mutation> overlays = new HashMap<>();
for (DocumentKey key : entry.getValue()) {
if (!processed.contains(key)) {
overlays.put(key, Mutation.calculateOverlayMutation(docs.get(key), masks.get(key)));
processed.add(key);
}
}
documentOverlayCache.saveOverlays(entry.getKey(), overlays);
}
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalStore method handleUserChange.
// PORTING NOTE: no shutdown for LocalStore or persistence components on Android.
public ImmutableSortedMap<DocumentKey, Document> handleUserChange(User user) {
// Swap out the mutation queue, grabbing the pending mutation batches before and after.
List<MutationBatch> oldBatches = mutationQueue.getAllMutationBatches();
initializeUserComponents(user);
startIndexManager();
startMutationQueue();
List<MutationBatch> newBatches = mutationQueue.getAllMutationBatches();
// Union the old/new changed keys.
ImmutableSortedSet<DocumentKey> changedKeys = DocumentKey.emptyKeySet();
for (List<MutationBatch> batches : asList(oldBatches, newBatches)) {
for (MutationBatch batch : batches) {
for (Mutation mutation : batch.getMutations()) {
changedKeys = changedKeys.insert(mutation.getKey());
}
}
}
// Return the set of all (potentially) changed documents as the result of the user change.
return localDocuments.getDocuments(changedKeys);
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalStore method writeLocally.
/**
* Accepts locally generated Mutations and commits them to storage.
*/
public LocalDocumentsResult writeLocally(List<Mutation> mutations) {
Timestamp localWriteTime = Timestamp.now();
// TODO: Call queryEngine.handleDocumentChange() appropriately.
Set<DocumentKey> keys = new HashSet<>();
for (Mutation mutation : mutations) {
keys.add(mutation.getKey());
}
return persistence.runTransaction("Locally write mutations", () -> {
// Load and apply all existing mutations. This lets us compute the current base state for
// all non-idempotent transforms before applying any additional user-provided writes.
ImmutableSortedMap<DocumentKey, Document> documents = localDocuments.getDocuments(keys);
// For non-idempotent mutations (such as `FieldValue.increment()`), we record the base
// state in a separate patch mutation. This is later used to guarantee consistent values
// and prevents flicker even if the backend sends us an update that already includes our
// transform.
List<Mutation> baseMutations = new ArrayList<>();
for (Mutation mutation : mutations) {
ObjectValue baseValue = mutation.extractTransformBaseValue(documents.get(mutation.getKey()));
if (baseValue != null) {
// NOTE: The base state should only be applied if there's some existing
// document to override, so use a Precondition of exists=true
baseMutations.add(new PatchMutation(mutation.getKey(), baseValue, baseValue.getFieldMask(), Precondition.exists(true)));
}
}
MutationBatch batch = mutationQueue.addMutationBatch(localWriteTime, baseMutations, mutations);
Map<DocumentKey, Mutation> overlays = batch.applyToLocalDocumentSet(documents);
documentOverlayCache.saveOverlays(batch.getBatchId(), overlays);
return new LocalDocumentsResult(batch.getBatchId(), documents);
});
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalStore method acknowledgeBatch.
/**
* Acknowledges the given batch.
*
* <p>On the happy path when a batch is acknowledged, the local store will
*
* <ul>
* <li>remove the batch from the mutation queue;
* <li>apply the changes to the remote document cache;
* <li>recalculate the latency compensated view implied by those changes (there may be mutations
* in the queue that affect the documents but haven't been acknowledged yet); and
* <li>give the changed documents back the sync engine
* </ul>
*
* @return The resulting (modified) documents.
*/
public ImmutableSortedMap<DocumentKey, Document> acknowledgeBatch(MutationBatchResult batchResult) {
return persistence.runTransaction("Acknowledge batch", () -> {
MutationBatch batch = batchResult.getBatch();
mutationQueue.acknowledgeBatch(batch, batchResult.getStreamToken());
applyWriteToRemoteDocuments(batchResult);
mutationQueue.performConsistencyCheck();
documentOverlayCache.removeOverlaysForBatchId(batchResult.getBatch().getBatchId());
localDocuments.recalculateAndSaveOverlays(getKeysWithTransformResults(batchResult));
return localDocuments.getDocuments(batch.getKeys());
});
}
use of com.google.firebase.firestore.model.mutation.MutationBatch in project firebase-android-sdk by firebase.
the class LocalStore method applyWriteToRemoteDocuments.
private void applyWriteToRemoteDocuments(MutationBatchResult batchResult) {
MutationBatch batch = batchResult.getBatch();
Set<DocumentKey> docKeys = batch.getKeys();
for (DocumentKey docKey : docKeys) {
MutableDocument doc = remoteDocuments.get(docKey);
SnapshotVersion ackVersion = batchResult.getDocVersions().get(docKey);
hardAssert(ackVersion != null, "docVersions should contain every doc in the write.");
if (doc.getVersion().compareTo(ackVersion) < 0) {
batch.applyToRemoteDocument(doc, batchResult);
if (doc.isValidDocument()) {
remoteDocuments.add(doc, batchResult.getCommitVersion());
}
}
}
mutationQueue.removeMutationBatch(batch);
}
Aggregations