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

realm / realm-core / 2085

01 Mar 2024 12:26PM UTC coverage: 90.926% (-0.001%) from 90.927%
2085

push

Evergreen

jedelbo
Avoid doing unneeded logger work in Replication

Most of the replication log statements do some work including memory
allocations which are then thrown away if the log level it too high, so always
check the log level first. A few places don't actually benefit from this, but
it's easier to consistently check the log level every time.

93986 of 173116 branches covered (54.29%)

63 of 100 new or added lines in 2 files covered. (63.0%)

114 existing lines in 17 files now uncovered.

238379 of 262169 relevant lines covered (90.93%)

6007877.32 hits per line

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

74.04
/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
{
83,934✔
49
    // Nothing needs to be done here
41,199✔
50
}
83,934✔
51

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

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

67
void Replication::add_class(TableKey table_key, StringData name, Table::Type type)
68
{
162,831✔
69
    if (auto logger = would_log(LogLevel::debug)) {
162,831✔
70
        if (type == Table::Type::Embedded) {
282✔
71
            logger->log(LogCategory::object, LogLevel::debug, "Add %1 class '%2'", type, name);
126✔
72
        }
126✔
73
        else {
156✔
74
            logger->log(LogCategory::object, LogLevel::debug, "Add class '%1'", name);
156✔
75
        }
156✔
76
    }
282✔
77
    unselect_all();
162,831✔
78
    m_encoder.insert_group_level_table(table_key); // Throws
162,831✔
79
}
162,831✔
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
{
92,241✔
84
    if (auto logger = would_log(LogLevel::debug)) {
92,241✔
85
        logger->log(LogCategory::object, LogLevel::debug, "Add %1 class '%2' with primary key property '%3' of %4",
132✔
86
                    table_type, Group::table_name_to_class_name(name), pk_name, pk_type);
132✔
87
    }
132✔
88
    REALM_ASSERT(table_type != Table::Type::Embedded);
92,241✔
89
    unselect_all();
92,241✔
90
    m_encoder.insert_group_level_table(tk); // Throws
92,241✔
91
}
92,241✔
92

93
void Replication::erase_class(TableKey tk, StringData table_name, size_t)
94
{
549✔
95
    if (auto logger = would_log(LogLevel::debug)) {
549✔
NEW
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();
549✔
100
    m_encoder.erase_class(tk); // Throws
549✔
101
}
549✔
102

103

104
void Replication::insert_column(const Table* t, ColKey col_key, DataType type, StringData col_name,
105
                                Table* target_table)
106
{
516,339✔
107
    if (auto logger = would_log(LogLevel::debug)) {
516,339✔
108
        const char* collection_type = "";
1,974✔
109
        if (col_key.is_collection()) {
1,974✔
110
            if (col_key.is_list()) {
582✔
111
                collection_type = "list ";
282✔
112
            }
282✔
113
            else if (col_key.is_dictionary()) {
300✔
114
                collection_type = "dictionary ";
126✔
115
            }
126✔
116
            else {
174✔
117
                collection_type = "set ";
174✔
118
            }
174✔
119
        }
582✔
120
        if (target_table) {
1,974✔
121
            logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Add property '%2' %3linking '%4'",
156✔
122
                        t->get_class_name(), col_name, collection_type, target_table->get_class_name());
156✔
123
        }
156✔
124
        else {
1,818✔
125
            logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Add property '%2' %3of %4",
1,818✔
126
                        t->get_class_name(), col_name, collection_type, type);
1,818✔
127
        }
1,818✔
128
    }
1,974✔
129
    select_table(t);                  // Throws
516,339✔
130
    m_encoder.insert_column(col_key); // Throws
516,339✔
131
}
516,339✔
132

133
void Replication::erase_column(const Table* t, ColKey col_key)
134
{
528✔
135
    if (auto logger = would_log(LogLevel::debug)) {
528✔
NEW
136
        logger->log(LogCategory::object, LogLevel::debug, "On class '%1': Remove property '%2'", t->get_class_name(),
×
NEW
137
                    t->get_column_name(col_key));
×
UNCOV
138
    }
×
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,293,993✔
145
    if (auto logger = would_log(LogLevel::debug)) {
4,293,993✔
146
        logger->log(LogCategory::object, LogLevel::debug, "Create object '%1'", t->get_class_name());
198✔
147
    }
198✔
148
    select_table(t);                              // Throws
4,293,993✔
149
    m_encoder.create_object(id.get_local_key(0)); // Throws
4,293,993✔
150
}
4,293,993✔
151

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

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

180
inline void Replication::select_obj(ObjKey key)
181
{
16,592,391✔
182
    if (key == m_selected_obj) {
16,592,391✔
183
        return;
2,914,377✔
184
    }
2,914,377✔
185
    if (auto logger = would_log(LogLevel::debug)) {
13,678,014✔
186
        auto class_name = m_selected_table->get_class_name();
1,140✔
187
        if (m_selected_table->get_primary_key_column()) {
1,140✔
188
            auto pk = m_selected_table->get_primary_key(key);
102✔
189
            logger->log(LogCategory::object, LogLevel::debug, "Mutating object '%1' with primary key %2", class_name,
102✔
190
                        pk);
102✔
191
        }
102✔
192
        else if (m_selected_table->is_embedded()) {
1,038✔
193
            auto obj = m_selected_table->get_object(key);
180✔
194
            logger->log(LogCategory::object, LogLevel::debug, "Mutating object '%1' with path '%2'", class_name,
180✔
195
                        obj.get_id());
180✔
196
        }
180✔
197
        else {
858✔
198
            logger->log(LogCategory::object, LogLevel::debug, "Mutating anonymous object '%1'[%2]", class_name, key);
858✔
199
        }
858✔
200
    }
1,140✔
201
    m_selected_obj = key;
13,678,014✔
202
}
13,678,014✔
203

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

