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

realm / realm-core / 2213

10 Apr 2024 11:21PM UTC coverage: 91.792% (-0.8%) from 92.623%
2213

push

Evergreen

web-flow
Add missing availability checks for SecCopyErrorMessageString (#7577)

This requires iOS 11.3 and we currently target iOS 11.

94842 of 175770 branches covered (53.96%)

7 of 22 new or added lines in 2 files covered. (31.82%)

1861 existing lines in 82 files now uncovered.

242866 of 264583 relevant lines covered (91.79%)

5593111.45 hits per line

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

78.17
/src/realm/replication.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/replication.hpp>
20

21
#include <realm/list.hpp>
22
#include <realm/path.hpp>
23
#include <iostream>
24

25
using namespace realm;
26
using namespace realm::util;
27
using LogLevel = util::Logger::Level;
28

29
const char* Replication::history_type_name(int type)
30
{
18✔
31
    switch (type) {
18✔
32
        case hist_None:
✔
33
            return "None";
×
34
        case hist_OutOfRealm:
✔
35
            return "Local out of Realm";
×
36
        case hist_InRealm:
12✔
37
            return "Local in-Realm";
12✔
38
        case hist_SyncClient:
6✔
39
            return "SyncClient";
6✔
40
        case hist_SyncServer:
✔
41
            return "SyncServer";
×
42
        default:
✔
43
            return "Unknown";
×
44
    }
18✔
45
}
18✔
46

47
void Replication::initialize(DB&)
48
{
92,625✔
49
    // Nothing needs to be done here
45,426✔
50
}
92,625✔
51

52
void Replication::do_initiate_transact(Group&, version_type, bool)
53
{
602,481✔
54
    char* data = m_stream.get_data();
602,481✔
55
    size_t size = m_stream.get_size();
602,481✔
56
    m_encoder.set_buffer(data, data + size);
602,481✔
57
}
602,481✔
58

59
Replication::version_type Replication::prepare_commit(version_type orig_version)
60
{
576,546✔
61
    char* data = m_stream.get_data();
576,546✔
62
    size_t size = m_encoder.write_position() - data;
576,546✔
63
    version_type new_version = prepare_changeset(data, size, orig_version); // Throws
576,546✔
64
    return new_version;
576,546✔
65
}
576,546✔
66

67
void Replication::add_class(TableKey table_key, StringData name, Table::Type type)
68
{
162,615✔
69
    if (auto logger = would_log(LogLevel::debug)) {
162,615✔
70
        if (type == Table::Type::Embedded) {
27,384✔
71
            logger->log(LogCategory::object, LogLevel::debug, "Add %1 class '%2'", type, name);
3,282✔
72
        }
3,282✔
73
        else {
24,102✔
74
            logger->log(LogCategory::object, LogLevel::debug, "Add class '%1'", name);
24,102✔
75
        }
24,102✔
76
    }
27,384✔
77
    unselect_all();
162,615✔
78
    m_encoder.insert_group_level_table(table_key); // Throws
162,615✔
79
}
162,615✔
80

81
void Replication::add_class_with_primary_key(TableKey tk, StringData name, DataType pk_type, StringData pk_name, bool,
82
                                             Table::Type table_type)
83
{
94,572✔
84
    if (auto logger = would_log(LogLevel::debug)) {
94,572✔
85
        logger->log(LogCategory::object, LogLevel::debug, "Add %1 class '%2' with primary key property '%3' of %4",
61,464✔
86
                    table_type, Group::table_name_to_class_name(name), pk_name, pk_type);
61,464✔
87
    }
61,464✔
88
    REALM_ASSERT(table_type != Table::Type::Embedded);
94,572✔
89
    unselect_all();
94,572✔
90
    m_encoder.insert_group_level_table(tk); // Throws
94,572✔
91
}
94,572✔
92

93
void Replication::erase_class(TableKey tk, StringData table_name, size_t)
94
{
1,329✔
95
    if (auto logger = would_log(LogLevel::debug)) {
1,329✔
UNCOV
96
        logger->log(LogCategory::object, LogLevel::debug, "Remove class '%1'",
×
UNCOV
97
                    Group::table_name_to_class_name(table_name));
×
UNCOV
98
    }
×
99
    unselect_all();
1,329✔
100
    m_encoder.erase_class(tk); // Throws
1,329✔
101
}
1,329✔
102

103

104
void Replication::insert_column(const Table* t, ColKey col_key, DataType type, StringData col_name,
105
                                Table* target_table)
106
{
518,010✔
107
    if (auto logger = would_log(LogLevel::debug)) {
518,010✔
108
        const char* collection_type = "";
248,859✔
109
        if (col_key.is_collection()) {
248,859✔
110
            if (col_key.is_list()) {
105,786✔
111
                collection_type = "list ";
38,058✔
112
            }
38,058✔
113
            else if (col_key.is_dictionary()) {
67,728✔
114
                collection_type = "dictionary ";
34,290✔
115
            }
34,290✔
116
            else {
33,438✔
117
                collection_type = "set ";
33,438✔
118
            }
33,438✔
119
        }
105,786✔
120
        if (target_table) {
248,859✔
121
            logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Add property '%2' %3linking '%4'",
15,114✔
122
                        t->get_class_name(), col_name, collection_type, target_table->get_class_name());
15,114✔
123
        }
15,114✔
124
        else {
233,745✔
125
            logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Add property '%2' %3of %4",
233,745✔
126
                        t->get_class_name(), col_name, collection_type, type);
233,745✔
127
        }
233,745✔
128
    }
