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

realm / realm-core / 1786

28 Oct 2023 12:35PM UTC coverage: 91.562% (-0.02%) from 91.582%
1786

push

Evergreen

web-flow
Improve configurations for sanitized builds (#6911)

* Refactor sanitizer flags for different build types:

** Enable address sanitizer for msvc
** Allow to build with sanitizer for diffent optimized build (also Debug)
** Make RelASAN, RelTSAN, RelUSAN, RelUSAN just shortcuts for half-optimized builds

* Fix usage of moved object for fuzz tester
* Check asan/tsan on macos x64/arm64
* Check asan with msvc 2019
* Remove Jenkins sanitized builders replaced by evergreen configs
* Work-around stack-use-after-scope with msvc2019 and mpark
* Fix crash on check with staled ColKeys
* fix a buffer overrun in a test
* fix a race in async_open_realm test util
* Add some logger related test fixes
* Work around catch2 limmitation with not thread safe asserts and TSAN races
* Run multiprocesses tests under sanitizers
* add assert for an error reported by undefined sanitizer
* Workaround uv scheduler main thread only constraint for callbacks called from non main thread and requesting a realm

---------

Co-authored-by: James Stone <james.stone@mongodb.com>

94310 of 173648 branches covered (0.0%)

54 of 63 new or added lines in 15 files covered. (85.71%)

2212 existing lines in 52 files now uncovered.

230602 of 251853 relevant lines covered (91.56%)

6943670.77 hits per line

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

77.4
/src/realm/sync/noinst/sync_metadata_schema.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2022 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/sync/noinst/sync_metadata_schema.hpp>
20

21
#include <realm/data_type.hpp>
22
#include <realm/transaction.hpp>
23
#include <realm/util/flat_map.hpp>
24
#include <stdexcept>
25

26
namespace realm::sync {
27
namespace {
28

29
constexpr static std::string_view c_flx_metadata_table("flx_metadata");
30
constexpr static std::string_view c_sync_internal_schemas_table("sync_internal_schemas");
31
constexpr static std::string_view c_meta_schema_version_field("schema_version");
32
constexpr static std::string_view c_meta_schema_schema_group_field("schema_group_name");
33

34
} // namespace
35

36
void create_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadataTable>* tables)
37
{
2,624✔
38
    util::FlatMap<std::string_view, TableRef> found_tables;
2,624✔
39
    for (auto& table : *tables) {
4,804✔
40
        if (tr->has_table(table.name)) {
4,804✔
41
            throw std::runtime_error(
×
42
                util::format("table %1 already existed when creating internal tables for sync", table.name));
×
43
        }
×
44
        TableRef table_ref;
4,804✔
45
        if (table.is_embedded) {
4,804✔
46
            table_ref = tr->add_table(table.name, Table::Type::Embedded);
2,180✔
47
        }
2,180✔
48
        else if (table.pk_info) {
2,624✔
49
            table_ref = tr->add_table_with_primary_key(table.name, table.pk_info->data_type, table.pk_info->name,
2,384✔
50
                                                       table.pk_info->is_optional);
2,384✔
51
            *table.pk_info->key_out = table_ref->get_primary_key_column();
2,384✔
52
        }
2,384✔
53
        else {
240✔
54
            table_ref = tr->add_table(table.name);
240✔
55
        }
240✔
56

2,390✔
57
        found_tables.insert({table.name, table_ref});
4,804✔
58
        *table.key_out = table_ref->get_key();
4,804✔
59
    }
4,804✔
60

1,306✔
61
    for (auto& table : *tables) {
4,804✔
62
        auto& table_ref = found_tables.at(table.name);
4,804✔
63
        for (auto& column : table.columns) {
19,844✔
64
            if (column.data_type == type_LinkList) {
19,844✔
65
                auto target_table_it = found_tables.find(column.target_table);
1,468✔
66
                if (target_table_it == found_tables.end()) {
1,468✔
67
                    throw std::runtime_error(
×
68
                        util::format("cannot link to non-existant table %1 from internal sync table %2",
×
69
                                     column.target_table, table.name));
×
70
                }
×
71
                *column.key_out = table_ref->add_column_list(*target_table_it->second, column.name);
1,468✔
72
            }
1,468✔
73
            else if (column.data_type == type_Link) {
18,376✔
74
                auto target_table_it = found_tables.find(column.target_table);
712✔
75
                if (target_table_it == found_tables.end()) {
712✔
76
                    throw std::runtime_error(
×
77
                        util::format("cannot link to non-existant table %1 from internal sync table %2",
×
78
                                     column.target_table, table.name));
×
79
                }
×
80
                *column.key_out = table_ref->add_column(*target_table_it->second, column.name);
712✔
81
            }
712✔
82
            else {
17,664✔
83
                *column.key_out = table_ref->add_column(column.data_type, column.name, column.is_optional);
17,664✔
84
            }
17,664✔
85
        }
19,844✔
86
    }
4,804✔
87
}
2,624✔
88

89
void load_sync_metadata_schema(const TransactionRef& tr, std::vector<SyncMetadataTable>* tables)
90
{
1,890✔
91
    for (auto& table : *tables) {
2,652✔
92
        auto table_ref = tr->get_table(table.name);
2,652✔
93
        if (!table_ref) {
2,652✔
94
            throw std::runtime_error(util::format("could not find internal sync table %1", table.name));
×
95
        }
×
96

1,348✔
97
        *table.key_out = table_ref->get_key();
2,652✔
98
        if (table.pk_info) {
2,652✔
99
            auto pk_col = table_ref->get_primary_key_column();
1,854✔
100
            if (auto pk_name = table_ref->get_column_name(pk_col); pk_name != table.pk_info->name) {
1,854✔
101
                throw std::runtime_error(util::format(
×
102
                    "primary key name of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
×
103
                    pk_name, table.pk_info->name));
×
104
            }
×
105
            if (auto pk_type = table_ref->get_column_type(pk_col); pk_type != table.pk_info->data_type) {
1,854✔
106
                throw std::runtime_error(util::format(
×
107
                    "primary key type of sync internal table %1 does not match (stored: %2, defined: %3)", table.name,
×
108
                    pk_type, table.pk_info->data_type));
×
109
            }
×
110
            if (auto is_nullable = table_ref->is_nullable(pk_col); is_nullable != table.pk_info->is_optional) {
1,854✔
111
                throw std::runtime_error(util::format(
×
112
                    "primary key nullabilty of sync internal table %1 does not match (stored: %2, defined: %3)",
×
113
                    table.name, is_nullable, table.pk_info->is_optional));
×
114
            }
×
115
            *table.pk_info->key_out = pk_col;
1,854✔
116
        }
1,854✔
117
        else if (table.is_embedded && !table_ref->is_embedded()) {
798✔
118
            throw std::runtime_error(
×
119
                util::format("internal sync table %1 should be embedded, but is not", table.name));
×
120
        }
×
121

1,348✔
122
        if (table.columns.size() + size_t(table.pk_info ? 1 : 0) != table_ref->get_column_count()) {
2,652✔
123
            throw std::runtime_error(
×
124
                util::format("sync internal table %1 has a different number of columns than its schema", table.name));
×
125
        }
×
126

1,348✔
127
        for (auto& col : table.columns) {
7,338✔
128
            auto col_key = table_ref->get_column_key(col.name);
7,338✔
129
            if (!col_key) {
7,338✔
130
                throw std::runtime_error(
×
131
                    util::format("column %1 is missing in sync internal table %2", col.name, table.name));
×
132
            }
×
133

3,748✔
134
            auto found_col_type = table_ref->get_column_type(col_key);
7,338✔
135
            if (found_col_type != col.data_type) {
7,338✔
136
                throw std::runtime_error(
×
137
                    util::format("column %1 in sync internal table %2 is the wrong type", col.name, table.name));
×
138
            }
×
139

3,748✔
140
            if (col.is_optional != table_ref->is_nullable(col_key)) {
7,338✔
141
                throw std::runtime_error(
×
142
                    util::format("column %1 in sync internal table %2 has different nullabilty than in its schema",
×
143
                                 col.name, table.name));
×
144
            }
×
145

3,748✔
146
            if (col.data_type == type_LinkList &&
7,338✔
147
                table_ref->get_link_target(col_key)->get_name() != col.target_table) {
3,970✔
148
                throw std::runtime_error(
×
149
                    util::format("column %1 in sync internal table %2 links to the wrong table %3", col.name,
×
150
                                 table.name, table_ref->get_link_target(col_key)->get_name()));
×
151
            }
×
152
            *col.key_out = col_key;
7,338✔
153
        }
7,338✔
154
    }
2,652✔
155
}
1,890✔
156

157
SyncMetadataSchemaVersionsReader::SyncMetadataSchemaVersionsReader(const TransactionRef& tr)
158
{
4,916✔
159
    TableKey legacy_table_key;
4,916✔
160
    ColKey legacy_version_key;
4,916✔
161
    std::vector<SyncMetadataTable> legacy_table_def{
4,916✔
162
        {&legacy_table_key, c_flx_metadata_table, {{&legacy_version_key, c_meta_schema_version_field, type_Int}}}};
4,916✔
163
    std::vector<SyncMetadataTable> unified_schema_version_table_def{
4,916✔
164
        {&m_table,
4,916✔
165
         c_sync_internal_schemas_table,
4,916✔
166
         {&m_schema_group_field, c_meta_schema_schema_group_field, type_String},
4,916✔
167
         {{&m_version_field, c_meta_schema_version_field, type_Int}}}};
4,916✔
168

2,288✔
169
    REALM_ASSERT_3(tr->get_transact_stage(), ==, DB::transact_Reading);
4,916✔
170
    // If the legacy_meta_table exists, then this table hasn't been converted and
2,288✔
171
    // the metadata schema versions information has not been upgraded/not accurate
2,288✔
172
    if (tr->has_table(c_flx_metadata_table)) {
4,916✔
173
        return;
16✔
174
    }
16✔
175

2,280✔
176
    if (tr->has_table(c_sync_internal_schemas_table)) {
4,900✔
177
        // Load m_table with the table/schema information
704✔
178
        load_sync_metadata_schema(tr, &unified_schema_version_table_def);
1,394✔
179
    }
1,394✔
180
}
4,900✔
181

182
std::optional<int64_t> SyncMetadataSchemaVersionsReader::get_version_for(const TransactionRef& tr,
183
                                                                         std::string_view schema_group_name)
184
{
4,952✔
185
    if (!m_table) {
4,952✔
186
        return util::none;
2,602✔
187
    }
2,602✔
188

1,180✔
189
    auto schema_versions = tr->get_table(m_table);
2,350✔
190
    auto obj_key = schema_versions->find_primary_key(Mixed{StringData(schema_group_name)});
2,350✔
191
    if (!obj_key) {
2,350✔
192
        return util::none;
1,802✔
193
    }
1,802✔
194
    auto metadata_obj = schema_versions->get_object(obj_key);
548✔
195
    if (!metadata_obj) {
548✔
UNCOV
196
        return util::none;
×
UNCOV
197
    }
×
198

280✔
199
    return metadata_obj.get<int64_t>(m_version_field);
548✔
200
}
548✔
201

202
SyncMetadataSchemaVersions::SyncMetadataSchemaVersions(const TransactionRef& tr)
203
    : SyncMetadataSchemaVersionsReader(tr)
204
{
2,184✔
205
    TableKey legacy_table_key;
2,184✔
206
    ColKey legacy_version_key;
2,184✔
207
    std::vector<SyncMetadataTable> legacy_table_def{
2,184✔
208
        {&legacy_table_key, c_flx_metadata_table, {{&legacy_version_key, c_meta_schema_version_field, type_Int}}}};
2,184✔
209
    std::vector<SyncMetadataTable> unified_schema_version_table_def{
2,184✔
210
        {&m_table,
2,184✔
211
         c_sync_internal_schemas_table,
2,184✔
212
         {&m_schema_group_field, c_meta_schema_schema_group_field, type_String},
2,184✔
213
         {{&m_version_field, c_meta_schema_version_field, type_Int}}}};
2,184✔
214

1,094✔
215
    REALM_ASSERT_3(tr->get_transact_stage(), ==, DB::transact_Reading);
2,184✔
216
    // If the versions table exists, then m_table would have been initialized by the reader constructor
1,094✔
217
    // If the versions table doesn't exist, then initialize it now
1,094✔
218
    if (!m_table) {
2,184✔
219
        // table should have already been initialized or needs to be created,
458✔
220
        // but re-initialize in case it isn't (e.g. both unified and legacy tables exist in DB)
458✔
221
        if (REALM_UNLIKELY(tr->has_table(c_sync_internal_schemas_table))) {
920✔
222
            load_sync_metadata_schema(tr, &unified_schema_version_table_def);
4✔
223
        }
4✔
224
        else {
916✔
225
            tr->promote_to_write();
916✔
226
            create_sync_metadata_schema(tr, &unified_schema_version_table_def);
916✔
227
            tr->commit_and_continue_as_read();
916✔
228
        }
916✔
229
    }
920✔
230

1,094✔
231
    if (!tr->has_table(c_flx_metadata_table)) {
2,184✔
232
        return;
2,172✔
233
    }
2,172✔
234

6✔
235
    // Convert the legacy table to the regular schema versions table if it exists
6✔
236
    load_sync_metadata_schema(tr, &legacy_table_def);
12✔
237
    // Migrate from just having a subscription store metadata table to having multiple table groups with multiple
6✔
238
    // versions.
6✔
239
    tr->promote_to_write();
12✔
240
    auto legacy_meta_table = tr->get_table(legacy_table_key);
12✔
241
    auto legacy_obj = legacy_meta_table->get_object(0);
12✔
242
    // Only the flx subscription store can potentially have the legacy metadata table
6✔
243
    set_version_for(tr, internal_schema_groups::c_flx_subscription_store,
12✔
244
                    legacy_obj.get<int64_t>(legacy_version_key));
12✔
245
    tr->remove_table(legacy_table_key);
12✔
246
    tr->commit_and_continue_as_read();
12✔
247
}
12✔
248

249
void SyncMetadataSchemaVersions::set_version_for(const TransactionRef& tr, std::string_view schema_group_name,
250
                                                 int64_t version)
251
{
1,740✔
252
    REALM_ASSERT(m_table);
1,740✔
253

866✔
254
    auto schema_versions = tr->get_table(m_table);
1,740✔
255
    auto metadata_obj = schema_versions->create_object_with_primary_key(Mixed{StringData(schema_group_name)});
1,740✔
256
    metadata_obj.set(m_version_field, version);
1,740✔
257
}
1,740✔
258

259
} // namespace realm::sync
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