213
void Replication::set(const Table* t, ColKey col_key, ObjKey key, Mixed value, _impl::Instruction variant)
214
{
16,351,062✔
215
    do_set(t, col_key, key, variant); // Throws
16,351,062✔
216
    if (auto logger = would_log(LogLevel::trace)) {
16,351,062✔
217
        if (col_key.get_type() == col_type_Link && value.is_type(type_Link)) {
30!
NEW
218
            auto target_table = t->get_opposite_table(col_key);
×
NEW
219
            if (target_table->is_embedded()) {
×
NEW
220
                logger->log(LogCategory::object, LogLevel::trace, "   Creating embedded object '%1' in '%2'",
×
NEW
221
                            target_table->get_class_name(), t->get_column_name(col_key));
×
NEW
222
            }
×
NEW
223
            else if (target_table->get_primary_key_column()) {
×
NEW
224
                auto link = value.get<ObjKey>();
×
NEW
225
                auto pk = target_table->get_primary_key(link);
×
NEW
226
                logger->log(LogCategory::object, LogLevel::trace,
×
NEW
227
                            "   Linking object '%1' with primary key %2 from '%3'", target_table->get_class_name(),
×
NEW
228
                            pk, t->get_column_name(col_key));
×
UNCOV
229
            }
×
UNCOV
230
            else {
×
NEW
231
                logger->log(LogCategory::object, LogLevel::trace, "   Linking object '%1'[%2] from '%3'",
×
NEW
232
                            target_table->get_class_name(), key, t->get_column_name(col_key));
×
UNCOV
233
            }
×
UNCOV
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,351,062✔
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✔
NEW
248
        logger->log(LogCategory::object, LogLevel::trace, "   Nullify '%1'", t->get_column_name(col_key));
×
UNCOV
249
    }
×
250
}
759✔
251

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

260

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

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

15✔
276
    auto path = collection.get_short_path();
21✔
277
    auto col_key = path[0].get_col_key();
21✔
278
    auto prop_name = m_selected_table->get_column_name(col_key);
21✔
279
    path[0] = PathElement(prop_name);
21✔
280
    std::string position;
21✔
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)) {
21!
285
        auto target_table = m_selected_table->get_opposite_table(col_key);
×
286
        if (target_table->is_embedded()) {
×
NEW
287
            logger->log(LogCategory::object, LogLevel::trace, "   %1 embedded object '%2' in %3%4 ", operation,
×
NEW
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);
×
NEW
293
            logger->log(LogCategory::object, LogLevel::trace, "   %1 object '%2' with primary key %3 in %4%5",
×
NEW
294
                        operation, target_table->get_class_name(), pk, path, position);
×
295
        }
×
296
        else {
×
297
            auto link = value.get<ObjKey>();
×
NEW
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 {
21✔
303
        logger->log(LogCategory::object, LogLevel::trace, "   %1 %2 in %3%4", operation,
21✔
304
                    value.to_string(util::Logger::max_width_of_value), path, position);
21✔
305
    }
21✔
306
}
21✔
307

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

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

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

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

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

343
void Replication::set_insert(const CollectionBase& set, size_t set_ndx, Mixed value)
344
{
63,378✔
345
    select_collection(set);               // Throws
63,378✔
346
    m_encoder.collection_insert(set_ndx); // Throws
63,378✔
347
    log_collection_operation("Insert", set, value, Mixed());
63,378✔
348
}
63,378✔
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✔
NEW
355
        logger->log(LogCategory::object, LogLevel::trace, "   Erase %1 from '%2'", value,
×
UNCOV
356
                    get_prop_name(set.get_short_path()));
×
UNCOV
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✔
NEW
365
        logger->log(LogCategory::object, LogLevel::trace, "   Clear '%1'", get_prop_name(set.get_short_path()));
×
UNCOV
366
    }
×
367
}
2,418✔
368

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

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

115,947✔
384
    select_obj(key);
232,800✔
385

115,947✔
386
    m_encoder.select_collection(col_key, key, path); // Throws
232,800✔
387
    m_selected_list = CollectionId(list.get_table()->get_key(), key, std::move(path));
232,800✔
388
}
232,800✔
389

390
void Replication::list_clear(const CollectionBase& list)
391
{
5,013✔
392
    select_collection(list);                 // Throws
5,013✔
393
    m_encoder.collection_clear(list.size()); // Throws
5,013✔
394
    if (auto logger = would_log(LogLevel::trace)) {
5,013✔
NEW
395
        logger->log(LogCategory::object, LogLevel::trace, "   Clear '%1'", get_prop_name(list.get_short_path()));
×
UNCOV
396
    }
×
397
}
5,013✔
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✔
NEW
404
        logger->log(LogCategory::object, LogLevel::trace, "   Nullify '%1' position %2",
×
UNCOV
405
                    m_selected_table->get_column_name(list.get_col_key()), link_ndx);
×
UNCOV
406
    }
×
407
}
2,136✔
408

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

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

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

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

© 2026 Coveralls, Inc