248,859✔
129
    select_table(t);                  // Throws
518,010✔
130
    m_encoder.insert_column(col_key); // Throws
518,010✔
131
}
518,010✔
132

133
void Replication::erase_column(const Table* t, ColKey col_key)
134
{
528✔
135
    if (auto logger = would_log(LogLevel::debug)) {
528✔
136
        logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Remove property '%2'", t->get_class_name(),
60✔
137
                    t->get_column_name(col_key));
60✔
138
    }
60✔
139
    select_table(t);                 // Throws
528✔
140
    m_encoder.erase_column(col_key); // Throws
528✔
141
}
528✔
142

143
void Replication::create_object(const Table* t, GlobalKey id)
144
{
4,300,470✔
145
    if (auto logger = would_log(LogLevel::debug)) {
4,300,470✔
146
        logger->log(LogCategory::object, LogLevel::debug, "Create object '%1'", t->get_class_name());
25,362✔
147
    }
25,362✔
148
    select_table(t);                              // Throws
4,300,470✔
149
    m_encoder.create_object(id.get_local_key(0)); // Throws
4,300,470✔
150
}
4,300,470✔
151

152
void Replication::create_object_with_primary_key(const Table* t, ObjKey key, Mixed pk)
153
{
306,387✔
154
    if (auto logger = would_log(LogLevel::debug)) {
306,387✔
155
        logger->log(LogCategory::object, LogLevel::debug, "Create object '%1' with primary key %2",
106,377✔
156
                    t->get_class_name(), pk);
106,377✔
157
    }
106,377✔
158
    select_table(t);              // Throws
306,387✔
159
    m_encoder.create_object(key); // Throws
306,387✔
160
}
306,387✔
161

162
void Replication::remove_object(const Table* t, ObjKey key)
163
{
4,924,917✔
164
    if (auto logger = would_log(LogLevel::debug)) {
4,924,917✔
165
        if (t->is_embedded()) {
7,488✔
166
            logger->log(LogCategory::object, LogLevel::debug, "Remove embedded object '%1'", t->get_class_name());
3,651✔
167
        }
3,651✔
168
        else if (t->get_primary_key_column()) {
3,837✔
169
            logger->log(LogCategory::object, LogLevel::debug, "Remove object '%1' with primary key %2",
3,660✔
170
                        t->get_class_name(), t->get_primary_key(key));
3,660✔
171
        }
3,660✔
172
        else {
177✔
173
            logger->log(LogCategory::object, LogLevel::debug, "Remove object '%1'[%2]", t->get_class_name(), key);
177✔
174
        }
177✔
175
    }
7,488✔
176
    select_table(t);              // Throws
4,924,917✔
177
    m_encoder.remove_object(key); // Throws
4,924,917✔
178
}
4,924,917✔
179

180
void Replication::select_obj(ObjKey key)
181
{
16,628,028✔
182
    if (key == m_selected_obj) {
16,628,028✔
183
        return;
2,941,332✔
184
    }
2,941,332✔
185
    if (auto logger = would_log(LogLevel::debug)) {
13,686,696✔
186
        auto class_name = m_selected_table->get_class_name();
214,962✔
187
        if (m_selected_table->get_primary_key_column()) {
214,962✔
188
            auto pk = m_selected_table->get_primary_key(key);
146,169✔
189
            logger->log(LogCategory::object, LogLevel::debug, "Mutating object '%1' with primary key %2", class_name,
146,169✔
190
                        pk);
146,169✔
191
        }
146,169✔
192
        else if (m_selected_table->is_embedded()) {
68,793✔
193
            auto obj = m_selected_table->get_object(key);
19,323✔
194
            logger->log(LogCategory::object, LogLevel::debug, "Mutating object '%1' with path '%2'", class_name,
19,323✔
195
                        obj.get_id());
19,323✔
196
        }
19,323✔
197
        else {
49,470✔
198
            logger->log(LogCategory::object, LogLevel::debug, "Mutating anonymous object '%1'[%2]", class_name, key);
49,470✔
199
        }
49,470✔
200
    }
214,962✔
201
    m_selected_obj = key;
13,686,696✔
202
}
13,686,696✔
203

