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

realm / realm-core / github_pull_request_281750

30 Oct 2023 03:37PM UTC coverage: 90.528% (-1.0%) from 91.571%
github_pull_request_281750

Pull #6073

Evergreen

jedelbo
Log free space and history sizes when opening file
Pull Request #6073: Merge next-major

95488 of 175952 branches covered (0.0%)

8973 of 12277 new or added lines in 149 files covered. (73.09%)

622 existing lines in 51 files now uncovered.

233503 of 257934 relevant lines covered (90.53%)

6533720.56 hits per line

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

83.15
/src/realm/collection_parent.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2023 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/collection_parent.hpp>
20
#include "realm/list.hpp"
21
#include "realm/set.hpp"
22
#include "realm/dictionary.hpp"
23
#include "realm/util/overload.hpp"
24

25
#include <random>
26
#include <mutex>
27

28
namespace realm {
29

30
std::ostream& operator<<(std::ostream& ostr, const PathElement& elem)
31
{
33,831✔
32
    if (elem.is_ndx()) {
33,831✔
33
        size_t ndx = elem.get_ndx();
1,086✔
34
        if (ndx == 0) {
1,086✔
35
            ostr << "FIRST";
378✔
36
        }
378✔
37
        else if (ndx == size_t(-1)) {
708✔
38
            ostr << "LAST";
330✔
39
        }
330✔
40
        else {
378✔
41
            ostr << elem.get_ndx();
378✔
42
        }
378✔
43
    }
1,086✔
44
    else if (elem.is_col_key()) {
32,745✔
NEW
45
        ostr << elem.get_col_key();
×
NEW
46
    }
×
47
    else if (elem.is_key()) {
32,745✔
48
        ostr << "'" << elem.get_key() << "'";
32,631✔
49
    }
32,631✔
50
    else if (elem.is_all()) {
114✔
51
        ostr << '*';
114✔
52
    }
114✔
53

16,917✔
54
    return ostr;
33,831✔
55
}
33,831✔
56

57
std::ostream& operator<<(std::ostream& ostr, const Path& path)
58
{
33,183✔
59
    for (auto& elem : path) {
32,979✔
60
        ostr << '[' << elem << ']';
32,775✔
61
    }
32,775✔
62
    return ostr;
33,183✔
63
}
33,183✔
64

65
/***************************** CollectionParent ******************************/
66

67
CollectionParent::~CollectionParent() {}
179,295,888✔
68

69
void CollectionParent::check_level() const
70
{
708✔
71
    if (m_level + 1 > s_max_level) {
708✔
72
        throw LogicError(ErrorCodes::LimitExceeded, "Max nesting level reached");
6✔
73
    }
6✔
74
}
708✔
75
void CollectionParent::set_backlink(ColKey col_key, ObjLink new_link) const
76
{
6,772,026✔
77
    if (new_link && new_link.get_obj_key()) {
6,772,026✔
78
        auto t = get_table();
6,730,173✔
79
        auto target_table = t->get_parent_group()->get_table(new_link.get_table_key());
6,730,173✔
80
        ColKey backlink_col_key;
6,730,173✔
81
        auto type = col_key.get_type();
6,730,173✔
82
        if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
6,730,416✔
83
            // This may modify the target table
14,928✔
84
            backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
30,072✔
85
            // it is possible that this was a link to the same table and that adding a backlink column has
14,928✔
86
            // caused the need to update this object as well.
14,928✔
87
            update_if_needed();
30,072✔
88
        }
30,072✔
89
        else {
6,700,101✔
90
            backlink_col_key = t->get_opposite_column(col_key);
6,700,101✔
91
        }
6,700,101✔
92
        auto obj_key = new_link.get_obj_key();
6,730,173✔
93
        auto target_obj = obj_key.is_unresolved() ? target_table->try_get_tombstone(obj_key)
3,369,453✔
94
                                                  : target_table->try_get_object(obj_key);
6,725,232✔
95
        if (!target_obj) {
6,730,173✔
96
            throw InvalidArgument(ErrorCodes::KeyNotFound, "Target object not found");
12✔
97
        }
12✔
98
        target_obj.add_backlink(backlink_col_key, get_object().get_key());
6,730,161✔
99
    }
6,730,161✔
100
}
6,772,026✔
101

102
bool CollectionParent::replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const
103
{
337,476✔
104
    bool recurse = remove_backlink(col_key, old_link, state);
337,476✔
105
    set_backlink(col_key, new_link);
337,476✔
106

168,585✔
107
    return recurse;
337,476✔
108
}
337,476✔
109

