Skip to content

Commit 8f9e7f4

Browse files
committed
Clean up a bunch of old encryption cruft
The global shared cache of encrypted file maps was originally required because we actually opened Realm files mulitple times in normal usage, so each of the open files had to know about each other to copy things around. #4839 made it so that in normal usage we only ever have one DB instance per file per process, so it became dead code. Multiprocess encryption made it unneccesary even when the one-DB-per-process rule is violated, as the multiprocess code path covers that. This eliminates our last reliance on file UniqueIDs, so it lets us get rid of hacks related to that. The encryption page reclaimer mostly never actually worked. It used a very conserative page reclaimation rule that meant that pages would never be reclaimed if there was a long-lived Transaction, even if it was frozen or kept refreshed. This is very common in practice, and when it doesn't happen the DB usually isn't kept open either, making it redundant. Encryption used to rely on handling BAD_EXEC signals (or mach exceptions) rather than explicit barriers, so it had to read and write in page-sized chunks. That's no longer the case, so we can eliminate a lot of complexity by always reading and writing in 4k blocks.
1 parent b7e545a commit 8f9e7f4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1335
-2845
lines changed

src/realm/alloc.cpp

+14-22
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ char* Allocator::translate_less_critical(RefTranslation* ref_translation_ptr, re
119119
RefTranslation& txl = ref_translation_ptr[idx];
120120
size_t offset = ref - get_section_base(idx);
121121
char* addr = txl.mapping_addr + offset;
122-
#if REALM_ENABLE_ENCRYPTION
123-
realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping, nullptr);
124-
#endif
122+
realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping);
125123
auto size = NodeHeader::get_byte_size_from_header(addr);
126124
bool crosses_mapping = offset + size > (1 << section_shift);
127125
// Move the limit on use of the existing primary mapping.
@@ -135,27 +133,21 @@ char* Allocator::translate_less_critical(RefTranslation* ref_translation_ptr, re
135133
}
136134
if (REALM_LIKELY(!crosses_mapping)) {
137135
// Array fits inside primary mapping, no new mapping needed.
138-
#if REALM_ENABLE_ENCRYPTION
139-
realm::util::encryption_read_barrier(addr, size, txl.encrypted_mapping, nullptr);
140-
#endif
136+
realm::util::encryption_read_barrier(addr, size, txl.encrypted_mapping);
141137
return addr;
142138
}
143-
else {
144-
// we need a cross-over mapping. If one is already established, use that.
145-
auto xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_acquire);
146-
if (!xover_mapping_addr) {
147-
// we need to establish a xover mapping - or wait for another thread to finish
148-
// establishing one:
149-
const_cast<Allocator*>(this)->get_or_add_xover_mapping(txl, idx, offset, size);
150-
// reload (can be relaxed since the call above synchronizes on a mutex)
151-
xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_relaxed);
152-
}
153-
// array is now known to be inside the established xover mapping:
154-
addr = xover_mapping_addr + (offset - txl.xover_mapping_base);
155-
#if REALM_ENABLE_ENCRYPTION
156-
realm::util::encryption_read_barrier(addr, size, txl.xover_encrypted_mapping, nullptr);
157-
#endif
158-
return addr;
139+
// we need a cross-over mapping. If one is already established, use that.
140+
auto xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_acquire);
141+
if (!xover_mapping_addr) {
142+
// we need to establish a xover mapping - or wait for another thread to finish
143+
// establishing one:
144+
const_cast<Allocator*>(this)->get_or_add_xover_mapping(txl, idx, offset, size);
145+
// reload (can be relaxed since the call above synchronizes on a mutex)
146+
xover_mapping_addr = txl.xover_mapping_addr.load(std::memory_order_relaxed);
159147
}
148+
// array is now known to be inside the established xover mapping:
149+
addr = xover_mapping_addr + (offset - txl.xover_mapping_base);
150+
realm::util::encryption_read_barrier(addr, size, txl.xover_encrypted_mapping);
151+
return addr;
160152
}
161153
} // namespace realm

src/realm/alloc.hpp

