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

realm / realm-core / jorgen.edelbo_334

01 Jul 2024 07:22AM UTC coverage: 90.829% (-0.04%) from 90.865%
jorgen.edelbo_334

Pull #7803

Evergreen

jedelbo
Merge branch 'next-major' into feature/string-compression
Pull Request #7803: Feature/string compression

102912 of 180568 branches covered (56.99%)

1141 of 1267 new or added lines in 33 files covered. (90.06%)

172 existing lines in 24 files now uncovered.

218291 of 240332 relevant lines covered (90.83%)

7818396.4 hits per line

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

87.97
/src/realm/array_string.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_string.hpp>
20
#include <realm/impl/array_writer.hpp>
21
#include <realm/table.hpp>
22
#include <realm/string_interner.hpp>
23
#include <realm/mixed.hpp>
24

25
using namespace realm;
26

27
ArrayString::ArrayString(Allocator& a)
28
    : m_alloc(a)
39,164,406✔
29
{
78,649,512✔
30
    m_arr = new (&m_storage) ArrayStringShort(a, true);
78,649,512✔
31
}
78,649,512✔
32

33
void ArrayString::create()
34
{
261,753✔
35
    static_cast<ArrayStringShort*>(m_arr)->create();
261,753✔
36
}
261,753✔
37

38
void ArrayString::init_from_mem(MemRef mem) noexcept
39
{
77,009,184✔
40
    char* header = mem.get_addr();
77,009,184✔
41

42
    ArrayParent* parent = m_arr->get_parent();
77,009,184✔
43
    size_t ndx_in_parent = m_arr->get_ndx_in_parent();
77,009,184✔
44

45
    bool long_strings = Array::get_hasrefs_from_header(header);
77,009,184✔
46
    if (!long_strings) {
77,009,184✔
47
        // Small strings
48
        bool is_small = Array::get_wtype_from_header(header) == Array::wtype_Multiply;
71,593,539✔
49
        if (is_small) {
71,593,539✔
50
            auto arr = new (&m_storage) ArrayStringShort(m_alloc, m_nullable);
66,066,078✔
51
            arr->init_from_mem(mem);
66,066,078✔
52
            m_type = Type::small_strings;
66,066,078✔
53
        }
66,066,078✔
54
        else {
5,527,461✔
55
            auto arr = new (&m_storage) Array(m_alloc);
5,527,461✔
56
            arr->init_from_mem(mem);
5,527,461✔
57
            // The context flag is used to indicate interned strings vs old enum strings
58
            // (in conjunction with has_refs() == false)
59
            if (arr->get_context_flag_from_header(arr->get_header())) {
5,527,461✔
60
                // init for new interned strings (replacing old enum strings)
61
                m_type = Type::interned_strings;
1,865,556✔
62
                // consider if we want this invariant: REALM_ASSERT_DEBUG(m_string_interner);
63
            }
1,865,556✔
64
            else {
3,661,905✔
65
                // init for old enum strings
66
                m_string_enum_values = std::make_unique<ArrayString>(m_alloc);
3,661,905✔
67
                ArrayParent* p;
3,661,905✔
68
                REALM_ASSERT(m_spec != nullptr);
3,661,905✔
69
                REALM_ASSERT(m_col_ndx != realm::npos);
3,661,905✔
70
                ref_type r = m_spec->get_enumkeys_ref(m_col_ndx, p);
3,661,905✔
71
                m_string_enum_values->init_from_ref(r);
3,661,905✔
72
                m_string_enum_values->set_parent(p, m_col_ndx);
3,661,905✔
73
                m_type = Type::enum_strings;
3,661,905✔
74
            }
3,661,905✔
75
        }
5,527,461✔
76
    }
71,593,539✔
77
    else {
5,415,645✔
78
        bool is_big = Array::get_context_flag_from_header(header);
5,415,645✔
79
        if (!is_big) {
5,415,645✔
80
            auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
803,571✔
81
            arr->init_from_mem(mem);
803,571✔
82
            m_type = Type::medium_strings;
803,571✔
83
        }
803,571✔
84
        else {
4,612,074✔
85
            auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, m_nullable);
4,612,074✔
86
            arr->init_from_mem(mem);
4,612,074✔
87
            m_type = Type::big_strings;
4,612,074✔
88
        }
4,612,074✔
89
    }
5,415,645✔
90
    m_arr->set_parent(parent, ndx_in_parent);
77,009,184✔
91
}
77,009,184✔
92

