use of com.google.firebase.firestore.model.DocumentKey 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.DocumentKey in project firebase-android-sdk by firebase.
the class LocalDocumentsView method getNextDocuments.
/**
* Given a collection group, returns the next documents that follow the provided offset, along
* with an updated batch ID.
*
* <p>The documents returned by this method are ordered by remote version from the provided
* offset. If there are no more remote documents after the provided offset, documents with
* mutations in order of batch id from the offset are returned. Since all documents in a batch are
* returned together, the total number of documents returned can exceed {@code count}.
*
* @param collectionGroup The collection group for the documents.
* @param offset The offset to index into.
* @param count The number of documents to return
* @return A LocalDocumentsResult with the documents that follow the provided offset and the last
* processed batch id.
*/
LocalDocumentsResult getNextDocuments(String collectionGroup, IndexOffset offset, int count) {
Map<DocumentKey, MutableDocument> docs = remoteDocumentCache.getAll(collectionGroup, offset, count);
Map<DocumentKey, Overlay> overlays = count - docs.size() > 0 ? documentOverlayCache.getOverlays(collectionGroup, offset.getLargestBatchId(), count - docs.size()) : Collections.emptyMap();
int largestBatchId = FieldIndex.INITIAL_LARGEST_BATCH_ID;
for (Overlay overlay : overlays.values()) {
if (!docs.containsKey(overlay.getKey())) {
docs.put(overlay.getKey(), getBaseDocument(overlay.getKey(), overlay));
}
// The callsite will use the largest batch ID together with the latest read time to create
// a new index offset. Since we only process batch IDs if all remote documents have been read,
// no overlay will increase the overall read time. This is why we only need to special case
// the batch id.
largestBatchId = Math.max(largestBatchId, overlay.getLargestBatchId());
}
populateOverlays(overlays, docs.keySet());
ImmutableSortedMap<DocumentKey, Document> localDocs = computeViews(docs, overlays, Collections.emptySet());
return new LocalDocumentsResult(largestBatchId, localDocs);
}
use of com.google.firebase.firestore.model.DocumentKey in project firebase-android-sdk by firebase.
the class LocalStore method releaseTarget.
/**
* Unpin all the documents associated with the given target.
*
* <p>Releasing a non-existing target is an error.
*/
public void releaseTarget(int targetId) {
persistence.runTransaction("Release target", () -> {
TargetData targetData = queryDataByTarget.get(targetId);
hardAssert(targetData != null, "Tried to release nonexistent target: %s", targetId);
// References for documents sent via Watch are automatically removed when we delete a
// query's target data from the reference delegate. Since this does not remove references
// for locally mutated documents, we have to remove the target associations for these
// documents manually.
ImmutableSortedSet<DocumentKey> removedReferences = localViewReferences.removeReferencesForId(targetId);
for (DocumentKey key : removedReferences) {
persistence.getReferenceDelegate().removeReference(key);
}
// Note: This also updates the query cache
persistence.getReferenceDelegate().removeTarget(targetData);
queryDataByTarget.remove(targetId);
targetIdByTarget.remove(targetData.getTarget());
});
}
use of com.google.firebase.firestore.model.DocumentKey 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.DocumentKey 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);
});
}
Aggregations