Search in sources :

Example 26 with TargetData

use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.

the class RemoteStore method raiseWatchSnapshot.

/**
 * Takes a batch of changes from the Datastore, repackages them as a RemoteEvent, and passes that
 * on to the listener, which is typically the SyncEngine.
 */
private void raiseWatchSnapshot(SnapshotVersion snapshotVersion) {
    hardAssert(!snapshotVersion.equals(SnapshotVersion.NONE), "Can't raise event for unknown SnapshotVersion");
    RemoteEvent remoteEvent = watchChangeAggregator.createRemoteEvent(snapshotVersion);
    // applying the completed RemoteEvent.
    for (Entry<Integer, TargetChange> entry : remoteEvent.getTargetChanges().entrySet()) {
        TargetChange targetChange = entry.getValue();
        if (!targetChange.getResumeToken().isEmpty()) {
            int targetId = entry.getKey();
            TargetData targetData = this.listenTargets.get(targetId);
            // A watched target might have been removed already.
            if (targetData != null) {
                this.listenTargets.put(targetId, targetData.withResumeToken(targetChange.getResumeToken(), snapshotVersion));
            }
        }
    }
    // mismatches.
    for (int targetId : remoteEvent.getTargetMismatches()) {
        TargetData targetData = this.listenTargets.get(targetId);
        // A watched target might have been removed already.
        if (targetData != null) {
            // Clear the resume token for the query, since we're in a known mismatch state.
            this.listenTargets.put(targetId, targetData.withResumeToken(ByteString.EMPTY, targetData.getSnapshotVersion()));
            // Cause a hard reset by unwatching and rewatching immediately, but deliberately don't send
            // a resume token so that we get a full update.
            this.sendUnwatchRequest(targetId);
            // Mark the query we send as being on behalf of an existence filter  mismatch, but don't
            // actually retain that in listenTargets. This ensures that we flag the first re-listen this
            // way without impacting future listens of this target (that might happen e.g. on
            // reconnect).
            TargetData requestTargetData = new TargetData(targetData.getTarget(), targetId, targetData.getSequenceNumber(), QueryPurpose.EXISTENCE_FILTER_MISMATCH);
            this.sendWatchRequest(requestTargetData);
        }
    }
    // Finally raise remote event
    remoteStoreCallback.handleRemoteEvent(remoteEvent);
}
Also used : TargetData(com.google.firebase.firestore.local.TargetData) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange)

Example 27 with TargetData

use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.

the class WatchChangeAggregator method createRemoteEvent.

/**
 * Converts the currently accumulated state into a remote event at the provided snapshot version.
 * Resets the accumulated changes before returning.
 */
public RemoteEvent createRemoteEvent(SnapshotVersion snapshotVersion) {
    Map<Integer, TargetChange> targetChanges = new HashMap<>();
    for (Map.Entry<Integer, TargetState> entry : targetStates.entrySet()) {
        int targetId = entry.getKey();
        TargetState targetState = entry.getValue();
        TargetData targetData = queryDataForActiveTarget(targetId);
        if (targetData != null) {
            if (targetState.isCurrent() && targetData.getTarget().isDocumentQuery()) {
                // Document queries for document that don't exist can produce an empty result set. To
                // update our local cache, we synthesize a document delete if we have not previously
                // received the document. This resolves the limbo state of the document, removing it from
                // limboDocumentRefs.
                DocumentKey key = DocumentKey.fromPath(targetData.getTarget().getPath());
                if (pendingDocumentUpdates.get(key) == null && !targetContainsDocument(targetId, key)) {
                    MutableDocument result = MutableDocument.newNoDocument(key, snapshotVersion);
                    removeDocumentFromTarget(targetId, key, result);
                }
            }
            if (targetState.hasChanges()) {
                targetChanges.put(targetId, targetState.toTargetChange());
                targetState.clearChanges();
            }
        }
    }
    Set<DocumentKey> resolvedLimboDocuments = new HashSet<>();
    // TODO(gsoltis): Expand on this comment once GC is available in the Android client.
    for (Map.Entry<DocumentKey, Set<Integer>> entry : pendingDocumentTargetMapping.entrySet()) {
        DocumentKey key = entry.getKey();
        Set<Integer> targets = entry.getValue();
        boolean isOnlyLimboTarget = true;
        for (int targetId : targets) {
            TargetData targetData = queryDataForActiveTarget(targetId);
            if (targetData != null && !targetData.getPurpose().equals(QueryPurpose.LIMBO_RESOLUTION)) {
                isOnlyLimboTarget = false;
                break;
            }
        }
        if (isOnlyLimboTarget) {
            resolvedLimboDocuments.add(key);
        }
    }
    for (MutableDocument document : pendingDocumentUpdates.values()) {
        document.setReadTime(snapshotVersion);
    }
    RemoteEvent remoteEvent = new RemoteEvent(snapshotVersion, Collections.unmodifiableMap(targetChanges), Collections.unmodifiableSet(pendingTargetResets), Collections.unmodifiableMap(pendingDocumentUpdates), Collections.unmodifiableSet(resolvedLimboDocuments));
    // Re-initialize the current state to ensure that we do not modify the generated RemoteEvent.
    pendingDocumentUpdates = new HashMap<>();
    pendingDocumentTargetMapping = new HashMap<>();
    pendingTargetResets = new HashSet<>();
    return remoteEvent;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) ImmutableSortedSet(com.google.firebase.database.collection.ImmutableSortedSet) HashMap(java.util.HashMap) MutableDocument(com.google.firebase.firestore.model.MutableDocument) TargetData(com.google.firebase.firestore.local.TargetData) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange) DocumentKey(com.google.firebase.firestore.model.DocumentKey) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 28 with TargetData

