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

realm / realm-core / jorgen.edelbo_390

12 Aug 2024 12:13PM UTC coverage: 91.108% (+0.02%) from 91.085%
jorgen.edelbo_390

Pull #7979

Evergreen

jedelbo
Create test file in file-format 24
Pull Request #7979: Create test file in file-format 24

102766 of 181590 branches covered (56.59%)

19 of 19 new or added lines in 1 file covered. (100.0%)

1020 existing lines in 55 files now uncovered.

217365 of 238579 relevant lines covered (91.11%)

5621116.99 hits per line

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

89.47
/src/realm/node.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2018 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/node.hpp>
20
#include <realm/utilities.hpp>
21
#include <realm/mixed.hpp>
22

23
#if REALM_ENABLE_MEMDEBUG
24
#include <cstring>
25
#endif
26

27
using namespace realm;
28

29
MemRef Node::create_node(size_t size, Allocator& alloc, bool context_flag, Type type, WidthType width_type, int width)
30
{
54,624✔
31
    size_t byte_size_0 = calc_byte_size(width_type, size, width);
54,624✔
32
    size_t byte_size = std::max(byte_size_0, size_t(initial_capacity));
54,624✔
33

34
    MemRef mem = alloc.alloc(byte_size); // Throws
54,624✔
35
    char* header = mem.get_addr();
54,624✔
36

37
    init_header(header, type == type_InnerBptreeNode, type != type_Normal, context_flag, width_type, width, size,
54,624✔
38
                byte_size);
54,624✔
39

40
    return mem;
54,624✔
41
}
54,624✔
42

43
size_t Node::calc_byte_len(size_t num_items, size_t width) const
44
{
923,027,256✔
45
    REALM_ASSERT_3(get_wtype_from_header(get_header_from_data(m_data)), ==, wtype_Bits);
923,027,256✔
46

47
    // FIXME: Consider calling `calc_aligned_byte_size(size)`
48
    // instead. Note however, that calc_byte_len() is supposed to return
49
    // the unaligned byte size. It is probably the case that no harm
50
    // is done by returning the aligned version, and most callers of
51
    // calc_byte_len() will actually benefit if calc_byte_len() was
52
    // changed to always return the aligned byte size.
53

54
    size_t bits = num_items * width;
923,027,256✔
55
    size_t bytes = (bits + 7) / 8; // round up
923,027,256✔
56
    return bytes + header_size;    // add room for 8 byte header
923,027,256✔
57
}
923,027,256✔
58

59
size_t Node::calc_item_count(size_t bytes, size_t width) const noexcept
UNCOV
60
{
×
UNCOV
61
    if (width == 0)
×
UNCOV
62
        return std::numeric_limits<size_t>::max(); // Zero width gives "infinite" space
×
63

UNCOV
64
    size_t bytes_data = bytes - header_size; // ignore 8 byte header
×
UNCOV
65
    size_t total_bits = bytes_data * 8;
×
UNCOV
66
    return total_bits / width;
×
UNCOV
67
}
×
68

