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

realm / realm-core / jorgen.edelbo_337

03 Jul 2024 01:04PM UTC coverage: 90.864% (-0.1%) from 90.984%
jorgen.edelbo_337

Pull #7826

Evergreen

nicola-cab
Merge branch 'master' of github.com:realm/realm-core into next-major
Pull Request #7826: Merge Next major

102968 of 181176 branches covered (56.83%)

3131 of 3738 new or added lines in 54 files covered. (83.76%)

106 existing lines in 23 files now uncovered.

217725 of 239616 relevant lines covered (90.86%)

6844960.2 hits per line

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

83.33
/src/realm/cluster.hpp
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
#ifndef REALM_CLUSTER_HPP
20
#define REALM_CLUSTER_HPP
21

22
#include <realm/keys.hpp>
23
#include <realm/mixed.hpp>
24
#include <realm/array.hpp>
25
#include <realm/array_unsigned.hpp>
26
#include <realm/data_type.hpp>
27
#include <realm/column_type_traits.hpp>
28

29
namespace realm {
30

31
class Spec;
32
class Table;
33
class Obj;
34
class Cluster;
35
class ClusterNodeInner;
36
class ClusterTree;
37
class ColumnAttrMask;
38
class CascadeState;
39

40
struct FieldValue {
41
    FieldValue(ColKey k, Mixed val, bool is_default = false) noexcept
42
        : col_key(k)
455,070✔
43
        , value(val)
455,070✔
44
        , is_default(is_default)
455,070✔
45
    {
932,649✔
46
    }
932,649✔
47
    ColKey col_key;
48
    Mixed value;
49
    bool is_default;
50
};
51

52
class FieldValues {
53
public:
54
    FieldValues() {}
24,321,942✔
55
    FieldValues(std::initializer_list<FieldValue>);
56
    void insert(ColKey k, Mixed val, bool is_default = false);
57
    auto begin() const noexcept
58
    {
59,017,128✔
59
        return m_values.begin();
59,017,128✔
60
    }
59,017,128✔
61
    auto end() const noexcept
62
    {
83,939,994✔
63
        return m_values.end();
83,939,994✔
64
    }
83,939,994✔
65
    auto begin() noexcept
66
    {
173,400✔
67
        return m_values.begin();
173,400✔
68
    }
173,400✔
69
    auto end() noexcept
70
    {
173,400✔
71
        return m_values.end();
173,400✔
72
    }
173,400✔
73

74
private:
75
    std::vector<FieldValue> m_values;
76
};
77

78
class ClusterNode : public Array {
79
public:
80
    struct RowKey {
81
        RowKey()
82
            : value(-1)
192,526,545✔
83
        {
393,088,104✔
84
        }
393,088,104✔
85
        RowKey(uint64_t v)
86
            : value(v)
193,358,796✔
87
        {
395,353,272✔
88
        }
395,353,272✔
89
        explicit RowKey(ObjKey k)
90
            : value(k.value)
153,736,410✔
91
        {
315,400,800✔
92
        }
315,400,800✔
93
        uint64_t value;
94
    };
95
    // This structure is used to bring information back to the upper nodes when
96
    // inserting new objects or finding existing ones.
97
    struct State {
98
        int64_t split_key;          // When a node is split, this variable holds the value of the
99
                                    // first key in the new node. (Relative to the key offset)
100
        MemRef mem;                 // MemRef to the Cluster holding the new/found object
101
        size_t index = realm::npos; // The index within the Cluster at which the object is stored.
102

103
        operator bool() const
104
        {
27,441,030✔
105
            return index != realm::npos;
27,441,030✔
106
        }
27,441,030✔
107
    };
108

109
    struct IteratorState {
110
        IteratorState(Cluster& leaf)
111
            : m_current_leaf(leaf)
4,883,133✔
112
        {
10,147,140✔
113
        }
10,147,140✔
114
        IteratorState(const IteratorState&);
115
        void clear();
116
        void init(State&, ObjKey);
117

118
        Cluster& m_current_leaf;
119
        int64_t m_key_offset = 0;
120
        size_t m_current_index = 0;
121
    };
122

123
    ClusterNode(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
124
        : Array(allocator)
208,096,848✔
125
        , m_tree_top(tree_top)
208,096,848✔
126
        , m_keys(allocator)
208,096,848✔
127
        , m_offset(offset)
208,096,848✔
128
    {
427,330,701✔
129
        m_keys.set_parent(this, 0);
427,330,701✔
130
    }
427,330,701✔
131
    virtual ~ClusterNode() {}
426,316,008✔
132
    void init_from_parent()
133
    {
3,295,494✔
134
        ref_type ref = get_ref_from_parent();
3,295,494✔
135
        char* header = m_alloc.translate(ref);
3,295,494✔
136
        init(MemRef(header, ref, m_alloc));
3,295,494✔
137
    }
3,295,494✔
138
    int64_t get_key_value(size_t ndx) const
139
    {
42,625,137✔
140
        return m_keys.get(ndx);
42,625,137✔
141
    }
42,625,137✔
142

143
    const Table* get_owning_table() const noexcept;
144

145
    virtual void update_from_parent() noexcept = 0;
146
    virtual bool is_leaf() const = 0;
147
    virtual int get_sub_tree_depth() const = 0;
148
    virtual size_t node_size() const = 0;
149
    /// Number of elements in this subtree
150
    virtual size_t get_tree_size() const = 0;
151
    /// Last key in this subtree
152
    virtual int64_t get_last_key_value() const = 0;
153
    virtual void ensure_general_form() = 0;
154

155
    /// Initialize node from 'mem'
156
    virtual void init(MemRef mem) = 0;
157
    /// Descend the tree from the root and copy-on-write the leaf
158
    /// This will update all parents accordingly
159
    virtual MemRef ensure_writeable(RowKey k) = 0;
160
    /// A leaf cluster has got a new ref. Descend the tree from the root,
161
    /// find the leaf and update the ref in the parent node
162
    virtual void update_ref_in_parent(RowKey k, ref_type ref) = 0;
163

164
    /// Init and potentially Insert a column
165
    virtual void insert_column(ColKey col) = 0;
166
    /// Clear and potentially Remove a column
167
    virtual void remove_column(ColKey col) = 0;
168
    /// Return number of columns created. To be used by upgrade logic
169
    virtual size_t nb_columns() const
170
    {
×
171
        return realm::npos;
×
172
    }
×
173
    /// Create a new object identified by 'key' and update 'state' accordingly
174
    /// Return reference to new node created (if any)
175
    virtual ref_type insert(RowKey k, const FieldValues& init_values, State& state) = 0;
176
    /// Locate object identified by 'key' and update 'state' accordingly
177
    void get(ObjKey key, State& state) const;
178
    /// Locate object identified by 'key' and update 'state' accordingly
179
    /// Returns `false` if the object doesn't not exist.
180
    virtual bool try_get(RowKey key, State& state) const noexcept = 0;
181
    /// Locate object identified by 'ndx' and update 'state' accordingly
182
    virtual ObjKey get(size_t ndx, State& state) const = 0;
183
    /// Return the index at which key is stored
184
    virtual size_t get_ndx(RowKey key, size_t ndx) const noexcept = 0;
185

186
    /// Erase element identified by 'key'
187
    virtual size_t erase(RowKey key, CascadeState& state) = 0;
188

189
    /// Nullify links pointing to element identified by 'key'
190
    virtual void nullify_incoming_links(RowKey key, CascadeState& state) = 0;
191

192
    /// Move elements from position 'ndx' to 'new_node'. The new node is supposed
193
    /// to be a sibling positioned right after this one. All key values must
194
    /// be subtracted 'key_adj'
195
    virtual void move(size_t ndx, ClusterNode* new_leaf, int64_t key_adj) = 0;
196

197
    virtual void dump_objects(int64_t key_offset, std::string lead) const = 0;
198

199
    ObjKey get_real_key(size_t ndx) const
200
    {
41,335,530✔
201
        return ObjKey(get_key_value(ndx) + m_offset);
41,335,530✔
202
    }
41,335,530✔
203
    const ArrayUnsigned* get_key_array() const
204
    {
6,276,963✔
205
        return m_keys.is_attached() ? &m_keys : nullptr;
6,276,963✔
206
    }
6,276,963✔
207
    void set_offset(uint64_t offs)
208
    {
96,654,537✔
209
        m_offset = offs;
96,654,537✔
210
    }
96,654,537✔
211
    uint64_t get_offset() const
212
    {
44,073,426✔
213
        return m_offset;
44,073,426✔
214
    }
44,073,426✔
215
    virtual ref_type typed_write(ref_type ref, _impl::ArrayWriterBase& out) const = 0;
216

217
    virtual void typed_print(std::string prefix) const
NEW
218
    {
×
NEW
219
        static_cast<void>(get_owning_table());
×
NEW
220
        std::cout << "ClusterNode as ";
×
NEW
221
        Array::typed_print(prefix);
×
NEW
222
    }
×
223

224
protected:
225
#if REALM_MAX_BPNODE_SIZE > 256
226
    static constexpr int node_shift_factor = 8;
227
#else
228
    static constexpr int node_shift_factor = 2;
229
#endif
230

231
    static constexpr size_t cluster_node_size = 1 << node_shift_factor;
232

233
    class ClusterKeyArray : public ArrayUnsigned {
234
    public:
235
        using ArrayUnsigned::ArrayUnsigned;
236

237
        uint64_t get(size_t ndx) const
238
        {
519,854,463✔
239
            return is_attached() ? ArrayUnsigned::get(ndx) : uint64_t(ndx);
519,854,463✔
240
        }
519,854,463✔
241
    };
242

243
    const ClusterTree& m_tree_top;
244
    ClusterKeyArray m_keys;
245
    uint64_t m_offset;
246
};
247

248
class Cluster : public ClusterNode {
249
public:
250
    Cluster(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
251
        : ClusterNode(offset, allocator, tree_top)
159,682,503✔
252
    {
330,001,857✔
253
    }
330,001,857✔
254
    ~Cluster() override;
255

256
    static MemRef create_empty_cluster(Allocator& alloc);
257

258
    void create(); // Note: leaf columns - may include holes
259
    void init(MemRef mem) override;
260
    void update_from_parent() noexcept override;
261

262
    bool is_writeable() const
263
    {
×
264
        return !Array::is_read_only();
×
265
    }
×
266
    MemRef ensure_writeable(RowKey k) override;
267
    void update_ref_in_parent(RowKey, ref_type ref) override;
268

269
    bool is_leaf() const override
270
    {
12,539,844✔
271
        return true;
12,539,844✔
272
    }
12,539,844✔
273
    int get_sub_tree_depth() const override
274
    {
3,264✔
275
        return 0;
3,264✔
276
    }
3,264✔
277
    static size_t node_size_from_header(Allocator& alloc, const char* header);
278
    size_t node_size() const override
279
    {
50,750,958✔
280
        if (!is_attached()) {
50,750,958✔
281
            return 0;
×
282
        }
×
283
        return m_keys.is_attached() ? m_keys.size() : get_size_in_compact_form();
50,750,958✔
284
    }
50,750,958✔
285
    size_t get_tree_size() const override
286
    {
12,754,854✔
287
        return node_size();
12,754,854✔
288
    }
12,754,854✔
289
    int64_t get_last_key_value() const override
290
    {
×
291
        auto sz = node_size();
×
292
        return sz ? get_key_value(sz - 1) : -1;
×
293
    }
×
294
    size_t lower_bound_key(RowKey key) const
295
    {
2,274,435✔
296
        if (m_keys.is_attached()) {
2,274,435✔
297
            return m_keys.lower_bound(key.value);
327,003✔
298
        }
327,003✔
299
        size_t sz = size_t(Array::get(0)) >> 1;
1,947,432✔
300
        return key.value > sz ? sz : size_t(key.value);
1,947,432✔
301
    }
2,274,435✔
302

303
    void adjust_keys(int64_t offset)
304
    {
12,030✔
305
        ensure_general_form();
12,030✔
306
        m_keys.adjust(0, m_keys.size(), offset);
12,030✔
307
    }
12,030✔
308

309
    ColKey get_col_key(size_t ndx_in_parent) const;
310

311
    void ensure_general_form() override;
312
    void insert_column(ColKey col) override; // Does not move columns!
313
    void remove_column(ColKey col) override; // Does not move columns - may leave a 'hole'
314
    size_t nb_columns() const override
315
    {
×
316
        return size() - s_first_col_index;
×
317
    }
×
318
    ref_type insert(RowKey k, const FieldValues& init_values, State& state) override;
319
    bool try_get(RowKey k, State& state) const noexcept override;
320
    ObjKey get(size_t, State& state) const override;
321
    size_t get_ndx(RowKey key, size_t ndx) const noexcept override;
322
    size_t erase(RowKey k, CascadeState& state) override;
323
    void nullify_incoming_links(RowKey key, CascadeState& state) override;
324
    void upgrade_string_to_enum(ColKey col, ArrayString& keys);
325

326
    void init_leaf(ColKey col, ArrayPayload* leaf) const;
327
    void add_leaf(ColKey col, ref_type ref);
328

329
    void verify() const;
330
    void dump_objects(int64_t key_offset, std::string lead) const override;
331
    virtual ref_type typed_write(ref_type ref, _impl::ArrayWriterBase& out) const override;
332
    virtual void typed_print(std::string prefix) const override;
333
    static void remove_backlinks(const Table* origin_table, ObjKey origin_key, ColKey col,
334
                                 const std::vector<ObjKey>& keys, CascadeState& state);
335
    static void remove_backlinks(const Table* origin_table, ObjKey origin_key, ColKey col,
336
                                 const std::vector<ObjLink>& links, CascadeState& state);
337

338
private:
339
    friend class ClusterTree;
340

341
    static constexpr size_t s_key_ref_or_size_index = 0;
342
    static constexpr size_t s_first_col_index = 1;
343

344
    size_t get_size_in_compact_form() const
345
    {
37,991,727✔
346
        return size_t(Array::get(s_key_ref_or_size_index)) >> 1; // Size is stored as tagged value
37,991,727✔
347
    }
37,991,727✔
348
    void insert_row(size_t ndx, RowKey k, const FieldValues& init_values);
349
    void move(size_t ndx, ClusterNode* new_node, int64_t key_adj) override;
350
    template <class T>
351
    void do_create(ColKey col);
352
    template <class T>
353
    void do_insert_column(ColKey col, bool nullable);
354
    template <class T>
355
    void do_insert_row(size_t ndx, ColKey col, Mixed init_val, bool nullable);
356
    template <class T>
357
    void do_move(size_t ndx, ColKey col, Cluster* to);
358
    template <class T>
359
    void do_erase(size_t ndx, ColKey col);
360
    void do_remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjKey>& keys,
361
                             CascadeState& state) const
362
    {
91,125✔
363
        remove_backlinks(get_owning_table(), origin_key, col, keys, state);
91,125✔
364
    }
91,125✔
365
    void do_remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjLink>& links,
366
                             CascadeState& state) const
367
    {
144✔
368
        remove_backlinks(get_owning_table(), origin_key, col, links, state);
144✔
369
    }
144✔
370
    void do_erase_key(size_t ndx, ColKey col, CascadeState& state);
371
    void do_erase_mixed(size_t ndx, ColKey col, CascadeState& state);
372
    void do_insert_key(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
373
    void do_insert_link(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
374
    void do_insert_mixed(size_t ndx, ColKey col_key, Mixed init_value, ObjKey origin_key);
375
    template <class T>
376
    void set_spec(T&, ColKey::Idx) const;
377
    template <class ArrayType>
378
    void verify(ref_type ref, size_t index, util::Optional<size_t>& sz) const;
379
};
380

381
} // namespace realm
382

383
#endif /* SRC_REALM_CLUSTER_HPP_ */
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