• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / nicola.cabiddu_1042

27 Sep 2023 06:04PM UTC coverage: 91.085% (-1.8%) from 92.915%
nicola.cabiddu_1042

Pull #6766

Evergreen

nicola-cab
Fix logic for dictionaries
Pull Request #6766: Client Reset for collections in mixed / nested collections

97276 of 178892 branches covered (0.0%)

1994 of 2029 new or added lines in 7 files covered. (98.28%)

4556 existing lines in 112 files now uncovered.

237059 of 260260 relevant lines covered (91.09%)

6321099.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.06
/src/realm/object-store/thread_safe_reference.cpp
1
////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2016 Realm Inc.
4
//
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
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
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.
16
//
17
////////////////////////////////////////////////////////////////////////////
18

19
#include <realm/object-store/thread_safe_reference.hpp>
20

21
#include <realm/object-store/list.hpp>
22
#include <realm/object-store/set.hpp>
23
#include <realm/object-store/dictionary.hpp>
24
#include <realm/object-store/object.hpp>
25
#include <realm/object-store/object_schema.hpp>
26
#include <realm/object-store/results.hpp>
27
#include <realm/object-store/shared_realm.hpp>
28

29
#include "impl/realm_coordinator.hpp"
30

31
#include <realm/db.hpp>
32
#include <realm/keys.hpp>
33

