Search in sources :

Example 1 with MutableDocument

use of com.google.firebase.firestore.model.MutableDocument 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);
    }
}
Also used : SortedSet(java.util.SortedSet) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) MutableDocument(com.google.firebase.firestore.model.MutableDocument) TreeMap(java.util.TreeMap) MutationBatch(com.google.firebase.firestore.model.mutation.MutationBatch) DocumentKey(com.google.firebase.firestore.model.DocumentKey) PatchMutation(com.google.firebase.firestore.model.mutation.PatchMutation) Mutation(com.google.firebase.firestore.model.mutation.Mutation) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap) DocumentCollections.emptyDocumentMap(com.google.firebase.firestore.model.DocumentCollections.emptyDocumentMap) FieldMask(com.google.firebase.firestore.model.mutation.FieldMask) HashSet(java.util.HashSet)

Example 2 with MutableDocument

use of com.google.firebase.firestore.model.MutableDocument 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);
}
Also used : DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument) Overlay(com.google.firebase.firestore.model.mutation.Overlay) Document(com.google.firebase.firestore.model.Document) MutableDocument(com.google.firebase.firestore.model.MutableDocument)

Example 3 with MutableDocument

use of com.google.firebase.firestore.model.MutableDocument in project firebase-android-sdk by firebase.

the class LocalStore method applyBundledDocuments.

@Override
public ImmutableSortedMap<DocumentKey, Document> applyBundledDocuments(ImmutableSortedMap<DocumentKey, MutableDocument> documents, String bundleId) {
    // Allocates a target to hold all document keys from the bundle, such that
    // they will not get garbage collected right away.
    TargetData umbrellaTargetData = allocateTarget(newUmbrellaTarget(bundleId));
    return persistence.runTransaction("Apply bundle documents", () -> {
        ImmutableSortedSet<DocumentKey> documentKeys = DocumentKey.emptyKeySet();
        Map<DocumentKey, MutableDocument> documentMap = new HashMap<>();
        for (Entry<DocumentKey, MutableDocument> entry : documents) {
            DocumentKey documentKey = entry.getKey();
            MutableDocument document = entry.getValue();
            if (document.isFoundDocument()) {
                documentKeys = documentKeys.insert(documentKey);
            }
            documentMap.put(documentKey, document);
        }
        targetCache.removeMatchingKeysForTargetId(umbrellaTargetData.getTargetId());
        targetCache.addMatchingKeys(documentKeys, umbrellaTargetData.getTargetId());
        DocumentChangeResult result = populateDocumentChanges(documentMap);
        Map<DocumentKey, MutableDocument> changedDocs = result.changedDocuments;
        return localDocuments.getLocalViewOfDocuments(changedDocs, result.existenceChangedKeys);
    });
}
Also used : HashMap(java.util.HashMap) DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument)

Example 4 with MutableDocument

use of com.google.firebase.firestore.model.MutableDocument in project firebase-android-sdk by firebase.

the class LocalStore method populateDocumentChanges.

/**
 * Populates the remote document cache with documents from backend or a bundle. Returns the
 * document changes resulting from applying those documents, and also a set of documents whose
 * existence state are changed as a result.
 *
 * <p>Note: this function will use `documentVersions` if it is defined. When it is not defined, it
 * resorts to `globalVersion`.
 *
 * @param documents Documents to be applied.
 */
private DocumentChangeResult populateDocumentChanges(Map<DocumentKey, MutableDocument> documents) {
    Map<DocumentKey, MutableDocument> changedDocs = new HashMap<>();
    List<DocumentKey> removedDocs = new ArrayList<>();
    Set<DocumentKey> conditionChanged = new HashSet<>();
    // Each loop iteration only affects its "own" doc, so it's safe to get all the remote
    // documents in advance in a single call.
    Map<DocumentKey, MutableDocument> existingDocs = remoteDocuments.getAll(documents.keySet());
    for (Entry<DocumentKey, MutableDocument> entry : documents.entrySet()) {
        DocumentKey key = entry.getKey();
        MutableDocument doc = entry.getValue();
        MutableDocument existingDoc = existingDocs.get(key);
        // Check if see if there is a existence state change for this document.
        if (doc.isFoundDocument() != existingDoc.isFoundDocument()) {
            conditionChanged.add(key);
        }
        // never add documents to cache.
        if (doc.isNoDocument() && doc.getVersion().equals(SnapshotVersion.NONE)) {
            // NoDocuments with SnapshotVersion.NONE are used in manufactured events. We remove
            // these documents from cache since we lost access.
            removedDocs.add(doc.getKey());
            changedDocs.put(key, doc);
        } else if (!existingDoc.isValidDocument() || doc.getVersion().compareTo(existingDoc.getVersion()) > 0 || (doc.getVersion().compareTo(existingDoc.getVersion()) == 0 && existingDoc.hasPendingWrites())) {
            hardAssert(!SnapshotVersion.NONE.equals(doc.getReadTime()), "Cannot add a document when the remote version is zero");
            remoteDocuments.add(doc, doc.getReadTime());
            changedDocs.put(key, doc);
        } else {
            Logger.debug("LocalStore", "Ignoring outdated watch update for %s." + "Current version: %s  Watch version: %s", key, existingDoc.getVersion(), doc.getVersion());
        }
    }
    remoteDocuments.removeAll(removedDocs);
    return new DocumentChangeResult(changedDocs, conditionChanged);
}
Also used : HashMap(java.util.HashMap) DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet)

Example 5 with MutableDocument

use of com.google.firebase.firestore.model.MutableDocument 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);
}
Also used : MutationBatch(com.google.firebase.firestore.model.mutation.MutationBatch) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument)

Aggregations

MutableDocument (com.google.firebase.firestore.model.MutableDocument)159 Test (org.junit.Test)120 DocumentKey (com.google.firebase.firestore.model.DocumentKey)41 Mutation.calculateOverlayMutation (com.google.firebase.firestore.model.mutation.Mutation.calculateOverlayMutation)30 TestUtil.deleteMutation (com.google.firebase.firestore.testutil.TestUtil.deleteMutation)30 TestUtil.mergeMutation (com.google.firebase.firestore.testutil.TestUtil.mergeMutation)30 TestUtil.patchMutation (com.google.firebase.firestore.testutil.TestUtil.patchMutation)30 TestUtil.setMutation (com.google.firebase.firestore.testutil.TestUtil.setMutation)30 HashMap (java.util.HashMap)20 TestUtil.wrapObject (com.google.firebase.firestore.testutil.TestUtil.wrapObject)18 ArrayList (java.util.ArrayList)17 TargetData (com.google.firebase.firestore.local.TargetData)15 WatchTargetChange (com.google.firebase.firestore.remote.WatchChange.WatchTargetChange)14 DocumentChange (com.google.firebase.firestore.remote.WatchChange.DocumentChange)13 ResourcePath (com.google.firebase.firestore.model.ResourcePath)12 Document (com.google.firebase.firestore.model.Document)9 SnapshotVersion (com.google.firebase.firestore.model.SnapshotVersion)8 Map (java.util.Map)8 ListenOptions (com.google.firebase.firestore.core.EventManager.ListenOptions)6 Query (com.google.firebase.firestore.core.Query)6