Search in sources :

Example 41 with SnapshotVersion

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

the class LocalStoreTestCase method testLoadingNamedQueriesAllocatesTargetsAndUpdatesTargetDocumentMapping.

@Test
public void testLoadingNamedQueriesAllocatesTargetsAndUpdatesTargetDocumentMapping() {
    bundleDocuments(doc("foo1/bar", 1, map("sum", 1337)), doc("foo2/bar", 1, map("sum", 42)));
    assertChanged(doc("foo1/bar", 1, map("sum", 1337)), doc("foo2/bar", 1, map("sum", 42)));
    assertContains(doc("foo1/bar", 1, map("sum", 1337)));
    assertContains(doc("foo2/bar", 1, map("sum", 42)));
    Target target1 = Query.atPath(ResourcePath.fromString("foo1")).toTarget();
    NamedQuery namedQuery1 = new NamedQuery("query-1", new BundledQuery(target1, Query.LimitType.LIMIT_TO_FIRST), new SnapshotVersion(Timestamp.now()));
    saveNamedQuery(namedQuery1, key("foo1/bar"));
    assertHasNamedQuery(namedQuery1);
    assertQueryDocumentMapping(/* targetId= */
    4, key("foo1/bar"));
    Target target2 = Query.atPath(ResourcePath.fromString("foo2")).toTarget();
    NamedQuery namedQuery2 = new NamedQuery("query-2", new BundledQuery(target2, Query.LimitType.LIMIT_TO_FIRST), new SnapshotVersion(Timestamp.now()));
    saveNamedQuery(namedQuery2, key("foo2/bar"));
    assertHasNamedQuery(namedQuery2);
    assertQueryDocumentMapping(/* targetId= */
    6, key("foo2/bar"));
}
Also used : Target(com.google.firebase.firestore.core.Target) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) BundledQuery(com.google.firebase.firestore.bundle.BundledQuery) NamedQuery(com.google.firebase.firestore.bundle.NamedQuery) Test(org.junit.Test)

Example 42 with SnapshotVersion

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

the class LruGarbageCollectorTestCase method updateTargetInTransaction.

private void updateTargetInTransaction(TargetData targetData) {
    SnapshotVersion version = version(2);
    ByteString resumeToken = resumeToken(2);
    TargetData updated = targetData.withResumeToken(resumeToken, version).withSequenceNumber(persistence.getReferenceDelegate().getCurrentSequenceNumber());
    targetCache.updateTargetData(updated);
}
Also used : SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) ByteString(com.google.protobuf.ByteString)

Example 43 with SnapshotVersion

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

the class LruGarbageCollectorTestCase method testRemoveTargetsThenGC.

