Search in sources :

Example 6 with SnapshotVersion

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

the class LocalStore method applyRemoteEvent.

/**
 * Updates the "ground-state" (remote) documents. We assume that the remote event reflects any
 * write batches that have been acknowledged or rejected (i.e. we do not re-apply local mutations
 * to updates from this event).
 *
 * <p>LocalDocuments are re-calculated if there are remaining mutations in the queue.
 */
public ImmutableSortedMap<DocumentKey, Document> applyRemoteEvent(RemoteEvent remoteEvent) {
    SnapshotVersion remoteVersion = remoteEvent.getSnapshotVersion();
    // TODO: Call queryEngine.handleDocumentChange() appropriately.
    return persistence.runTransaction("Apply remote event", () -> {
        Map<Integer, TargetChange> targetChanges = remoteEvent.getTargetChanges();
        long sequenceNumber = persistence.getReferenceDelegate().getCurrentSequenceNumber();
        for (Map.Entry<Integer, TargetChange> entry : targetChanges.entrySet()) {
            Integer boxedTargetId = entry.getKey();
            int targetId = boxedTargetId;
            TargetChange change = entry.getValue();
            TargetData oldTargetData = queryDataByTarget.get(targetId);
            if (oldTargetData == null) {
                // we persist the updated query data along with the updated assignment.
                continue;
            }
            targetCache.removeMatchingKeys(change.getRemovedDocuments(), targetId);
            targetCache.addMatchingKeys(change.getAddedDocuments(), targetId);
            TargetData newTargetData = oldTargetData.withSequenceNumber(sequenceNumber);
            if (remoteEvent.getTargetMismatches().contains(targetId)) {
                newTargetData = newTargetData.withResumeToken(ByteString.EMPTY, SnapshotVersion.NONE).withLastLimboFreeSnapshotVersion(SnapshotVersion.NONE);
            } else if (!change.getResumeToken().isEmpty()) {
                newTargetData = newTargetData.withResumeToken(change.getResumeToken(), remoteEvent.getSnapshotVersion());
            }
            queryDataByTarget.put(targetId, newTargetData);
            // since the last update).
            if (shouldPersistTargetData(oldTargetData, newTargetData, change)) {
                targetCache.updateTargetData(newTargetData);
            }
        }
        Map<DocumentKey, MutableDocument> documentUpdates = remoteEvent.getDocumentUpdates();
        Set<DocumentKey> limboDocuments = remoteEvent.getResolvedLimboDocuments();
        for (DocumentKey key : documentUpdates.keySet()) {
            if (limboDocuments.contains(key)) {
                persistence.getReferenceDelegate().updateLimboDocument(key);
            }
        }
        DocumentChangeResult result = populateDocumentChanges(documentUpdates);
        Map<DocumentKey, MutableDocument> changedDocs = result.changedDocuments;
        // HACK: The only reason we allow snapshot version NONE is so that we can synthesize
        // remote events when we get permission denied errors while trying to resolve the
        // state of a locally cached document that is in limbo.
        SnapshotVersion lastRemoteVersion = targetCache.getLastRemoteSnapshotVersion();
        if (!remoteVersion.equals(SnapshotVersion.NONE)) {
            hardAssert(remoteVersion.compareTo(lastRemoteVersion) >= 0, "Watch stream reverted to previous snapshot?? (%s < %s)", remoteVersion, lastRemoteVersion);
            targetCache.setLastRemoteSnapshotVersion(remoteVersion);
        }
        return localDocuments.getLocalViewOfDocuments(changedDocs, result.existenceChangedKeys);
    });
}
Also used : MutableDocument(com.google.firebase.firestore.model.MutableDocument) TargetChange(com.google.firebase.firestore.remote.TargetChange) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap)

Example 7 with SnapshotVersion

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

the class SQLiteIndexManager method start.

@Override
public void start() {
    Map<Integer, FieldIndex.IndexState> indexStates = new HashMap<>();
    // Fetch all index states if persisted for the user. These states contain per user information
    // on how up to date the index is.
    db.query("SELECT index_id, sequence_number, read_time_seconds, read_time_nanos, document_key, " + "largest_batch_id FROM index_state WHERE uid = ?").binding(uid).forEach(row -> {
        int indexId = row.getInt(0);
        long sequenceNumber = row.getLong(1);
        SnapshotVersion readTime = new SnapshotVersion(new Timestamp(row.getLong(2), row.getInt(3)));
        DocumentKey documentKey = DocumentKey.fromPath(EncodedPath.decodeResourcePath(row.getString(4)));
        int largestBatchId = row.getInt(5);
        indexStates.put(indexId, FieldIndex.IndexState.create(sequenceNumber, readTime, documentKey, largestBatchId));
    });
    // Fetch all indices and combine with user's index state if available.
    db.query("SELECT index_id, collection_group, index_proto FROM index_configuration").forEach(row -> {
        try {
            int indexId = row.getInt(0);
            String collectionGroup = row.getString(1);
            List<FieldIndex.Segment> segments = serializer.decodeFieldIndexSegments(Index.parseFrom(row.getBlob(2)));
            // If we fetched an index state for the user above, combine it with this index.
            // We use the default state if we don't have an index state (e.g. the index was
            // created while a different user as logged in).
            FieldIndex.IndexState indexState = indexStates.containsKey(indexId) ? indexStates.get(indexId) : FieldIndex.INITIAL_STATE;
            FieldIndex fieldIndex = FieldIndex.create(indexId, collectionGroup, segments, indexState);
            // Store the index and update `memoizedMaxIndexId` and `memoizedMaxSequenceNumber`.
            memoizeIndex(fieldIndex);
        } catch (InvalidProtocolBufferException e) {
            throw fail("Failed to decode index: " + e);
        }
    });
    started = true;
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) HashMap(java.util.HashMap) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Timestamp(com.google.firebase.Timestamp) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey)