93
void ArrayString::init_from_parent()
94
{
6,471,942✔
95
    ref_type ref = m_arr->get_ref_from_parent();
6,471,942✔
96
    init_from_ref(ref);
6,471,942✔
97
}
6,471,942✔
98

99
void ArrayString::destroy() noexcept
100
{
1,044✔
101
    if (m_arr->is_attached()) {
1,044✔
102
        Array::destroy_deep(m_arr->get_ref(), m_alloc);
468✔
103
        detach();
468✔
104
    }
468✔
105
}
1,044✔
106

107
void ArrayString::detach() noexcept
108
{
495,975✔
109
    m_arr->detach();
495,975✔
110
    // Make sure the object is in a state like right after construction
111
    // Next call must be to create()
112
    m_arr = new (&m_storage) ArrayStringShort(m_alloc, true);
495,975✔
113
    m_type = Type::small_strings;
495,975✔
114
}
495,975✔
115

116
size_t ArrayString::size() const
117
{
14,174,067✔
118
    switch (m_type) {
14,174,067✔
119
        case Type::small_strings:
4,533,771✔
120
            return static_cast<ArrayStringShort*>(m_arr)->size();
4,533,771✔
121
        case Type::medium_strings:
442,908✔
122
            return static_cast<ArraySmallBlobs*>(m_arr)->size();
442,908✔
123
        case Type::big_strings:
8,800,458✔
124
            return static_cast<ArrayBigBlobs*>(m_arr)->size();
8,800,458✔
125
        case Type::enum_strings:
252✔
126
        case Type::interned_strings:
399,825✔
127
            return static_cast<Array*>(m_arr)->size();
399,825✔
128
    }
14,174,067✔
129
    return {};
×
130
}
14,174,067✔
131

132
void ArrayString::add(StringData value)
133
{
136,452✔
134
    switch (upgrade_leaf(value.size())) {
136,452✔
135
        case Type::small_strings:
77,394✔
136
            static_cast<ArrayStringShort*>(m_arr)->add(value);
77,394✔
137
            break;
77,394✔
138
        case Type::medium_strings:
27,252✔
139
            static_cast<ArraySmallBlobs*>(m_arr)->add_string(value);
27,252✔
140
            break;
27,252✔
141
        case Type::big_strings:
28,233✔
142
            static_cast<ArrayBigBlobs*>(m_arr)->add_string(value);
28,233✔
143
            break;
28,233✔
NEW
144
        case Type::enum_strings:
✔
145
        case Type::interned_strings: {
3,576✔
146
            auto a = static_cast<Array*>(m_arr);
3,576✔
147
            size_t ndx = a->size();
3,576✔
148
            a->add(0);
3,576✔
149
            set(ndx, value);
3,576✔
150
            break;
3,576✔
151
        }
×
152
    }
136,452✔
153
}
136,452✔
154

155
void ArrayString::set(size_t ndx, StringData value)
156
{
4,766,313✔
157
    switch (upgrade_leaf(value.size())) {
4,766,313✔
158
        case Type::small_strings:
481,851✔
159
            static_cast<ArrayStringShort*>(m_arr)->set(ndx, value);
481,851✔
160
            break;
481,851✔
161
        case Type::medium_strings:
220,326✔
162
            static_cast<ArraySmallBlobs*>(m_arr)->set_string(ndx, value);
220,326✔
163
            break;
220,326✔
164
        case Type::big_strings:
820,503✔
165
            static_cast<ArrayBigBlobs*>(m_arr)->set_string(ndx, value);
820,503✔
166
            break;
820,503✔
167
        case Type::interned_strings: {
621,453✔
168
            auto id = m_string_interner->intern(value);
621,453✔
169
            static_cast<Array*>(m_arr)->set(ndx, id);
621,453✔
170
            break;
621,453✔
NEW
171
        }
×
172
        case Type::enum_strings: {
2,625,729✔
173
            size_t sz = m_string_enum_values->size();
2,625,729✔
174
            size_t res = m_string_enum_values->find_first(value, 0, sz);
2,625,729✔
175
            if (res == realm::not_found) {
2,625,729✔
176
                m_string_enum_values->add(value);
9,687✔
177
                res = sz;
9,687✔
178
            }
9,687✔
179
            static_cast<Array*>(m_arr)->set(ndx, res);
2,625,729✔
180
            break;
2,625,729✔
181
        }
×
182
    }
4,766,313✔
183
}
4,766,313✔
184

