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

realm / realm-core / finn.schiermer-andersen_89

04 Jun 2024 02:04PM UTC coverage: 90.651% (-0.03%) from 90.685%
finn.schiermer-andersen_89

Pull #7654

Evergreen

finnschiermer
optimized string cache gc
Pull Request #7654: Fsa/string interning

102644 of 180648 branches covered (56.82%)

1005 of 1125 new or added lines in 15 files covered. (89.33%)

154 existing lines in 21 files now uncovered.

217953 of 240431 relevant lines covered (90.65%)

7671710.15 hits per line

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

81.43
/src/realm/alloc.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 <cerrno>
20
#include <cstdlib>
21
#include <stdexcept>
22
#include <algorithm>
23

24
#include <realm/array.hpp>
25
#include <realm/alloc_slab.hpp>
26
#include <realm/group.hpp>
27

28
using namespace realm;
29

30

31
namespace {
32

33
/// For use with free-standing objects (objects that are not part of a
34
/// Realm group)
35
///
36
/// Note that it is essential that this class is stateless as it may
37
/// be used by multiple threads. Although it has m_replication, this
38
/// is not a problem, as there is no way to modify it, so it will
39
/// remain zero.
40
class DefaultAllocator : public realm::Allocator {
41
public:
42
    DefaultAllocator()
43
    {
24✔
44
        m_baseline = 0;
24✔
45
    }
24✔
46

47
    MemRef do_alloc(const size_t size) override
48
    {
8,672,673✔
49
        char* addr = static_cast<char*>(::malloc(size));
8,672,673✔
50
        if (REALM_UNLIKELY(REALM_COVER_NEVER(!addr))) {
8,672,673✔
51
            // LCOV_EXCL_START
52
            REALM_ASSERT_DEBUG(errno == ENOMEM);
×
53
            throw std::bad_alloc();
×
54
            // LCOV_EXCL_STOP
55
        }
×
56
#if REALM_ENABLE_ALLOC_SET_ZERO
57
        std::fill(addr, addr + size, 0);
58
#endif
59
        return MemRef(addr, reinterpret_cast<size_t>(addr), *this);
8,672,673✔
60
    }
8,672,673✔
61

62
    MemRef do_realloc(ref_type, char* addr, size_t old_size, size_t new_size) override
63
    {
1,576,380✔
64
        char* new_addr = static_cast<char*>(::realloc(const_cast<char*>(addr), new_size));
1,576,380✔
65
        if (REALM_UNLIKELY(REALM_COVER_NEVER(!new_addr))) {
1,576,380✔
66
            // LCOV_EXCL_START
67
            REALM_ASSERT_DEBUG(errno == ENOMEM);
×
68
            throw std::bad_alloc();
×
69
            // LCOV_EXCL_STOP
70
        }
×
71
#if REALM_ENABLE_ALLOC_SET_ZERO
72
        std::fill(new_addr + old_size, new_addr + new_size, 0);
73
#else
74
        static_cast<void>(old_size);
1,576,380✔
75
#endif
1,576,380✔
76
        return MemRef(new_addr, reinterpret_cast<size_t>(new_addr), *this);
1,576,380✔
77
    }
1,576,380✔
78

79
    void do_free(ref_type, char* addr) override
80
    {
8,672,403✔
81
        ::free(addr);
8,672,403✔
82
    }
8,672,403✔
83

84
    char* do_translate(ref_type ref) const noexcept override
85
    {
365,254,287✔
86
        return reinterpret_cast<char*>(ref);
365,254,287✔
87
    }
365,254,287✔
88

89
    void verify() const override {}
×
90
    void get_or_add_xover_mapping(RefTranslation&, size_t, size_t, size_t) override
91
    {
×
92
        REALM_ASSERT(false);
×
93
    }
×
94
};
95

96
// This variable is declared such that get_default() can return it. It could be a static local variable, but
97
// Valgrind/Helgrind gives a false error report because it doesn't recognize gcc's static variable initialization
98
// mutex
99
DefaultAllocator default_alloc;
100

101
} // anonymous namespace
102

