FSTLevelDBQueryCache.mm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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/FSTLevelDBQueryCache.h"
  17. #include <memory>
  18. #include <string>
  19. #include <utility>
  20. #import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
  21. #import "Firestore/Source/Core/FSTQuery.h"
  22. #import "Firestore/Source/Local/FSTLevelDB.h"
  23. #import "Firestore/Source/Local/FSTLocalSerializer.h"
  24. #import "Firestore/Source/Local/FSTQueryData.h"
  25. #include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
  26. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  27. #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
  28. #include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
  29. #include "Firestore/core/src/firebase/firestore/util/string_apple.h"
  30. #include "absl/strings/match.h"
  31. NS_ASSUME_NONNULL_BEGIN
  32. using firebase::firestore::local::DescribeKey;
  33. using firebase::firestore::local::LevelDbDocumentTargetKey;
  34. using firebase::firestore::local::LevelDbQueryTargetKey;
  35. using firebase::firestore::local::LevelDbTargetDocumentKey;
  36. using firebase::firestore::local::LevelDbTargetGlobalKey;
  37. using firebase::firestore::local::LevelDbTargetKey;
  38. using firebase::firestore::local::LevelDbTransaction;
  39. using firebase::firestore::model::DocumentKey;
  40. using firebase::firestore::model::DocumentKeySet;
  41. using firebase::firestore::model::ListenSequenceNumber;
  42. using firebase::firestore::model::SnapshotVersion;
  43. using firebase::firestore::model::TargetId;
  44. using firebase::firestore::util::MakeString;
  45. using leveldb::DB;
  46. using leveldb::Slice;
  47. using leveldb::Status;
  48. @interface FSTLevelDBQueryCache ()
  49. /** A write-through cached copy of the metadata for the query cache. */
  50. @property(nonatomic, strong, nullable) FSTPBTargetGlobal *metadata;
  51. @property(nonatomic, strong, readonly) FSTLocalSerializer *serializer;
  52. @end
  53. @implementation FSTLevelDBQueryCache {
  54. FSTLevelDB *_db;
  55. /**
  56. * The last received snapshot version. This is part of `metadata` but we store it separately to
  57. * avoid extra conversion to/from GPBTimestamp.
  58. */
  59. SnapshotVersion _lastRemoteSnapshotVersion;
  60. }
  61. + (nullable FSTPBTargetGlobal *)readTargetMetadataWithTransaction:
  62. (firebase::firestore::local::LevelDbTransaction *)transaction {
  63. std::string key = LevelDbTargetGlobalKey::Key();
  64. std::string value;
  65. Status status = transaction->Get(key, &value);
  66. if (status.IsNotFound()) {
  67. return nil;
  68. } else if (!status.ok()) {
  69. HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, status.ToString());
  70. }
  71. NSData *data =
  72. [[NSData alloc] initWithBytesNoCopy:(void *)value.data() length:value.size() freeWhenDone:NO];
  73. NSError *error;
  74. FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error];
  75. if (!proto) {
  76. HARD_FAIL("FSTPBTargetGlobal failed to parse: %s", error);
  77. }
  78. return proto;
  79. }
  80. + (nullable FSTPBTargetGlobal *)readTargetMetadataFromDB:(DB *)db {
  81. std::string key = LevelDbTargetGlobalKey::Key();
  82. std::string value;
  83. Status status = db->Get([FSTLevelDB standardReadOptions], key, &value);
  84. if (status.IsNotFound()) {
  85. return nil;
  86. } else if (!status.ok()) {
  87. HARD_FAIL("metadataForKey: failed loading key %s with status: %s", key, status.ToString());
  88. }
  89. NSData *data =
  90. [[NSData alloc] initWithBytesNoCopy:(void *)value.data() length:value.size() freeWhenDone:NO];
  91. NSError *error;
  92. FSTPBTargetGlobal *proto = [FSTPBTargetGlobal parseFromData:data error:&error];
  93. if (!proto) {
  94. HARD_FAIL("FSTPBTargetGlobal failed to parse: %s", error);
  95. }
  96. return proto;
  97. }
  98. - (instancetype)initWithDB:(FSTLevelDB *)db serializer:(FSTLocalSerializer *)serializer {
  99. if (self = [super init]) {
  100. HARD_ASSERT(db, "db must not be NULL");
  101. _db = db;
  102. _serializer = serializer;
  103. }
  104. return self;
  105. }
  106. - (void)start {
  107. // TODO(gsoltis): switch this usage of ptr to currentTransaction
  108. FSTPBTargetGlobal *metadata = [FSTLevelDBQueryCache readTargetMetadataFromDB:_db.ptr];
  109. HARD_ASSERT(
  110. metadata != nil,
  111. "Found nil metadata, expected schema to be at version 0 which ensures metadata existence");
  112. _lastRemoteSnapshotVersion = [self.serializer decodedVersion:metadata.lastRemoteSnapshotVersion];
  113. self.metadata = metadata;
  114. }
  115. #pragma mark - FSTQueryCache implementation
  116. - (TargetId)highestTargetID {
  117. return self.metadata.highestTargetId;
  118. }
  119. - (ListenSequenceNumber)highestListenSequenceNumber {
  120. return self.metadata.highestListenSequenceNumber;
  121. }
  122. - (const SnapshotVersion &)lastRemoteSnapshotVersion {
  123. return _lastRemoteSnapshotVersion;
  124. }
  125. - (void)setLastRemoteSnapshotVersion:(SnapshotVersion)snapshotVersion {
  126. _lastRemoteSnapshotVersion = std::move(snapshotVersion);
  127. self.metadata.lastRemoteSnapshotVersion =
  128. [self.serializer encodedVersion:_lastRemoteSnapshotVersion];
  129. _db.currentTransaction->Put(LevelDbTargetGlobalKey::Key(), self.metadata);
  130. }
  131. - (void)enumerateTargetsUsingBlock:(void (^)(FSTQueryData *queryData, BOOL *stop))block {
  132. // Enumerate all targets, give their sequence numbers.
  133. std::string targetPrefix = LevelDbTargetKey::KeyPrefix();
  134. auto it = _db.currentTransaction->NewIterator();
  135. it->Seek(targetPrefix);
  136. BOOL stop = NO;
  137. for (; !stop && it->Valid() && absl::StartsWith(it->key(), targetPrefix); it->Next()) {
  138. FSTQueryData *target = [self decodedTarget:it->value()];
  139. block(target, &stop);
  140. }
  141. }
  142. - (void)enumerateOrphanedDocumentsUsingBlock:
  143. (void (^)(const DocumentKey &docKey, ListenSequenceNumber sequenceNumber, BOOL *stop))block {
  144. std::string documentTargetPrefix = LevelDbDocumentTargetKey::KeyPrefix();
  145. auto it = _db.currentTransaction->NewIterator();
  146. it->Seek(documentTargetPrefix);
  147. ListenSequenceNumber nextToReport = 0;
  148. DocumentKey keyToReport;
  149. LevelDbDocumentTargetKey key;
  150. BOOL stop = NO;
  151. for (; !stop && it->Valid() && absl::StartsWith(it->key(), documentTargetPrefix); it->Next()) {
  152. HARD_ASSERT(key.Decode(it->key()), "Failed to decode DocumentTarget key");
  153. if (key.IsSentinel()) {
  154. // if nextToReport is non-zero, report it, this is a new key so the last one
  155. // must be not be a member of any targets.
  156. if (nextToReport != 0) {
  157. block(keyToReport, nextToReport, &stop);
  158. }
  159. // set nextToReport to be this sequence number. It's the next one we might
  160. // report, if we don't find any targets for this document.
  161. nextToReport = LevelDbDocumentTargetKey::DecodeSentinelValue(it->value());
  162. keyToReport = key.document_key();
  163. } else {
  164. // set nextToReport to be 0, we know we don't need to report this one since
  165. // we found a target for it.
  166. nextToReport = 0;
  167. }
  168. }
  169. // if not stop and nextToReport is non-zero, report it. We didn't find any targets for
  170. // that document, and we weren't asked to stop.
  171. if (!stop && nextToReport != 0) {
  172. block(keyToReport, nextToReport, &stop);
  173. }
  174. }
  175. - (void)saveQueryData:(FSTQueryData *)queryData {
  176. TargetId targetID = queryData.targetID;
  177. std::string key = LevelDbTargetKey::Key(targetID);
  178. _db.currentTransaction->Put(key, [self.serializer encodedQueryData:queryData]);
  179. }
  180. - (BOOL)updateMetadataForQueryData:(FSTQueryData *)queryData {
  181. BOOL updatedMetadata = NO;
  182. if (queryData.targetID > self.metadata.highestTargetId) {
  183. self.metadata.highestTargetId = queryData.targetID;
  184. updatedMetadata = YES;
  185. }
  186. if (queryData.sequenceNumber > self.metadata.highestListenSequenceNumber) {
  187. self.metadata.highestListenSequenceNumber = queryData.sequenceNumber;
  188. updatedMetadata = YES;
  189. }
  190. return updatedMetadata;
  191. }
  192. - (void)addQueryData:(FSTQueryData *)queryData {
  193. [self saveQueryData:queryData];
  194. NSString *canonicalID = queryData.query.canonicalID;
  195. std::string indexKey = LevelDbQueryTargetKey::Key(MakeString(canonicalID), queryData.targetID);
  196. std::string emptyBuffer;
  197. _db.currentTransaction->Put(indexKey, emptyBuffer);
  198. self.metadata.targetCount += 1;
  199. [self updateMetadataForQueryData:queryData];
  200. _db.currentTransaction->Put(LevelDbTargetGlobalKey::Key(), self.metadata);
  201. }
  202. - (void)updateQueryData:(FSTQueryData *)queryData {
  203. [self saveQueryData:queryData];
  204. if ([self updateMetadataForQueryData:queryData]) {
  205. _db.currentTransaction->Put(LevelDbTargetGlobalKey::Key(), self.metadata);
  206. }
  207. }
  208. - (void)removeQueryData:(FSTQueryData *)queryData {
  209. TargetId targetID = queryData.targetID;
  210. [self removeMatchingKeysForTargetID:targetID];
  211. std::string key = LevelDbTargetKey::Key(targetID);
  212. _db.currentTransaction->Delete(key);
  213. std::string indexKey =
  214. LevelDbQueryTargetKey::Key(MakeString(queryData.query.canonicalID), targetID);
  215. _db.currentTransaction->Delete(indexKey);
  216. self.metadata.targetCount -= 1;
  217. _db.currentTransaction->Put(LevelDbTargetGlobalKey::Key(), self.metadata);
  218. }
  219. - (int)removeQueriesThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber
  220. liveQueries:(NSDictionary<NSNumber *, FSTQueryData *> *)liveQueries {
  221. int count = 0;
  222. std::string targetPrefix = LevelDbTargetKey::KeyPrefix();
  223. auto it = _db.currentTransaction->NewIterator();
  224. it->Seek(targetPrefix);
  225. for (; it->Valid() && absl::StartsWith(it->key(), targetPrefix); it->Next()) {
  226. FSTQueryData *queryData = [self decodedTarget:it->value()];
  227. if (queryData.sequenceNumber <= sequenceNumber && !liveQueries[@(queryData.targetID)]) {
  228. [self removeQueryData:queryData];
  229. count++;
  230. }
  231. }
  232. return count;
  233. }
  234. - (int32_t)count {
  235. return self.metadata.targetCount;
  236. }
  237. /**
  238. * Parses the given bytes as an FSTPBTarget protocol buffer and then converts to the equivalent
  239. * query data.
  240. */
  241. - (FSTQueryData *)decodedTarget:(absl::string_view)encoded {
  242. NSData *data = [[NSData alloc] initWithBytesNoCopy:(void *)encoded.data()
  243. length:encoded.size()
  244. freeWhenDone:NO];
  245. NSError *error;
  246. FSTPBTarget *proto = [FSTPBTarget parseFromData:data error:&error];
  247. if (!proto) {
  248. HARD_FAIL("FSTPBTarget failed to parse: %s", error);
  249. }
  250. return [self.serializer decodedQueryData:proto];
  251. }
  252. - (nullable FSTQueryData *)queryDataForQuery:(FSTQuery *)query {
  253. // Scan the query-target index starting with a prefix starting with the given query's canonicalID.
  254. // Note that this is a scan rather than a get because canonicalIDs are not required to be unique
  255. // per target.
  256. std::string canonicalID = MakeString(query.canonicalID);
  257. auto indexItererator = _db.currentTransaction->NewIterator();
  258. std::string indexPrefix = LevelDbQueryTargetKey::KeyPrefix(canonicalID);
  259. indexItererator->Seek(indexPrefix);
  260. // Simultaneously scan the targets table. This works because each (canonicalID, targetID) pair is
  261. // unique and ordered, so when scanning a table prefixed by exactly one canonicalID, all the
  262. // targetIDs will be unique and in order.
  263. std::string targetPrefix = LevelDbTargetKey::KeyPrefix();
  264. auto targetIterator = _db.currentTransaction->NewIterator();
  265. LevelDbQueryTargetKey rowKey;
  266. for (; indexItererator->Valid(); indexItererator->Next()) {
  267. // Only consider rows matching exactly the specific canonicalID of interest.
  268. if (!absl::StartsWith(indexItererator->key(), indexPrefix) ||
  269. !rowKey.Decode(indexItererator->key()) || canonicalID != rowKey.canonical_id()) {
  270. // End of this canonicalID's possible targets.
  271. break;
  272. }
  273. // Each row is a unique combination of canonicalID and targetID, so this foreign key reference
  274. // can only occur once.
  275. std::string targetKey = LevelDbTargetKey::Key(rowKey.target_id());
  276. targetIterator->Seek(targetKey);
  277. if (!targetIterator->Valid() || targetIterator->key() != targetKey) {
  278. HARD_FAIL(
  279. "Dangling query-target reference found: "
  280. "%s points to %s; seeking there found %s",
  281. DescribeKey(indexItererator), DescribeKey(targetKey), DescribeKey(targetIterator));
  282. }
  283. // Finally after finding a potential match, check that the query is actually equal to the
  284. // requested query.
  285. FSTQueryData *target = [self decodedTarget:targetIterator->value()];
  286. if ([target.query isEqual:query]) {
  287. return target;
  288. }
  289. }
  290. return nil;
  291. }
  292. #pragma mark Matching Key tracking
  293. - (void)addMatchingKeys:(const DocumentKeySet &)keys forTargetID:(TargetId)targetID {
  294. // Store an empty value in the index which is equivalent to serializing a GPBEmpty message. In the
  295. // future if we wanted to store some other kind of value here, we can parse these empty values as
  296. // with some other protocol buffer (and the parser will see all default values).
  297. std::string emptyBuffer;
  298. for (const DocumentKey &key : keys) {
  299. self->_db.currentTransaction->Put(LevelDbTargetDocumentKey::Key(targetID, key), emptyBuffer);
  300. self->_db.currentTransaction->Put(LevelDbDocumentTargetKey::Key(key, targetID), emptyBuffer);
  301. [self->_db.referenceDelegate addReference:key];
  302. };
  303. }
  304. - (void)removeMatchingKeys:(const DocumentKeySet &)keys forTargetID:(TargetId)targetID {
  305. for (const DocumentKey &key : keys) {
  306. self->_db.currentTransaction->Delete(LevelDbTargetDocumentKey::Key(targetID, key));
  307. self->_db.currentTransaction->Delete(LevelDbDocumentTargetKey::Key(key, targetID));
  308. [self->_db.referenceDelegate removeReference:key];
  309. }
  310. }
  311. - (void)removeMatchingKeysForTargetID:(TargetId)targetID {
  312. std::string indexPrefix = LevelDbTargetDocumentKey::KeyPrefix(targetID);
  313. auto indexIterator = _db.currentTransaction->NewIterator();
  314. indexIterator->Seek(indexPrefix);
  315. LevelDbTargetDocumentKey rowKey;
  316. for (; indexIterator->Valid(); indexIterator->Next()) {
  317. absl::string_view indexKey = indexIterator->key();
  318. // Only consider rows matching this specific targetID.
  319. if (!rowKey.Decode(indexKey) || rowKey.target_id() != targetID) {
  320. break;
  321. }
  322. const DocumentKey &documentKey = rowKey.document_key();
  323. // Delete both index rows
  324. _db.currentTransaction->Delete(indexKey);
  325. _db.currentTransaction->Delete(LevelDbDocumentTargetKey::Key(documentKey, targetID));
  326. }
  327. }
  328. - (DocumentKeySet)matchingKeysForTargetID:(TargetId)targetID {
  329. std::string indexPrefix = LevelDbTargetDocumentKey::KeyPrefix(targetID);
  330. auto indexIterator = _db.currentTransaction->NewIterator();
  331. indexIterator->Seek(indexPrefix);
  332. DocumentKeySet result;
  333. LevelDbTargetDocumentKey rowKey;
  334. for (; indexIterator->Valid(); indexIterator->Next()) {
  335. // Only consider rows matching this specific targetID.
  336. if (!rowKey.Decode(indexIterator->key()) || rowKey.target_id() != targetID) {
  337. break;
  338. }
  339. result = result.insert(rowKey.document_key());
  340. }
  341. return result;
  342. }
  343. - (BOOL)containsKey:(const DocumentKey &)key {
  344. // ignore sentinel rows when determining if a key belongs to a target. Sentinel row just says the
  345. // document exists, not that it's a member of any particular target.
  346. std::string indexPrefix = LevelDbDocumentTargetKey::KeyPrefix(key.path());
  347. auto indexIterator = _db.currentTransaction->NewIterator();
  348. indexIterator->Seek(indexPrefix);
  349. for (; indexIterator->Valid() && absl::StartsWith(indexIterator->key(), indexPrefix);
  350. indexIterator->Next()) {
  351. LevelDbDocumentTargetKey rowKey;
  352. if (rowKey.Decode(indexIterator->key()) && !rowKey.IsSentinel() &&
  353. rowKey.document_key() == key) {
  354. return YES;
  355. }
  356. }
  357. return NO;
  358. }
  359. @end
  360. NS_ASSUME_NONNULL_END