use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.

the class RemoteEventTest method testResumeTokenHandledPerTarget.

@Test
public void testResumeTokenHandledPerTarget() {
    Map<Integer, TargetData> targetMap = activeQueries(1, 2);
    WatchChangeAggregator aggregator = createAggregator(targetMap, noOutstandingResponses, noExistingKeys);
    WatchTargetChange change1 = new WatchTargetChange(WatchTargetChangeType.Current, asList(1));
    aggregator.handleTargetChange(change1);
    ByteString resumeToken2 = ByteString.copyFromUtf8("resumeToken2");
    WatchTargetChange change2 = new WatchTargetChange(WatchTargetChangeType.Current, asList(2), resumeToken2);
    aggregator.handleTargetChange(change2);
    RemoteEvent event = aggregator.createRemoteEvent(version(3));
    assertEquals(2, event.getTargetChanges().size());
    TargetChange mapping1 = targetChange(resumeToken, true, null, null, null);
    assertEquals(mapping1, event.getTargetChanges().get(1));
    TargetChange mapping2 = targetChange(resumeToken2, true, null, null, null);
    assertEquals(mapping2, event.getTargetChanges().get(2));
}
Also used : TargetData(com.google.firebase.firestore.local.TargetData) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange) ByteString(com.google.protobuf.ByteString) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange) Test(org.junit.Test)

Example 29 with TargetData

use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.

the class RemoteEventTest method testDoesNotSynthesizeDeleteWithExistingDocument.

@Test
public void testDoesNotSynthesizeDeleteWithExistingDocument() {
    Map<Integer, TargetData> targetMap = activeLimboQueries("foo/doc", 1);
    WatchTargetChange hasDocument = new WatchTargetChange(WatchTargetChangeType.Current, asList(1));
    RemoteEvent event = createRemoteEvent(3, targetMap, noOutstandingResponses, keySet(key("foo/doc")), hasDocument);
    assertEquals(0, event.getDocumentUpdates().size());
    assertEquals(0, event.getResolvedLimboDocuments().size());
}
Also used : TargetData(com.google.firebase.firestore.local.TargetData) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange) Test(org.junit.Test)

Example 30 with TargetData

use of com.google.firebase.firestore.local.TargetData in project firebase-android-sdk by firebase.

the class RemoteEventTest method testWillIgnoreEventsForRemovedTargets.

@Test
public void testWillIgnoreEventsForRemovedTargets() {
    Map<Integer, TargetData> targetMap = activeQueries();
    MutableDocument doc1 = doc("docs/1", 1, map("value", 1));
    // We're waiting for the unwatch ack
    Map<Integer, Integer> outstanding = new HashMap<>();
    outstanding.put(1, 1);
    WatchChange change1 = new DocumentChange(asList(1), emptyList(), doc1.getKey(), doc1);
    WatchChange change2 = new WatchTargetChange(WatchTargetChangeType.Removed, asList(1));
    RemoteEvent event = createRemoteEvent(3, targetMap, outstanding, noExistingKeys, change1, change2);
    assertEquals(version(3), event.getSnapshotVersion());
    // doc1 is ignored because it was not apart of an active target.
    assertEquals(0, event.getDocumentUpdates().size());
    // Target 1 is ignored because it was removed
    assertEquals(0, event.getTargetChanges().size());
}
Also used : TargetData(com.google.firebase.firestore.local.TargetData) HashMap(java.util.HashMap) MutableDocument(com.google.firebase.firestore.model.MutableDocument) DocumentChange(com.google.firebase.firestore.remote.WatchChange.DocumentChange) WatchTargetChange(com.google.firebase.firestore.remote.WatchChange.WatchTargetChange) Test(org.junit.Test)

Aggregations

TargetData (com.google.firebase.firestore.local.TargetData)38 Test (org.junit.Test)23 WatchTargetChange (com.google.firebase.firestore.remote.WatchChange.WatchTargetChange)22 MutableDocument (com.google.firebase.firestore.model.MutableDocument)15 DocumentChange (com.google.firebase.firestore.remote.WatchChange.DocumentChange)14 HashMap (java.util.HashMap)8 Query (com.google.firebase.firestore.core.Query)7 StructuredQuery (com.google.firestore.v1.StructuredQuery)6 DocumentKey (com.google.firebase.firestore.model.DocumentKey)5 WatchChangeAggregator (com.google.firebase.firestore.remote.WatchChangeAggregator)4 ByteString (com.google.protobuf.ByteString)4 ImmutableSortedSet (com.google.firebase.database.collection.ImmutableSortedSet)3 Target (com.google.firestore.v1.Target)3 DocumentsTarget (com.google.firestore.v1.Target.DocumentsTarget)3 QueryTarget (com.google.firestore.v1.Target.QueryTarget)3 Map (java.util.Map)3 WatchChange (com.google.firebase.firestore.remote.WatchChange)2 ArrayList (java.util.ArrayList)2 LinkedHashMap (java.util.LinkedHashMap)2 Target (com.google.firebase.firestore.core.Target)1