185
void ArrayString::insert(size_t ndx, StringData value)
186
{
4,139,544✔
187
    switch (upgrade_leaf(value.size())) {
4,139,544✔
188
        case Type::small_strings:
931,026✔
189
            static_cast<ArrayStringShort*>(m_arr)->insert(ndx, value);
931,026✔
190
            break;
931,026✔
191
        case Type::medium_strings:
269,238✔
192
            static_cast<ArraySmallBlobs*>(m_arr)->insert_string(ndx, value);
269,238✔
193
            break;
269,238✔
194
        case Type::big_strings:
1,299,390✔
195
            static_cast<ArrayBigBlobs*>(m_arr)->insert_string(ndx, value);
1,299,390✔
196
            break;
1,299,390✔
197
        case Type::enum_strings: {
1,312,830✔
198
            static_cast<Array*>(m_arr)->insert(ndx, 0);
1,312,830✔
199
            set(ndx, value);
1,312,830✔
200
            break;
1,312,830✔
NEW
201
        }
×
202
        case Type::interned_strings: {
328,305✔
203
            static_cast<Array*>(m_arr)->insert(ndx, 0);
328,305✔
204
            set(ndx, value);
328,305✔
205
            break;
328,305✔
UNCOV
206
        }
×
207
    }
4,139,544✔
208
}
4,139,544✔
209

210
StringData ArrayString::get(size_t ndx) const
211
{
85,035,093✔
212
    switch (m_type) {
85,035,093✔
213
        case Type::small_strings:
63,372,447✔
214
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
63,372,447✔
215
        case Type::medium_strings:
1,143,939✔
216
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string(ndx);
1,143,939✔
217
        case Type::big_strings:
10,521,264✔
218
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
10,521,264✔
219
        case Type::enum_strings: {
1,142,994✔
220
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
1,142,994✔
221
            return m_string_enum_values->get(index);
1,142,994✔
222
        }
×
223
        case Type::interned_strings: {
9,096,024✔
224
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
9,096,024✔
225
            return m_string_interner->get(id);
9,096,024✔
NEW
226
        }
×
227
    }
85,035,093✔
228
    return {};
×
229
}
85,035,093✔
230

231
StringData ArrayString::get_legacy(size_t ndx) const
232
{
×
233
    switch (m_type) {
×
234
        case Type::small_strings:
×
235
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
×
236
        case Type::medium_strings:
×
237
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string_legacy(ndx);
×
238
        case Type::big_strings:
×
239
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
×
240
        case Type::enum_strings: {
×
241
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
242
            return m_string_enum_values->get(index);
×
243
        }
×
NEW
244
        case Type::interned_strings: {
×
NEW
245
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
NEW
246
            return m_string_interner->get(id);
×
NEW
247
        }
×
248
    }
×
249
    return {};
×
250
}
×
251

252
Mixed ArrayString::get_any(size_t ndx) const
253
{
132,786✔
254
    return Mixed(get(ndx));
132,786✔
255
}
132,786✔
256

257
bool ArrayString::is_null(size_t ndx) const
258
{
3,976,485✔
259
    switch (m_type) {
3,976,485✔
260
        case Type::small_strings:
375,144✔
261
            return static_cast<ArrayStringShort*>(m_arr)->is_null(ndx);
375,144✔
262
        case Type::medium_strings:
13,284✔
263
            return static_cast<ArraySmallBlobs*>(m_arr)->is_null(ndx);
13,284✔
264
        case Type::big_strings:
3,349,356✔
265
            return static_cast<ArrayBigBlobs*>(m_arr)->is_null(ndx);
3,349,356✔
266
        case Type::enum_strings: {
✔
NEW
267
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
NEW
268
            return m_string_enum_values->is_null(id);
×
NEW
269
        }
×
270
        case Type::interned_strings: {
238,701✔
271
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
238,701✔
272
            return id == 0;
238,701✔
UNCOV
273
        }
×
274
    }
3,976,485✔
275
    return {};
×
276
}
3,976,485✔
277

278
void ArrayString::erase(size_t ndx)
279
{
127,962✔
280
    switch (m_type) {
127,962✔
281
        case Type::small_strings:
14,433✔
282
            static_cast<ArrayStringShort*>(m_arr)->erase(ndx);
14,433✔
283
            break;
14,433✔
284
        case Type::medium_strings:
54,513✔
285
            static_cast<ArraySmallBlobs*>(m_arr)->erase(ndx);
54,513✔
286
            break;
54,513✔
287
        case Type::big_strings:
22,455✔
288
            static_cast<ArrayBigBlobs*>(m_arr)->erase(ndx);
22,455✔
289
            break;
22,455✔
290
        case Type::interned_strings:
28,269✔
291
        case Type::enum_strings:
36,564✔
292
            static_cast<Array*>(m_arr)->erase(ndx);
36,564✔
293
            break;
36,564✔
294
    }
127,962✔
295
}
127,962✔
296