@Test
public void testRemoveTargetsThenGC() {
    // Create 3 targets, add docs to all of them
    // Leave oldest target alone, it is still live
    // Remove newest target
    // Blind write 2 documents
    // Add one of the blind write docs to oldest target (preserves it)
    // Remove some documents from middle target (bumps sequence number)
    // Add some documents from newest target to oldest target (preserves them)
    // Update a doc from middle target
    // Remove middle target
    // Do a blind write
    // GC up to but not including the removal of the middle target
    // 
    // Expect:
    // All docs in oldest target are still around
    // One blind write is gone, the first one not added to oldest target
    // Documents removed from middle target are gone, except ones added to oldest target
    // Documents from newest target are gone, except those added to the old target as well
    // Through the various steps, track which documents we expect to be removed vs
    // documents we expect to be retained.
    Set<DocumentKey> expectedRetained = new HashSet<>();
    Set<DocumentKey> expectedRemoved = new HashSet<>();
    // Add oldest target, 5 documents, and add those documents to the target.
    // This target will not be removed, so all documents that are part of it will
    // be retained.
    TargetData oldestTarget = persistence.runTransaction("Add oldest target and docs", () -> {
        TargetData targetData = addNextQueryInTransaction();
        for (int i = 0; i < 5; i++) {
            MutableDocument doc = cacheADocumentInTransaction();
            expectedRetained.add(doc.getKey());
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
        }
        return targetData;
    });
    // Add middle target and docs. Some docs will be removed from this target later,
    // which we track here.
    Set<DocumentKey> middleDocsToRemove = new HashSet<>();
    // This will be the document in this target that gets an update later.
    DocumentKey[] middleDocToUpdateHolder = new DocumentKey[1];
    TargetData middleTarget = persistence.runTransaction("Add middle target and docs", () -> {
        TargetData targetData = addNextQueryInTransaction();
        // expect them to be removed.
        for (int i = 0; i < 2; i++) {
            MutableDocument doc = cacheADocumentInTransaction();
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
            expectedRemoved.add(doc.getKey());
            middleDocsToRemove.add(doc.getKey());
        }
        // target prevents them from being GC'd, so they are also expected to be retained.
        for (int i = 2; i < 4; i++) {
            MutableDocument doc = cacheADocumentInTransaction();
            expectedRetained.add(doc.getKey());
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
        }
        // This doc stays in this target, but gets updated.
        {
            MutableDocument doc = cacheADocumentInTransaction();
            expectedRetained.add(doc.getKey());
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
            middleDocToUpdateHolder[0] = doc.getKey();
        }
        return targetData;
    });
    DocumentKey middleDocToUpdate = middleDocToUpdateHolder[0];
    // Add the newest target and add 5 documents to it. Some of those documents will
    // additionally be added to the oldest target, which will cause those documents to
    // be retained. The remaining documents are expected to be removed, since this target
    // will be removed.
    Set<DocumentKey> newestDocsToAddToOldest = new HashSet<>();
    persistence.runTransaction("Add newest target and docs", () -> {
        TargetData targetData = addNextQueryInTransaction();
        // because this target will also be removed.
        for (int i = 0; i < 3; i++) {
            MutableDocument doc = cacheADocumentInTransaction();
            expectedRemoved.add(doc.getKey());
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
        }
        // docs to add to the oldest target in addition to this target. They will be retained
        for (int i = 3; i < 5; i++) {
            MutableDocument doc = cacheADocumentInTransaction();
            expectedRetained.add(doc.getKey());
            addDocumentToTarget(doc.getKey(), targetData.getTargetId());
            newestDocsToAddToOldest.add(doc.getKey());
        }
    });
    // 2 doc writes, add one of them to the oldest target.
    persistence.runTransaction("2 doc writes, add one of them to the oldest target", () -> {
        // write two docs and have them ack'd by the server. can skip mutation queue
        // and set them in document cache. Add potentially orphaned first, also add one
        // doc to a target.
        MutableDocument doc1 = cacheADocumentInTransaction();
        markDocumentEligibleForGcInTransaction(doc1.getKey());
        updateTargetInTransaction(oldestTarget);
        addDocumentToTarget(doc1.getKey(), oldestTarget.getTargetId());
        // doc1 should be retained by being added to oldestTarget
        expectedRetained.add(doc1.getKey());
        MutableDocument doc2 = cacheADocumentInTransaction();
        markDocumentEligibleForGcInTransaction(doc2.getKey());
        // nothing is keeping doc2 around, it should be removed
        expectedRemoved.add(doc2.getKey());
    });
    // Remove some documents from the middle target.
    persistence.runTransaction("Remove some documents from the middle target", () -> {
        updateTargetInTransaction(middleTarget);
        for (DocumentKey key : middleDocsToRemove) {
            removeDocumentFromTarget(key, middleTarget.getTargetId());
        }
    });
    // Add a couple docs from the newest target to the oldest (preserves them past the point where
    // newest was removed)
    // upperBound is the sequence number right before middleTarget is updated, then removed.
    long upperBound = persistence.runTransaction("Add a couple docs from the newest target to the oldest", () -> {
        updateTargetInTransaction(oldestTarget);
        for (DocumentKey key : newestDocsToAddToOldest) {
            addDocumentToTarget(key, oldestTarget.getTargetId());
        }
        return persistence.getReferenceDelegate().getCurrentSequenceNumber();
    });
    // Update a doc in the middle target
    persistence.runTransaction("Update a doc in the middle target", () -> {
        SnapshotVersion newVersion = version(3);
        MutableDocument doc = MutableDocument.newFoundDocument(middleDocToUpdate, newVersion, testValue);
        documentCache.add(doc, newVersion);
        updateTargetInTransaction(middleTarget);
    });
    // Remove the middle target
    persistence.runTransaction("remove middle target", () -> persistence.getReferenceDelegate().removeTarget(middleTarget));
    // Write a doc and get an ack, not part of a target
    persistence.runTransaction("Write a doc and get an ack, not part of a target", () -> {
        MutableDocument doc = cacheADocumentInTransaction();
        // Mark it as eligible for GC, but this is after our upper bound for what we will collect.
        markDocumentEligibleForGcInTransaction(doc.getKey());
        // This should be retained, it's too new to get removed.
        expectedRetained.add(doc.getKey());
    });
    // Finally, do the garbage collection, up to but not including the removal of middleTarget
    SparseArray<TargetData> activeTargetIds = new SparseArray<>();
    activeTargetIds.put(oldestTarget.getTargetId(), oldestTarget);
    int targetsRemoved = garbageCollector.removeTargets(upperBound, activeTargetIds);
    // Expect to remove newest target
    assertEquals(1, targetsRemoved);
    int docsRemoved = garbageCollector.removeOrphanedDocuments(upperBound);
    assertEquals(expectedRemoved.size(), docsRemoved);
    persistence.runTransaction("verify results", () -> {
        for (DocumentKey key : expectedRemoved) {
            assertFalse(documentCache.get(key).isValidDocument());
            assertFalse(targetCache.containsKey(key));
        }
        for (DocumentKey key : expectedRetained) {
            assertTrue(documentCache.get(key).isValidDocument());
        }
    });
}
Also used : SparseArray(android.util.SparseArray) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument) HashSet(java.util.HashSet) Test(org.junit.Test)

Aggregations

SnapshotVersion (com.google.firebase.firestore.model.SnapshotVersion)43 DocumentKey (com.google.firebase.firestore.model.DocumentKey)16 Test (org.junit.Test)13 MutableDocument (com.google.firebase.firestore.model.MutableDocument)9 Target (com.google.firebase.firestore.core.Target)8 BundledQuery (com.google.firebase.firestore.bundle.BundledQuery)7 ByteString (com.google.protobuf.ByteString)7 NamedQuery (com.google.firebase.firestore.bundle.NamedQuery)6 ArrayList (java.util.ArrayList)6 Timestamp (com.google.firebase.Timestamp)5 ObjectValue (com.google.firebase.firestore.model.ObjectValue)5 MutationResult (com.google.firebase.firestore.model.mutation.MutationResult)4 JSONObject (org.json.JSONObject)4 Query (com.google.firebase.firestore.core.Query)3 Timestamp (com.google.protobuf.Timestamp)3 ResourcePath (com.google.firebase.firestore.model.ResourcePath)2 MutationBatch (com.google.firebase.firestore.model.mutation.MutationBatch)2 DocumentChange (com.google.firebase.firestore.remote.WatchChange.DocumentChange)2 ExistenceFilterWatchChange (com.google.firebase.firestore.remote.WatchChange.ExistenceFilterWatchChange)2 WatchTargetChange (com.google.firebase.firestore.remote.WatchChange.WatchTargetChange)2