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

realm / realm-core / jorgen.edelbo_333

01 Jul 2024 07:21AM UTC coverage: 90.865% (-0.08%) from 90.948%
jorgen.edelbo_333

Pull #7826

Evergreen

jedelbo
Merge tag 'v14.10.2' into next-major
Pull Request #7826: Merge Next major

102912 of 181138 branches covered (56.81%)

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

80 existing lines in 14 files now uncovered.

217498 of 239364 relevant lines covered (90.86%)

6655796.15 hits per line

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

82.91
/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)
242,196✔
43
        , value(val)
242,196✔
44
        , is_default(is_default)
242,196✔
45
    {
506,757✔
46
    }
506,757✔
47
    ColKey col_key;
48
    Mixed value;
49
    bool is_default;
50
};
51

52
class FieldValues {
53
public:
54
    FieldValues() {}
24,387,255✔
55
    FieldValues(std::initializer_list<FieldValue>);
56
    void insert(ColKey k, Mixed val, bool is_default = false);
57
    auto begin() const noexcept
58
    {
58,304,112✔
59
        return m_values.begin();
58,304,112✔
60
    }
58,304,112✔
61
    auto end() const noexcept
62
    {
82,387,536✔
63
        return m_values.end();
82,387,536✔
64
    }
82,387,536✔
65
    auto begin() noexcept
66
    {
47,547✔
67
        return m_values.begin();
47,547✔
68
    }
47,547✔
69
    auto end() noexcept
70
    {
47,550✔
71
        return m_values.end();
47,550✔
72
    }
47,550✔
73

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

78
class ClusterNode : public Array {
79
public:
80
    // This structure is used to bring information back to the upper nodes when
81
    // inserting new objects or finding existing ones.
82
    struct State {
83
        int64_t split_key;          // When a node is split, this variable holds the value of the
84
                                    // first key in the new node. (Relative to the key offset)
85
        MemRef mem;                 // MemRef to the Cluster holding the new/found object
86
        size_t index = realm::npos; // The index within the Cluster at which the object is stored.
87

88
        operator bool() const
89
        {
27,601,200✔
90
            return index != realm::npos;
27,601,200✔
91
        }
27,601,200✔
92
    };
93

94
    struct IteratorState {
95
        IteratorState(Cluster& leaf)
96
            : m_current_leaf(leaf)
4,911,096✔
97
        {
10,122,747✔
98
        }
10,122,747✔
99
        IteratorState(const IteratorState&);
100
        void clear();
101
        void init(State&, ObjKey);
102

103
        Cluster& m_current_leaf;
104
        int64_t m_key_offset = 0;
105
        size_t m_current_index = 0;
106
    };
107

108
    ClusterNode(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
109
        : Array(allocator)
205,983,837✔
110
        , m_tree_top(tree_top)
205,983,837✔
111
        , m_keys(allocator)
205,983,837✔
112
        , m_offset(offset)
205,983,837✔
113
    {
422,432,358✔
114
        m_keys.set_parent(this, 0);
422,432,358✔
115
    }
422,432,358✔
116
    virtual ~ClusterNode() {}
421,711,221✔
117
    void init_from_parent()
118
    {
3,252,735✔
119
        ref_type ref = get_ref_from_parent();
3,252,735✔
120
        char* header = m_alloc.translate(ref);
3,252,735✔
121
        init(MemRef(header, ref, m_alloc));
3,252,735✔
122
    }
3,252,735✔
123
    int64_t get_key_value(size_t ndx) const
124
    {
36,548,721✔
125
        return m_keys.get(ndx);
36,548,721✔
126
    }
36,548,721✔
127

128
    const Table* get_owning_table() const noexcept;
129

130
    virtual void update_from_parent() noexcept = 0;
131
    virtual bool is_leaf() const = 0;
132
    virtual int get_sub_tree_depth() const = 0;
133
    virtual size_t node_size() const = 0;
134
    /// Number of elements in this subtree
135
    virtual size_t get_tree_size() const = 0;
136
    /// Last key in this subtree
137
    virtual int64_t get_last_key_value() const = 0;
138
    virtual void ensure_general_form() = 0;
139

140
    /// Initialize node from 'mem'
141
    virtual void init(MemRef mem) = 0;
142
    /// Descend the tree from the root and copy-on-write the leaf
143
    /// This will update all parents accordingly
144
    virtual MemRef ensure_writeable(ObjKey k) = 0;
145
    /// A leaf cluster has got a new ref. Descend the tree from the root,
146
    /// find the leaf and update the ref in the parent node
147
    virtual void update_ref_in_parent(ObjKey k, ref_type ref) = 0;
148

149
    /// Init and potentially Insert a column
150
    virtual void insert_column(ColKey col) = 0;
151
    /// Clear and potentially Remove a column
152
    virtual void remove_column(ColKey col) = 0;
153
    /// Return number of columns created. To be used by upgrade logic
154
    virtual size_t nb_columns() const
155
    {
×
156
        return realm::npos;
×
157
    }
×
158
    /// Create a new object identified by 'key' and update 'state' accordingly
159
    /// Return reference to new node created (if any)
160
    virtual ref_type insert(ObjKey k, const FieldValues& init_values, State& state) = 0;
161
    /// Locate object identified by 'key' and update 'state' accordingly
162
    void get(ObjKey key, State& state) const;
163
    /// Locate object identified by 'key' and update 'state' accordingly
164
    /// Returns `false` if the object doesn't not exist.
165
    virtual bool try_get(ObjKey key, State& state) const noexcept = 0;
166
    /// Locate object identified by 'ndx' and update 'state' accordingly
167
    virtual ObjKey get(size_t ndx, State& state) const = 0;
168
    /// Return the index at which key is stored
169
    virtual size_t get_ndx(ObjKey key, size_t ndx) const noexcept = 0;
170

171
    /// Erase element identified by 'key'
172
    virtual size_t erase(ObjKey key, CascadeState& state) = 0;
173

174
    /// Nullify links pointing to element identified by 'key'
175
    virtual void nullify_incoming_links(ObjKey key, CascadeState& state) = 0;
176

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

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

184
    ObjKey get_real_key(size_t ndx) const
185
    {
35,186,169✔
186
        return ObjKey(get_key_value(ndx) + m_offset);
35,186,169✔
187
    }
35,186,169✔
188
    const ArrayUnsigned* get_key_array() const
189
    {
6,597,432✔
190
        return m_keys.is_attached() ? &m_keys : nullptr;
6,597,432✔
191
    }
6,597,432✔
192
    void set_offset(uint64_t offs)
193
    {
96,480,210✔
194
        m_offset = offs;
96,480,210✔
195
    }
96,480,210✔
196
    uint64_t get_offset() const
197
    {
7,040,058✔
198
        return m_offset;
7,040,058✔
199
    }
7,040,058✔
200
    virtual ref_type typed_write(ref_type ref, _impl::ArrayWriterBase& out) const = 0;
201

202
    virtual void typed_print(std::string prefix) const
NEW
203
    {
×
NEW
204
        static_cast<void>(get_owning_table());
×
NEW
205
        std::cout << "ClusterNode as ";
×
NEW
206
        Array::typed_print(prefix);
×
NEW
207
    }
×
208

209
protected:
210
#if REALM_MAX_BPNODE_SIZE > 256
211
    static constexpr int node_shift_factor = 8;
212
#else
213
    static constexpr int node_shift_factor = 2;
214
#endif
215

216
    static constexpr size_t cluster_node_size = 1 << node_shift_factor;
217

218
    class ClusterKeyArray : public ArrayUnsigned {
219
    public:
220
        using ArrayUnsigned::ArrayUnsigned;
221

222
        uint64_t get(size_t ndx) const
223
        {
509,925,513✔
224
            return is_attached() ? ArrayUnsigned::get(ndx) : uint64_t(ndx);
509,925,513✔
225
        }
509,925,513✔
226
    };
227

228
    const ClusterTree& m_tree_top;
229
    ClusterKeyArray m_keys;
230
    uint64_t m_offset;
231
};
232

233
class Cluster : public ClusterNode {
234
public:
235
    Cluster(uint64_t offset, Allocator& allocator, const ClusterTree& tree_top)
236
        : ClusterNode(offset, allocator, tree_top)
158,089,470✔
237
    {
325,857,006✔
238
    }
325,857,006✔
239
    ~Cluster() override;
240

241
    static MemRef create_empty_cluster(Allocator& alloc);
242

243
    void create(); // Note: leaf columns - may include holes
244
    void init(MemRef mem) override;
245
    void update_from_parent() noexcept override;
246

247
    bool is_writeable() const
248
    {
×
249
        return !Array::is_read_only();
×
250
    }
×
251
    MemRef ensure_writeable(ObjKey k) override;
252
    void update_ref_in_parent(ObjKey, ref_type ref) override;
253

254
    bool is_leaf() const override
255
    {
12,466,599✔
256
        return true;
12,466,599✔
257
    }
12,466,599✔
258
    int get_sub_tree_depth() const override
259
    {
3,111✔
260
        return 0;
3,111✔
261
    }
3,111✔
262
    static size_t node_size_from_header(Allocator& alloc, const char* header);
263
    size_t node_size() const override
264
    {
50,609,172✔
265
        if (!is_attached()) {
50,609,172✔
266
            return 0;
×
267
        }
×
268
        return m_keys.is_attached() ? m_keys.size() : get_size_in_compact_form();
50,609,172✔
269
    }
50,609,172✔
270
    size_t get_tree_size() const override
271
    {
12,766,335✔
272
        return node_size();
12,766,335✔
273
    }
12,766,335✔
274
    int64_t get_last_key_value() const override
275
    {
×
276
        auto sz = node_size();
×
277
        return sz ? get_key_value(sz - 1) : -1;
×
278
    }
×
279
    size_t lower_bound_key(ObjKey key) const
280
    {
2,293,182✔
281
        if (m_keys.is_attached()) {
2,293,182✔
282
            return m_keys.lower_bound(uint64_t(key.value));
329,193✔
283
        }
329,193✔
284
        else {
1,963,989✔
285
            size_t sz = size_t(Array::get(0)) >> 1;
1,963,989✔
286
            if (key.value < 0)
1,963,989✔
287
                return 0;
12✔
288
            if (size_t(key.value) > sz)
1,963,977✔
289
                return sz;
12✔
290
        }
1,963,977✔
291
        return size_t(key.value);
1,963,965✔
292
    }
2,293,182✔
293

294
    void adjust_keys(int64_t offset)
295
    {
12,030✔
296
        ensure_general_form();
12,030✔
297
        m_keys.adjust(0, m_keys.size(), offset);
12,030✔
298
    }
12,030✔
299

300
    ColKey get_col_key(size_t ndx_in_parent) const;
301

302
    void ensure_general_form() override;
303
    void insert_column(ColKey col) override; // Does not move columns!
304
    void remove_column(ColKey col) override; // Does not move columns - may leave a 'hole'
305
    size_t nb_columns() const override
306
    {
×
307
        return size() - s_first_col_index;
×
308
    }
×
309
    ref_type insert(ObjKey k, const FieldValues& init_values, State& state) override;
310
    bool try_get(ObjKey k, State& state) const noexcept override;
311
    ObjKey get(size_t, State& state) const override;
312
    size_t get_ndx(ObjKey key, size_t ndx) const noexcept override;
313
    size_t erase(ObjKey k, CascadeState& state) override;
314
    void nullify_incoming_links(ObjKey key, CascadeState& state) override;
315
    void upgrade_string_to_enum(ColKey col, ArrayString& keys);
316

317
    void init_leaf(ColKey col, ArrayPayload* leaf) const;
318
    void add_leaf(ColKey col, ref_type ref);
319

320
    void verify() const;
321
    void dump_objects(int64_t key_offset, std::string lead) const override;
322
    virtual ref_type typed_write(ref_type ref, _impl::ArrayWriterBase& out) const override;
323
    virtual void typed_print(std::string prefix) const override;
324
    static void remove_backlinks(const Table* origin_table, ObjKey origin_key, ColKey col,
325
                                 const std::vector<ObjKey>& keys, CascadeState& state);
326
    static void remove_backlinks(const Table* origin_table, ObjKey origin_key, ColKey col,
327
                                 const std::vector<ObjLink>& links, CascadeState& state);
328

329
private:
330
    friend class ClusterTree;
331

332
    static constexpr size_t s_key_ref_or_size_index = 0;
333
    static constexpr size_t s_first_col_index = 1;
334

335
    size_t get_size_in_compact_form() const
336
    {
38,788,254✔
337
        return size_t(Array::get(s_key_ref_or_size_index)) >> 1; // Size is stored as tagged value
38,788,254✔
338
    }
38,788,254✔
339
    void insert_row(size_t ndx, ObjKey k, const FieldValues& init_values);
340
    void move(size_t ndx, ClusterNode* new_node, int64_t key_adj) override;
341
    template <class T>
342
    void do_create(ColKey col);
343
    template <class T>
344
    void do_insert_column(ColKey col, bool nullable);
345
    template <class T>
346
    void do_insert_row(size_t ndx, ColKey col, Mixed init_val, bool nullable);
347
    template <class T>
348
    void do_move(size_t ndx, ColKey col, Cluster* to);
349
    template <class T>
350
    void do_erase(size_t ndx, ColKey col);
351
    void do_remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjKey>& keys,
352
                             CascadeState& state) const
353
    {
67,191✔
354
        remove_backlinks(get_owning_table(), origin_key, col, keys, state);
67,191✔
355
    }
67,191✔
356
    void do_remove_backlinks(ObjKey origin_key, ColKey col, const std::vector<ObjLink>& links,
357
                             CascadeState& state) const
358
    {
144✔
359
        remove_backlinks(get_owning_table(), origin_key, col, links, state);
144✔
360
    }
144✔
361
    void do_erase_key(size_t ndx, ColKey col, CascadeState& state);
362
    void do_erase_mixed(size_t ndx, ColKey col, ObjKey key, CascadeState& state);
363
    void do_insert_key(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
364
    void do_insert_link(size_t ndx, ColKey col, Mixed init_val, ObjKey origin_key);
365
    void do_insert_mixed(size_t ndx, ColKey col_key, Mixed init_value, ObjKey origin_key);
366
    template <class T>
367
    void set_spec(T&, ColKey::Idx) const;
368
    template <class ArrayType>
369
    void verify(ref_type ref, size_t index, util::Optional<size_t>& sz) const;
370
};
371

372
} // namespace realm
373

374
#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