use of com.google.firebase.firestore.model.mutation.Mutation 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.Mutation 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.Mutation 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.Mutation in project firebase-android-sdk by firebase.
the class LocalSerializer method decodeMutationBatch.
/**
* Decodes a WriteBatch proto into a MutationBatch model.
*/
MutationBatch decodeMutationBatch(com.google.firebase.firestore.proto.WriteBatch batch) {
int batchId = batch.getBatchId();
Timestamp localWriteTime = rpcSerializer.decodeTimestamp(batch.getLocalWriteTime());
int baseMutationsCount = batch.getBaseWritesCount();
List<Mutation> baseMutations = new ArrayList<>(baseMutationsCount);
for (int i = 0; i < baseMutationsCount; i++) {
baseMutations.add(rpcSerializer.decodeMutation(batch.getBaseWrites(i)));
}
List<Mutation> mutations = new ArrayList<>(batch.getWritesCount());
// TODO(b/174608374): Remove this code once we perform a schema migration.
for (int i = 0; i < batch.getWritesCount(); ++i) {
Write currentMutation = batch.getWrites(i);
boolean hasTransform = i + 1 < batch.getWritesCount() && batch.getWrites(i + 1).hasTransform();
if (hasTransform) {
hardAssert(batch.getWrites(i).hasUpdate(), "TransformMutation should be preceded by a patch or set mutation");
Builder newMutationBuilder = Write.newBuilder(currentMutation);
Write transformMutation = batch.getWrites(i + 1);
for (FieldTransform fieldTransform : transformMutation.getTransform().getFieldTransformsList()) {
newMutationBuilder.addUpdateTransforms(fieldTransform);
}
mutations.add(rpcSerializer.decodeMutation(newMutationBuilder.build()));
++i;
} else {
mutations.add(rpcSerializer.decodeMutation(currentMutation));
}
}
return new MutationBatch(batchId, localWriteTime, baseMutations, mutations);
}
use of com.google.firebase.firestore.model.mutation.Mutation in project firebase-android-sdk by firebase.
the class LocalSerializer method encodeMutationBatch.
/**
* Encodes a MutationBatch model for local storage in the mutation queue.
*/
com.google.firebase.firestore.proto.WriteBatch encodeMutationBatch(MutationBatch batch) {
com.google.firebase.firestore.proto.WriteBatch.Builder result = com.google.firebase.firestore.proto.WriteBatch.newBuilder();
result.setBatchId(batch.getBatchId());
result.setLocalWriteTime(rpcSerializer.encodeTimestamp(batch.getLocalWriteTime()));
for (Mutation mutation : batch.getBaseMutations()) {
result.addBaseWrites(rpcSerializer.encodeMutation(mutation));
}
for (Mutation mutation : batch.getMutations()) {
result.addWrites(rpcSerializer.encodeMutation(mutation));
}
return result.build();
}
Aggregations