Skip to content

Port FSTMemoryQueryCache to C++ #2197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Dec 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 23 additions & 77 deletions Firestore/Source/Local/FSTMemoryQueryCache.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#import <Protobuf/GPBProtocolBuffers.h>

#include <memory>
#include <utility>

#import "Firestore/Protos/objc/firestore/local/Target.pbobjc.h"
Expand All @@ -26,9 +27,12 @@
#import "Firestore/Source/Local/FSTQueryData.h"
#import "Firestore/Source/Local/FSTReferenceSet.h"

#include "Firestore/core/src/firebase/firestore/local/memory_query_cache.h"
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
#include "absl/memory/memory.h"

using firebase::firestore::local::MemoryQueryCache;
using firebase::firestore::model::DocumentKey;
using firebase::firestore::model::DocumentKeySet;
using firebase::firestore::model::ListenSequenceNumber;
Expand All @@ -37,33 +41,13 @@

NS_ASSUME_NONNULL_BEGIN

@interface FSTMemoryQueryCache ()

/** Maps a query to the data about that query. */
@property(nonatomic, strong, readonly) NSMutableDictionary<FSTQuery *, FSTQueryData *> *queries;

/** A ordered bidirectional mapping between documents and the remote target IDs. */
@property(nonatomic, strong, readonly) FSTReferenceSet *references;

/** The highest numbered target ID encountered. */
@property(nonatomic, assign) TargetId highestTargetID;

@property(nonatomic, assign) ListenSequenceNumber highestListenSequenceNumber;

@end

@implementation FSTMemoryQueryCache {
FSTMemoryPersistence *_persistence;
/** The last received snapshot version. */
SnapshotVersion _lastRemoteSnapshotVersion;
std::unique_ptr<MemoryQueryCache> _cache;
}

