use of com.google.firebase.firestore.model.DocumentKey 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);
});
}
use of com.google.firebase.firestore.model.DocumentKey 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);
}
use of com.google.firebase.firestore.model.DocumentKey in project firebase-android-sdk by firebase.
the class LocalStore method notifyLocalViewChanges.
/**
* Notify the local store of the changed views to locally pin / unpin documents.
*/
public void notifyLocalViewChanges(List<LocalViewChanges> viewChanges) {
persistence.runTransaction("notifyLocalViewChanges", () -> {
for (LocalViewChanges viewChange : viewChanges) {
int targetId = viewChange.getTargetId();
localViewReferences.addReferences(viewChange.getAdded(), targetId);
ImmutableSortedSet<DocumentKey> removed = viewChange.getRemoved();
for (DocumentKey key : removed) {
persistence.getReferenceDelegate().removeReference(key);
}
localViewReferences.removeReferences(removed, targetId);
if (!viewChange.isFromCache()) {
TargetData targetData = queryDataByTarget.get(targetId);
hardAssert(targetData != null, "Can't set limbo-free snapshot version for unknown target: %s", targetId);
// Advance the last limbo free snapshot version
SnapshotVersion lastLimboFreeSnapshotVersion = targetData.getSnapshotVersion();
TargetData updatedTargetData = targetData.withLastLimboFreeSnapshotVersion(lastLimboFreeSnapshotVersion);
queryDataByTarget.put(targetId, updatedTargetData);
}
}
});
}
use of com.google.firebase.firestore.model.DocumentKey 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);
}
use of com.google.firebase.firestore.model.DocumentKey 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);
});
}
Aggregations