Skip to content

Commit 3d8a869

Browse files
cynthiajianga-maurice
authored andcommitted
[RemoteConfig V2] desktop impl 1/n
+ Replace the thread call for fetch with scheduler to get a better central control of all async calls. PiperOrigin-RevId: 312582360
1 parent a5c678f commit 3d8a869

File tree

2 files changed

+102
-96
lines changed

2 files changed

+102
-96
lines changed

remote_config/src/desktop/remote_config_desktop.cc

Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,10 @@
2424
#include <thread> // NOLINT
2525
#include <vector>
2626

27-
#include "firebase/app.h"
28-
#include "firebase/future.h"
27+
#include "app/src/callback.h"
28+
#include "app/src/time.h"
2929
#include "remote_config/src/common.h"
30-
#include "remote_config/src/desktop/config_data.h"
31-
#include "remote_config/src/desktop/file_manager.h"
3230
#include "remote_config/src/desktop/rest.h"
33-
#include "remote_config/src/include/firebase/remote_config.h"
3431

3532
#ifndef SWIG
3633
#include "firebase/variant.h"
@@ -40,6 +37,8 @@ namespace firebase {
4037
namespace remote_config {
4138
namespace internal {
4239

40+
using callback::NewCallback;
41+
4342
const char* const RemoteConfigInternal::kDefaultNamespace = "configns:firebase";
4443
const char* const RemoteConfigInternal::kDefaultValueForString = "";
4544
const int64_t RemoteConfigInternal::kDefaultValueForLong = 0L;
@@ -48,39 +47,54 @@ const bool RemoteConfigInternal::kDefaultValueForBool = false;
4847

4948
static const char* kFilePathSuffix = "remote_config_data";
5049

50+
template <typename T>
51+
struct RCDataHandle {
52+
RCDataHandle(
53+
ReferenceCountedFutureImpl* _future_api,
54+
const SafeFutureHandle<T>& _future_handle,
55+
RemoteConfigInternal* _rc_internal,
56+
std::vector<std::string> _default_keys = std::vector<std::string>())
57+
: future_api(_future_api),
58+
future_handle(_future_handle),
59+
rc_internal(_rc_internal),
60+
default_keys(_default_keys) {}
61+
ReferenceCountedFutureImpl* future_api;
62+
SafeFutureHandle<T> future_handle;
63+
RemoteConfigInternal* rc_internal;
64+
std::vector<std::string> default_keys;
65+
};
66+
5167
RemoteConfigInternal::RemoteConfigInternal(
5268
const firebase::App& app, const RemoteConfigFileManager& file_manager)
5369
: app_(app),
5470
file_manager_(file_manager),
5571
is_fetch_process_have_task_(false),
56-
future_impl_(kRemoteConfigFnCount) {
72+
future_impl_(kRemoteConfigFnCount),
73+
safe_this_(this) {
5774
InternalInit();
5875
}
5976

6077
RemoteConfigInternal::RemoteConfigInternal(const firebase::App& app)
6178
: app_(app),
6279
file_manager_(kFilePathSuffix),
6380
is_fetch_process_have_task_(false),
64-
future_impl_(kRemoteConfigFnCount) {
81+
future_impl_(kRemoteConfigFnCount),
82+
safe_this_(this) {
6583
InternalInit();
6684
}
6785

6886
RemoteConfigInternal::~RemoteConfigInternal() {
69-
fetch_channel_.Close();
70-
if (fetch_thread_.joinable()) {
71-
fetch_thread_.join();
72-
}
73-
7487
save_channel_.Close();
7588
if (save_thread_.joinable()) {
7689
save_thread_.join();
7790
}
91+
92+
safe_this_.ClearReference();
7893
}
7994

8095
void RemoteConfigInternal::InternalInit() {
8196
file_manager_.Load(&configs_);
8297
AsyncSaveToFile();
83-
AsyncFetch();
8498
}
8599

86100
bool RemoteConfigInternal::Initialized() const{
@@ -151,7 +165,7 @@ void RemoteConfigInternal::AsyncSaveToFile() {
151165
while (save_channel_.Get()) {
152166
LayeredConfigs copy;
153167
{
154-
std::unique_lock<std::mutex> lock(mutex_);
168+
MutexLock lock(internal_mutex_);
155169
copy = configs_;
156170
}
157171
file_manager_.Save(copy);
@@ -225,14 +239,14 @@ Future<void> RemoteConfigInternal::SetDefaults(const ConfigKeyValue* defaults,
225239
void RemoteConfigInternal::SetDefaults(
226240
const std::map<std::string, std::string>& defaults_map) {
227241
{
228-
std::unique_lock<std::mutex> lock(mutex_);
242+
MutexLock lock(internal_mutex_);
229243
configs_.defaults.SetNamespace(defaults_map, kDefaultNamespace);
230244
}
231245
save_channel_.Put();
232246
}
233247

234248
std::string RemoteConfigInternal::GetConfigSetting(ConfigSetting setting) {
235-
std::unique_lock<std::mutex> lock(mutex_);
249+
MutexLock lock(internal_mutex_);
236250
return configs_.metadata.GetSetting(setting);
237251
}
238252

@@ -242,7 +256,7 @@ void RemoteConfigInternal::SetConfigSetting(ConfigSetting setting,
242256
return;
243257
}
244258
{
245-
std::unique_lock<std::mutex> lock(mutex_);
259+
MutexLock lock(internal_mutex_);
246260
configs_.metadata.AddSetting(setting, value);
247261
}
248262
save_channel_.Put();
@@ -263,8 +277,7 @@ bool RemoteConfigInternal::CheckValueInConfig(
263277
if (!key) return false;
264278

265279
{
266-
// TODO(b/74461360): Replace the thread locks with firebase ones.
267-
std::unique_lock<std::mutex> lock(mutex_);
280+
MutexLock lock(internal_mutex_);
268281
if (!config.HasValue(key, kDefaultNamespace)) {
269282
return false;
270283
}
@@ -418,7 +431,7 @@ std::vector<std::string> RemoteConfigInternal::GetKeysByPrefix(
418431
if (prefix == nullptr) return std::vector<std::string>();
419432
std::set<std::string> unique_keys;
420433
{
421-
std::unique_lock<std::mutex> lock(mutex_);
434+
MutexLock lock(internal_mutex_);
422435
configs_.active.GetKeysByPrefix(prefix, kDefaultNamespace, &unique_keys);
423436
configs_.defaults.GetKeysByPrefix(prefix, kDefaultNamespace, &unique_keys);
424437
}
@@ -433,7 +446,7 @@ std::map<std::string, Variant> RemoteConfigInternal::GetAll() {
433446

434447
bool RemoteConfigInternal::ActivateFetched() {
435448
{
436-
std::unique_lock<std::mutex> lock(mutex_);
449+
MutexLock lock(internal_mutex_);
437450
// Fetched config not found or already activated.
438451
if (configs_.fetched.timestamp() <= configs_.active.timestamp())
439452
return false;
@@ -444,63 +457,24 @@ bool RemoteConfigInternal::ActivateFetched() {
444457
}
445458

446459
const ConfigInfo RemoteConfigInternal::GetInfo() const {
447-
std::unique_lock<std::mutex> lock(mutex_);
460+
MutexLock lock(internal_mutex_);
448461
return configs_.metadata.info();
449462
}
450463

451-
void RemoteConfigInternal::AsyncFetch() {
452-
fetch_thread_ = std::thread([this]() {
453-
SafeFutureHandle<void> handle;
454-
while (fetch_channel_.Get()) {
455-
RemoteConfigREST* rest = nullptr;
456-
457-
{
458-
std::unique_lock<std::mutex> lock(mutex_);
459-
handle = fetch_handle_;
460-
rest = new RemoteConfigREST(app_.options(), configs_,
461-
cache_expiration_in_seconds_);
462-
}
463-
464-
// Fetch fresh config from server.
465-
rest->Fetch(app_);
466-
467-
{
468-
std::unique_lock<std::mutex> lock(mutex_);
469-
470-
// Need to copy everything to `configs_.fetched`.
471-
configs_.fetched = rest->fetched();
472-
473-
// Need to copy only info and digests to `configs_.metadata`.
474-
const RemoteConfigMetadata& metadata = rest->metadata();
475-
configs_.metadata.set_info(metadata.info());
476-
configs_.metadata.set_digest_by_namespace(
477-
metadata.digest_by_namespace());
478-
479-
delete rest;
480-
481-
is_fetch_process_have_task_ = false;
482-
}
483-
FutureStatus futureResult =
484-
(GetInfo().last_fetch_status == kLastFetchStatusSuccess)
485-
? kFutureStatusSuccess
486-
: kFutureStatusFailure;
487-
488-
FutureData* future_data = FutureData::Get();
489-
future_data->api()->Complete(handle, futureResult);
490-
}
491-
});
492-
}
493-
494464
Future<void> RemoteConfigInternal::Fetch(uint64_t cache_expiration_in_seconds) {
495-
std::unique_lock<std::mutex> lock(mutex_);
465+
MutexLock lock(internal_mutex_);
496466

497467
uint64_t milliseconds_since_epoch =
498468
std::chrono::duration_cast<std::chrono::milliseconds>(
499469
std::chrono::system_clock::now().time_since_epoch())
500470
.count();
501471

502472
uint64_t cache_expiration_timestamp =
503-
configs_.fetched.timestamp() + 1000 * cache_expiration_in_seconds;
473+
configs_.fetched.timestamp() +
474+
::firebase::internal::kMillisecondsPerSecond *
475+
cache_expiration_in_seconds;
476+
477+
const auto future_handle = future_impl_.SafeAlloc<void>(kRemoteConfigFnFetch);
504478

505479
// Need to fetch in two cases:
506480
// - we are not fetching at this moment
@@ -511,19 +485,58 @@ Future<void> RemoteConfigInternal::Fetch(uint64_t cache_expiration_in_seconds) {
511485
if (!is_fetch_process_have_task_ &&
512486
((cache_expiration_in_seconds == 0) ||
513487
(cache_expiration_timestamp < milliseconds_since_epoch))) {
514-
ReferenceCountedFutureImpl* api = FutureData::Get()->api();
515-
fetch_handle_ = api->SafeAlloc<void>(kRemoteConfigFnFetch);
488+
auto data_handle =
489+
MakeShared<RCDataHandle<void>>(&future_impl_, future_handle, this);
490+
491+
auto callback = NewCallback(
492+
[](ThisRef ref, SharedPtr<RCDataHandle<void>> handle) {
493+
ThisRefLock lock(&ref);
494+
if (lock.GetReference() != nullptr) {
495+
MutexLock lock(handle->rc_internal->internal_mutex_);
496+
RemoteConfigREST* rest = new RemoteConfigREST(
497+
handle->rc_internal->app_.options(),
498+
handle->rc_internal->configs_,
499+
handle->rc_internal->cache_expiration_in_seconds_);
500+
501+
// Fetch fresh config from server.
502+
rest->Fetch(handle->rc_internal->app_);
503+
504+
// Need to copy everything to `configs_.fetched`.
505+
handle->rc_internal->configs_.fetched = rest->fetched();
506+
507+
// Need to copy only info and digests to `configs_.metadata`.
508+
const RemoteConfigMetadata& metadata = rest->metadata();
509+
handle->rc_internal->configs_.metadata.set_info(metadata.info());
510+
handle->rc_internal->configs_.metadata.set_digest_by_namespace(
511+
metadata.digest_by_namespace());
512+
513+
delete rest;
514+
515+
handle->rc_internal->is_fetch_process_have_task_ = false;
516+
517+
FutureStatus futureResult =
518+
(handle->rc_internal->GetInfo().last_fetch_status ==
519+
kLastFetchStatusSuccess)
520+
? kFutureStatusSuccess
521+
: kFutureStatusFailure;
522+
handle->future_api->Complete(handle->future_handle, futureResult);
523+
}
524+
},
525+
safe_this_, data_handle);
526+
527+
scheduler_.Schedule(callback);
516528
is_fetch_process_have_task_ = true;
517-
fetch_channel_.Put();
518529
cache_expiration_in_seconds_ = cache_expiration_in_seconds;
530+
} else {
531+
// Do not fetch, complete future immediately.
532+
future_impl_.Complete(future_handle, kFutureStatusSuccess);
519533
}
520-
return FetchLastResult();
534+
return MakeFuture<void>(&future_impl_, future_handle);
521535
}
522536

523537
Future<void> RemoteConfigInternal::FetchLastResult() {
524-
ReferenceCountedFutureImpl* api = FutureData::Get()->api();
525538
return static_cast<const Future<void>&>(
526-
api->LastResult(kRemoteConfigFnFetch));
539+
future_impl_.LastResult(kRemoteConfigFnFetch));
527540
}
528541

529542
} // namespace internal

remote_config/src/desktop/remote_config_desktop.h

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
#include <string>
2020
#include <thread> // NOLINT
2121

22-
#include "app/src/reference_counted_future_impl.h"
2322
#include "firebase/app.h"
23+
#include "app/src/mutex.h"
24+
#include "app/src/reference_counted_future_impl.h"
25+
#include "app/src/safe_reference.h"
26+
#include "app/src/scheduler.h"
2427
#include "firebase/future.h"
2528
#include "remote_config/src/desktop/config_data.h"
2629
#include "remote_config/src/desktop/file_manager.h"
@@ -131,10 +134,6 @@ class RemoteConfigInternal {
131134
// notifications in loop from the `save_channel_` until it will be closed.
132135
void AsyncSaveToFile();
133136

134-
// Open a new thread for fetching fresh config. Thread will wait nofitications
135-
// in loop from the `fetch_channel_` until it will be closed.
136-
void AsyncFetch();
137-
138137
void InternalInit();
139138

140139
// Convert the `firebase::Variant` type to the `std::string` type.
@@ -190,22 +189,6 @@ class RemoteConfigInternal {
190189
// `configs_` variable. Call `save_channel_.Close()` to close the channel.
191190
NotificationChannel save_channel_;
192191

193-
// Used for fetching the fresh config in background. Will be created in the
194-
// constructor and removed in the destructor.
195-
//
196-
// Wait notifications in loop from `fetch_channel_` until it will be closed.
197-
std::thread fetch_thread_;
198-
199-
// Thread safety notification channel.
200-
//
201-
// Call non blocking `fetch_channel_.Put()` function to fetch config. Call
202-
// `fetch_channel_.Close()` to close the channel.
203-
NotificationChannel fetch_channel_;
204-
205-
// Create new FutureHandle when it's possible to start fetching and complete
206-
// future with `fetch_handle_` after fetching.
207-
firebase::SafeFutureHandle<void> fetch_handle_;
208-
209192
// Last value of `Fetch` function argument. Update only if we will fetch.
210193
uint64_t cache_expiration_in_seconds_;
211194

@@ -216,10 +199,20 @@ class RemoteConfigInternal {
216199
// will finish it will be assigned to `false`.
217200
bool is_fetch_process_have_task_;
218201

219-
mutable std::mutex mutex_;
202+
mutable Mutex internal_mutex_;
220203

221-
/// Handle calls from Futures that the API returns.
204+
// Handle calls from Futures that the API returns.
222205
ReferenceCountedFutureImpl future_impl_;
206+
207+
scheduler::Scheduler scheduler_;
208+
209+
// Safe reference to this. Set in constructor and cleared in destructor
210+
// Should be safe to be copied in any thread because the SharedPtr never
211+
// changes, until safe_this_ is completely destroyed.
212+
typedef firebase::internal::SafeReference<RemoteConfigInternal> ThisRef;
213+
typedef firebase::internal::SafeReferenceLock<RemoteConfigInternal>
214+
ThisRefLock;
215+
ThisRef safe_this_;
223216
};
224217

225218
} // namespace internal

0 commit comments

Comments
 (0)