204
void Replication::do_set(const Table* t, ColKey col_key, ObjKey key, _impl::Instruction variant)
205
{
16,387,590✔
206
    if (variant != _impl::Instruction::instr_SetDefault) {
16,387,590✔
207
        select_table(t); // Throws
16,387,260✔
208
        select_obj(key);
16,387,260✔
209
        m_encoder.modify_object(col_key, key); // Throws
16,387,260✔
210
    }
16,387,260✔
211
}
16,387,590✔
212

213
void Replication::set(const Table* t, ColKey col_key, ObjKey key, Mixed value, _impl::Instruction variant)
214
{
16,378,263✔
215
    do_set(t, col_key, key, variant); // Throws
16,378,263✔
216
    if (auto logger = would_log(LogLevel::trace)) {
16,378,263✔
217
        if (col_key.get_type() == col_type_Link && value.is_type(type_Link)) {
30!
218
            auto target_table = t->get_opposite_table(col_key);
×
219
            if (target_table->is_embedded()) {
×
220
                logger->log(LogCategory::object, LogLevel::trace, "   Creating embedded object '%1' in '%2'",
×
221
                            target_table->get_class_name(), t->get_column_name(col_key));
×
222
            }
×
223
            else if (target_table->get_primary_key_column()) {
×
224
                auto link = value.get<ObjKey>();
×
225
                auto pk = target_table->get_primary_key(link);
×
226
                logger->log(LogCategory::object, LogLevel::trace,
×
227
                            "   Linking object '%1' with primary key %2 from '%3'", target_table->get_class_name(),
×
228
                            pk, t->get_column_name(col_key));
×
229
            }
×
230
            else {
×
231
                logger->log(LogCategory::object, LogLevel::trace, "   Linking object '%1'[%2] from '%3'",
×
232
                            target_table->get_class_name(), key, t->get_column_name(col_key));
×
233
            }
×
234
        }
×
235
        else {
30✔
236
            logger->log(LogCategory::object, LogLevel::trace, "   Set '%1' to %2", t->get_column_name(col_key),
30✔
237
                        value.to_string(util::Logger::max_width_of_value));
30✔
238
        }
30✔
239
    }
30✔
240
}
16,378,263✔
241

242
void Replication::nullify_link(const Table* t, ColKey col_key, ObjKey key)
243
{
759✔
244
    select_table(t); // Throws
759✔
245
    select_obj(key);
759✔
246
    m_encoder.modify_object(col_key, key); // Throws
759✔
247
    if (auto logger = would_log(LogLevel::trace)) {
759✔
248
        logger->log(LogCategory::object, LogLevel::trace, "   Nullify '%1'", t->get_column_name(col_key));
×
249
    }
×
250
}
759✔
251

252
void Replication::add_int(const Table* t, ColKey col_key, ObjKey key, int_fast64_t value)
253
{
8,397✔
254
    do_set(t, col_key, key); // Throws
8,397✔
255
    if (auto logger = get_logger()) {
8,397✔
256
        logger->log(LogCategory::object, LogLevel::trace, "   Adding %1 to '%2'", value, t->get_column_name(col_key));
90✔
257
    }
90✔
258
}
8,397✔
259

260

261
Path Replication::get_prop_name(Path&& path) const
262
{
×
263
    auto col_key = path[0].get_col_key();
×
264
    auto prop_name = m_selected_table->get_column_name(col_key);
×
265
    path[0] = PathElement(prop_name);
×
266
    return std::move(path);
×
267
}
×
268

269
void Replication::log_collection_operation(const char* operation, const CollectionBase& collection, Mixed value,
270
                                           Mixed index) const