103
namespace realm {
104

105
Allocator& Allocator::get_default() noexcept
106
{
109,409,181✔
107
    return default_alloc;
109,409,181✔
108
}
109,409,181✔
109

110
// This function is called to handle translation of a ref which is above the limit for its
111
// memory mapping. This requires one of three:
112
// * bumping the limit of the mapping. (if the entire array is inside the mapping)
113
// * adding a cross-over mapping. (if the array crosses a mapping boundary)
114
// * using an already established cross-over mapping. (ditto)
115
// this can proceed concurrently with other calls to translate()
116
char* Allocator::translate_less_critical(RefTranslation* ref_translation_ptr, ref_type ref,
117
                                         bool known_in_slab) const noexcept
118
{
361,023✔
119
    size_t idx = get_section_index(ref);
361,023✔
120
    RefTranslation& txl = ref_translation_ptr[idx];
361,023✔
121
    size_t offset = ref - get_section_base(idx);
361,023✔
122
    char* addr = txl.mapping_addr + offset;
361,023✔
123
#if REALM_ENABLE_ENCRYPTION
361,023✔
124
    realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping, nullptr);
361,023✔
125
#endif
361,023✔
126
    // if we know the translation is inside the slab area, we don't need to check
127
    // for anything beyond the header, and we don't need to check if decryption is needed
128
    auto size = known_in_slab ? 8 : NodeHeader::get_byte_size_from_header(addr);
361,023✔
129
    bool crosses_mapping = offset + size > (1 << section_shift);
361,023✔
130
    // Move the limit on use of the existing primary mapping.
131
    // Take into account that another thread may attempt to change / have changed it concurrently,
132
    size_t lowest_possible_xover_offset = txl.lowest_possible_xover_offset.load(std::memory_order_relaxed);
361,023✔
133
    auto new_lowest_possible_xover_offset = offset + (crosses_mapping ? 0 : size);
361,023✔
134
    while (new_lowest_possible_xover_offset > lowest_possible_xover_offset) {
361,056✔
135
        if (txl.lowest_possible_xover_offset.compare_exchange_weak(
360,909✔
136
                lowest_possible_xover_offset, new_lowest_possible_xover_offset, std::memory_order_relaxed))
360,909✔
137
            break;
360,876✔
138
    }
360,909✔
139
    if (REALM_LIKELY(!crosses_mapping)) {
361,032✔
140
        // Array fits inside primary mapping, no new mapping needed.
141
#if REALM_ENABLE_ENCRYPTION
361,032✔
142
        realm::util::encryption_read_barrier(addr, size, txl.encrypted_mapping, nullptr);
361,032✔
143
#endif
361,032✔
144
        return addr;
361,032✔
145
    }
361,032✔
146
    else {
2,147,483,647✔
147
        // we need a cross-over mapping. If one is already established, use that.
148
        auto xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_acquire);
2,147,483,647✔
149
        if (!xover_mapping_addr) {
2,147,483,647✔
150
            // we need to establish a xover mapping - or wait for another thread to finish
151
            // establishing one:
UNCOV
152
            const_cast<Allocator*>(this)->get_or_add_xover_mapping(txl, idx, offset, size);
×
153
            // reload (can be relaxed since the call above synchronizes on a mutex)
UNCOV
154
            xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_relaxed);
×
UNCOV
155
        }
×
156
        // array is now known to be inside the established xover mapping:
157
        addr = xover_mapping_addr + (offset - txl.xover_mapping_base);
2,147,483,647✔
158
#if REALM_ENABLE_ENCRYPTION
2,147,483,647✔
159
        realm::util::encryption_read_barrier(addr, size, txl.xover_encrypted_mapping, nullptr);
2,147,483,647✔
160
#endif
2,147,483,647✔
161
        return addr;
2,147,483,647✔
162
    }
2,147,483,647✔
163
}
361,023✔
164
} // 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