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

realm / realm-core / nicola.cabiddu_1040

26 Sep 2023 05:08PM UTC coverage: 91.056% (-1.9%) from 92.915%
nicola.cabiddu_1040

Pull #6766

Evergreen

nicola-cab
several fixes and final client reset algo for collection in mixed
Pull Request #6766: Client Reset for collections in mixed / nested collections

97128 of 178458 branches covered (0.0%)

1524 of 1603 new or added lines in 5 files covered. (95.07%)

4511 existing lines in 109 files now uncovered.

236619 of 259862 relevant lines covered (91.06%)

7169640.31 hits per line

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

95.79
/src/realm/array_backlink.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/array_backlink.hpp>
20
#include <realm/util/assert.hpp>
21
#include <realm/table.hpp>
22
#include <realm/group.hpp>
23
#include <realm/list.hpp>
24
#include <realm/set.hpp>
25
#include <realm/dictionary.hpp>
26

27
using namespace realm;
28

29
// nullify forward links corresponding to any backward links at index 'ndx'.
30
void ArrayBacklink::nullify_fwd_links(size_t ndx, CascadeState& state)
31
{
189,006✔
32
    uint64_t value = Array::get(ndx);
189,006✔
33
    if (value == 0) {
189,006✔
34
        return;
184,317✔
35
    }
184,317✔
36

2,343✔
37
    // Naming: Links go from source to target.
2,343✔
38
    // Backlinks go from target to source.
2,343✔
39
    // This array holds backlinks, hence it is the target.
2,343✔
40
    // The table which holds the corresponding fwd links is the source.
2,343✔
41

2,343✔
42
    // determine target table, column and key.
2,343✔
43
    REALM_ASSERT_DEBUG(dynamic_cast<Cluster*>(get_parent()));
4,689✔
44
    auto cluster = static_cast<Cluster*>(get_parent());
4,689✔
45
    const Table* target_table = cluster->get_owning_table();
4,689✔
46
    ColKey target_col_key = cluster->get_col_key(get_ndx_in_parent());
4,689✔
47
    ObjKey target_key = cluster->get_real_key(ndx);
4,689✔
48

2,343✔
49
    // determine the source table/col - which is the one holding the forward links
2,343✔
50
    TableRef source_table = target_table->get_opposite_table(target_col_key);
4,689✔
51
    ColKey src_col_key = target_table->get_opposite_column(target_col_key);
4,689✔
52

2,343✔
53
    // Now follow all backlinks to their origin and clear forward links.
2,343✔
54
    if ((value & 1) != 0) {
4,689✔
55
        // just a single one
2,064✔
56
        state.enqueue_for_nullification(*source_table, src_col_key, ObjKey(value >> 1),
4,131✔
57
                                        {target_table->get_key(), target_key});
4,131✔
58
    }
4,131✔
59
    else {
558✔
60
        // There is more than one backlink - Iterate through them all
279✔
61
        ref_type ref = to_ref(value);
558✔
62
        BPlusTree<int64_t> backlink_list(m_alloc);
558✔
63
        backlink_list.init_from_ref(ref);
558✔
64

279✔
65
        size_t sz = backlink_list.size();
558✔
66
        for (size_t i = 0; i < sz; i++) {
1,680✔
67
            state.enqueue_for_nullification(*source_table, src_col_key, ObjKey(backlink_list.get(i)),
1,122✔
68
                                            {target_table->get_key(), target_key});
1,122✔
69
        }
1,122✔
70
    }
558✔
71
}
4,689✔
72

73
void ArrayBacklink::add(size_t ndx, ObjKey key)
74
{
6,729,903✔
75
    uint64_t value = Array::get(ndx);
6,729,903✔
76

3,364,278✔
77
    // A backlink list of size 1 is stored as a single non-ref column value.
3,364,278✔
78
    if (value == 0) {
6,729,903✔
79
        set(ndx, key.value << 1 | 1); // Throws
614,262✔
80
        return;
614,262✔
81
    }
614,262✔
82

3,057,648✔
83
    // When increasing the size of the backlink list from 1 to 2, we need to
3,057,648✔
84
    // convert from the single non-ref column value representation, to a B+-tree
3,057,648✔
85
    // representation.
3,057,648✔
86
    BPlusTree<int64_t> backlink_list(m_alloc);
6,115,641✔
87
    if ((value & 1) != 0) {
6,115,641✔
88
        // Create new column to hold backlinks
9,867✔
89
        backlink_list.create();
19,710✔
90
        set_as_ref(ndx, backlink_list.get_ref());
19,710✔
91
        backlink_list.add(value >> 1);
19,710✔
92
    }
19,710✔
93
    else {
6,095,931✔
94
        backlink_list.init_from_ref(to_ref(value));
6,095,931✔
95
        backlink_list.set_parent(this, ndx);
6,095,931✔
96
        backlink_list.split_if_needed();
6,095,931✔
97
    }
6,095,931✔
98
    backlink_list.add(key.value); // Throws
6,115,641✔
99
}
6,115,641✔
100

101
// Return true if the last link was removed
102
bool ArrayBacklink::remove(size_t ndx, ObjKey key)
103
{
204,036✔
104
    uint64_t value = Array::get(ndx);
204,036✔
105
    REALM_ASSERT_DEBUG(value != 0);
204,036✔
106
    if (value == 0)
204,036✔
UNCOV
107
        return true;
×
108

101,964✔
109
    // If there is only a single backlink, it can be stored as
101,964✔
110
    // a tagged value
101,964✔
111
    if ((value & 1) != 0) {
204,036✔
112
        REALM_ASSERT_DEBUG(int64_t(value >> 1) == key.value);
74,955✔
113
        if (int64_t(value >> 1) == key.value) {
74,955✔
114
            set(ndx, 0);
74,955✔
115
            return true;
74,955✔
116
        }
74,955✔
117
        return false;
×
UNCOV
118
    }
×
119

64,521✔
120
    // if there is a list of backlinks we have to find
64,521✔
121
    // the right one and remove it.
64,521✔
122
    BPlusTree<int64_t> backlink_list(m_alloc);
129,081✔
123
    backlink_list.init_from_ref(ref_type(value));
129,081✔
124
    backlink_list.set_parent(this, ndx);
129,081✔
125
    backlink_list.split_if_needed();
129,081✔
126

64,521✔
127
    size_t last_ndx = backlink_list.size() - 1;
129,081✔
128
    size_t backlink_ndx = backlink_list.find_first(key.value);
129,081✔
129
    REALM_ASSERT_DEBUG(backlink_ndx != not_found);
129,081✔
130
    if (backlink_ndx != not_found) {
129,081✔
131
        if (backlink_ndx != last_ndx)
129,081✔
132
            backlink_list.set(backlink_ndx, backlink_list.get(last_ndx));
68,172✔
133
        backlink_list.erase(last_ndx); // Throws
129,081✔
134
    }
129,081✔
135

64,521✔
136
    // If there is only one backlink left we can inline it as tagged value
64,521✔
137
    if (last_ndx == 1) {
129,081✔
138
        uint64_t key_value = backlink_list.get(0);
2,214✔
139
        backlink_list.destroy();
2,214✔
140

1,077✔
141
        set(ndx, key_value << 1 | 1);
2,214✔
142
    }
2,214✔
143

64,521✔
144
    return false;
129,081✔
145
}
129,081✔
146

147
void ArrayBacklink::erase(size_t ndx)
148
{
203,307✔
149
    uint64_t value = Array::get(ndx);
203,307✔
150
    if (value && (value & 1) == 0) {
203,307✔
151
        Array::destroy_deep(ref_type(value), m_alloc);
402✔
152
    }
402✔
153
    Array::erase(ndx);
203,307✔
154
}
203,307✔
155

156
size_t ArrayBacklink::get_backlink_count(size_t ndx) const
157
{
820,764✔
158
    uint64_t value = Array::get(ndx);
820,764✔
159
    if (value == 0) {
820,764✔
160
        return 0;
417,000✔
161
    }
417,000✔
162

201,591✔
163
    // If there is only a single backlink, it can be stored as
201,591✔
164
    // a tagged value
201,591✔
165
    if ((value & 1) != 0) {
403,764✔
166
        return 1;
399,522✔
167
    }
399,522✔
168

2,121✔
169
    // return size of list
2,121✔
170
    MemRef mem(ref_type(value), m_alloc);
4,242✔
171
    return BPlusTree<int64_t>::size_from_header(mem.get_addr());
4,242✔
172
}
4,242✔
173

174
ObjKey ArrayBacklink::get_backlink(size_t ndx, size_t index) const
175
{
365,031✔
176
    uint64_t value = Array::get(ndx);
365,031✔
177
    REALM_ASSERT(value != 0);
365,031✔
178

182,379✔
179
    // If there is only a single backlink, it can be stored as
182,379✔
180
    // a tagged value
182,379✔
181
    if ((value & 1) != 0) {
365,031✔
182
        REALM_ASSERT(index == 0);
215,475✔
183
        return ObjKey(int64_t(value >> 1));
215,475✔
184
    }
215,475✔
185

74,778✔
186
    BPlusTree<int64_t> backlink_list(m_alloc);
149,556✔
187
    backlink_list.init_from_ref(ref_type(value));
149,556✔
188

74,778✔
189
    REALM_ASSERT(index < backlink_list.size());
149,556✔
190
    return ObjKey(backlink_list.get(index));
149,556✔
191
}
149,556✔
192

193
void ArrayBacklink::verify() const
194
{
2,451✔
195
#ifdef REALM_DEBUG
2,451✔
196
    Array::verify();
2,451✔
197

1,260✔
198
    REALM_ASSERT(dynamic_cast<Cluster*>(get_parent()));
2,451✔
199
    auto cluster = static_cast<Cluster*>(get_parent());
2,451✔
200
    const Table* target_table = cluster->get_owning_table();
2,451✔
201
    ColKey backlink_col_key = cluster->get_col_key(get_ndx_in_parent());
2,451✔
202

1,260✔
203
    TableRef src_table = target_table->get_opposite_table(backlink_col_key);
2,451✔
204
    ColKey src_col_key = target_table->get_opposite_column(backlink_col_key);
2,451✔
205

1,260✔
206
    // Verify that each backlink has a corresponding forward link
1,260✔
207
    for (size_t i = 0; i < size(); ++i) {
21,069✔
208
        ObjKey target_key = cluster->get_real_key(i);
18,618✔
209
        ObjLink target_link(target_table->get_key(), target_key);
18,618✔
210
        auto cnt = get_backlink_count(i);
18,618✔
211
        for (size_t j = 0; j < cnt; ++j) {
88,998✔
212
            Obj src_obj = src_table->get_object(get_backlink(i, j));
70,380✔
213
            if (src_col_key.is_dictionary()) {
70,380✔
214
                REALM_ASSERT(src_obj.get_dictionary_ptr(src_col_key)->find_any(target_link) != npos);
294✔
215
                continue;
294✔
216
            }
294✔
217

35,043✔
218
            if (src_col_key.get_type() == col_type_Mixed) {
70,086✔
219
                if (src_col_key.is_collection()) {
6✔
220
                    REALM_ASSERT(src_obj.get_collection_ptr(src_col_key)->find_any(target_link) != npos);
6✔
221
                }
6✔
222
                else {
×
UNCOV
223
                    REALM_ASSERT(src_obj.get<Mixed>(src_col_key).get_link() == target_link);
×
UNCOV
224
                }
×
225
                continue;
6✔
226
            }
6✔
227

35,040✔
228
            if (src_col_key.is_list()) {
70,080✔
229
                REALM_ASSERT(src_obj.get_list<ObjKey>(src_col_key).find_first(target_key) != npos);
9,420✔
230
            }
9,420✔
231
            else if (src_col_key.is_set()) {
60,660✔
UNCOV
232
                REALM_ASSERT(src_obj.get_set<ObjKey>(src_col_key).find(target_key) != npos);
×
UNCOV
233
            }
×
234
            else {
60,660✔
235
                REALM_ASSERT(src_obj.get_unfiltered_link(src_col_key) == target_key);
60,660✔
236
            }
60,660✔
237
        }
70,080✔
238
    }
18,618✔
239
#endif
2,451✔
240
}
2,451✔
241

242
bool ArrayBacklink::verify_backlink(size_t ndx, int64_t link)
243
{
60,660✔
244
#ifdef REALM_DEBUG
60,660✔
245
    uint64_t value = Array::get(ndx);
60,660✔
246
    if (value == 0)
60,660✔
UNCOV
247
        return false;
×
248

30,330✔
249
    // If there is only a single backlink, it can be stored as
30,330✔
250
    // a tagged value
30,330✔
251
    if ((value & 1) != 0) {
60,660✔
252
        return int64_t(value >> 1) == link;
552✔
253
    }
552✔
254

30,054✔
255
    BPlusTree<int64_t> backlink_list(m_alloc);
60,108✔
256
    backlink_list.init_from_ref(ref_type(value));
60,108✔
257

30,054✔
258
    return backlink_list.find_first(link) != realm::not_found;
60,108✔
259
#else
260
    static_cast<void>(ndx);
261
    static_cast<void>(link);
262
    return true;
263
#endif
264
}
60,108✔
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