271
{
1,415,673✔
272
    auto logger = would_log(LogLevel::trace);
1,415,673✔
273
    if (REALM_LIKELY(!logger))
1,415,673✔
274
        return;
1,415,670✔
275

15✔
276
    auto path = collection.get_short_path();
18✔
277
    auto col_key = path[0].get_col_key();
18✔
278
    auto prop_name = m_selected_table->get_column_name(col_key);
18✔
279
    path[0] = PathElement(prop_name);
18✔
280
    std::string position;
18✔
281
    if (!index.is_null()) {
21✔
282
        position = util::format(" at position %1", index);
12✔
283
    }
12✔
284
    if (Table::is_link_type(col_key.get_type()) && value.is_type(type_Link)) {
18!
285
        auto target_table = m_selected_table->get_opposite_table(col_key);
×
286
        if (target_table->is_embedded()) {
×
287
            logger->log(LogCategory::object, LogLevel::trace, "   %1 embedded object '%2' in %3%4 ", operation,
×
288
                        target_table->get_class_name(), path, position);
×
289
        }
×
290
        else if (target_table->get_primary_key_column()) {
×
291
            auto link = value.get<ObjKey>();
×
292
            auto pk = target_table->get_primary_key(link);
×
293
            logger->log(LogCategory::object, LogLevel::trace, "   %1 object '%2' with primary key %3 in %4%5",
×
294
                        operation, target_table->get_class_name(), pk, path, position);
×
295
        }
×
296
        else {
×
297
            auto link = value.get<ObjKey>();
×
298
            logger->log(LogCategory::object, LogLevel::trace, "   %1 object '%2'[%3] in %4%5", operation,
×
299
                        target_table->get_class_name(), link, path, position);
×
300
        }
×
301
    }
×
302
    else {
18✔
303
        logger->log(LogCategory::object, LogLevel::trace, "   %1 %2 in %3%4", operation,
18✔
304
                    value.to_string(util::Logger::max_width_of_value), path, position);
18✔
305
    }
18✔
306
}
18✔
307

308
void Replication::list_insert(const CollectionBase& list, size_t list_ndx, Mixed value, size_t)
309
{
1,205,433✔
310
    select_collection(list);                                     // Throws
1,205,433✔
311
    m_encoder.collection_insert(list.translate_index(list_ndx)); // Throws
1,205,433✔
312
    log_collection_operation("Insert", list, value, int64_t(list_ndx));
1,205,433✔
313
}
1,205,433✔
314

315
void Replication::list_set(const CollectionBase& list, size_t list_ndx, Mixed value)
316
{
49,446✔
317
    select_collection(list);                                  // Throws
49,446✔
318
    m_encoder.collection_set(list.translate_index(list_ndx)); // Throws
49,446✔
319
    log_collection_operation("Set", list, value, int64_t(list_ndx));
49,446✔
320
}
49,446✔
321

322
void Replication::list_erase(const CollectionBase& list, size_t link_ndx)
323
{
200,064✔
324
    select_collection(list);                                    // Throws
200,064✔
325
    m_encoder.collection_erase(list.translate_index(link_ndx)); // Throws
200,064✔
326
    if (auto logger = would_log(LogLevel::trace)) {
200,064✔
327

328
        logger->log(LogCategory::object, LogLevel::trace, "   Erase '%1' at position %2",
×
329
                    get_prop_name(list.get_short_path()), link_ndx);
×
330
    }
×
331
}
200,064✔
332

333
void Replication::list_move(const CollectionBase& list, size_t from_link_ndx, size_t to_link_ndx)
334
{
1,746✔
335
    select_collection(list);                                                                           // Throws
1,746✔
336
    m_encoder.collection_move(list.translate_index(from_link_ndx), list.translate_index(to_link_ndx)); // Throws
1,746✔
337
    if (auto logger = would_log(LogLevel::trace)) {
1,746✔
338
        logger->log(LogCategory::object, LogLevel::trace, "   Move %1 to %2 in '%3'", from_link_ndx, to_link_ndx,
×
339
                    get_prop_name(list.get_short_path()));
×
340
    }
×
341
}
1,746✔
342

343
void Replication::set_insert(const CollectionBase& set, size_t set_ndx, Mixed value)
344
{
63,291✔
345
    select_collection(set);               // Throws
63,291✔
346
    m_encoder.collection_insert(set_ndx); // Throws
63,291✔
347
    log_collection_operation("Insert", set, value, Mixed());
63,291✔
348
}
63,291✔
349

