Skip to content
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

Snapshot listener source from cache #12370

Merged
merged 20 commits into from
Mar 11, 2024
Prev Previous commit
Next Next commit
upload feature implementation
  • Loading branch information
milaGGL committed Feb 6, 2024
commit d6c0d13dd2c8732210ded8a51c3a382c4f3ad02d
6 changes: 4 additions & 2 deletions Firestore/Source/API/FIRDocumentReference.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <utility>

#import "FIRFirestoreErrors.h"
#import "Firestore/Source/API/converters.h"
#import "Firestore/Source/API/FIRCollectionReference+Internal.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
Expand Down Expand Up @@ -50,6 +51,7 @@
using firebase::firestore::api::DocumentSnapshotListener;
using firebase::firestore::api::Firestore;
using firebase::firestore::api::ListenerRegistration;
using firebase::firestore::api::MakeListenSource;
using firebase::firestore::api::MakeSource;
using firebase::firestore::api::Source;
using firebase::firestore::core::EventListener;
Expand Down Expand Up @@ -214,8 +216,8 @@ - (void)getDocumentWithSource:(FIRFirestoreSource)source

- (id<FIRListenerRegistration>)addSnapshotListenerWithOptions:(FIRSnapshotListenOptions *)options
listener:(FIRDocumentSnapshotBlock)listener {
// Mila
ListenOptions listenOptions = ListenOptions::FromIncludeMetadataChanges(false);
ListenOptions listenOptions =
ListenOptions::FromOptions(options.includeMetadataChanges, MakeListenSource(options.source));
return [self addSnapshotListenerInternalWithOptions:listenOptions listener:listener];
}

Expand Down
5 changes: 4 additions & 1 deletion Firestore/Source/API/FIRQuery.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import "FIRDocumentReference.h"
#import "FIRFirestoreErrors.h"

#import "Firestore/Source/API/converters.h"
#import "Firestore/Source/API/FIRAggregateField+Internal.h"
#import "Firestore/Source/API/FIRAggregateQuery+Internal.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
Expand Down Expand Up @@ -69,6 +70,7 @@
using firebase::firestore::google_firestore_v1_Value;
using firebase::firestore::google_firestore_v1_Value_fields;
using firebase::firestore::api::Firestore;
using firebase::firestore::api::MakeListenSource;
using firebase::firestore::api::Query;
using firebase::firestore::api::QueryListenerRegistration;
using firebase::firestore::api::QuerySnapshot;
Expand Down Expand Up @@ -193,7 +195,8 @@ - (void)getDocumentsWithSource:(FIRFirestoreSource)publicSource

- (id<FIRListenerRegistration>)addSnapshotListenerWithOptions:(FIRSnapshotListenOptions *)options
listener:(FIRQuerySnapshotBlock)listener {
auto listenOptions = ListenOptions::FromIncludeMetadataChanges(false);
ListenOptions listenOptions =
ListenOptions::FromOptions(options.includeMetadataChanges, MakeListenSource(options.source));
return [self addSnapshotListenerInternalWithOptions:listenOptions listener:listener];
}

Expand Down
4 changes: 4 additions & 0 deletions Firestore/Source/API/converters.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#import <Foundation/Foundation.h>

#include <memory>
#import "FIRSnapshotListenOptions.h"
#import "Firestore/core/src/api/listen_source.h"

@class FIRGeoPoint;
@class FIRTimestamp;
Expand Down Expand Up @@ -62,6 +64,8 @@ FIRTimestamp* MakeFIRTimestamp(const Timestamp& timestamp);
FIRDocumentReference* MakeFIRDocumentReference(const model::DocumentKey& document_key,
std::shared_ptr<Firestore> firestore);

ListenSource MakeListenSource(const FIRListenSource& source);

} // namespace api
} // namespace firestore
} // namespace firebase
Expand Down
12 changes: 12 additions & 0 deletions Firestore/Source/API/converters.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Firestore/core/include/firebase/firestore/geo_point.h"
#include "Firestore/core/include/firebase/firestore/timestamp.h"
#include "Firestore/core/src/api/firestore.h"
#import "Firestore/core/src/api/listen_source.h"
#include "Firestore/core/src/model/document_key.h"

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -61,6 +62,17 @@ Timestamp MakeTimestamp(NSDate* date) {
return [[FIRDocumentReference alloc] initWithKey:key firestore:std::move(firestore)];
}