297
void ArrayString::move(ArrayString& dst, size_t ndx)
298
{
66✔
299
    size_t sz = size();
66✔
300
    for (size_t i = ndx; i < sz; i++) {
20,730✔
301
        dst.add(get(i));
20,664✔
302
    }
20,664✔
303

304
    switch (m_type) {
66✔
305
        case Type::small_strings:
✔
306
            static_cast<ArrayStringShort*>(m_arr)->truncate(ndx);
×
307
            break;
×
308
        case Type::medium_strings:
60✔
309
            static_cast<ArraySmallBlobs*>(m_arr)->truncate(ndx);
60✔
310
            break;
60✔
311
        case Type::big_strings:
6✔
312
            static_cast<ArrayBigBlobs*>(m_arr)->truncate(ndx);
6✔
313
            break;
6✔
314
        case Type::enum_strings:
✔
315
            // this operation will never be called for enumerated columns
316
            REALM_UNREACHABLE();
317
            break;
×
NEW
318
        case Type::interned_strings:
✔
NEW
319
            m_arr->truncate(ndx);
×
NEW
320
            break;
×
321
    }
66✔
322
}
66✔
323

324
void ArrayString::clear()
325
{
366✔
326
    switch (m_type) {
366✔
327
        case Type::small_strings:
174✔
328
            static_cast<ArrayStringShort*>(m_arr)->clear();
174✔
329
            break;
174✔
330
        case Type::medium_strings:
6✔
331
            static_cast<ArraySmallBlobs*>(m_arr)->clear();
6✔
332
            break;
6✔
333
        case Type::big_strings:
48✔
334
            static_cast<ArrayBigBlobs*>(m_arr)->clear();
48✔
335
            break;
48✔
336
        case Type::enum_strings:
✔
337
        case Type::interned_strings:
138✔
338
            static_cast<Array*>(m_arr)->clear();
138✔
339
            break;
138✔
340
    }
366✔
341
}
366✔
342

343
size_t ArrayString::find_first(StringData value, size_t begin, size_t end) const noexcept
344
{
4,109,505✔
345
    switch (m_type) {
4,109,505✔
346
        case Type::small_strings:
3,098,958✔
347
            return static_cast<ArrayStringShort*>(m_arr)->find_first(value, begin, end);
3,098,958✔
348
        case Type::medium_strings: {
94,914✔
349
            BinaryData as_binary(value.data(), value.size());
94,914✔
350
            return static_cast<ArraySmallBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
94,914✔
351
            break;
×
352
        }
×
353
        case Type::big_strings: {
255,972✔
354
            BinaryData as_binary(value.data(), value.size());
255,972✔
355
            return static_cast<ArrayBigBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
255,972✔
356
            break;
×
357
        }
×
358
        case Type::enum_strings: {
595,920✔
359
            size_t sz = m_string_enum_values->size();
595,920✔
360
            size_t res = m_string_enum_values->find_first(value, 0, sz);
595,920✔
361
            if (res != realm::not_found) {
595,920✔
362
                return static_cast<Array*>(m_arr)->find_first(res, begin, end);
595,920✔
363
            }
595,920✔
364
            break;
×
365
        }
595,920✔
366
        case Type::interned_strings: {
63,834✔
367
            // we need a way to avoid this lookup for each leaf array. The lookup must appear
368
            // higher up the call stack and passed down.
369
            auto id = m_string_interner->lookup(value);
63,834✔
370
            if (id) {
63,834✔
371
                return static_cast<Array*>(m_arr)->find_first(*id, begin, end);
60,618✔
372
            }
60,618✔
373
            break;
3,216✔
374
        }
63,834✔
375
    }
4,109,505✔
376
    return not_found;
3,216✔
377
}
4,109,505✔
378

