1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2016 Realm Inc.
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 ////////////////////////////////////////////////////////////////////////////
19 #include "thread_safe_reference.hpp"
21 #include "impl/realm_coordinator.hpp"
24 #include "object_schema.hpp"
25 #include "results.hpp"
27 #include <realm/util/scope_exit.hpp>
29 using namespace realm;
31 ThreadSafeReferenceBase::ThreadSafeReferenceBase(SharedRealm source_realm) : m_source_realm(std::move(source_realm))
33 m_source_realm->verify_thread();
34 if (m_source_realm->is_in_transaction()) {
35 throw InvalidTransactionException("Cannot obtain thread safe reference during a write transaction.");
39 m_version_id = get_source_shared_group().pin_version();
46 ThreadSafeReferenceBase::~ThreadSafeReferenceBase()
48 if (!is_invalidated())
52 template <typename V, typename T>
53 V ThreadSafeReferenceBase::invalidate_after_import(Realm& destination_realm, T construct_with_shared_group) {
54 destination_realm.verify_thread();
55 REALM_ASSERT_DEBUG(!m_source_realm->is_in_transaction());
56 REALM_ASSERT_DEBUG(!is_invalidated());
58 SharedGroup& destination_shared_group = *Realm::Internal::get_shared_group(destination_realm);
59 auto unpin_version = util::make_scope_exit([&]() noexcept { invalidate(); });
61 return construct_with_shared_group(destination_shared_group);
64 SharedGroup& ThreadSafeReferenceBase::get_source_shared_group() const {
65 return *Realm::Internal::get_shared_group(*m_source_realm);
68 bool ThreadSafeReferenceBase::has_same_config(Realm& realm) const {
69 return &Realm::Internal::get_coordinator(*m_source_realm) == &Realm::Internal::get_coordinator(realm);
72 void ThreadSafeReferenceBase::invalidate() {
73 REALM_ASSERT_DEBUG(m_source_realm);
74 SharedRealm thread_local_realm = Realm::Internal::get_coordinator(*m_source_realm).get_realm();
75 Realm::Internal::get_shared_group(*thread_local_realm)->unpin_version(m_version_id);
76 m_source_realm = nullptr;
79 ThreadSafeReference<List>::ThreadSafeReference(List const& list)
80 : ThreadSafeReferenceBase(list.get_realm())
81 , m_link_view(get_source_shared_group().export_linkview_for_handover(list.m_link_view))
82 , m_table(get_source_shared_group().export_table_for_handover(list.m_table))
85 List ThreadSafeReference<List>::import_into_realm(SharedRealm realm) && {
86 return invalidate_after_import<List>(*realm, [&](SharedGroup& shared_group) {
87 if (auto link_view = shared_group.import_linkview_from_handover(std::move(m_link_view)))
88 return List(std::move(realm), std::move(link_view));
89 return List(std::move(realm), shared_group.import_table_from_handover(std::move(m_table)));
93 ThreadSafeReference<Object>::ThreadSafeReference(Object const& object)
94 : ThreadSafeReferenceBase(object.realm())
95 , m_row(get_source_shared_group().export_for_handover(Row(object.row())))
96 , m_object_schema_name(object.get_object_schema().name) { }
98 Object ThreadSafeReference<Object>::import_into_realm(SharedRealm realm) && {
99 return invalidate_after_import<Object>(*realm, [&](SharedGroup& shared_group) {
100 Row row = *shared_group.import_from_handover(std::move(m_row));
101 auto object_schema = realm->schema().find(m_object_schema_name);
102 REALM_ASSERT_DEBUG(object_schema != realm->schema().end());
103 return Object(std::move(realm), *object_schema, row);
107 ThreadSafeReference<Results>::ThreadSafeReference(Results const& results)
108 : ThreadSafeReferenceBase(results.get_realm())
109 , m_query(get_source_shared_group().export_for_handover(results.get_query(), ConstSourcePayload::Copy))
110 , m_ordering_patch([&]() {
111 DescriptorOrdering::HandoverPatch ordering_patch;
112 DescriptorOrdering::generate_patch(results.get_descriptor_ordering(), ordering_patch);
113 return ordering_patch;
116 Results ThreadSafeReference<Results>::import_into_realm(SharedRealm realm) && {
117 return invalidate_after_import<Results>(*realm, [&](SharedGroup& shared_group) {
118 Query query = *shared_group.import_from_handover(std::move(m_query));
119 Table& table = *query.get_table();
120 DescriptorOrdering descriptors = DescriptorOrdering::create_from_and_consume_patch(m_ordering_patch, table);
121 return Results(std::move(realm), std::move(query), std::move(descriptors));