ListenSource MakeListenSource( const FIRListenSource& source) {
switch (source) {
case FIRListenSourceDefault:
return ListenSource::Default;
case FIRListenSourceCache:
return ListenSource::Cache;
default:
return ListenSource::Default;
}
}

} // namespace api
} // namespace firestore
} // namespace firebase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,11 @@ addSnapshotListenerWithIncludeMetadataChanges:(BOOL)includeMetadataChanges
*
* @return A `ListenerRegistration` that can be used to remove this listener.
*/
// clang-format off
- (id<FIRListenerRegistration>)addSnapshotListenerWithOptions:
(FIRSnapshotListenOptions *)options
listener:(void (^)(FIRDocumentSnapshot *_Nullable snapshot,NSError *_Nullable error))listener
- (id<FIRListenerRegistration>)
addSnapshotListenerWithOptions:(FIRSnapshotListenOptions *)options
listener:(void (^)(FIRDocumentSnapshot *_Nullable snapshot,
NSError *_Nullable error))listener
NS_SWIFT_NAME(addSnapshotListener(options:listener:));
// clang-format on

@end

Expand Down
37 changes: 37 additions & 0 deletions Firestore/core/src/api/listen_source.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2019 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_API_LISTEN_SOURCE_H_
#define FIRESTORE_CORE_SRC_API_LISTEN_SOURCE_H_

namespace firebase {
namespace firestore {
namespace api {

/**
* An enum that configures the source of snapshot listeners listening to. By
* providing a source enum, listener raises snapshot from local cache changes
* only, or from both local cache and watch changes(which is the default).
*
* See `FIRFirestoreListenSource` for more details.
*/
enum class ListenSource { Default, Cache };

} // namespace api
} // namespace firestore
} // namespace firebase

#endif // FIRESTORE_CORE_SRC_API_LISTEN_SOURCE_H_
9 changes: 9 additions & 0 deletions Firestore/core/src/core/event_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ model::TargetId EventManager::AddQueryListener(
auto inserted = queries_.emplace(query, QueryListenersInfo{});
bool first_listen = inserted.second;
QueryListenersInfo& query_info = inserted.first->second;
bool first_listen_to_remote_store = !query_info.has_remote_listeners() && listener->listens_to_remote_store();

query_info.listeners.push_back(listener);

Expand All @@ -58,6 +59,8 @@ model::TargetId EventManager::AddQueryListener(

if (first_listen) {
query_info.target_id = query_event_source_->Listen(query);
} else if(first_listen_to_remote_store){
query_event_source_->ListenToRemoteStore(query);
}
return query_info.target_id;
}
Expand All @@ -66,17 +69,23 @@ void EventManager::RemoveQueryListener(
std::shared_ptr<core::QueryListener> listener) {
const Query& query = listener->query();
bool last_listen = false;
bool last_listen_to_remote_store = false;

auto found_iter = queries_.find(query);
if (found_iter != queries_.end()) {
QueryListenersInfo& query_info = found_iter->second;
query_info.Erase(listener);
last_listen = query_info.listeners.empty();
last_listen_to_remote_store = !query_info.has_remote_listeners() && listener->listens_to_remote_store();

}

if (last_listen) {
queries_.erase(found_iter);
query_event_source_->StopListening(query);
} else if(last_listen_to_remote_store){
query_event_source_->StopListeningToRemoteStore(query);

}
}

Expand Down
11 changes: 10 additions & 1 deletion Firestore/core/src/core/event_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
#include "Firestore/core/src/util/empty.h"
#include "Firestore/core/src/util/status_fwd.h"
#include "absl/types/optional.h"
#include "Firestore/core/src/core/query_listener.h"

namespace firebase {
namespace firestore {
namespace core {

class QueryEventSource;
class QueryListener;

/**
* EventManager is responsible for mapping queries to query event listeners.
Expand Down Expand Up @@ -97,6 +97,15 @@ class EventManager : public SyncEngineCallback {
snapshot_ = snapshot;
}

bool has_remote_listeners() {
for (const auto& listener : listeners) {
if (listener->listens_to_remote_store()) {
return true;
}
}
return false;
}

private:
// Other members are public in this struct, ensure that any reads are
// copies by requiring reads to go through a const getter.
Expand Down
50 changes: 46 additions & 4 deletions Firestore/core/src/core/listen_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
#ifndef FIRESTORE_CORE_SRC_CORE_LISTEN_OPTIONS_H_
#define FIRESTORE_CORE_SRC_CORE_LISTEN_OPTIONS_H_

#include "Firestore/core/src/api/listen_source.h"
namespace firebase {
namespace firestore {
namespace core {

using api::ListenSource;

class ListenOptions {
public:
ListenOptions() = default;
Expand All @@ -44,14 +47,36 @@ class ListenOptions {
}

/**
* Creates a default ListenOptions, with metadata changes and
* wait_for_sync_when_online disabled.
* Creates a new ListenOptions.
*
* @param include_query_metadata_changes Raise events when only metadata of
* the query changes.
* @param include_document_metadata_changes Raise events when only metadata of
* documents changes.
* @param wait_for_sync_when_online Wait for a sync with the server when
* online, but still raise events while offline.
* @param source sets the source snapshot listeners listen to.
*/
ListenOptions(bool include_query_metadata_changes,
bool include_document_metadata_changes,
bool wait_for_sync_when_online,
ListenSource source)
: include_query_metadata_changes_(include_query_metadata_changes),
include_document_metadata_changes_(include_document_metadata_changes),
wait_for_sync_when_online_(wait_for_sync_when_online),
source_(std::move(source)) {
}

/**
* Creates a default ListenOptions, with metadata changes,
* wait_for_sync_when_online disabled, and listen source set to default.
*/
static ListenOptions DefaultOptions() {
return ListenOptions(
/*include_query_metadata_changes=*/false,
/*include_document_metadata_changes=*/false,
/*wait_for_sync_when_online=*/false);
/*wait_for_sync_when_online=*/false,
/*source=*/ListenSource::Default);
}

/**
Expand All @@ -63,7 +88,19 @@ class ListenOptions {
return ListenOptions(
/*include_query_metadata_changes=*/include_metadata_changes,
/*include_document_metadata_changes=*/include_metadata_changes,
/*wait_for_sync_when_online=*/false);
/*wait_for_sync_when_online=*/false,
/*source=*/ListenSource::Default);
}