379
namespace {
380

381
template <class T>
382
inline StringData get_string(const T* arr, size_t ndx)
383
{
437,337✔
384
    return arr->get_string(ndx);
437,337✔
385
}
437,337✔
386

387
template <>
388
inline StringData get_string(const ArrayStringShort* arr, size_t ndx)
389
{
93,687✔
390
    return arr->get(ndx);
93,687✔
391
}
93,687✔
392

393
template <class T, class U>
394
size_t lower_bound_string(const T* arr, U value)
395
{
234,912✔
396
    size_t i = 0;
234,912✔
397
    size_t sz = arr->size();
234,912✔
398
    while (0 < sz) {
765,936✔
399
        size_t half = sz / 2;
531,024✔
400
        size_t mid = i + half;
531,024✔
401
        auto probe = get_string(arr, mid);
531,024✔
402
        if (probe < value) {
531,024✔
403
            i = mid + 1;
190,863✔
404
            sz -= half + 1;
190,863✔
405
        }
190,863✔
406
        else {
340,161✔
407
            sz = half;
340,161✔
408
        }
340,161✔
409
    }
531,024✔
410
    return i;
234,912✔
411
}
234,912✔
412
} // namespace
413

414
size_t ArrayString::lower_bound(StringData value)
415
{
234,912✔
416
    switch (m_type) {
234,912✔
417
        case Type::small_strings:
58,434✔
418
            return lower_bound_string(static_cast<ArrayStringShort*>(m_arr), value);
58,434✔
419
        case Type::medium_strings:
68,418✔
420
            return lower_bound_string(static_cast<ArraySmallBlobs*>(m_arr), value);
68,418✔
421
        case Type::big_strings:
108,060✔
422
            return lower_bound_string(static_cast<ArrayBigBlobs*>(m_arr), value);
108,060✔
423
        case Type::enum_strings:
✔
424
            break;
×
NEW
425
        case Type::interned_strings:
✔
426
            REALM_UNREACHABLE();
NEW
427
            break;
×
428
    }
234,912✔
429
    return realm::npos;
×
430
}
234,912✔
431

432
ArrayString::Type ArrayString::upgrade_leaf(size_t value_size)
433
{
9,038,904✔
434
    if (m_type == Type::big_strings)
9,038,904✔
435
        return Type::big_strings;
2,142,279✔
436

437
    if (m_type == Type::enum_strings)
6,896,625✔
438
        return Type::enum_strings;
3,938,535✔
439

440
    if (m_type == Type::interned_strings)
2,958,090✔
441
        return Type::interned_strings;
953,316✔
442

443
    if (m_type == Type::medium_strings) {
2,004,774✔
444
        if (value_size <= medium_string_max_size)
500,691✔
445
            return Type::medium_strings;
500,181✔
446

447
        // Upgrade root leaf from medium to big strings
448
        auto string_medium = static_cast<ArraySmallBlobs*>(m_arr);
510✔
449
        ArrayBigBlobs big_blobs(m_alloc, true);
510✔
450
        big_blobs.create(); // Throws
510✔
451

452
        size_t n = string_medium->size();
510✔
453
        for (size_t i = 0; i < n; i++) {
9,651✔
454
            big_blobs.add_string(string_medium->get_string(i)); // Throws
9,141✔
455
        }
9,141✔
456
        auto parent = string_medium->get_parent();
510✔
457
        auto ndx_in_parent = string_medium->get_ndx_in_parent();
510✔
458
        string_medium->destroy();
510✔
459

460
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
510✔
461
        arr->init_from_mem(big_blobs.get_mem());
510✔
462
        arr->set_parent(parent, ndx_in_parent);
510✔
463
        arr->update_parent();
510✔
464

465
        m_type = Type::big_strings;
510✔
466
        return Type::big_strings;
510✔
467
    }
500,691✔
468

469
    // m_type == Type::small
470
    if (value_size <= small_string_max_size)
1,504,083✔
471
        return Type::small_strings;
1,490,211✔
472

473
    if (value_size <= medium_string_max_size) {
17,790✔
474
        // Upgrade root leaf from small to medium strings
475
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
16,623✔
476
        ArraySmallBlobs string_long(m_alloc);
16,623✔
477
        string_long.create(); // Throws
16,623✔
478

479
        size_t n = string_short->size();
16,623✔
480
        for (size_t i = 0; i < n; i++) {
38,799✔
481
            string_long.add_string(string_short->get(i)); // Throws
22,176✔
482
        }
22,176✔
483
        auto parent = string_short->get_parent();
16,623✔
484
        auto ndx_in_parent = string_short->get_ndx_in_parent();
16,623✔
485
        string_short->destroy();
16,623✔
486

487
        auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
16,623✔
488
        arr->init_from_mem(string_long.get_mem());
16,623✔
489
        arr->set_parent(parent, ndx_in_parent);
16,623✔
490
        arr->update_parent();
16,623✔
491

492
        m_type = Type::medium_strings;
16,623✔
493
    }
16,623✔
494
    else {
2,147,484,814✔
495
        // Upgrade root leaf from small to big strings
496
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
2,147,484,814✔
497
        ArrayBigBlobs big_blobs(m_alloc, true);
2,147,484,814✔
498
        big_blobs.create(); // Throws
2,147,484,814✔
499

500
        size_t n = string_short->size();
2,147,484,814✔
501
        for (size_t i = 0; i < n; i++) {
2,147,487,499✔
502
            big_blobs.add_string(string_short->get(i)); // Throws
5,220✔
503
        }
5,220✔
504
        auto parent = string_short->get_parent();
2,147,484,814✔
505
        auto ndx_in_parent = string_short->get_ndx_in_parent();
2,147,484,814✔
506
        string_short->destroy();
2,147,484,814✔
507

508
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
2,147,484,814✔
509
        arr->init_from_mem(big_blobs.get_mem());
2,147,484,814✔
510
        arr->set_parent(parent, ndx_in_parent);
2,147,484,814✔
511
        arr->update_parent();
2,147,484,814✔
512

513
        m_type = Type::big_strings;
2,147,484,814✔
514
    }
2,147,484,814✔
515

516
    return m_type;
13,872✔
517
}
1,504,083✔
518

