aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/Source/Local/FSTLocalStore.h
blob: 84aeb589662f05ff477267a253caaa156d84f7f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
 * Copyright 2017 Google
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import <Foundation/Foundation.h>

#import "Firestore/Source/Core/FSTTypes.h"
#import "Firestore/Source/Model/FSTDocumentDictionary.h"
#import "Firestore/Source/Model/FSTDocumentKeySet.h"
#import "Firestore/Source/Model/FSTDocumentVersionDictionary.h"

#include "Firestore/core/src/firebase/firestore/auth/user.h"
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"

@class FSTLocalViewChanges;
@class FSTLocalWriteResult;
@class FSTMutation;
@class FSTMutationBatch;
@class FSTMutationBatchResult;
@class FSTQuery;
@class FSTQueryData;
@class FSTRemoteEvent;
@protocol FSTPersistence;
@protocol FSTGarbageCollector;

NS_ASSUME_NONNULL_BEGIN

/**
 * Local storage in the Firestore client. Coordinates persistence components like the mutation
 * queue and remote document cache to present a latency compensated view of stored data.
 *
 * The LocalStore is responsible for accepting mutations from the Sync Engine. Writes from the
 * client are put into a queue as provisional Mutations until they are processed by the RemoteStore
 * and confirmed as having been written to the server.
 *
 * The local store provides the local version of documents that have been modified locally. It
 * maintains the constraint:
 *
 *  LocalDocument = RemoteDocument + Active(LocalMutations)
 *
 * (Active mutations are those that are enqueued and have not been previously acknowledged or
 * rejected).
 *
 * The RemoteDocument ("ground truth") state is provided via the applyChangeBatch method. It will
 * be some version of a server-provided document OR will be a server-provided document PLUS
 * acknowledged mutations:
 *
 *  RemoteDocument' = RemoteDocument + Acknowledged(LocalMutations)
 *
 * Note that this "dirty" version of a RemoteDocument will not be identical to a server base
 * version, since it has LocalMutations added to it pending getting an authoritative copy from the
 * server.
 *
 * Since LocalMutations can be rejected by the server, we have to be able to revert a LocalMutation
 * that has already been applied to the LocalDocument (typically done by replaying all remaining
 * LocalMutations to the RemoteDocument to re-apply).
 *
 * The LocalStore is responsible for the garbage collection of the documents it contains. For now,
 * it every doc referenced by a view, the mutation queue, or the RemoteStore.
 *
 * It also maintains the persistence of mapping queries to resume tokens and target ids. It needs
 * to know this data about queries to properly know what docs it would be allowed to garbage
 * collect.
 *
 * The LocalStore must be able to efficiently execute queries against its local cache of the
 * documents, to provide the initial set of results before any remote changes have been received.
 */
@interface FSTLocalStore : NSObject

/** Creates a new instance of the FSTLocalStore with its required dependencies as parameters. */
- (instancetype)initWithPersistence:(id<FSTPersistence>)persistence
                   garbageCollector:(id<FSTGarbageCollector>)garbageCollector
                        initialUser:(const firebase::firestore::auth::User &)initialUser
    NS_DESIGNATED_INITIALIZER;

- (instancetype)init NS_UNAVAILABLE;

/** Performs any initial startup actions required by the local store. */
- (void)start;

/**
 * Tells the FSTLocalStore that the currently authenticated user has changed.
 *
 * In response the local store switches the mutation queue to the new user and returns any
 * resulting document changes.
 */
- (FSTMaybeDocumentDictionary *)userDidChange:(const firebase::firestore::auth::User &)user;

/** Accepts locally generated Mutations and commits them to storage. */
- (FSTLocalWriteResult *)locallyWriteMutations:(NSArray<FSTMutation *> *)mutations;

/** Returns the current value of a document with a given key, or nil if not found. */
- (nullable FSTMaybeDocument *)readDocument:(const firebase::firestore::model::DocumentKey &)key;

/**
 * Acknowledges the given batch.
 *
 * On the happy path when a batch is acknowledged, the local store will
 *
 * + remove the batch from the mutation queue;
 * + apply the changes to the remote document cache;
 * + recalculate the latency compensated view implied by those changes (there may be mutations in
 *   the queue that affect the documents but haven't been acknowledged yet); and
 * + give the changed documents back the sync engine
 *
 * @return The resulting (modified) documents.
 */
- (FSTMaybeDocumentDictionary *)acknowledgeBatchWithResult:(FSTMutationBatchResult *)batchResult;

/**
 * Removes mutations from the MutationQueue for the specified batch. LocalDocuments will be
 * recalculated.
 *
 * @return The resulting (modified) documents.
 */
- (FSTMaybeDocumentDictionary *)rejectBatchID:(FSTBatchID)batchID;

/** Returns the last recorded stream token for the current user. */
- (nullable NSData *)lastStreamToken;

/**
 * Sets the stream token for the current user without acknowledging any mutation batch. This is
 * usually only useful after a stream handshake or in response to an error that requires clearing
 * the stream token.
 */
- (void)setLastStreamToken:(nullable NSData *)streamToken;

/**
 * Returns the last consistent snapshot processed (used by the RemoteStore to determine whether to
 * buffer incoming snapshots from the backend).
 */
- (const firebase::firestore::model::SnapshotVersion &)lastRemoteSnapshotVersion;

/**
 * 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).
 *
 * LocalDocuments are re-calculated if there are remaining mutations in the queue.
 */
- (FSTMaybeDocumentDictionary *)applyRemoteEvent:(FSTRemoteEvent *)remoteEvent;

/**
 * Returns the keys of the documents that are associated with the given targetID in the remote
 * table.
 */
- (FSTDocumentKeySet *)remoteDocumentKeysForTarget:(FSTTargetID)targetID;

/**
 * Collects garbage if necessary.
 *
 * Should be called periodically by Sync Engine to recover resources. The implementation must
 * guarantee that GC won't happen in other places than this method call.
 */
- (void)collectGarbage;

/**
 * Assigns @a query an internal ID so that its results can be pinned so they don't get GC'd.
 * A query must be allocated in the local store before the store can be used to manage its view.
 */
- (FSTQueryData *)allocateQuery:(FSTQuery *)query;

/** Unpin all the documents associated with @a query. */
- (void)releaseQuery:(FSTQuery *)query;

/** Runs @a query against all the documents in the local store and returns the results. */
- (FSTDocumentDictionary *)executeQuery:(FSTQuery *)query;

/** Notify the local store of the changed views to locally pin / unpin documents. */
- (void)notifyLocalViewChanges:(NSArray<FSTLocalViewChanges *> *)viewChanges;

/**
 * Gets the mutation batch after the passed in batchId in the mutation queue or nil if empty.
 *
 * @param batchID The batch to search after, or -1 for the first mutation in the queue.
 * @return the next mutation or nil if there wasn't one.
 */
- (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID;

@end

NS_ASSUME_NONNULL_END