350
void Replication::set_erase(const CollectionBase& set, size_t set_ndx, Mixed value)
351
{
12,504✔
352
    select_collection(set);              // Throws
12,504✔
353
    m_encoder.collection_erase(set_ndx); // Throws
12,504✔
354
    if (auto logger = would_log(LogLevel::trace)) {
12,504✔
355
        logger->log(LogCategory::object, LogLevel::trace, "   Erase %1 from '%2'", value,
×
356
                    get_prop_name(set.get_short_path()));
×
357
    }
×
358
}
12,504✔
359

360
void Replication::set_clear(const CollectionBase& set)
361
{
2,418✔
362
    select_collection(set);                 // Throws
2,418✔
363
    m_encoder.collection_clear(set.size()); // Throws
2,418✔
364
    if (auto logger = would_log(LogLevel::trace)) {
2,418✔
365
        logger->log(LogCategory::object, LogLevel::trace, "   Clear '%1'", get_prop_name(set.get_short_path()));
×
366
    }
×
367
}
2,418✔
368

369
void Replication::do_select_table(const Table* table)
370
{
905,838✔
371
    m_encoder.select_table(table->get_key()); // Throws
905,838✔
372
    m_selected_table = table;
905,838✔
373
    m_selected_list = CollectionId();
905,838✔
374
    m_selected_obj = ObjKey();
905,838✔
375
}
905,838✔
376

377
void Replication::do_select_collection(const CollectionBase& list)
378
{
240,777✔
379
    select_table(list.get_table().unchecked_ptr());
240,777✔
380
    ColKey col_key = list.get_col_key();
240,777✔
381
    ObjKey key = list.get_owner_key();
240,777✔
382
    auto path = list.get_stable_path();
240,777✔
383

120,648✔
384
    select_obj(key);
240,777✔
385

120,648✔
386
    m_encoder.select_collection(col_key, key, path); // Throws
240,777✔
387
    m_selected_list = CollectionId(list.get_table()->get_key(), key, std::move(path));
240,777✔
388
}
240,777✔
389

390
void Replication::list_clear(const CollectionBase& list)
391
{
5,505✔
392
    select_collection(list);                 // Throws
5,505✔
393
    m_encoder.collection_clear(list.size()); // Throws
5,505✔
394
    if (auto logger = would_log(LogLevel::trace)) {
5,505✔
395
        logger->log(LogCategory::object, LogLevel::trace, "   Clear '%1'", get_prop_name(list.get_short_path()));
×
396
    }
×
397
}
5,505✔
398

399
void Replication::link_list_nullify(const Lst<ObjKey>& list, size_t link_ndx)
400
{
2,136✔
401
    select_collection(list);
2,136✔
402
    m_encoder.collection_erase(link_ndx);
2,136✔
403
    if (auto logger = would_log(LogLevel::trace)) {
2,136✔
404
        logger->log(LogCategory::object, LogLevel::trace, "   Nullify '%1' position %2",
×
405
                    m_selected_table->get_column_name(list.get_col_key()), link_ndx);
×
406
    }
×
407
}
2,136✔
408

409
void Replication::dictionary_insert(const CollectionBase& dict, size_t ndx, Mixed key, Mixed value)
410
{
88,089✔
411
    select_collection(dict);
88,089✔
412
    m_encoder.collection_insert(ndx);
88,089✔
413
    log_collection_operation("Insert", dict, value, key);
88,089✔
414
}
88,089✔
415

416
void Replication::dictionary_set(const CollectionBase& dict, size_t ndx, Mixed key, Mixed value)
417
{
9,432✔
418
    select_collection(dict);
9,432✔
419
    m_encoder.collection_set(ndx);
9,432✔
420
    log_collection_operation("Set", dict, value, key);
9,432✔
421
}
9,432✔
422

423
void Replication::dictionary_erase(const CollectionBase& dict, size_t ndx, Mixed key)
424
{
12,093✔
425
    select_collection(dict);
12,093✔
426
    m_encoder.collection_erase(ndx);
12,093✔
427
    if (auto logger = would_log(LogLevel::trace)) {
12,093✔
428
        logger->log(LogCategory::object, LogLevel::trace, "   Erase %1 from '%2'", key,
×
429
                    get_prop_name(dict.get_short_path()));
×
430
    }
×
431
}
12,093✔
432

433
void Replication::dictionary_clear(const CollectionBase& dict)
434
{
2,478✔
435
    select_collection(dict);
2,478✔
436
    m_encoder.collection_clear(dict.size());
2,478✔
437
    if (auto logger = would_log(LogLevel::trace)) {
2,478✔
438
        logger->log(LogCategory::object, LogLevel::trace, "   Clear '%1'", get_prop_name(dict.get_short_path()));
×
439
    }
×
440
}
2,478✔
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