519
void ArrayString::verify() const
520
{
201,222✔
521
#ifdef REALM_DEBUG
201,222✔
522
    switch (m_type) {
201,222✔
523
        case Type::small_strings:
18,666✔
524
            static_cast<ArrayStringShort*>(m_arr)->verify();
18,666✔
525
            break;
18,666✔
526
        case Type::medium_strings:
798✔
527
            static_cast<ArraySmallBlobs*>(m_arr)->verify();
798✔
528
            break;
798✔
529
        case Type::big_strings:
5,307✔
530
            static_cast<ArrayBigBlobs*>(m_arr)->verify();
5,307✔
531
            break;
5,307✔
532
        case Type::enum_strings:
252✔
533
        case Type::interned_strings:
176,451✔
534
            static_cast<Array*>(m_arr)->verify();
176,451✔
535
            break;
176,451✔
536
    }
201,222✔
537
#endif
201,222✔
538
}
201,222✔
539

540
template <>
541
ref_type ArrayString::typed_write(ref_type ref, _impl::ArrayWriterBase& out, Allocator& alloc)
542
{
310,959✔
543
    Array leaf(alloc);
310,959✔
544
    leaf.init_from_ref(ref);
310,959✔
545
    ref_type ret_val;
310,959✔
546
    auto header = leaf.get_header();
310,959✔
547
    if (NodeHeader::get_hasrefs_from_header(header) ||
310,959✔
548
        NodeHeader::get_wtype_from_header(header) == NodeHeader::wtype_Multiply) {
310,959✔
549
        // We're interning these strings
550
        ArrayString as(alloc);
174,003✔
551
        as.init_from_ref(ref);
174,003✔
552
        StringInterner* interner = out.table->get_string_interner(out.col_key);
174,003✔
553
        auto sz = as.size();
174,003✔
554
        Array interned(Allocator::get_default());
174,003✔
555
        interned.create(NodeHeader::type_Normal, true, sz);
174,003✔
556
        for (size_t i = 0; i < sz; ++i) {
1,651,194✔
557
            interned.set(i, interner->intern(as.get(i)));
1,477,191✔
558
        }
1,477,191✔
559
        ret_val = interned.write(out, false, false, out.compress);
174,003✔
560
        interned.destroy();
174,003✔
561
        // in a transactional setting:
562
        // Destroy all sub-arrays if present, in order to release memory in file
563
        // This is contrary to the rest of the handling in this function, but needed
564
        // here since sub-arrays may not have been COW'ed and therefore not freed in file.
565
        // We rely on 'only_modified' to indicate that we're in a transactional setting.
566
        if (out.only_modified)
174,003✔
567
            leaf.destroy_deep(true);
173,925✔
568
    }
174,003✔
569
    else {
136,956✔
570
        // whether it's the old enum strings or the new interned strings,
571
        // just write out the array using integer leaf compression
572
        ret_val = leaf.write(out, false, out.only_modified, out.compress);
136,956✔
573
    }
136,956✔
574
    return ret_val;
310,959✔
575
}
310,959✔
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