FSTLevelDBQueryCache.mm 16 KB

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