110
bool CollectionParent::remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const
111
{
356,070✔
112
    if (old_link && old_link.get_obj_key()) {
356,070✔
113
        auto t = get_table();
133,296✔
114
        REALM_ASSERT(t->valid_column(col_key));
133,296✔
115
        ObjKey old_key = old_link.get_obj_key();
133,296✔
116
        auto target_obj = t->get_parent_group()->get_object(old_link);
133,296✔
117
        TableRef target_table = target_obj.get_table();
133,296✔
118
        ColKey backlink_col_key;
133,296✔
119
        auto type = col_key.get_type();
133,296✔
120
        if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
133,296✔
121
            backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
11,370✔
122
        }
11,370✔
123
        else {
121,926✔
124
            backlink_col_key = t->get_opposite_column(col_key);
121,926✔
125
        }
121,926✔
126

66,642✔
127
        bool strong_links = target_table->is_embedded();
133,296✔
128
        bool is_unres = old_key.is_unresolved();
133,296✔
129

66,642✔
130
        bool last_removed = target_obj.remove_one_backlink(backlink_col_key, get_object().get_key()); // Throws
133,296✔
131
        if (is_unres) {
133,296✔
132
            if (last_removed) {
9,252✔
133
                // Check is there are more backlinks
4,611✔
134
                if (!target_obj.has_backlinks(false)) {
9,222✔
135
                    // Tombstones can be erased right away - there is no cascading effect
4,605✔
136
                    target_table->m_tombstones->erase(old_key, state);
9,210✔
137
                }
9,210✔
138
            }
9,222✔
139
        }
9,252✔
140
        else {
124,044✔
141
            return state.enqueue_for_cascade(target_obj, strong_links, last_removed);
124,044✔
142
        }
124,044✔
143
    }
232,026✔
144

115,857✔
145
    return false;
232,026✔
146
}
232,026✔
147

148
LstBasePtr CollectionParent::get_listbase_ptr(ColKey col_key) const
149
{
336,600✔
150
    auto table = get_table();
336,600✔
151
    auto attr = table->get_column_attr(col_key);
336,600✔
152
    REALM_ASSERT(attr.test(col_attr_List) || attr.test(col_attr_Nullable));
336,600✔
153
    bool nullable = attr.test(col_attr_Nullable);
336,600✔
154

170,088✔
155
    switch (table->get_column_type(col_key)) {
336,600✔
156
        case type_Int: {
41,004✔
157
            if (nullable)
41,004✔
158
                return std::make_unique<Lst<util::Optional<Int>>>(col_key);
1,959✔
159
            else
39,045✔
160
                return std::make_unique<Lst<Int>>(col_key);
39,045✔
NEW
161
        }
×
162
        case type_Bool: {
3,360✔
163
            if (nullable)
3,360✔
164
                return std::make_unique<Lst<util::Optional<Bool>>>(col_key);
1,704✔
165
            else
1,656✔
166
                return std::make_unique<Lst<Bool>>(col_key);
1,656✔
NEW
167
        }
×
168
        case type_Float: {
3,384✔
169
            if (nullable)
3,384✔
170
                return std::make_unique<Lst<util::Optional<Float>>>(col_key);
1,734✔
171
            else
1,650✔
172
                return std::make_unique<Lst<Float>>(col_key);
1,650✔
NEW
173
        }
×
174
        case type_Double: {
3,450✔
175
            if (nullable)
3,450✔
176
                return std::make_unique<Lst<util::Optional<Double>>>(col_key);
1,734✔
177
            else
1,716✔
178
                return std::make_unique<Lst<Double>>(col_key);
1,716✔
NEW
179
        }
×
180
        case type_String: {
232,596✔
181
            return std::make_unique<Lst<String>>(col_key);
232,596✔
NEW
182
        }
×
183
        case type_Binary: {
3,354✔
184
            return std::make_unique<Lst<Binary>>(col_key);
3,354✔
NEW
185
        }
×
186
        case type_Timestamp: {
3,378✔
187
            return std::make_unique<Lst<Timestamp>>(col_key);
3,378✔
NEW
188
        }
×
189
        case type_Decimal: {
3,366✔
190
            return std::make_unique<Lst<Decimal128>>(col_key);
3,366✔
NEW
191
        }
×
192
        case type_ObjectId: {
3,426✔
193
            if (nullable)
3,426✔
194
                return std::make_unique<Lst<util::Optional<ObjectId>>>(col_key);
1,752✔
195
            else
1,674✔
196
                return std::make_unique<Lst<ObjectId>>(col_key);
1,674✔
NEW
197
        }
×
198
        case type_UUID: {
3,402✔
199
            if (nullable)
3,402✔
200
                return std::make_unique<Lst<util::Optional<UUID>>>(col_key);
1,740✔
201
            else
1,662✔
202
                return std::make_unique<Lst<UUID>>(col_key);
1,662✔
NEW
203
        }
×
NEW
204
        case type_TypedLink: {
✔
NEW
205
            return std::make_unique<Lst<ObjLink>>(col_key);
×
NEW
206
        }
×
207
        case type_Mixed: {
4,614✔
208
            return std::make_unique<Lst<Mixed>>(col_key, get_level() + 1);
4,614✔
NEW
209
        }
×
210
        case type_LinkList:
31,266✔
211
            return std::make_unique<LnkLst>(col_key);
31,266✔
NEW
212
        case type_Link:
✔
NEW
213
            break;
×
NEW
214
    }
×
NEW
215
    REALM_TERMINATE("Unsupported column type");
×
NEW
216
}
×
217