Example 8 with SnapshotVersion

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

the class StreamTest method testWriteStreamStopAfterHandshake.

@Test
public void testWriteStreamStopAfterHandshake() throws Exception {
    AsyncQueue testQueue = new AsyncQueue();
    Datastore datastore = new Datastore(IntegrationTestUtil.testEnvDatabaseInfo(), testQueue, new EmptyCredentialsProvider(), new EmptyAppCheckTokenProvider(), ApplicationProvider.getApplicationContext(), null);
    final WriteStream[] writeStreamWrapper = new WriteStream[1];
    StreamStatusCallback streamCallback = new StreamStatusCallback() {

        @Override
        public void onHandshakeComplete() {
            assertThat(writeStreamWrapper[0].getLastStreamToken()).isNotEmpty();
            super.onHandshakeComplete();
        }

        @Override
        public void onWriteResponse(SnapshotVersion commitVersion, List<MutationResult> mutationResults) {
            assertThat(mutationResults).hasSize(1);
            assertThat(writeStreamWrapper[0].getLastStreamToken()).isNotEmpty();
            super.onWriteResponse(commitVersion, mutationResults);
        }
    };
    WriteStream writeStream = writeStreamWrapper[0] = datastore.createWriteStream(streamCallback);
    testQueue.enqueueAndForget(writeStream::start);
    waitFor(streamCallback.openSemaphore);
    // Writing before the handshake should throw
    testQueue.enqueueAndForget(() -> assertThrows(Throwable.class, () -> writeStream.writeMutations(mutations)));
    // Handshake should always be called
    testQueue.enqueueAndForget(writeStream::writeHandshake);
    waitFor(streamCallback.handshakeSemaphore);
    // Now writes should succeed
    testQueue.enqueueAndForget(() -> writeStream.writeMutations(mutations));
    waitFor(streamCallback.responseReceivedSemaphore);
    testQueue.runSync(writeStream::stop);
}
Also used : EmptyAppCheckTokenProvider(com.google.firebase.firestore.testutil.EmptyAppCheckTokenProvider) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) ArrayList(java.util.ArrayList) List(java.util.List) AsyncQueue(com.google.firebase.firestore.util.AsyncQueue) EmptyCredentialsProvider(com.google.firebase.firestore.testutil.EmptyCredentialsProvider) Test(org.junit.Test)

Example 9 with SnapshotVersion

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

the class TestUtil method addedRemoteEvent.

public static RemoteEvent addedRemoteEvent(List<MutableDocument> docs, List<Integer> updatedInTargets, List<Integer> removedFromTargets) {
    Preconditions.checkArgument(!docs.isEmpty(), "Cannot pass empty docs array");
    WatchChangeAggregator aggregator = new WatchChangeAggregator(new WatchChangeAggregator.TargetMetadataProvider() {

        @Override
        public ImmutableSortedSet<DocumentKey> getRemoteKeysForTarget(int targetId) {
            return DocumentKey.emptyKeySet();
        }

        @Override
        public TargetData getTargetDataForTarget(int targetId) {
            ResourcePath collectionPath = docs.get(0).getKey().getCollectionPath();
            return targetData(targetId, QueryPurpose.LISTEN, collectionPath.toString());
        }
    });
    SnapshotVersion version = SnapshotVersion.NONE;
    for (MutableDocument doc : docs) {
        DocumentChange change = new DocumentChange(updatedInTargets, removedFromTargets, doc.getKey(), doc);
        aggregator.handleDocumentChange(change);
        version = doc.getVersion().compareTo(version) > 0 ? doc.getVersion() : version;
    }
    return aggregator.createRemoteEvent(version);
}
Also used : TargetData(com.google.firebase.firestore.local.TargetData) WatchChangeAggregator(com.google.firebase.firestore.remote.WatchChangeAggregator) ResourcePath(com.google.firebase.firestore.model.ResourcePath) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) ImmutableSortedSet(com.google.firebase.database.collection.ImmutableSortedSet) MutableDocument(com.google.firebase.firestore.model.MutableDocument) DocumentChange(com.google.firebase.firestore.remote.WatchChange.DocumentChange)

Example 10 with SnapshotVersion

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

the class TestUtil method version.

public static SnapshotVersion version(long versionMicros) {
    long seconds = versionMicros / 1000000;
    int nanos = (int) (versionMicros % 1000000L) * 1000;
    return new SnapshotVersion(new Timestamp(seconds, nanos));
}
Also used : SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) Timestamp(com.google.firebase.Timestamp)

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