+18-37
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class Allocator {
171171
// into equal chunks.
172172
struct RefTranslation {
173173
char* mapping_addr;
174-
uint64_t cookie;
174+
uint64_t cookie = 0x1234567890;
175175
std::atomic<size_t> lowest_possible_xover_offset = 0;
176176

177177
// member 'xover_mapping_addr' is used for memory synchronization of the fields
@@ -183,14 +183,12 @@ class Allocator {
183183
#if REALM_ENABLE_ENCRYPTION
184184
util::EncryptedFileMapping* encrypted_mapping = nullptr;
185185
util::EncryptedFileMapping* xover_encrypted_mapping = nullptr;
186+
#else
187+
static inline util::EncryptedFileMapping* const encrypted_mapping = nullptr;
188+
static inline util::EncryptedFileMapping* const xover_encrypted_mapping = nullptr;
186189
#endif
187-
explicit RefTranslation(char* addr)
190+
explicit RefTranslation(char* addr = nullptr)
188191
: mapping_addr(addr)
189-
, cookie(0x1234567890)
190-
{
191-
}
192-
RefTranslation()
193-
: RefTranslation(nullptr)
194192
{
195193
}
196194
~RefTranslation()
@@ -222,7 +220,7 @@ class Allocator {
222220
};
223221
// This pointer may be changed concurrently with access, so make sure it is
224222
// atomic!
225-
std::atomic<RefTranslation*> m_ref_translation_ptr;
223+
std::atomic<RefTranslation*> m_ref_translation_ptr{nullptr};
226224

227225
/// The specified size must be divisible by 8, and must not be
228226
/// zero.
@@ -252,7 +250,7 @@ class Allocator {
252250
char* translate_critical(RefTranslation*, ref_type ref) const noexcept;
253251
char* translate_less_critical(RefTranslation*, ref_type ref) const noexcept;
254252
virtual void get_or_add_xover_mapping(RefTranslation&, size_t, size_t, size_t) = 0;
255-
Allocator() noexcept;
253+
Allocator() noexcept = default;
256254
size_t get_section_index(size_t pos) const noexcept;
257255
inline size_t get_section_base(size_t index) const noexcept;
258256

@@ -271,11 +269,9 @@ class Allocator {
271269
// used to detect if the allocator (and owning structure, e.g. Table)
272270
// is recycled. Mismatch on this counter will cause accesors
273271
// lower in the hierarchy to throw if access is attempted.
274-
std::atomic<uint_fast64_t> m_content_versioning_counter;
275-
276-
std::atomic<uint_fast64_t> m_storage_versioning_counter;
277-
278-
std::atomic<uint_fast64_t> m_instance_versioning_counter;
272+
std::atomic<uint_fast64_t> m_content_versioning_counter{0};
273+
std::atomic<uint_fast64_t> m_storage_versioning_counter{0};
274+
std::atomic<uint_fast64_t> m_instance_versioning_counter{0};
279275

280276
inline uint_fast64_t get_storage_version(uint64_t instance_version)
281277
{
@@ -547,14 +543,6 @@ inline bool Allocator::is_read_only(ref_type ref) const noexcept
547543
return ref < m_baseline.load(std::memory_order_relaxed);
548544
}
549545

550-
inline Allocator::Allocator() noexcept
551-
{
552-
m_content_versioning_counter = 0;
553-
m_storage_versioning_counter = 0;
554-
m_instance_versioning_counter = 0;
555-
m_ref_translation_ptr = nullptr;
556-
}
557-
558546
// performance critical part of the translation process. Less critical code is in translate_less_critical.
559547
inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr, ref_type ref) const noexcept
560548
{
@@ -566,30 +554,23 @@ inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr,
566554
if (REALM_LIKELY(offset < lowest_possible_xover_offset)) {
567555
// the lowest possible xover offset may grow concurrently, but that will not affect this code path
568556
char* addr = txl.mapping_addr + offset;
569-
#if REALM_ENABLE_ENCRYPTION
570-
realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping,
571-
NodeHeader::get_byte_size_from_header);
572-
#endif
557+
util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping);
558+
size_t size = NodeHeader::get_byte_size_from_header(addr);
559+
util::encryption_read_barrier(addr, size, txl.encrypted_mapping);
573560
return addr;
574561
}
575-
else {
576-
// the lowest possible xover offset may grow concurrently, but that will be handled inside the call
577-
return translate_less_critical(ref_translation_ptr, ref);
578-
}
562+
// the lowest possible xover offset may grow concurrently, but that will be handled inside the call
563+
return translate_less_critical(ref_translation_ptr, ref);
579564
}
580565
realm::util::terminate("Invalid ref translation entry", __FILE__, __LINE__, txl.cookie, 0x1234567890, ref, idx);
581-
return nullptr;
582566
}
583567

584568
inline char* Allocator::translate(ref_type ref) const noexcept
585569
{
586-
auto ref_translation_ptr = m_ref_translation_ptr.load(std::memory_order_acquire);
587-
if (REALM_LIKELY(ref_translation_ptr)) {
588-
return translate_critical(ref_translation_ptr, ref);
589-
}
590-
else {
591-
return do_translate(ref);
570+
if (auto ptr = m_ref_translation_ptr.load(std::memory_order_acquire); REALM_LIKELY(ptr)) {
571+
return translate_critical(ptr, ref);
592572
}
573+
return do_translate(ref);
593574
}
594575

595576

src/realm/alloc_slab.cpp

+22-70
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616
*
1717
**************************************************************************/
1818

19-
#include <cinttypes>
20-
#include <type_traits>
21-
#include <exception>
2219
#include <algorithm>
23-
#include <memory>
24-
#include <mutex>
25-
#include <map>
2620
#include <atomic>
21+
#include <cinttypes>
2722
#include <cstring>
23+
#include <exception>
24+
#include <memory>
25+
#include <type_traits>
2826

2927
#if REALM_DEBUG
3028
#include <iostream>
@@ -35,13 +33,13 @@
3533
#include <cstdlib>
3634
#endif
3735

38-
#include <realm/util/errno.hpp>
3936
#include <realm/util/encrypted_file_mapping.hpp>
40-
#include <realm/util/terminate.hpp>
41-
#include <realm/util/thread.hpp>
37+
#include <realm/util/errno.hpp>
4238
#include <realm/util/scope_exit.hpp>
39+
#include <realm/util/terminate.hpp>
4340
#include <realm/array.hpp>
4441
#include <realm/alloc_slab.hpp>
42+
#include <realm/disable_sync_to_disk.hpp>
4543
#include <realm/group.hpp>
4644

4745
using namespace realm;
@@ -164,9 +162,6 @@ void SlabAlloc::detach(bool keep_file_open) noexcept
164162
// placed correctly (logically) after the end of the file.
165163
m_slabs.clear();
166164
clear_freelists();
167-
#if REALM_ENABLE_ENCRYPTION
168-
m_realm_file_info = nullptr;
169-
#endif
170165

171166
m_attach_mode = attach_None;
172167
}
@@ -805,10 +800,6 @@ ref_type SlabAlloc::attach_file(const std::string& path, Config& cfg, util::Writ
805800
// the call below to set_encryption_key.
806801
m_file.set_encryption_key(cfg.encryption_key);
807802

808-
note_reader_start(this);
809-
util::ScopeExit reader_end_guard([this]() noexcept {
810-
note_reader_end(this);
811-
});
812803
size_t size = 0;
813804
// The size of a database file must not exceed what can be encoded in
814805
// size_t.
@@ -840,26 +831,17 @@ ref_type SlabAlloc::attach_file(const std::string& path, Config& cfg, util::Writ
840831
if (size == 0) {
841832
if (REALM_UNLIKELY(cfg.read_only))
842833
throw InvalidDatabase("Read-only access to empty Realm file", path);
843-
844-
size_t initial_size = page_size();
845-
// exFAT does not allocate a unique id for the file until it is non-empty. It must be
846-
// valid at this point because File::get_unique_id() is used to distinguish
847-
// mappings_for_file in the encryption layer. So the prealloc() is required before
848-
// interacting with the encryption layer in File::write().
849-
// Pre-alloc initial space
850-
m_file.prealloc(initial_size); // Throws
851-
// seek() back to the start of the file in preparation for writing the header
852-
// This sequence of File operations is protected from races by
853-
// DB::m_controlmutex, so we know we are the only ones operating on the file
854-
m_file.seek(0);
834+
// We want all non-streaming files to be a multiple of the page size
835+
// to simplify memory mapping, so just pre-reserve the required space now
836+
m_file.prealloc(page_size()); // Throws
855837
const char* data = reinterpret_cast<const char*>(&empty_file_header);
856-
m_file.write(data, sizeof empty_file_header); // Throws
838+
m_file.write(0, data, sizeof empty_file_header); // Throws
857839

858840
bool disable_sync = get_disable_sync_to_disk() || cfg.disable_sync;
859841
if (!disable_sync)
860842
m_file.sync(); // Throws
861843

862-
size = initial_size;
844+
size = m_file.get_size();
863845
}
864846

865847
ref_type top_ref = read_and_validate_header(m_file, path, size, cfg.session_initiator, m_write_observer);
@@ -886,9 +868,6 @@ ref_type SlabAlloc::attach_file(const std::string& path, Config& cfg, util::Writ
886868
realm::util::encryption_read_barrier(m_mappings[0].primary_mapping, 0, sizeof(Header));
887869
dg.release(); // Do not detach
888870
fcg.release(); // Do not close
889-
#if REALM_ENABLE_ENCRYPTION
890-
m_realm_file_info = util::get_file_info_for_file(m_file);
891-
#endif
892871
return top_ref;
893872
}
894873

@@ -905,12 +884,12 @@ void SlabAlloc::convert_from_streaming_form(ref_type top_ref)
905884
{
906885
File::Map<Header> writable_map(m_file, File::access_ReadWrite, sizeof(Header)); // Throws
907886
Header& writable_header = *writable_map.get_addr();
908-
realm::util::encryption_read_barrier_for_write(writable_map, 0);
887+
realm::util::encryption_read_barrier(writable_map, 0);
909888
writable_header.m_top_ref[1] = top_ref;
910889
writable_header.m_file_format[1] = writable_header.m_file_format[0];
911890
realm::util::encryption_write_barrier(writable_map, 0);
912891
writable_map.sync();
913-
realm::util::encryption_read_barrier_for_write(writable_map, 0);
892+
realm::util::encryption_read_barrier(writable_map, 0);
914893
writable_header.m_flags |= flags_SelectBit;
915894
realm::util::encryption_write_barrier(writable_map, 0);
916895
writable_map.sync();
@@ -919,26 +898,6 @@ void SlabAlloc::convert_from_streaming_form(ref_type top_ref)
919898
}
920899
}
921900

922-
void SlabAlloc::note_reader_start(const void* reader_id)
923-
{
924-
#if REALM_ENABLE_ENCRYPTION
925-
if (m_realm_file_info)
926-
util::encryption_note_reader_start(*m_realm_file_info, reader_id);
927-
#else
928-
static_cast<void>(reader_id);
929-
#endif
930-
}
931-
932-
void SlabAlloc::note_reader_end(const void* reader_id) noexcept
933-
{
934-
#if REALM_ENABLE_ENCRYPTION
935-
if (m_realm_file_info)
936-
util::encryption_note_reader_end(*m_realm_file_info, reader_id);
937-
#else
938-
static_cast<void>(reader_id);
939-
#endif
940-
}
941-
942901
ref_type SlabAlloc::attach_buffer(const char* data, size_t size)
943902
{
944903
// ExceptionSafety: If this function throws, it must leave the allocator in
@@ -1009,7 +968,7 @@ ref_type SlabAlloc::read_and_validate_header(util::File& file, const std::string
1009968
{
1010969
try {
1011970
// we'll read header and (potentially) footer
1012-
File::Map<char> map_header(file, File::access_ReadOnly, sizeof(Header), 0, write_observer);
971+
File::Map<char> map_header(file, File::access_ReadOnly, sizeof(Header), write_observer);
1013972
realm::util::encryption_read_barrier(map_header, 0, sizeof(Header));
1014973
auto header = reinterpret_cast<const Header*>(map_header.get_addr());
1015974

@@ -1020,12 +979,12 @@ ref_type SlabAlloc::read_and_validate_header(util::File& file, const std::string
1020979
size_t footer_page_base = footer_ref & ~(page_size() - 1);
1021980
size_t footer_offset = footer_ref - footer_page_base;
1022981
map_footer = File::Map<char>(file, footer_page_base, File::access_ReadOnly,
1023-
sizeof(StreamingFooter) + footer_offset, 0, write_observer);
982+
sizeof(StreamingFooter) + footer_offset, write_observer);
1024983
realm::util::encryption_read_barrier(map_footer, footer_offset, sizeof(StreamingFooter));
1025984
footer = reinterpret_cast<const StreamingFooter*>(map_footer.get_addr() + footer_offset);
1026985
}
1027986

1028-
auto top_ref = validate_header(header, footer, size, path, file.get_encryption_key() != nullptr); // Throws
987+
auto top_ref = validate_header(header, footer, size, path, file.get_encryption() != nullptr); // Throws
1029988

1030989
if (session_initiator && is_file_on_streaming_form(*header)) {
1031990
// Don't compare file format version fields as they are allowed to differ.
@@ -1278,7 +1237,7 @@ void SlabAlloc::update_reader_view(size_t file_size)
12781237
const size_t section_size = std::min<size_t>(1 << section_shift, file_size - section_start_offset);
12791238
if (section_size == (1 << section_shift)) {
12801239
new_mappings.push_back({util::File::Map<char>(m_file, section_start_offset, File::access_ReadOnly,
1281-
section_size, 0, m_write_observer)});
1240+
section_size, m_write_observer)});
12821241
}
12831242
else {
12841243
new_mappings.push_back({util::File::Map<char>()});
@@ -1291,7 +1250,7 @@ void SlabAlloc::update_reader_view(size_t file_size)
12911250
throw std::bad_alloc();
12921251
}
12931252
else {
1294-
new_mappings.back().primary_mapping.map(m_file, File::access_ReadOnly, section_size, 0,
1253+
new_mappings.back().primary_mapping.map(m_file, File::access_ReadOnly, section_size,
12951254
section_start_offset, m_write_observer);
12961255
}
12971256
}
@@ -1352,16 +1311,9 @@ void SlabAlloc::update_reader_view(size_t file_size)
13521311
void SlabAlloc::schedule_refresh_of_outdated_encrypted_pages()
13531312
{
13541313
#if REALM_ENABLE_ENCRYPTION
1355-
// callers must already hold m_mapping_mutex
1356-
for (auto& e : m_mappings) {
1357-
if (auto m = e.primary_mapping.get_encrypted_mapping()) {
1358-
encryption_mark_pages_for_IV_check(m);
1359-
}
1360-
if (auto m = e.xover_mapping.get_encrypted_mapping()) {
1361-
encryption_mark_pages_for_IV_check(m);
1362-
}
1314+
if (auto encryption = m_file.get_encryption()) {
1315+
encryption->mark_data_as_possibly_stale();
13631316
}
1364-
// unsafe to do outside writing thread: verify();
13651317
#endif // REALM_ENABLE_ENCRYPTION
13661318
}
13671319

@@ -1457,7 +1409,7 @@ void SlabAlloc::get_or_add_xover_mapping(RefTranslation& txl, size_t index, size
14571409
auto end_offset = file_offset + size;
14581410
auto mapping_file_offset = file_offset & ~(_page_size - 1);
14591411
auto minimal_mapping_size = end_offset - mapping_file_offset;
1460-
util::File::Map<char> mapping(m_file, mapping_file_offset, File::access_ReadOnly, minimal_mapping_size, 0,
1412+
util::File::Map<char> mapping(m_file, mapping_file_offset, File::access_ReadOnly, minimal_mapping_size,
14611413
m_write_observer);
14621414
map_entry->xover_mapping = std::move(mapping);
14631415
}

0 commit comments

Comments
 (0)