69
void Node::alloc(size_t init_size, size_t new_width)
70
{
939,552,093✔
71
    REALM_ASSERT(is_attached());
939,552,093✔
72

73
    size_t needed_bytes = calc_byte_len(init_size, new_width);
939,552,093✔
74
    // this method is not public and callers must (and currently do) ensure that
75
    // needed_bytes are never larger than max_array_payload.
76
    REALM_ASSERT_RELEASE(init_size <= max_array_size);
939,552,093✔
77

78
    if (is_read_only())
939,552,093✔
79
        do_copy_on_write(needed_bytes);
7,141,452✔
80

81
    REALM_ASSERT(!m_alloc.is_read_only(m_ref));
939,552,093✔
82
    char* header = get_header_from_data(m_data);
939,552,093✔
83
    size_t orig_capacity_bytes = get_capacity_from_header(header);
939,552,093✔
84
    size_t orig_width = get_width_from_header(header);
939,552,093✔
85

86
    if (orig_capacity_bytes < needed_bytes) {
939,552,093✔
87
        // Double to avoid too many reallocs (or initialize to initial size), but truncate if that exceeds the
88
        // maximum allowed payload (measured in bytes) for arrays. This limitation is due to 24-bit capacity
89
        // field in the header.
90
        size_t new_capacity_bytes = orig_capacity_bytes * 2;
3,877,839✔
91
        if (new_capacity_bytes < orig_capacity_bytes) // overflow detected, clamp to max
3,877,839✔
UNCOV
92
            new_capacity_bytes = max_array_payload_aligned;
×
93
        if (new_capacity_bytes > max_array_payload_aligned) // cap at max allowed allocation
3,877,839✔
94
            new_capacity_bytes = max_array_payload_aligned;
6✔
95

96
        // If doubling is not enough, expand enough to fit
97
        if (new_capacity_bytes < needed_bytes) {
3,877,839✔
98
            size_t rest = (~needed_bytes & 0x7) + 1;
1,856,721✔
99
            new_capacity_bytes = needed_bytes;
1,856,721✔
100
            if (rest < 8)
1,856,721✔
101
                new_capacity_bytes += rest; // 64bit align
1,674,147✔
102
        }
1,856,721✔
103

104
        // Allocate and update header
105
        MemRef mem_ref = m_alloc.realloc_(m_ref, header, orig_capacity_bytes, new_capacity_bytes); // Throws
3,877,839✔
106

107
        header = mem_ref.get_addr();
3,877,839✔
108
        set_capacity_in_header(new_capacity_bytes, header);
3,877,839✔
109

110
        // Update this accessor and its ancestors
111
        m_ref = mem_ref.get_ref();
3,877,839✔
112
        m_data = get_data_from_header(header);
3,877,839✔
113
        // FIXME: Trouble when this one throws. We will then leave
114
        // this array instance in a corrupt state
115
        update_parent(); // Throws
3,877,839✔
116
    }
3,877,839✔
117

118
    // Update header
119
    if (new_width != orig_width) {
939,552,093✔
120
        set_width_in_header(int(new_width), header);
24,110,529✔
121
    }
24,110,529✔
122
    set_size_in_header(init_size, header);
939,552,093✔
123
    m_size = init_size;
939,552,093✔
124
}
939,552,093✔
125

126
void Node::do_copy_on_write(size_t minimum_size)
127
{
15,408,249✔
128
    const char* header = get_header_from_data(m_data);
15,408,249✔
129

130
    // Calculate size in bytes
131
    size_t array_size = calc_byte_size(get_wtype_from_header(header), m_size, get_width_from_header(header));
15,408,249✔
132
    size_t new_size = std::max(array_size, minimum_size);
15,408,249✔
133
    new_size = (new_size + 0x7) & ~size_t(0x7); // 64bit blocks
15,408,249✔
134
    // Plus a bit of matchcount room for expansion
135
    new_size += 64;
15,408,249✔
136

137
    // Create new copy of array
138
    MemRef mref = m_alloc.alloc(new_size); // Throws
15,408,249✔
139
    const char* old_begin = header;
15,408,249✔
140
    const char* old_end = header + array_size;
15,408,249✔
141
    char* new_begin = mref.get_addr();
15,408,249✔
142
    realm::safe_copy_n(old_begin, old_end - old_begin, new_begin);
15,408,249✔
143

144
    ref_type old_ref = m_ref;
15,408,249✔
145

146
    // Update internal data
147
    m_ref = mref.get_ref();
15,408,249✔
148
    m_data = get_data_from_header(new_begin);
15,408,249✔
149

150
    // Update capacity in header. Uses m_data to find header, so
151
    // m_data must be initialized correctly first.
152
    set_capacity_in_header(new_size, new_begin);
15,408,249✔
153

154
    update_parent();
15,408,249✔
155

156
#if REALM_ENABLE_MEMDEBUG
157
    if (!m_alloc.is_read_only(old_ref)) {
158
        // Overwrite free'd array with 0x77. We cannot overwrite the header because free_() needs to know the size
159
        // of the allocated block in order to free it. This size is computed from the width and size header
160
        // fields.
161
        memset(const_cast<char*>(old_begin) + header_size, 0x77, old_end - old_begin - header_size);
162
    }
163
#endif
164

165
    // Mark original as deleted, so that the space can be reclaimed in
166
    // future commits, when no versions are using it anymore
167
    m_alloc.free_(old_ref, old_begin);
15,408,249✔
168
}
15,408,249✔
169

170
ArrayPayload::~ArrayPayload() {}
262,438,827✔
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