- (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence {
if (self = [super init]) {
_persistence = persistence;
_queries = [NSMutableDictionary dictionary];
_references = [[FSTReferenceSet alloc] init];
_lastRemoteSnapshotVersion = SnapshotVersion::None();
_cache = absl::make_unique<MemoryQueryCache>(persistence);
}
return self;
}
Expand All @@ -72,112 +56,74 @@ - (instancetype)initWithPersistence:(FSTMemoryPersistence *)persistence {
#pragma mark Query tracking

- (TargetId)highestTargetID {
return _highestTargetID;
return _cache->highest_target_id();
}

- (ListenSequenceNumber)highestListenSequenceNumber {
return _highestListenSequenceNumber;
return _cache->highest_listen_sequence_number();
}

- (const SnapshotVersion &)lastRemoteSnapshotVersion {
return _lastRemoteSnapshotVersion;
return _cache->last_remote_snapshot_version();
}

- (void)setLastRemoteSnapshotVersion:(SnapshotVersion)snapshotVersion {
_lastRemoteSnapshotVersion = std::move(snapshotVersion);
_cache->set_last_remote_snapshot_version(std::move(snapshotVersion));
}

- (void)addQueryData:(FSTQueryData *)queryData {
self.queries[queryData.query] = queryData;
if (queryData.targetID > self.highestTargetID) {
self.highestTargetID = queryData.targetID;
}
if (queryData.sequenceNumber > self.highestListenSequenceNumber) {
self.highestListenSequenceNumber = queryData.sequenceNumber;
}
_cache->AddTarget(queryData);
}

- (void)updateQueryData:(FSTQueryData *)queryData {
self.queries[queryData.query] = queryData;
if (queryData.targetID > self.highestTargetID) {
self.highestTargetID = queryData.targetID;
}
if (queryData.sequenceNumber > self.highestListenSequenceNumber) {
self.highestListenSequenceNumber = queryData.sequenceNumber;
}
_cache->UpdateTarget(queryData);
}

- (int32_t)count {
return (int32_t)[self.queries count];
return _cache->count();
}

- (void)removeQueryData:(FSTQueryData *)queryData {
[self.queries removeObjectForKey:queryData.query];
[self.references removeReferencesForID:queryData.targetID];
_cache->RemoveTarget(queryData);
}

- (nullable FSTQueryData *)queryDataForQuery:(FSTQuery *)query {
return self.queries[query];
return _cache->GetTarget(query);
}

- (void)enumerateTargetsUsingBlock:(void (^)(FSTQueryData *queryData, BOOL *stop))block {
[self.queries
enumerateKeysAndObjectsUsingBlock:^(FSTQuery *key, FSTQueryData *queryData, BOOL *stop) {
block(queryData, stop);
}];
_cache->EnumerateTargets(block);
}

- (int)removeQueriesThroughSequenceNumber:(ListenSequenceNumber)sequenceNumber
liveQueries:(NSDictionary<NSNumber *, FSTQueryData *> *)liveQueries {
NSMutableArray<FSTQuery *> *toRemove = [NSMutableArray array];
[self.queries
enumerateKeysAndObjectsUsingBlock:^(FSTQuery *query, FSTQueryData *queryData, BOOL *stop) {
if (queryData.sequenceNumber <= sequenceNumber) {
if (liveQueries[@(queryData.targetID)] == nil) {
[toRemove addObject:query];
[self.references removeReferencesForID:queryData.targetID];
}
}
}];
[self.queries removeObjectsForKeys:toRemove];
return (int)[toRemove count];
return _cache->RemoveTargets(sequenceNumber, liveQueries);
}

#pragma mark Reference tracking

- (void)addMatchingKeys:(const DocumentKeySet &)keys forTargetID:(TargetId)targetID {
[self.references addReferencesToKeys:keys forID:targetID];
for (const DocumentKey &key : keys) {
[_persistence.referenceDelegate addReference:key];
}
_cache->AddMatchingKeys(keys, targetID);
}

- (void)removeMatchingKeys:(const DocumentKeySet &)keys forTargetID:(TargetId)targetID {
[self.references removeReferencesToKeys:keys forID:targetID];
for (const DocumentKey &key : keys) {
[_persistence.referenceDelegate removeReference:key];
}
_cache->RemoveMatchingKeys(keys, targetID);
}

- (void)removeMatchingKeysForTargetID:(TargetId)targetID {
[self.references removeReferencesForID:targetID];
_cache->RemoveAllKeysForTarget(targetID);
}

- (DocumentKeySet)matchingKeysForTargetID:(TargetId)targetID {
return [self.references referencedKeysForID:targetID];
return _cache->GetMatchingKeys(targetID);
}

- (BOOL)containsKey:(const firebase::firestore::model::DocumentKey &)key {
return [self.references containsKey:key];
return _cache->Contains(key);
}

- (size_t)byteSizeWithSerializer:(FSTLocalSerializer *)serializer {
__block size_t count = 0;
[self.queries
enumerateKeysAndObjectsUsingBlock:^(FSTQuery *key, FSTQueryData *queryData, BOOL *stop) {
count += [[serializer encodedQueryData:queryData] serializedSize];
}];
return count;
return _cache->CalculateByteSize(serializer);
}

@end
Expand Down
123 changes: 123 additions & 0 deletions Firestore/core/src/firebase/firestore/local/memory_query_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2018 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.
*/

#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_

#if !defined(__OBJC__)
#error "For now, this file must only be included by ObjC source files."
#endif // !defined(__OBJC__)

#import <Foundation/Foundation.h>

#include <cstdint>
#include <utility>

#include "Firestore/core/src/firebase/firestore/model/document_key_set.h"
#include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
#include "Firestore/core/src/firebase/firestore/model/types.h"

@class FSTLocalSerializer;
@class FSTMemoryPersistence;
@class FSTQuery;
@class FSTQueryData;
@class FSTReferenceSet;

NS_ASSUME_NONNULL_BEGIN

namespace firebase {
namespace firestore {
namespace local {

typedef void (^TargetEnumerator)(FSTQueryData*, BOOL*);

class MemoryQueryCache {
public:
explicit MemoryQueryCache(FSTMemoryPersistence* persistence);

// Target-related methods
void AddTarget(FSTQueryData* query_data);

void UpdateTarget(FSTQueryData* query_data);

void RemoveTarget(FSTQueryData* query_data);

FSTQueryData* _Nullable GetTarget(FSTQuery* query);

void EnumerateTargets(TargetEnumerator block);

int RemoveTargets(model::ListenSequenceNumber upper_bound,
NSDictionary<NSNumber*, FSTQueryData*>* live_targets);

// Key-related methods
void AddMatchingKeys(const model::DocumentKeySet& keys,
model::TargetId target_id);

void RemoveMatchingKeys(const model::DocumentKeySet& keys,
model::TargetId target_id);

void RemoveAllKeysForTarget(model::TargetId target_id);

model::DocumentKeySet GetMatchingKeys(model::TargetId target_id);

bool Contains(const model::DocumentKey& key);

// Other methods and accessors
size_t CalculateByteSize(FSTLocalSerializer* serializer);

int32_t count() const {
return static_cast<int32_t>([queries_ count]);
}

model::ListenSequenceNumber highest_listen_sequence_number() const {
return highest_listen_sequence_number_;
}

model::TargetId highest_target_id() const {
return highest_target_id_;
}

const model::SnapshotVersion& last_remote_snapshot_version() const {
return last_remote_snapshot_version_;
}

void set_last_remote_snapshot_version(model::SnapshotVersion version) {
last_remote_snapshot_version_ = std::move(version);
}

private:
FSTMemoryPersistence* persistence_;
/** The highest sequence number encountered */
model::ListenSequenceNumber highest_listen_sequence_number_;
/** The highest numbered target ID encountered. */
model::TargetId highest_target_id_;
/** The last received snapshot version. */
model::SnapshotVersion last_remote_snapshot_version_;

/** Maps a query to the data about that query. */
NSMutableDictionary<FSTQuery*, FSTQueryData*>* queries_;
/** A ordered bidirectional mapping between documents and the remote target
* IDs. */
FSTReferenceSet* references_;
};

} // namespace local
} // namespace firestore
} // namespace firebase

NS_ASSUME_NONNULL_END

#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_MEMORY_QUERY_CACHE_H_
Loading