/**
* Creates a ListenOptions which sets the source snapshot listeners listen to.
*/
static ListenOptions FromOptions(bool include_metadata_changes,
ListenSource source) {
return ListenOptions(
/*include_query_metadata_changes=*/include_metadata_changes,
/*include_document_metadata_changes=*/include_metadata_changes,
/*wait_for_sync_when_online=*/false, std::move(source));
}

bool include_query_metadata_changes() const {
Expand All @@ -78,10 +115,15 @@ class ListenOptions {
return wait_for_sync_when_online_;
}

ListenSource source() const {
return source_;
}

private:
bool include_query_metadata_changes_ = false;
bool include_document_metadata_changes_ = false;
bool wait_for_sync_when_online_ = false;
ListenSource source_ = ListenSource::Default;
};

} // namespace core
Expand Down
5 changes: 5 additions & 0 deletions Firestore/core/src/core/query_listener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ bool QueryListener::ShouldRaiseInitialEvent(const ViewSnapshot& snapshot,
return true;
}

// Always raise first event if listening to cache
if (!listens_to_remote_store()) {
return true;
}

// NOTE: We consider OnlineState::Unknown as online (it should become Offline
// or Online if we wait long enough).
bool maybe_online = online_state != OnlineState::Offline;
Expand Down
4 changes: 4 additions & 0 deletions Firestore/core/src/core/query_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class QueryListener {
return query_;
}

bool listens_to_remote_store() const {
return options_.source() != ListenSource::Cache;
}

/** The last received view snapshot. */
const absl::optional<ViewSnapshot>& snapshot() const {
return snapshot_;
Expand Down
22 changes: 22 additions & 0 deletions Firestore/core/src/core/sync_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ ViewSnapshot SyncEngine::InitializeViewAndComputeSnapshot(
return view_change.snapshot().value();
}

void SyncEngine::ListenToRemoteStore(Query query) {
AssertCallbackExists("ListenToRemoteStore");
TargetData target_data = local_store_->AllocateTarget(query.ToTarget());
remote_store_->Listen(std::move(target_data));;
}

void SyncEngine::StopListening(const Query& query) {
AssertCallbackExists("StopListening");

Expand All @@ -181,6 +187,22 @@ void SyncEngine::StopListening(const Query& query) {
}
}

void SyncEngine::StopListeningToRemoteStore(const Query& query) {
AssertCallbackExists("stopListeningToRemoteStore");

auto query_view = query_views_by_query_[query];
HARD_ASSERT(query_view, "Trying to stop listening to a query not found");

TargetId target_id = query_view->target_id();
auto& queries = queries_by_target_[target_id];
queries.erase(std::remove(queries.begin(), queries.end(), query),
wu-hui marked this conversation as resolved.
Show resolved Hide resolved
queries.end());

if (queries.empty()) {
remote_store_->StopListening(target_id);
}
}

void SyncEngine::RemoveAndCleanupTarget(TargetId target_id, Status status) {
for (const Query& query : queries_by_target_.at(target_id)) {
query_views_by_query_.erase(query);
Expand Down
Loading
Loading