diff options
author | Gil <mcg@google.com> | 2017-10-03 08:55:22 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-03 08:55:22 -0700 |
commit | bde743ed25166a0b320ae157bfb1d68064f531c9 (patch) | |
tree | 4dd7525d9df32fa5dbdb721d4b0d4f9b87f5e884 /Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm | |
parent | bf550507ffa8beee149383a5bf1e2363bccefbb4 (diff) |
Release 4.3.0 (#327)
Initial release of Firestore at 0.8.0
Bump FirebaseCommunity to 0.1.3
Diffstat (limited to 'Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm')
-rw-r--r-- | Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm new file mode 100644 index 0000000..e2424b9 --- /dev/null +++ b/Firestore/Source/Local/FSTLevelDBRemoteDocumentCache.mm @@ -0,0 +1,153 @@ +/* + * 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 "FSTLevelDBRemoteDocumentCache.h" + +#include <leveldb/db.h> +#include <leveldb/write_batch.h> +#include <string> + +#import "MaybeDocument.pbobjc.h" +#import "FSTLevelDBKey.h" +#import "FSTLocalSerializer.h" +#import "FSTWriteGroup.h" +#import "FSTDocument.h" +#import "FSTDocumentDictionary.h" +#import "FSTDocumentKey.h" +#import "FSTDocumentSet.h" +#import "FSTAssert.h" + +#include "ordered_code.h" +#include "string_util.h" + +NS_ASSUME_NONNULL_BEGIN + +using Firestore::OrderedCode; +using leveldb::DB; +using leveldb::Iterator; +using leveldb::ReadOptions; +using leveldb::Slice; +using leveldb::Status; +using leveldb::WriteOptions; + +@interface FSTLevelDBRemoteDocumentCache () + +@property(nonatomic, strong, readonly) FSTLocalSerializer *serializer; + +@end + +/** + * Returns a standard set of read options. + * + * For now this is paranoid, but perhaps disable that in production builds. + */ +static ReadOptions StandardReadOptions() { + ReadOptions options; + options.verify_checksums = true; + return options; +} + +@implementation FSTLevelDBRemoteDocumentCache { + // The DB pointer is shared with all cooperating LevelDB-related objects. + std::shared_ptr<DB> _db; +} + +- (instancetype)initWithDB:(std::shared_ptr<DB>)db serializer:(FSTLocalSerializer *)serializer { + if (self = [super init]) { + _db = db; + _serializer = serializer; + } + return self; +} + +- (void)shutdown { + _db.reset(); +} + +- (void)addEntry:(FSTMaybeDocument *)document group:(FSTWriteGroup *)group { + std::string key = [self remoteDocumentKey:document.key]; + [group setMessage:[self.serializer encodedMaybeDocument:document] forKey:key]; +} + +- (void)removeEntryForKey:(FSTDocumentKey *)documentKey group:(FSTWriteGroup *)group { + std::string key = [self remoteDocumentKey:documentKey]; + [group removeMessageForKey:key]; +} + +- (nullable FSTMaybeDocument *)entryForKey:(FSTDocumentKey *)documentKey { + std::string key = [FSTLevelDBRemoteDocumentKey keyWithDocumentKey:documentKey]; + std::string value; + Status status = _db->Get(StandardReadOptions(), key, &value); + if (status.IsNotFound()) { + return nil; + } else if (status.ok()) { + return [self decodedMaybeDocument:value withKey:documentKey]; + } else { + FSTFail(@"Fetch document for key (%@) failed with status: %s", documentKey, + status.ToString().c_str()); + } +} + +- (FSTDocumentDictionary *)documentsMatchingQuery:(FSTQuery *)query { + // TODO(mikelehen): PERF: At least filter to the documents that match the path of the query. + FSTDocumentDictionary *results = [FSTDocumentDictionary documentDictionary]; + + std::string startKey = [FSTLevelDBRemoteDocumentKey keyPrefix]; + std::unique_ptr<Iterator> it(_db->NewIterator(StandardReadOptions())); + it->Seek(startKey); + + FSTLevelDBRemoteDocumentKey *currentKey = [[FSTLevelDBRemoteDocumentKey alloc] init]; + for (; it->Valid() && [currentKey decodeKey:it->key()]; it->Next()) { + FSTMaybeDocument *maybeDoc = + [self decodedMaybeDocument:it->value() withKey:currentKey.documentKey]; + if ([maybeDoc isKindOfClass:[FSTDocument class]]) { + results = [results dictionaryBySettingObject:(FSTDocument *)maybeDoc forKey:maybeDoc.key]; + } + } + + Status status = it->status(); + if (!status.ok()) { + FSTFail(@"Find documents matching query (%@) failed with status: %s", query, + status.ToString().c_str()); + } + + return results; +} + +- (std::string)remoteDocumentKey:(FSTDocumentKey *)key { + return [FSTLevelDBRemoteDocumentKey keyWithDocumentKey:key]; +} + +- (FSTMaybeDocument *)decodedMaybeDocument:(Slice)slice withKey:(FSTDocumentKey *)documentKey { + NSData *data = + [[NSData alloc] initWithBytesNoCopy:(void *)slice.data() length:slice.size() freeWhenDone:NO]; + + NSError *error; + FSTPBMaybeDocument *proto = [FSTPBMaybeDocument parseFromData:data error:&error]; + if (!proto) { + FSTFail(@"FSTPBMaybeDocument failed to parse: %@", error); + } + + FSTMaybeDocument *maybeDocument = [self.serializer decodedMaybeDocument:proto]; + FSTAssert([maybeDocument.key isEqualToKey:documentKey], + @"Read document has key (%@) instead of expected key (%@).", maybeDocument.key, + documentKey); + return maybeDocument; +} + +@end + +NS_ASSUME_NONNULL_END |