218
SetBasePtr CollectionParent::get_setbase_ptr(ColKey col_key) const
219
{
116,946✔
220
    auto table = get_table();
116,946✔
221
    auto attr = table->get_column_attr(col_key);
116,946✔
222
    REALM_ASSERT(attr.test(col_attr_Set));
116,946✔
223
    bool nullable = attr.test(col_attr_Nullable);
116,946✔
224

58,302✔
225
    switch (table->get_column_type(col_key)) {
116,946✔
226
        case type_Int: {
7,938✔
227
            if (nullable)
7,938✔
228
                return std::make_unique<Set<util::Optional<Int>>>(col_key);
3,663✔
229
            else
4,275✔
230
                return std::make_unique<Set<Int>>(col_key);
4,275✔
NEW
231
        }
×
232
        case type_Bool: {
5,904✔
233
            if (nullable)
5,904✔
234
                return std::make_unique<Set<util::Optional<Bool>>>(col_key);
3,108✔
235
            else
2,796✔
236
                return std::make_unique<Set<Bool>>(col_key);
2,796✔
NEW
237
        }
×
238
        case type_Float: {
6,672✔
239
            if (nullable)
6,672✔
240
                return std::make_unique<Set<util::Optional<Float>>>(col_key);
3,492✔
241
            else
3,180✔
242
                return std::make_unique<Set<Float>>(col_key);
3,180✔
NEW
243
        }
×
244
        case type_Double: {
6,672✔
245
            if (nullable)
6,672✔
246
                return std::make_unique<Set<util::Optional<Double>>>(col_key);
3,492✔
247
            else
3,180✔
248
                return std::make_unique<Set<Double>>(col_key);
3,180✔
NEW
249
        }
×
250
        case type_String: {
6,672✔
251
            return std::make_unique<Set<String>>(col_key);
6,672✔
NEW
252
        }
×
253
        case type_Binary: {
6,528✔
254
            return std::make_unique<Set<Binary>>(col_key);
6,528✔
NEW
255
        }
×
256
        case type_Timestamp: {
6,600✔
257
            return std::make_unique<Set<Timestamp>>(col_key);
6,600✔
NEW
258
        }
×
259
        case type_Decimal: {
6,198✔
260
            return std::make_unique<Set<Decimal128>>(col_key);
6,198✔
NEW
261
        }
×
262
        case type_ObjectId: {
14,772✔
263
            if (nullable)
14,772✔
264
                return std::make_unique<Set<util::Optional<ObjectId>>>(col_key);
11,976✔
265
            else
2,796✔
266
                return std::make_unique<Set<ObjectId>>(col_key);
2,796✔
NEW
267
        }
×
268
        case type_UUID: {
5,904✔
269
            if (nullable)
5,904✔
270
                return std::make_unique<Set<util::Optional<UUID>>>(col_key);
3,108✔
271
            else
2,796✔
272
                return std::make_unique<Set<UUID>>(col_key);
2,796✔
NEW
273
        }
×
NEW
274
        case type_TypedLink: {
✔
NEW
275
            return std::make_unique<Set<ObjLink>>(col_key);
×
NEW
276
        }
×
277
        case type_Mixed: {
10,170✔
278
            return std::make_unique<Set<Mixed>>(col_key);
10,170✔
NEW
279
        }
×
280
        case type_Link: {
32,916✔
281
            return std::make_unique<LnkSet>(col_key);
32,916✔
NEW
282
        }
×
NEW
283
        case type_LinkList:
✔
NEW
284
            break;
×
NEW
285
    }
×
NEW
286
    REALM_TERMINATE("Unsupported column type.");
×
NEW
287
}
×
288

289
CollectionBasePtr CollectionParent::get_collection_ptr(ColKey col_key) const
290
{
127,317✔
291
    if (col_key.is_list()) {
127,317✔
292
        return get_listbase_ptr(col_key);
23,451✔
293
    }
23,451✔
294
    else if (col_key.is_set()) {
103,866✔
295
        return get_setbase_ptr(col_key);
74,193✔
296
    }
74,193✔
297
    else if (col_key.is_dictionary()) {
29,673✔
298
        return std::make_unique<Dictionary>(col_key, get_level() + 1);
29,673✔
299
    }
29,673✔
NEW
300
    return {};
×
NEW
301
}
×
302

303

304
int64_t CollectionParent::generate_key(size_t sz)
305
{
984✔
306
    static std::mt19937 gen32;
984✔
307
    static std::mutex mutex;
984✔
308

492✔
309
    int64_t key;
984✔
310
    const std::lock_guard<std::mutex> lock(mutex);
984✔
311
    do {
984✔
312
        if (sz < 0x10) {
984✔
313
            key = int8_t(gen32());
696✔
314
        }
696✔
315
        else if (sz < 0x1000) {
288✔
316
            key = int16_t(gen32());
288✔
317
        }
288✔
NEW
318
        else {
×
NEW
319
            key = int32_t(gen32());
×
NEW
320
        }
×
321
    } while (key == 0);
984✔
322

492✔
323
    return key;
984✔
324
}
984✔
325

326

327
} // 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