34
namespace realm {
35

36
using OsDict = object_store::Dictionary;
37

38
class ThreadSafeReference::Payload {
39
public:
40
    virtual ~Payload() = default;
510✔
41
    Payload(Realm& realm)
42
        : m_source_version(realm.current_transaction_version())
43
        , m_created_in_write_transaction(realm.is_in_transaction())
44
    {
510✔
45
    }
510✔
46

47
    void refresh_target_realm(Realm&);
48

49
private:
50
    const util::Optional<VersionID> m_source_version;
51
    const bool m_created_in_write_transaction;
52
};
53

54
void ThreadSafeReference::Payload::refresh_target_realm(Realm& realm)
55
{
330✔
56
    if (!m_source_version)
330✔
57
        return;
×
58
    if (!realm.is_in_read_transaction()) {
330✔
59
        try {
70✔
60
            // If the TSR was created in a write transaction then we want to
35✔
61
            // resolve it at the version created by committing that transaction.
35✔
62
            // That's not possible, so we just use latest.
35✔
63
            if (!m_created_in_write_transaction) {
70✔
64
                Realm::Internal::begin_read(realm, *m_source_version);
44✔
65
                return;
44✔
66
            }
44✔
67
        }
8✔
68
        catch (const DB::BadVersion&) {
8✔
69
            // The TSR's source version was cleaned up, so just use the latest
4✔
70
        }
8✔
71
        realm.read_group();
52✔
72
    }
34✔
73
    else {
260✔
74
        auto version = realm.read_transaction_version();
260✔
75
        if (version < m_source_version || (version == m_source_version && m_created_in_write_transaction))
260✔
76
            realm.refresh();
2✔
77
    }
260✔
78
}
330✔
79

80
template <typename Collection>
81
class ThreadSafeReference::CollectionPayload : public ThreadSafeReference::Payload {
82
public:
83
    CollectionPayload(object_store::Collection const& collection)
84
        : Payload(*collection.get_realm())
85
        , m_key(collection.get_parent_object_key())
86
        , m_table_key(collection.get_parent_table_key())
87
        , m_col_key(collection.get_parent_column_key())
88
    {
152✔
89
    }
152✔
90

91
    Collection import_into(std::shared_ptr<Realm> const& r)
92
    {
130✔
93
        Obj obj = r->read_group().get_table(m_table_key)->get_object(m_key);
130✔
94
        return Collection(r, obj, m_col_key);
130✔
95
    }
130✔
96

97
private:
98
    ObjKey m_key;
99
    TableKey m_table_key;
100
    ColKey m_col_key;
101
};
102

103
template <>
104
class ThreadSafeReference::PayloadImpl<List> : public ThreadSafeReference::CollectionPayload<List> {
105
public:
106
    using ThreadSafeReference::CollectionPayload<List>::CollectionPayload;
107
};
108

109
template <>
110
class ThreadSafeReference::PayloadImpl<object_store::Set>
111
    : public ThreadSafeReference::CollectionPayload<object_store::Set> {
112
public:
113
    using ThreadSafeReference::CollectionPayload<object_store::Set>::CollectionPayload;
114
};
115

116
template <>
117
class ThreadSafeReference::PayloadImpl<OsDict> : public ThreadSafeReference::CollectionPayload<OsDict> {
118
public:
119
    using ThreadSafeReference::CollectionPayload<OsDict>::CollectionPayload;
120
};
121

122
template <>
123
class ThreadSafeReference::PayloadImpl<Object> : public ThreadSafeReference::Payload {
124
public:
125
    PayloadImpl(Object const& object)
126
        : Payload(*object.get_realm())
127
        , m_key(object.get_obj().get_key())
128
        , m_object_schema_name(object.get_object_schema().name)
129
    {
56✔
130
    }
56✔
131

132
    Object import_into(std::shared_ptr<Realm> const& r)
133
    {
46✔
134
        return Object(r, m_object_schema_name, m_key);
46✔
135
    }
46✔
136

137
private:
138
    ObjKey m_key;
139
    std::string m_object_schema_name;
140
};
141

142
template <>
143
class ThreadSafeReference::PayloadImpl<Results> : public ThreadSafeReference::Payload {
144
public:
145
    PayloadImpl(Results const& r)
146
        : Payload(*r.get_realm())
147
        , m_coordinator(Realm::Internal::get_coordinator(*r.get_realm()).shared_from_this())
148
        , m_ordering(r.get_descriptor_ordering())
149
    {
126✔
150
        if (r.get_type() != PropertyType::Object) {
126✔
151
            auto list = r.get_collection();
96✔
152
            REALM_ASSERT(list);
96✔
153
            m_key = list->get_owner_key();
96✔
154
            m_table_key = list->get_table()->get_key();
96✔
155
            // FIXME: Use path for list when supporting notifications for nested collections
48✔
156
            m_col_key = list->get_col_key();
96✔
157
        }
96✔
158
        else {
30✔
159
            Query q(r.get_query());
30✔
160
            m_transaction = r.get_realm()->duplicate();
30✔
161
            m_query = m_transaction->import_copy_of(q, PayloadPolicy::Stay);
30✔
162
            // If the Query is derived from a collection which was created in
15✔
163
            // the current write transaction then the collection cannot be
15✔
164
            // handed over and would just be empty when resolved.
15✔
165
            if (q.view_owner_obj_key() != m_query->view_owner_obj_key()) {
30✔
166
                throw WrongTransactionState(
4✔
167
                    "Cannot create a ThreadSafeReference to Results backed by a collection of objects "
4✔
168
                    "inside the write transaction which created the collection.");
4✔
169
            }
4✔
170
        }
30✔
171
    }
126✔
172

173
    Results import_into(std::shared_ptr<Realm> const& r)
174
    {
154✔
175
        if (m_key) {
154✔
176
            CollectionBasePtr collection;
138✔
177
            auto table = r->read_group().get_table(m_table_key);
138✔
178
            try {
138✔
179
                collection = table->get_object(m_key).get_collection_ptr(m_col_key);
138✔
180
            }
138✔
181
            catch (KeyNotFound const&) {
91✔
182
                // Create a detached list of the appropriate type so that we
22✔
183
                // return an invalid Results rather than an Empty Results, to
22✔
184
                // match what happens for other types of handover where the
22✔
185
                // object doesn't exist.
22✔
186
                if (m_col_key.is_dictionary()) {
44✔
187
                    collection = std::make_unique<Dictionary>();
42✔
188
                }
42✔
189
                else {
2✔
190
                    switch_on_type(ObjectSchema::from_core_type(m_col_key), [&](auto* t) -> void {
2✔
191
                        if (m_col_key.is_list()) {
2!
192
                            collection = std::make_unique<Lst<NonObjTypeT<decltype(*t)>>>();
2✔
193
                        }
2✔
194
                        else if (m_col_key.is_set()) {
×
195
                            collection = std::make_unique<Set<NonObjTypeT<decltype(*t)>>>();
×
UNCOV
196
                        }
×
197
                    });
2✔
198
                }
2✔
199
            }
44✔
200
            return Results(r, std::move(collection), m_ordering);
138✔
201
        }
16✔
202
        auto q = r->import_copy_of(*m_query, PayloadPolicy::Stay);
16✔
203
        return Results(std::move(r), std::move(*q), m_ordering);
16✔
204
    }
16✔
205

206
private:
207
    const std::shared_ptr<_impl::RealmCoordinator> m_coordinator;
208
    TransactionRef m_transaction;
209
    DescriptorOrdering m_ordering;
210
    std::unique_ptr<Query> m_query;
211
    ObjKey m_key;
212
    TableKey m_table_key;
213
    ColKey m_col_key;
214
};
215

216
template <>
217
class ThreadSafeReference::PayloadImpl<std::shared_ptr<Realm>> : public ThreadSafeReference::Payload {
218
public:
219
    PayloadImpl(std::shared_ptr<Realm> const& realm)
220
        : Payload(*realm)
221
        , m_realm(realm)
222
    {
176✔
223
    }
176✔
224

225
    std::shared_ptr<Realm> get_realm()
226
    {
138✔
227
        return std::move(m_realm);
138✔
228
    }
138✔
229

230
private:
231
    std::shared_ptr<Realm> m_realm;
232
};
233

234
ThreadSafeReference::ThreadSafeReference() noexcept = default;
174✔
235
ThreadSafeReference::~ThreadSafeReference() = default;
1,184✔
236
ThreadSafeReference::ThreadSafeReference(ThreadSafeReference&&) noexcept = default;
504✔
237
ThreadSafeReference& ThreadSafeReference::operator=(ThreadSafeReference&&) noexcept = default;
154✔
238

239
template <typename T>
240
ThreadSafeReference::ThreadSafeReference(T const& value)
241
{
334✔
242
    auto realm = value.get_realm();
334✔
243
    realm->verify_thread();
334✔
244
    m_payload.reset(new PayloadImpl<T>(value));
334✔
245
}
334✔
246

247
template <>
248
ThreadSafeReference::ThreadSafeReference(std::shared_ptr<Realm> const& value)
249
{
176✔
250
    m_payload.reset(new PayloadImpl<std::shared_ptr<Realm>>(value));
176✔
251
}
176✔
252

253
template ThreadSafeReference::ThreadSafeReference(List const&);
254
template ThreadSafeReference::ThreadSafeReference(object_store::Set const&);
255
template ThreadSafeReference::ThreadSafeReference(OsDict const&);
256
template ThreadSafeReference::ThreadSafeReference(Results const&);
257
template ThreadSafeReference::ThreadSafeReference(Object const&);
258

259
template <typename T>
260
T ThreadSafeReference::resolve(std::shared_ptr<Realm> const& realm)
261
{
330✔
262
    REALM_ASSERT(realm);
330✔
263
    realm->verify_thread();
330✔
264

165✔
265
    REALM_ASSERT(m_payload);
330✔
266
    auto& payload = static_cast<PayloadImpl<T>&>(*m_payload);
330✔
267
    REALM_ASSERT(typeid(payload) == typeid(PayloadImpl<T>));
330✔
268

165✔
269
    m_payload->refresh_target_realm(*realm);
330✔
270
    try {
330✔
271
        return payload.import_into(realm);
330✔
272
    }
330✔
273
    catch (KeyNotFound const&) {
14✔
274
        // Object was deleted in a version after when the TSR was created
7✔
275
        return {};
14✔
276
    }
14✔
277
}
330✔
278

279
template <>
280
std::shared_ptr<Realm> ThreadSafeReference::resolve<std::shared_ptr<Realm>>(std::shared_ptr<Realm> const&)
281
{
138✔
282
    REALM_ASSERT(m_payload);
138✔
283
    auto& payload = static_cast<PayloadImpl<std::shared_ptr<Realm>>&>(*m_payload);
138✔
284
    REALM_ASSERT(typeid(payload) == typeid(PayloadImpl<std::shared_ptr<Realm>>));
138✔
285

69✔
286
    return payload.get_realm();
138✔
287
}
138✔
288

289
template <typename T>
290
bool ThreadSafeReference::is() const
291
{
4✔
292
    return dynamic_cast<PayloadImpl<T>*>(m_payload.get()) != nullptr;
4✔
293
}
4✔
294

295
template Results ThreadSafeReference::resolve<Results>(std::shared_ptr<Realm> const&);
296
template List ThreadSafeReference::resolve<List>(std::shared_ptr<Realm> const&);
297
template object_store::Set ThreadSafeReference::resolve<object_store::Set>(std::shared_ptr<Realm> const&);
298
template OsDict ThreadSafeReference::resolve<OsDict>(std::shared_ptr<Realm> const&);
299
template Object ThreadSafeReference::resolve<Object>(std::shared_ptr<Realm> const&);
300

301
template bool ThreadSafeReference::is<std::shared_ptr<Realm>>() const;
302
template bool ThreadSafeReference::is<Results>() const;
303
template bool ThreadSafeReference::is<List>() const;
304
template bool ThreadSafeReference::is<object_store::Set>() const;
305
template bool ThreadSafeReference::is<OsDict>() const;
306
template bool ThreadSafeReference::is<Object>() const;
307

308
} // namespace realm
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc