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

realm / realm-core / jorgen.edelbo_402

21 Aug 2024 11:10AM UTC coverage: 91.054% (-0.03%) from 91.085%
jorgen.edelbo_402

Pull #7803

Evergreen

jedelbo
Small fix to Table::typed_write

When writing the realm to a new file from a write transaction,
the Table may be COW so that the top ref is changed. So don't
use the ref that is present in the group when the operation starts.
Pull Request #7803: Feature/string compression

103494 of 181580 branches covered (57.0%)

1929 of 1999 new or added lines in 46 files covered. (96.5%)

695 existing lines in 51 files now uncovered.

220142 of 241772 relevant lines covered (91.05%)

7344461.76 hits per line

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

91.95
/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
{
234,936✔
32
    uint64_t value = Array::get(ndx);
234,936✔
33
    if (value == 0) {
234,936✔
34
        return;
228,543✔
35
    }
228,543✔
36

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

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

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

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

65
        size_t sz = backlink_list.size();
594✔
66
        for (size_t i = 0; i < sz; i++) {
1,794✔
67
            state.enqueue_for_nullification(*source_table, src_col_key, ObjKey(backlink_list.get(i)),
1,200✔
68
                                            {target_table->get_key(), target_key});
1,200✔
69
        }
1,200✔
70
    }
594✔
71
}
6,393✔
72

73
void ArrayBacklink::add(size_t ndx, ObjKey key)
74
{
7,061,022✔
75
    uint64_t value = Array::get(ndx);
7,061,022✔
76

77
    // A backlink list of size 1 is stored as a single non-ref column value.
78
    if (value == 0) {
7,061,022✔
79
        set(ndx, key.value << 1 | 1); // Throws
807,777✔
80
        return;
807,777✔
81
    }
807,777✔
82

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

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

109
    // If there is only a single backlink, it can be stored as
110
    // a tagged value
111
    if ((value & 1) != 0) {
514,032✔
112
        REALM_ASSERT_DEBUG(int64_t(value >> 1) == key.value);
259,002✔
113
        if (int64_t(value >> 1) == key.value) {
259,008✔
114
            set(ndx, 0);
259,008✔
115
            return true;
259,008✔
116
        }
259,008✔
117
        return false;
2,147,483,647✔
118
    }
259,002✔
119

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

127
    size_t last_ndx = backlink_list.size() - 1;
255,030✔
128
    size_t backlink_ndx = backlink_list.find_first(key.value);
255,030✔
129
    REALM_ASSERT_DEBUG(backlink_ndx != not_found);
255,030✔
130
    if (backlink_ndx != not_found) {
255,246✔
131
        if (backlink_ndx != last_ndx)
255,231✔
132
            backlink_list.set(backlink_ndx, backlink_list.get(last_ndx));
148,707✔
133
        backlink_list.erase(last_ndx); // Throws
255,231✔
134
    }
255,231✔
135

136
    // If there is only one backlink left we can inline it as tagged value
137
    if (last_ndx == 1) {
255,030✔
138
        uint64_t key_value = backlink_list.get(0);
44,337✔
139
        backlink_list.destroy();
44,337✔
140

141
        set(ndx, key_value << 1 | 1);
44,337✔
142
    }
44,337✔
143

144
    return false;
255,030✔
145
}
514,032✔
146

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

156
size_t ArrayBacklink::get_backlink_count(size_t ndx) const
157
{
1,488,882✔
158
    uint64_t value = Array::get(ndx);
1,488,882✔
159
    if (value == 0) {
1,488,882✔
160
        return 0;
634,731✔
161
    }
634,731✔
162

163
    // If there is only a single backlink, it can be stored as
164
    // a tagged value
165
    if ((value & 1) != 0) {
854,151✔
166
        return 1;
622,188✔
167
    }
622,188✔
168

169
    // return size of list
170
    MemRef mem(ref_type(value), m_alloc);
231,963✔
171
    return BPlusTree<int64_t>::size_from_header(mem.get_addr());
231,963✔
172
}
854,151✔
173

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

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

186
    BPlusTree<int64_t> backlink_list(m_alloc);
9,194,460✔
187
    backlink_list.init_from_ref(ref_type(value));
9,194,460✔
188

189
    REALM_ASSERT(index < backlink_list.size());
9,194,460✔
190
    return ObjKey(backlink_list.get(index));
9,194,460✔
191
}
9,407,259✔
192

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

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

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

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

218
            if (src_col_key.get_type() == col_type_Mixed) {
88,170✔
219
                if (src_col_key.is_collection()) {
24✔
220
                    REALM_ASSERT(src_obj.get_collection_ptr(src_col_key)->find_any(target_link) != npos);
18✔
221
                }
18✔
222
                else {
6✔
223
                    auto val = src_obj.get<Mixed>(src_col_key);
6✔
224
                    if (val.is_type(type_TypedLink)) {
6✔
225
                        REALM_ASSERT(src_obj.get<Mixed>(src_col_key).get_link() == target_link);
6✔
226
                    }
6✔
227
                    else if (val.is_type(type_List)) {
×
NEW
228
                        DummyParent parent(src_table, val.get_ref(), src_col_key);
×
229
                        Lst<Mixed> list(parent, 0);
×
230
                        REALM_ASSERT(list.find_any(target_link) != npos);
×
231
                    }
×
232
                    else if (val.is_type(type_Dictionary)) {
×
NEW
233
                        DummyParent parent(src_table, val.get_ref(), src_col_key);
×
234
                        Dictionary dict(parent, 0);
×
235
                        REALM_ASSERT(dict.find_any(target_link) != npos);
×
236
                    }
×
237
                }
6✔
238
                continue;
24✔
239
            }
24✔
240

241
            if (src_col_key.is_list()) {
88,146✔
242
                REALM_ASSERT(src_obj.get_list<ObjKey>(src_col_key).find_first(target_key) != npos);
27,438✔
243
            }
27,438✔
244
            else if (src_col_key.is_set()) {
60,708✔
245
                REALM_ASSERT(src_obj.get_set<ObjKey>(src_col_key).find(target_key) != npos);
×
246
            }
×
247
            else {
60,708✔
248
                REALM_ASSERT(src_obj.get_unfiltered_link(src_col_key) == target_key);
60,708✔
249
            }
60,708✔
250
        }
88,146✔
251
    }
18,876✔
252
#endif
2,454✔
253
}
2,454✔
254

255
bool ArrayBacklink::verify_backlink(size_t ndx, int64_t link)
256
{
120,714✔
257
#ifdef REALM_DEBUG
120,714✔
258
    uint64_t value = Array::get(ndx);
120,714✔
259
    if (value == 0)
120,714✔
260
        return false;
×
261

262
    // If there is only a single backlink, it can be stored as
263
    // a tagged value
264
    if ((value & 1) != 0) {
120,714✔
265
        return int64_t(value >> 1) == link;
564✔
266
    }
564✔
267

268
    BPlusTree<int64_t> backlink_list(m_alloc);
120,150✔
269
    backlink_list.init_from_ref(ref_type(value));
120,150✔
270

271
    return backlink_list.find_first(link) != realm::not_found;
120,150✔
272
#else
273
    static_cast<void>(ndx);
274
    static_cast<void>(link);
275
    return true;
276
#endif
277
}
120,714✔
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