Skip to content

Commit 4a8f415

Browse files
authored
Merge pull request #7609 from realm/tg/session-lifecycle
RCORE-2092 Simplify the SessionWrapper lifecycle a bit
2 parents 702189a + 8a68a7f commit 4a8f415

20 files changed

+947
-1412
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
### Internals
1919
* Work around a bug in VC++ that resulted in runtime errors when running the tests in a debug build (#[7741](https://github.com/realm/realm-core/issues/7741)).
20+
* Refactor `sync::Session` to eliminate the bind() step of session creation ([#7609](https://github.com/realm/realm-core/pull/7609)).
21+
* Add ScopeExitFail which only calls the handler if exiting the scope via an uncaught exception ([#7609](https://github.com/realm/realm-core/pull/7609)).
2022

2123
----------------------------------------------
2224

src/realm/db.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,10 +1189,9 @@ void DB::open(const std::string& path, const DBOptions& options)
11891189
SlabAlloc::DetachGuard alloc_detach_guard(alloc);
11901190
alloc.note_reader_start(this);
11911191
// must come after the alloc detach guard
1192-
auto handler = [this, &alloc]() noexcept {
1192+
auto reader_end_guard = make_scope_exit([this, &alloc]() noexcept {
11931193
alloc.note_reader_end(this);
1194-
};
1195-
auto reader_end_guard = make_scope_exit(handler);
1194+
});
11961195

11971196
// Check validity of top array (to give more meaningful errors
11981197
// early)

src/realm/object-store/c_api/types.hpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ struct realm_sync_socket_callback : realm::c_api::WrapC,
870870
}
871871
};
872872

873-
struct CBindingThreadObserver : public realm::BindingCallbackThreadObserver {
873+
struct CBindingThreadObserver final : public realm::BindingCallbackThreadObserver {
874874
public:
875875
CBindingThreadObserver(realm_on_object_store_thread_callback_t on_thread_create,
876876
realm_on_object_store_thread_callback_t on_thread_destroy,
@@ -882,14 +882,11 @@ struct CBindingThreadObserver : public realm::BindingCallbackThreadObserver {
882882
, m_user_data{userdata, [&free_userdata] {
883883
if (free_userdata)
884884
return free_userdata;
885-
else
886-
return CBindingThreadObserver::m_default_free_userdata;
885+
return CBindingThreadObserver::m_default_free_userdata;
887886
}()}
888887
{
889888
}
890889

891-
virtual ~CBindingThreadObserver() = default;
892-
893890
void did_create_thread() override
894891
{
895892
if (m_create_callback_func)
@@ -918,25 +915,25 @@ struct CBindingThreadObserver : public realm::BindingCallbackThreadObserver {
918915
/// {@
919916
/// For testing: Return the values in this CBindingThreadObserver for comparing if two objects
920917
/// have the same callback functions and userdata ptr values.
921-
inline realm_on_object_store_thread_callback_t test_get_create_callback_func() const noexcept
918+
realm_on_object_store_thread_callback_t test_get_create_callback_func() const noexcept
922919
{
923920
return m_create_callback_func;
924921
}
925-
inline realm_on_object_store_thread_callback_t test_get_destroy_callback_func() const noexcept
922+
realm_on_object_store_thread_callback_t test_get_destroy_callback_func() const noexcept
926923
{
927924
return m_destroy_callback_func;
928925
}
929-
inline realm_on_object_store_error_callback_t test_get_error_callback_func() const noexcept
926+
realm_on_object_store_error_callback_t test_get_error_callback_func() const noexcept
930927
{
931928
return m_error_callback_func;
932929
}
933-
inline realm_userdata_t test_get_userdata_ptr() const noexcept
930+
realm_userdata_t test_get_userdata_ptr() const noexcept
934931
{
935932
return m_user_data.get();
936933
}
937934
/// @}
938935

939-
protected:
936+
private:
940937
CBindingThreadObserver() = default;
941938

942939
static constexpr realm_free_userdata_func_t m_default_free_userdata = [](realm_userdata_t) {};

src/realm/object-store/sync/impl/sync_client.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ struct SyncClient {
123123
std::unique_ptr<sync::Session> make_session(std::shared_ptr<DB> db,
124124
std::shared_ptr<sync::SubscriptionStore> flx_sub_store,
125125
std::shared_ptr<sync::MigrationStore> migration_store,
126-
sync::Session::Config config)
126+
sync::Session::Config&& config)
127127
{
128128
return std::make_unique<sync::Session>(m_client, std::move(db), std::move(flx_sub_store),
129129
std::move(migration_store), std::move(config));

src/realm/object-store/sync/sync_session.cpp

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,7 @@ void SyncSession::become_active()
108108
}
109109

110110
// when entering from the Dying state the session will still be bound
111-
if (!m_session) {
112-
create_sync_session();
113-
m_session->bind();
114-
}
111+
create_sync_session();
115112

116113
// Register all the pending wait-for-completion blocks. This can
117114
// potentially add a redundant callback if we're coming from the Dying
@@ -896,6 +893,8 @@ void SyncSession::create_sync_session()
896893
SyncConfig& sync_config = *m_config.sync_config;
897894
REALM_ASSERT(sync_config.user);
898895

896+
std::weak_ptr<SyncSession> weak_self = weak_from_this();
897+
899898
sync::Session::Config session_config;
900899
session_config.signed_user_token = sync_config.user->access_token();
901900
session_config.user_id = sync_config.user->user_id();
@@ -912,8 +911,8 @@ void SyncSession::create_sync_session()
912911

913912
if (sync_config.on_sync_client_event_hook) {
914913
session_config.on_sync_client_event_hook = [hook = sync_config.on_sync_client_event_hook,
915-
anchor = weak_from_this()](const SyncClientHookData& data) {
916-
return hook(anchor, data);
914+
weak_self](const SyncClientHookData& data) {
915+
return hook(weak_self, data);
917916
};
918917
}
919918

@@ -954,46 +953,41 @@ void SyncSession::create_sync_session()
954953
m_server_requests_action = sync::ProtocolErrorInfo::Action::NoAction;
955954
}
956955

957-
m_session = m_client.make_session(m_db, m_flx_subscription_store, m_migration_store, std::move(session_config));
958-
959-
std::weak_ptr<SyncSession> weak_self = weak_from_this();
960-
961-
// Set up the wrapped progress handler callback
962-
m_session->set_progress_handler([weak_self](uint_fast64_t downloaded, uint_fast64_t downloadable,
963-
uint_fast64_t uploaded, uint_fast64_t uploadable,
964-
uint_fast64_t snapshot_version, double download_estimate,
965-
double upload_estimate, int64_t query_version) {
956+
session_config.progress_handler = [weak_self](uint_fast64_t downloaded, uint_fast64_t downloadable,
957+
uint_fast64_t uploaded, uint_fast64_t uploadable,
958+
uint_fast64_t snapshot_version, double download_estimate,
959+
double upload_estimate, int64_t query_version) {
966960
if (auto self = weak_self.lock()) {
967961
self->handle_progress_update(downloaded, downloadable, uploaded, uploadable, snapshot_version,
968962
download_estimate, upload_estimate, query_version);
969963
}
970-
});
964+
};
971965

972-
// Sets up the connection state listener. This callback is used for both reporting errors as well as changes to
973-
// the connection state.
974-
m_session->set_connection_state_change_listener(
975-
[weak_self](sync::ConnectionState state, std::optional<sync::SessionErrorInfo> error) {
976-
using cs = sync::ConnectionState;
977-
ConnectionState new_state = [&] {
978-
switch (state) {
979-
case cs::disconnected:
980-
return ConnectionState::Disconnected;
981-
case cs::connecting:
982-
return ConnectionState::Connecting;
983-
case cs::connected:
984-
return ConnectionState::Connected;
985-
}
986-
REALM_UNREACHABLE();
987-
}();
988-
// If the OS SyncSession object is destroyed, we ignore any events from the underlying Session as there is
989-
// nothing useful we can do with them.
990-
if (auto self = weak_self.lock()) {
991-
self->update_connection_state(new_state);
992-
if (error) {
993-
self->handle_error(std::move(*error));
994-
}
966+
session_config.connection_state_change_listener = [weak_self](sync::ConnectionState state,
967+
std::optional<sync::SessionErrorInfo> error) {
968+
using cs = sync::ConnectionState;
969+
ConnectionState new_state = [&] {
970+
switch (state) {
971+
case cs::disconnected:
972+
return ConnectionState::Disconnected;
973+
case cs::connecting:
974+
return ConnectionState::Connecting;
975+
case cs::connected:
976+
return ConnectionState::Connected;
995977
}
996-
});
978+
REALM_UNREACHABLE();
979+
}();
980+
// If the OS SyncSession object is destroyed, we ignore any events from the underlying Session as there is
981+
// nothing useful we can do with them.
982+
if (auto self = weak_self.lock()) {
983+
self->update_connection_state(new_state);
984+
if (error) {
985+
self->handle_error(std::move(*error));
986+
}
987+
}
988+
};
989+
990+
m_session = m_client.make_session(m_db, m_flx_subscription_store, m_migration_store, std::move(session_config));
997991
}
998992

999993
void SyncSession::update_connection_state(ConnectionState new_state)

src/realm/sync/binding_callback_thread_observer.hpp

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,78 +20,31 @@
2020
#define REALM_OS_BINDING_CALLBACK_THREAD_OBSERVER_HPP
2121

2222
#include <exception>
23-
#include <functional>
24-
#include <optional>
25-
2623

2724
namespace realm {
28-
// Interface for bindings interested in registering callbacks before/after the ObjectStore thread runs.
29-
// This is for example helpful to attach/detach the pthread to the JavaVM in order to be able to perform JNI calls.
25+
// Interface for observing the lifecycle of the worker thread used by
26+
// DefaultSocketProvider. This is required to be able to attach/detach the thread
27+
// to the JVM to be able to perform JNI calls.
3028
struct BindingCallbackThreadObserver {
31-
using NotificationCallback = std::function<void()>;
32-
using ErrorCallback = std::function<bool(const std::exception&)>;
33-
34-
// Create a BindingCallbackThreadObserver that can be used in SyncClientConfig
35-
BindingCallbackThreadObserver(std::optional<NotificationCallback>&& did_create_thread,
36-
std::optional<NotificationCallback>&& will_destroy_thread,
37-
std::optional<ErrorCallback>&& error_handler)
38-
: m_create_thread_callback{std::move(did_create_thread)}
39-
, m_destroy_thread_callback{std::move(will_destroy_thread)}
40-
, m_handle_error_callback{std::move(error_handler)}
41-
{
42-
}
43-
4429
virtual ~BindingCallbackThreadObserver() = default;
4530

46-
///
47-
/// Execution Functions - check for a valid instance and if the function was set
48-
///
49-
50-
// Call the stored create thread callback function with the id of this thread
51-
// Can be overridden to provide a custom implementation
52-
virtual void did_create_thread()
53-
{
54-
if (m_create_thread_callback) {
55-
(*m_create_thread_callback)();
56-
}
57-
}
58-
59-
// Call the stored destroy thread callback function with the id of this thread
60-
// Can be overridden to provide a custom implementation
61-
virtual void will_destroy_thread()
62-
{
63-
if (m_destroy_thread_callback) {
64-
(*m_destroy_thread_callback)();
65-
}
66-
}
67-
68-
// Call the stored handle error callback function with the id of this thread
69-
// IMPORTANT: If a function is supplied that handles the exception, it must
70-
// call abort() or cause the application to crash since the SyncClient will
71-
// be in a bad state if this occurs and will not be able to shut down properly.
72-
// Can be overridden to provide a custom implementation
73-
// Return true if the exception was handled by this function, otherwise false
74-
virtual bool handle_error(const std::exception& e)
31+
// Called on the thread shortly after it is created. This is guaranteed to
32+
// be called before any other callbacks to the SDK are made.
33+
virtual void did_create_thread() {}
34+
// Called on the thread shortly before it is destroyed. No further callbacks
35+
// to the SDK on the thread will be made after this is called.
36+
virtual void will_destroy_thread() {}
37+
// If has_handle_error() returns true, any uncaught exceptions from the
38+
// event loop are passed to this. If this returns true, the thread exits
39+
// cleanly, while if it returns false the exception is rethrown.
40+
virtual bool handle_error(const std::exception&)
7541
{
76-
if (!m_handle_error_callback)
77-
return false;
78-
79-
return (*m_handle_error_callback)(e);
42+
return false;
8043
}
81-
82-
// Return true if this event loop observer has a handle error callback defined
8344
virtual bool has_handle_error()
8445
{
85-
return bool(m_handle_error_callback);
46+
return false;
8647
}
87-
88-
protected:
89-
// Default constructor
90-
BindingCallbackThreadObserver() = default;
91-
92-
std::optional<NotificationCallback> m_create_thread_callback;
93-
std::optional<NotificationCallback> m_destroy_thread_callback;
94-
std::optional<ErrorCallback> m_handle_error_callback;
9548
};
9649

9750
} // namespace realm

0 commit comments

Comments
 (0)