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

realm / realm-core / github_pull_request_281750

30 Oct 2023 03:37PM UTC coverage: 90.528% (-1.0%) from 91.571%
github_pull_request_281750

Pull #6073

Evergreen

jedelbo
Log free space and history sizes when opening file
Pull Request #6073: Merge next-major

95488 of 175952 branches covered (0.0%)

8973 of 12277 new or added lines in 149 files covered. (73.09%)

622 existing lines in 51 files now uncovered.

233503 of 257934 relevant lines covered (90.53%)

6533720.56 hits per line

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

96.89
/src/realm/collection.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2023 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/group.hpp>
20
#include <realm/collection.hpp>
21
#include <realm/bplustree.hpp>
22
#include <realm/array_key.hpp>
23
#include <realm/array_string.hpp>
24
#include <realm/array_mixed.hpp>
25

26
namespace realm {
27

28
namespace _impl {
29
size_t virtual2real(const std::vector<size_t>& vec, size_t ndx) noexcept
30
{
6,657,282✔
31
    for (auto i : vec) {
3,328,776✔
32
        if (i > ndx)
522✔
33
            break;
138✔
34
        ndx++;
384✔
35
    }
384✔
36
    return ndx;
6,657,282✔
37
}
6,657,282✔
38

39
size_t virtual2real(const BPlusTree<ObjKey>* tree, size_t ndx) noexcept
40
{
106,230✔
41
    // Only translate if context flag is set.
52,872✔
42
    if (tree->get_context_flag()) {
106,230✔
43
        size_t adjust = 0;
18,156✔
44
        auto func = [&adjust, ndx](BPlusTreeNode* node, size_t offset) {
24,150✔
45
            auto leaf = static_cast<BPlusTree<ObjKey>::LeafNode*>(node);
24,150✔
46
            size_t sz = leaf->size();
24,150✔
47
            for (size_t i = 0; i < sz; i++) {
13,515,900✔
48
                if (i + offset == ndx) {
13,500,888✔
49
                    return IteratorControl::Stop;
9,138✔
50
                }
9,138✔
51
                auto k = leaf->get(i);
13,491,750✔
52
                if (k.is_unresolved()) {
13,491,750✔
53
                    adjust++;
6,745,644✔
54
                }
6,745,644✔
55
            }
13,491,750✔
56
            return IteratorControl::AdvanceToNext;
19,581✔
57
        };
24,150✔
58

9,078✔
59
        tree->traverse(func);
18,156✔
60
        ndx -= adjust;
18,156✔
61
    }
18,156✔
62
    return ndx;
106,230✔
63
}
106,230✔
64

65
size_t real2virtual(const std::vector<size_t>& vec, size_t ndx) noexcept
66
{
32,730✔
67
    // Subtract the number of tombstones below ndx.
16,275✔
68
    auto it = std::lower_bound(vec.begin(), vec.end(), ndx);
32,730✔
69
    auto n = it - vec.begin();
32,730✔
70
    return ndx - n;
32,730✔
71
}
32,730✔
72

73
void update_unresolved(std::vector<size_t>& vec, const BPlusTree<ObjKey>* tree)
74
{
6,496,392✔
75
    vec.clear();
6,496,392✔
76

3,248,046✔
77
    // Only do the scan if context flag is set.
3,248,046✔
78
    if (tree && tree->is_attached() && tree->get_context_flag()) {
6,496,392✔
79
        auto func = [&vec](BPlusTreeNode* node, size_t offset) {
396✔
80
            auto leaf = static_cast<BPlusTree<ObjKey>::LeafNode*>(node);
396✔
81
            size_t sz = leaf->size();
396✔
82
            for (size_t i = 0; i < sz; i++) {
2,658✔
83
                auto k = leaf->get(i);
2,262✔
84
                if (k.is_unresolved()) {
2,262✔
85
                    vec.push_back(i + offset);
426✔
86
                }
426✔
87
            }
2,262✔
88
            return IteratorControl::AdvanceToNext;
396✔
89
        };
396✔
90

198✔
91
        tree->traverse(func);
396✔
92
    }
396✔
93
}
6,496,392✔
94

95
void check_for_last_unresolved(BPlusTree<ObjKey>* tree)
96
{
9,090✔
97
    if (tree) {
9,090✔
98
        bool no_more_unresolved = true;
9,090✔
99
        size_t sz = tree->size();
9,090✔
100
        for (size_t n = 0; n < sz; n++) {
6,764,067✔
101
            if (tree->get(n).is_unresolved()) {
6,763,971✔
102
                no_more_unresolved = false;
8,994✔
103
                break;
8,994✔
104
            }
8,994✔
105
        }
6,763,971✔
106
        if (no_more_unresolved)
9,090✔
107
            tree->set_context_flag(false);
96✔
108
    }
9,090✔
109
}
9,090✔
110

111
size_t get_collection_size_from_ref(ref_type ref, Allocator& alloc)
112
{
2,514✔
113
    size_t ret = 0;
2,514✔
114
    if (ref) {
2,514✔
115
        Array arr(alloc);
2,478✔
116
        arr.init_from_ref(ref);
2,478✔
117
        if (arr.is_inner_bptree_node()) {
2,478✔
118
            // This is a BPlusTree
119
            ret = size_t(arr.back()) >> 1;
×
120
        }
×
121
        else if (arr.has_refs()) {
2,478✔
122
            // This is a dictionary
609✔
123
            auto key_ref = arr.get_as_ref(0);
1,218✔
124
            ret = get_collection_size_from_ref(key_ref, alloc);
1,218✔
125
        }
1,218✔
126
        else {
1,260✔
127
            ret = arr.size();
1,260✔
128
        }
1,260✔
129
    }
2,478✔
130
    return ret;
2,514✔
131
}
2,514✔
132

133
} // namespace _impl
134

135
Collection::~Collection() {}
2,927,178✔
136

137
void Collection::get_any(QueryCtrlBlock& ctrl, Mixed val, size_t index)
138
{
27,228✔
139
    auto path_size = ctrl.path.size() - index;
27,228✔
140
    PathElement& pe = ctrl.path[index];
27,228✔
141
    if (val.is_type(type_Dictionary) && (pe.is_key() || pe.is_all())) {
27,228✔
142
        auto ref = val.get_ref();
26,610✔
143
        if (!ref)
26,610✔
NEW
144
            return;
×
145
        Array top(ctrl.alloc);
26,610✔
146
        top.init_from_ref(ref);
26,610✔
147

13,305✔
148
        BPlusTree<StringData> keys(ctrl.alloc);
26,610✔
149
        keys.set_parent(&top, 0);
26,610✔
150
        keys.init_from_parent();
26,610✔
151
        size_t start = 0;
26,610✔
152
        if (size_t finish = keys.size()) {
26,610✔
153
            if (pe.is_key()) {
26,610✔
154
                start = keys.find_first(StringData(pe.get_key()));
16,776✔
155
                if (start == realm::not_found) {
16,776✔
156
                    if (pe.get_key() == "@keys") {
4,152✔
157
                        keys.for_all([&](const auto& k) {
192✔
158
                            ctrl.matches.insert(k);
192✔
159
                        });
192✔
160
                    }
60✔
161
                    return;
4,152✔
162
                }
4,152✔
163
                finish = start + 1;
12,624✔
164
            }
12,624✔
165
            BPlusTree<Mixed> values(ctrl.alloc);
24,534✔
166
            values.set_parent(&top, 1);
22,458✔
167
            values.init_from_parent();
22,458✔
168
            for (; start < finish; start++) {
54,768✔
169
                val = values.get(start);
32,310✔
170
                if (path_size > 1) {
32,310✔
171
                    Collection::get_any(ctrl, val, index + 1);
504✔
172
                }
504✔
173
                else {
31,806✔
174
                    ctrl.matches.insert(val);
31,806✔
175
                }
31,806✔
176
            }
32,310✔
177
        }
22,458✔
178
    }
26,610✔
179
    else if (val.is_type(type_List) && (pe.is_ndx() || pe.is_all())) {
618✔
180
        auto ref = val.get_ref();
456✔
181
        if (!ref)
456✔
182
            return;
48✔
183
        BPlusTree<Mixed> list(ctrl.alloc);
408✔
184
        list.init_from_ref(ref);
408✔
185
        if (size_t sz = list.size()) {
408✔
186
            size_t start = 0;
408✔
187
            size_t finish = sz;
408✔
188
            if (pe.is_ndx()) {
408✔
189
                start = pe.get_ndx();
264✔
190
                if (start == size_t(-1)) {
264✔
191
                    start = sz - 1;
48✔
192
                }
48✔
193
                if (start < sz) {
264✔
194
                    finish = start + 1;
264✔
195
                }
264✔
196
            }
264✔
197
            for (; start < finish; start++) {
1,008✔
198
                val = list.get(start);
600✔
199
                if (path_size > 1) {
600✔
200
                    Collection::get_any(ctrl, val, index + 1);
540✔
201
                }
540✔
202
                else {
60✔
203
                    ctrl.matches.insert(val);
60✔
204
                }
60✔
205
            }
600✔
206
        }
408✔
207
    }
408✔
208
    else if (val.is_type(type_TypedLink) && pe.is_key()) {
162✔
209
        auto link = val.get_link();
54✔
210
        Obj obj = ctrl.group->get_object(link);
54✔
211
        auto col = obj.get_table()->get_column_key(pe.get_key());
54✔
212
        if (col) {
54✔
213
            val = obj.get_any(col);
48✔
214
            if (path_size > 1) {
48✔
215
                if (val.is_type(type_Link)) {
6✔
216
                    val = ObjLink(obj.get_target_table(col)->get_key(), val.get<ObjKey>());
6✔
217
                }
6✔
218
                Collection::get_any(ctrl, val, index + 1);
6✔
219
            }
6✔
220
            else {
42✔
221
                ctrl.matches.insert(val);
42✔
222
            }
42✔
223
        }
48✔
224
    }
54✔
225
}
27,228✔
226

227
std::pair<std::string, std::string> CollectionBase::get_open_close_strings(size_t link_depth,
228
                                                                           JSONOutputMode output_mode) const
229
{
1,062✔
230
    std::string open_str;
1,062✔
231
    std::string close_str;
1,062✔
232
    auto collection_type = get_collection_type();
1,062✔
233
    Table* target_table = get_target_table().unchecked_ptr();
1,062✔
234
    auto ck = get_col_key();
1,062✔
235
    auto type = ck.get_type();
1,062✔
236
    if (type == col_type_LinkList)
1,062✔
237
        type = col_type_Link;
408✔
238
    if (type == col_type_Link) {
1,062✔
239
        bool is_embedded = target_table->is_embedded();
642✔
240
        bool link_depth_reached = !is_embedded && (link_depth == 0);
642✔
241

321✔
242
        if (output_mode == output_mode_xjson_plus) {
642✔
243
            open_str = std::string("{ ") + (is_embedded ? "\"$embedded" : "\"$link");
117✔
244
            open_str += collection_type_name(collection_type, true);
126✔
245
            open_str += "\": ";
126✔
246
            close_str += " }";
126✔
247
        }
126✔
248

321✔
249
        if ((link_depth_reached && output_mode != output_mode_xjson) || output_mode == output_mode_xjson_plus) {
642✔
250
            open_str += "{ \"table\": \"" + std::string(target_table->get_name()) + "\", ";
252✔
251
            open_str += ((is_embedded || collection_type == CollectionType::Dictionary) ? "\"values" : "\"keys");
252✔
252
            open_str += "\": ";
252✔
253
            close_str += "}";
252✔
254
        }
252✔
255
    }
642✔
256
    else {
420✔
257
        if (output_mode == output_mode_xjson_plus) {
420✔
258
            switch (collection_type) {
138✔
259
                case CollectionType::List:
18✔
260
                    break;
18✔
NEW
261
                case CollectionType::Set:
✔
NEW
262
                    open_str = "{ \"$set\": ";
×
NEW
263
                    close_str = " }";
×
NEW
264
                    break;
×
265
                case CollectionType::Dictionary:
120✔
266
                    open_str = "{ \"$dictionary\": ";
120✔
267
                    close_str = " }";
120✔
268
                    break;
120✔
269
            }
1,062✔
270
        }
1,062✔
271
    }
420✔
272
    return {open_str, close_str};
1,062✔
273
}
1,062✔
274

275
} // namespace realm
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