FSTMemoryPersistence.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Local/FSTMemoryPersistence.h"
  17. #include <memory>
  18. #include <unordered_map>
  19. #include <unordered_set>
  20. #import "Firestore/Source/Core/FSTListenSequence.h"
  21. #import "Firestore/Source/Local/FSTMemoryMutationQueue.h"
  22. #import "Firestore/Source/Local/FSTMemoryQueryCache.h"
  23. #import "Firestore/Source/Local/FSTMemoryRemoteDocumentCache.h"
  24. #import "Firestore/Source/Local/FSTReferenceSet.h"
  25. #include "absl/memory/memory.h"
  26. #include "Firestore/core/src/firebase/firestore/auth/user.h"
  27. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  28. #include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
  29. using firebase::firestore::auth::HashUser;
  30. using firebase::firestore::auth::User;
  31. using firebase::firestore::model::DocumentKey;
  32. using firebase::firestore::model::DocumentKeyHash;
  33. using MutationQueues = std::unordered_map<User, FSTMemoryMutationQueue *, HashUser>;
  34. NS_ASSUME_NONNULL_BEGIN
  35. @interface FSTMemoryPersistence ()
  36. @property(nonatomic, readonly) MutationQueues &mutationQueues;
  37. @property(nonatomic, assign, getter=isStarted) BOOL started;
  38. // Make this property writable so we can wire up a delegate.
  39. @property(nonatomic, strong) id<FSTReferenceDelegate> referenceDelegate;
  40. @end
  41. @implementation FSTMemoryPersistence {
  42. /**
  43. * The FSTQueryCache representing the persisted cache of queries.
  44. *
  45. * Note that this is retained here to make it easier to write tests affecting both the in-memory
  46. * and LevelDB-backed persistence layers. Tests can create a new FSTLocalStore wrapping this
  47. * FSTPersistence instance and this will make the in-memory persistence layer behave as if it
  48. * were actually persisting values.
  49. */
  50. FSTMemoryQueryCache *_queryCache;
  51. /** The FSTRemoteDocumentCache representing the persisted cache of remote documents. */
  52. FSTMemoryRemoteDocumentCache *_remoteDocumentCache;
  53. FSTTransactionRunner _transactionRunner;
  54. id<FSTReferenceDelegate> _referenceDelegate;
  55. }
  56. + (instancetype)persistenceWithEagerGC {
  57. FSTMemoryPersistence *persistence = [[FSTMemoryPersistence alloc] init];
  58. persistence.referenceDelegate =
  59. [[FSTMemoryEagerReferenceDelegate alloc] initWithPersistence:persistence];
  60. return persistence;
  61. }
  62. + (instancetype)persistenceWithLRUGC {
  63. FSTMemoryPersistence *persistence = [[FSTMemoryPersistence alloc] init];
  64. persistence.referenceDelegate =
  65. [[FSTMemoryLRUReferenceDelegate alloc] initWithPersistence:persistence];
  66. return persistence;
  67. }
  68. - (instancetype)init {
  69. if (self = [super init]) {
  70. _queryCache = [[FSTMemoryQueryCache alloc] initWithPersistence:self];
  71. _remoteDocumentCache = [[FSTMemoryRemoteDocumentCache alloc] init];
  72. }
  73. return self;
  74. }
  75. - (void)setReferenceDelegate:(id<FSTReferenceDelegate>)referenceDelegate {
  76. _referenceDelegate = referenceDelegate;
  77. id delegate = _referenceDelegate;
  78. if ([delegate conformsToProtocol:@protocol(FSTTransactional)]) {
  79. _transactionRunner.SetBackingPersistence((id<FSTTransactional>)_referenceDelegate);
  80. }
  81. }
  82. - (BOOL)start:(NSError **)error {
  83. // No durable state to read on startup.
  84. HARD_ASSERT(!self.isStarted, "FSTMemoryPersistence double-started!");
  85. self.started = YES;
  86. return YES;
  87. }
  88. - (void)shutdown {
  89. // No durable state to ensure is closed on shutdown.
  90. HARD_ASSERT(self.isStarted, "FSTMemoryPersistence shutdown without start!");
  91. self.started = NO;
  92. }
  93. - (id<FSTReferenceDelegate>)referenceDelegate {
  94. return _referenceDelegate;
  95. }
  96. - (FSTListenSequenceNumber)currentSequenceNumber {
  97. return [_referenceDelegate currentSequenceNumber];
  98. }
  99. - (const FSTTransactionRunner &)run {
  100. return _transactionRunner;
  101. }
  102. - (id<FSTMutationQueue>)mutationQueueForUser:(const User &)user {
  103. id<FSTMutationQueue> queue = _mutationQueues[user];
  104. if (!queue) {
  105. queue = [[FSTMemoryMutationQueue alloc] initWithPersistence:self];
  106. _mutationQueues[user] = queue;
  107. }
  108. return queue;
  109. }
  110. - (id<FSTQueryCache>)queryCache {
  111. return _queryCache;
  112. }
  113. - (id<FSTRemoteDocumentCache>)remoteDocumentCache {
  114. return _remoteDocumentCache;
  115. }
  116. @end
  117. @implementation FSTMemoryLRUReferenceDelegate {
  118. // This delegate should have the same lifetime as the persistence layer, but mark as
  119. // weak to avoid retain cycle.
  120. __weak FSTMemoryPersistence *_persistence;
  121. std::unordered_map<DocumentKey, FSTListenSequenceNumber, DocumentKeyHash> _sequenceNumbers;
  122. FSTReferenceSet *_additionalReferences;
  123. FSTLRUGarbageCollector *_gc;
  124. FSTListenSequence *_listenSequence;
  125. FSTListenSequenceNumber _currentSequenceNumber;
  126. }
  127. - (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence {
  128. if (self = [super init]) {
  129. _persistence = persistence;
  130. _gc =
  131. [[FSTLRUGarbageCollector alloc] initWithQueryCache:[_persistence queryCache] delegate:self];
  132. _currentSequenceNumber = kFSTListenSequenceNumberInvalid;
  133. // Theoretically this is always 0, since this is all in-memory...
  134. FSTListenSequenceNumber highestSequenceNumber =
  135. _persistence.queryCache.highestListenSequenceNumber;
  136. _listenSequence = [[FSTListenSequence alloc] initStartingAfter:highestSequenceNumber];
  137. }
  138. return self;
  139. }
  140. - (FSTLRUGarbageCollector *)gc {
  141. return _gc;
  142. }
  143. - (FSTListenSequenceNumber)currentSequenceNumber {
  144. HARD_ASSERT(_currentSequenceNumber != kFSTListenSequenceNumberInvalid,
  145. "Asking for a sequence number outside of a transaction");
  146. return _currentSequenceNumber;
  147. }
  148. - (void)addInMemoryPins:(FSTReferenceSet *)set {
  149. // Technically can't assert this, due to restartWithNoopGarbageCollector (for now...)
  150. // FSTAssert(_additionalReferences == nil, @"Overwriting additional references");
  151. _additionalReferences = set;
  152. }
  153. - (void)removeTarget:(FSTQueryData *)queryData {
  154. FSTQueryData *updated = [queryData queryDataByReplacingSnapshotVersion:queryData.snapshotVersion
  155. resumeToken:queryData.resumeToken
  156. sequenceNumber:_currentSequenceNumber];
  157. [_persistence.queryCache updateQueryData:updated];
  158. }
  159. - (void)limboDocumentUpdated:(const DocumentKey &)key {
  160. _sequenceNumbers[key] = self.currentSequenceNumber;
  161. }
  162. - (void)startTransaction:(absl::string_view)label {
  163. _currentSequenceNumber = [_listenSequence next];
  164. }
  165. - (void)commitTransaction {
  166. _currentSequenceNumber = kFSTListenSequenceNumberInvalid;
  167. }
  168. - (void)enumerateTargetsUsingBlock:(void (^)(FSTQueryData *queryData, BOOL *stop))block {
  169. return [_persistence.queryCache enumerateTargetsUsingBlock:block];
  170. }
  171. - (void)enumerateMutationsUsingBlock:
  172. (void (^)(const DocumentKey &key, FSTListenSequenceNumber sequenceNumber, BOOL *stop))block {
  173. BOOL stop = NO;
  174. for (auto it = _sequenceNumbers.begin(); !stop && it != _sequenceNumbers.end(); ++it) {
  175. FSTListenSequenceNumber sequenceNumber = it->second;
  176. const DocumentKey &key = it->first;
  177. if (![_persistence.queryCache containsKey:key]) {
  178. block(key, sequenceNumber, &stop);
  179. }
  180. }
  181. }
  182. - (int)removeTargetsThroughSequenceNumber:(FSTListenSequenceNumber)sequenceNumber
  183. liveQueries:(NSDictionary<NSNumber *, FSTQueryData *> *)liveQueries {
  184. return [_persistence.queryCache removeQueriesThroughSequenceNumber:sequenceNumber
  185. liveQueries:liveQueries];
  186. }
  187. - (int)removeOrphanedDocumentsThroughSequenceNumber:(FSTListenSequenceNumber)upperBound {
  188. return [(FSTMemoryRemoteDocumentCache *)_persistence.remoteDocumentCache
  189. removeOrphanedDocuments:self
  190. throughSequenceNumber:upperBound];
  191. }
  192. - (void)addReference:(const DocumentKey &)key {
  193. _sequenceNumbers[key] = self.currentSequenceNumber;
  194. }
  195. - (void)removeReference:(const DocumentKey &)key {
  196. _sequenceNumbers[key] = self.currentSequenceNumber;
  197. }
  198. - (BOOL)mutationQueuesContainKey:(const DocumentKey &)key {
  199. const MutationQueues &queues = [_persistence mutationQueues];
  200. for (auto it = queues.begin(); it != queues.end(); ++it) {
  201. if ([it->second containsKey:key]) {
  202. return YES;
  203. }
  204. }
  205. return NO;
  206. }
  207. - (void)removeMutationReference:(const DocumentKey &)key {
  208. _sequenceNumbers[key] = self.currentSequenceNumber;
  209. }
  210. - (BOOL)isPinnedAtSequenceNumber:(FSTListenSequenceNumber)upperBound
  211. document:(const DocumentKey &)key {
  212. if ([self mutationQueuesContainKey:key]) {
  213. return YES;
  214. }
  215. if ([_additionalReferences containsKey:key]) {
  216. return YES;
  217. }
  218. if ([_persistence.queryCache containsKey:key]) {
  219. return YES;
  220. }
  221. auto it = _sequenceNumbers.find(key);
  222. if (it != _sequenceNumbers.end() && it->second > upperBound) {
  223. return YES;
  224. }
  225. return NO;
  226. }
  227. @end
  228. @implementation FSTMemoryEagerReferenceDelegate {
  229. std::unique_ptr<std::unordered_set<DocumentKey, DocumentKeyHash>> _orphaned;
  230. // This delegate should have the same lifetime as the persistence layer, but mark as
  231. // weak to avoid retain cycle.
  232. __weak FSTMemoryPersistence *_persistence;
  233. FSTReferenceSet *_additionalReferences;
  234. }
  235. - (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence {
  236. if (self = [super init]) {
  237. _persistence = persistence;
  238. }
  239. return self;
  240. }
  241. - (FSTListenSequenceNumber)currentSequenceNumber {
  242. return kFSTListenSequenceNumberInvalid;
  243. }
  244. - (void)addInMemoryPins:(FSTReferenceSet *)set {
  245. // We should be able to assert that _additionalReferences is nil, but due to restarts in spec
  246. // tests it would fail.
  247. _additionalReferences = set;
  248. }
  249. - (void)removeTarget:(FSTQueryData *)queryData {
  250. for (const DocumentKey &docKey :
  251. [_persistence.queryCache matchingKeysForTargetID:queryData.targetID]) {
  252. _orphaned->insert(docKey);
  253. }
  254. [_persistence.queryCache removeQueryData:queryData];
  255. }
  256. - (void)addReference:(const DocumentKey &)key {
  257. _orphaned->erase(key);
  258. }
  259. - (void)removeReference:(const DocumentKey &)key {
  260. _orphaned->insert(key);
  261. }
  262. - (void)removeMutationReference:(const DocumentKey &)key {
  263. _orphaned->insert(key);
  264. }
  265. - (BOOL)isReferenced:(const DocumentKey &)key {
  266. if ([[_persistence queryCache] containsKey:key]) {
  267. return YES;
  268. }
  269. if ([self mutationQueuesContainKey:key]) {
  270. return YES;
  271. }
  272. if ([_additionalReferences containsKey:key]) {
  273. return YES;
  274. }
  275. return NO;
  276. }
  277. - (void)limboDocumentUpdated:(const DocumentKey &)key {
  278. if ([self isReferenced:key]) {
  279. _orphaned->erase(key);
  280. } else {
  281. _orphaned->insert(key);
  282. }
  283. }
  284. - (void)startTransaction:(__unused absl::string_view)label {
  285. _orphaned = absl::make_unique<std::unordered_set<DocumentKey, DocumentKeyHash>>();
  286. }
  287. - (BOOL)mutationQueuesContainKey:(const DocumentKey &)key {
  288. const MutationQueues &queues = [_persistence mutationQueues];
  289. for (auto it = queues.begin(); it != queues.end(); ++it) {
  290. if ([it->second containsKey:key]) {
  291. return YES;
  292. }
  293. }
  294. return NO;
  295. }
  296. - (void)commitTransaction {
  297. for (auto it = _orphaned->begin(); it != _orphaned->end(); ++it) {
  298. const DocumentKey key = *it;
  299. if (![self isReferenced:key]) {
  300. [[_persistence remoteDocumentCache] removeEntryForKey:key];
  301. }
  302. }
  303. _orphaned.reset();
  304. }
  305. @end
  306. NS_ASSUME_NONNULL_END