123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- #ifndef REALM_ALLOC_HPP
- #define REALM_ALLOC_HPP
- #include <cstdint>
- #include <cstddef>
- #include <atomic>
- #include <realm/util/features.h>
- #include <realm/util/terminate.hpp>
- #include <realm/util/assert.hpp>
- #include <realm/util/file.hpp>
- #include <realm/exceptions.hpp>
- #include <realm/util/safe_int_ops.hpp>
- #include <realm/node_header.hpp>
- #include <realm/util/file_mapper.hpp>
- #if defined REALM_ARCHITECTURE_X86_32 && defined REALM_WINDOWS
- #define REALM_WORKAROUND_MSVC_BUG REALM_NOINLINE
- #else
- #define REALM_WORKAROUND_MSVC_BUG
- #endif
- namespace realm {
- class Allocator;
- using ref_type = size_t;
- int_fast64_t from_ref(ref_type) noexcept;
- ref_type to_ref(int_fast64_t) noexcept;
- int64_t to_int64(size_t value) noexcept;
- class MemRef {
- public:
- MemRef() noexcept;
- ~MemRef() noexcept;
- MemRef(char* addr, ref_type ref, Allocator& alloc) noexcept;
- MemRef(ref_type ref, Allocator& alloc) noexcept;
- char* get_addr() const;
- ref_type get_ref() const;
- void set_ref(ref_type ref);
- void set_addr(char* addr);
- private:
- char* m_addr;
- ref_type m_ref;
- #if REALM_ENABLE_MEMDEBUG
-
-
- const Allocator* m_alloc = nullptr;
- #endif
- };
- class Allocator {
- public:
-
-
-
-
- MemRef alloc(size_t size);
-
-
-
-
- MemRef realloc_(ref_type, const char* addr, size_t old_size, size_t new_size);
-
-
-
-
- void free_(ref_type, const char* addr) noexcept;
-
- void free_(MemRef mem) noexcept;
-
- char* translate(ref_type ref) const noexcept;
-
-
-
-
-
- bool is_read_only(ref_type) const noexcept;
- void set_read_only(bool ro)
- {
- m_is_read_only = ro;
- }
-
-
-
-
- static Allocator& get_default() noexcept;
- virtual ~Allocator() noexcept;
-
- Allocator(const Allocator&) = delete;
- Allocator& operator=(const Allocator&) = delete;
- virtual void verify() const = 0;
- #ifdef REALM_DEBUG
-
-
-
-
-
- void watch(ref_type ref)
- {
- m_debug_watch = ref;
- }
- #endif
- struct MappedFile;
- static constexpr size_t section_size() noexcept
- {
- return 1 << section_shift;
- }
- protected:
- constexpr static int section_shift = 26;
- std::atomic<size_t> m_baseline;
- ref_type m_debug_watch = 0;
-
-
-
-
- struct RefTranslation {
- char* mapping_addr;
- uint64_t cookie;
- std::atomic<size_t> lowest_possible_xover_offset = 0;
-
-
-
-
- std::atomic<char*> xover_mapping_addr = nullptr;
- size_t xover_mapping_base = 0;
- #if REALM_ENABLE_ENCRYPTION
- util::EncryptedFileMapping* encrypted_mapping = nullptr;
- util::EncryptedFileMapping* xover_encrypted_mapping = nullptr;
- #endif
- explicit RefTranslation(char* addr)
- : mapping_addr(addr)
- , cookie(0x1234567890)
- {
- }
- RefTranslation()
- : RefTranslation(nullptr)
- {
- }
- ~RefTranslation()
- {
- cookie = 0xdeadbeefdeadbeef;
- }
- RefTranslation& operator=(const RefTranslation& from)
- {
- if (&from != this) {
- mapping_addr = from.mapping_addr;
- #if REALM_ENABLE_ENCRYPTION
- encrypted_mapping = from.encrypted_mapping;
- #endif
- const auto local_xover_mapping_addr = from.xover_mapping_addr.load(std::memory_order_acquire);
-
- lowest_possible_xover_offset.store(from.lowest_possible_xover_offset, std::memory_order_relaxed);
- if (local_xover_mapping_addr) {
- xover_mapping_base = from.xover_mapping_base;
- #if REALM_ENABLE_ENCRYPTION
- xover_encrypted_mapping = from.xover_encrypted_mapping;
- #endif
- xover_mapping_addr.store(local_xover_mapping_addr, std::memory_order_release);
- }
- }
- return *this;
- }
- };
-
-
- std::atomic<RefTranslation*> m_ref_translation_ptr;
-
-
-
-
- virtual MemRef do_alloc(const size_t size) = 0;
-
-
-
-
-
-
-
-
- virtual MemRef do_realloc(ref_type, char* addr, size_t old_size, size_t new_size) = 0;
-
- virtual void do_free(ref_type, char* addr) = 0;
-
-
-
-
-
- virtual char* do_translate(ref_type ref) const noexcept = 0;
- char* translate_critical(RefTranslation*, ref_type ref) const noexcept;
- char* translate_less_critical(RefTranslation*, ref_type ref) const noexcept;
- virtual void get_or_add_xover_mapping(RefTranslation&, size_t, size_t, size_t) = 0;
- Allocator() noexcept;
- size_t get_section_index(size_t pos) const noexcept;
- inline size_t get_section_base(size_t index) const noexcept;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- std::atomic<uint_fast64_t> m_content_versioning_counter;
- std::atomic<uint_fast64_t> m_storage_versioning_counter;
- std::atomic<uint_fast64_t> m_instance_versioning_counter;
- inline uint_fast64_t get_storage_version(uint64_t instance_version)
- {
- if (instance_version != m_instance_versioning_counter) {
- throw LogicError(LogicError::detached_accessor);
- }
- return m_storage_versioning_counter.load(std::memory_order_acquire);
- }
- public:
- inline uint_fast64_t get_storage_version()
- {
- return m_storage_versioning_counter.load(std::memory_order_acquire);
- }
- protected:
- inline void bump_storage_version() noexcept
- {
- m_storage_versioning_counter.fetch_add(1, std::memory_order_acq_rel);
- }
- public:
- REALM_WORKAROUND_MSVC_BUG inline uint_fast64_t get_content_version() noexcept
- {
- return m_content_versioning_counter.load(std::memory_order_acquire);
- }
- protected:
- inline uint_fast64_t bump_content_version() noexcept
- {
- return m_content_versioning_counter.fetch_add(1, std::memory_order_acq_rel) + 1;
- }
- REALM_WORKAROUND_MSVC_BUG inline uint_fast64_t get_instance_version() noexcept
- {
- return m_instance_versioning_counter.load(std::memory_order_relaxed);
- }
- inline void bump_instance_version() noexcept
- {
- m_instance_versioning_counter.fetch_add(1, std::memory_order_relaxed);
- }
- private:
- bool m_is_read_only = false;
- friend class Table;
- friend class ClusterTree;
- friend class Group;
- friend class WrappedAllocator;
- friend class Obj;
- template <class>
- friend class CollectionBaseImpl;
- friend class Dictionary;
- };
- class WrappedAllocator : public Allocator {
- public:
- WrappedAllocator(Allocator& underlying_allocator)
- : m_alloc(&underlying_allocator)
- {
- m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed);
- m_debug_watch = 0;
- m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr);
- }
- ~WrappedAllocator() {}
- void switch_underlying_allocator(Allocator& underlying_allocator)
- {
- m_alloc = &underlying_allocator;
- m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed);
- m_debug_watch = 0;
- refresh_ref_translation();
- }
- void update_from_underlying_allocator(bool writable)
- {
- switch_underlying_allocator(*m_alloc);
- set_read_only(!writable);
- }
- void refresh_ref_translation()
- {
- m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr);
- }
- protected:
- void get_or_add_xover_mapping(RefTranslation& txl, size_t index, size_t offset, size_t size) override
- {
- m_alloc->get_or_add_xover_mapping(txl, index, offset, size);
- }
- private:
- Allocator* m_alloc;
- MemRef do_alloc(const size_t size) override
- {
- auto result = m_alloc->do_alloc(size);
- bump_storage_version();
- m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed);
- m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr);
- return result;
- }
- virtual MemRef do_realloc(ref_type ref, char* addr, size_t old_size, size_t new_size) override
- {
- auto result = m_alloc->do_realloc(ref, addr, old_size, new_size);
- bump_storage_version();
- m_baseline.store(m_alloc->m_baseline, std::memory_order_relaxed);
- m_ref_translation_ptr.store(m_alloc->m_ref_translation_ptr);
- return result;
- }
- virtual void do_free(ref_type ref, char* addr) noexcept override
- {
- return m_alloc->do_free(ref, addr);
- }
- virtual char* do_translate(ref_type ref) const noexcept override
- {
- return m_alloc->translate(ref);
- }
- virtual void verify() const override
- {
- m_alloc->verify();
- }
- };
- inline int_fast64_t from_ref(ref_type v) noexcept
- {
-
- REALM_ASSERT_DEBUG(v % 8 == 0);
- static_assert(std::is_same<ref_type, size_t>::value,
- "If ref_type changes, from_ref and to_ref should probably be updated");
-
- return int_fast64_t(uint_fast64_t(v));
- }
- inline ref_type to_ref(int_fast64_t v) noexcept
- {
-
- REALM_ASSERT_DEBUG(v % 8 == 0);
-
-
-
-
-
- static_assert(std::is_unsigned<ref_type>::value,
- "If ref_type changes, from_ref and to_ref should probably be updated");
- return ref_type(v);
- }
- inline int64_t to_int64(size_t value) noexcept
- {
- int64_t res = static_cast<int64_t>(value);
- REALM_ASSERT_DEBUG(res >= 0);
- return static_cast<int64_t>(value);
- }
- inline MemRef::MemRef() noexcept
- : m_addr(nullptr)
- , m_ref(0)
- {
- }
- inline MemRef::~MemRef() noexcept {}
- inline MemRef::MemRef(char* addr, ref_type ref, Allocator& alloc) noexcept
- : m_addr(addr)
- , m_ref(ref)
- {
- static_cast<void>(alloc);
- #if REALM_ENABLE_MEMDEBUG
- m_alloc = &alloc;
- #endif
- }
- inline MemRef::MemRef(ref_type ref, Allocator& alloc) noexcept
- : m_addr(alloc.translate(ref))
- , m_ref(ref)
- {
- static_cast<void>(alloc);
- #if REALM_ENABLE_MEMDEBUG
- m_alloc = &alloc;
- #endif
- }
- inline char* MemRef::get_addr() const
- {
- #if REALM_ENABLE_MEMDEBUG
-
- m_alloc->translate(m_ref);
- #endif
- return m_addr;
- }
- inline ref_type MemRef::get_ref() const
- {
- #if REALM_ENABLE_MEMDEBUG
-
- m_alloc->translate(m_ref);
- #endif
- return m_ref;
- }
- inline void MemRef::set_ref(ref_type ref)
- {
- #if REALM_ENABLE_MEMDEBUG
-
- m_alloc->translate(ref);
- #endif
- m_ref = ref;
- }
- inline void MemRef::set_addr(char* addr)
- {
- m_addr = addr;
- }
- inline MemRef Allocator::alloc(size_t size)
- {
- if (m_is_read_only)
- throw realm::LogicError(realm::LogicError::wrong_transact_state);
- return do_alloc(size);
- }
- inline MemRef Allocator::realloc_(ref_type ref, const char* addr, size_t old_size, size_t new_size)
- {
- #ifdef REALM_DEBUG
- if (ref == m_debug_watch)
- REALM_TERMINATE("Allocator watch: Ref was reallocated");
- #endif
- if (m_is_read_only)
- throw realm::LogicError(realm::LogicError::wrong_transact_state);
- return do_realloc(ref, const_cast<char*>(addr), old_size, new_size);
- }
- inline void Allocator::free_(ref_type ref, const char* addr) noexcept
- {
- #ifdef REALM_DEBUG
- if (ref == m_debug_watch)
- REALM_TERMINATE("Allocator watch: Ref was freed");
- #endif
- REALM_ASSERT(!m_is_read_only);
- return do_free(ref, const_cast<char*>(addr));
- }
- inline void Allocator::free_(MemRef mem) noexcept
- {
- free_(mem.get_ref(), mem.get_addr());
- }
- inline size_t Allocator::get_section_base(size_t index) const noexcept
- {
- return index << section_shift;
- }
- inline size_t Allocator::get_section_index(size_t pos) const noexcept
- {
- return pos >> section_shift;
- }
- inline bool Allocator::is_read_only(ref_type ref) const noexcept
- {
- REALM_ASSERT_DEBUG(ref != 0);
-
- return ref < m_baseline.load(std::memory_order_relaxed);
- }
- inline Allocator::Allocator() noexcept
- {
- m_content_versioning_counter = 0;
- m_storage_versioning_counter = 0;
- m_instance_versioning_counter = 0;
- m_ref_translation_ptr = nullptr;
- }
- inline Allocator::~Allocator() noexcept {}
- inline char* Allocator::translate_critical(RefTranslation* ref_translation_ptr, ref_type ref) const noexcept
- {
- size_t idx = get_section_index(ref);
- RefTranslation& txl = ref_translation_ptr[idx];
- if (REALM_LIKELY(txl.cookie == 0x1234567890)) {
- size_t offset = ref - get_section_base(idx);
- size_t lowest_possible_xover_offset = txl.lowest_possible_xover_offset.load(std::memory_order_relaxed);
- if (REALM_LIKELY(offset < lowest_possible_xover_offset)) {
-
- char* addr = txl.mapping_addr + offset;
- #if REALM_ENABLE_ENCRYPTION
- realm::util::encryption_read_barrier(addr, NodeHeader::header_size, txl.encrypted_mapping,
- NodeHeader::get_byte_size_from_header);
- #endif
- return addr;
- }
- else {
-
- return translate_less_critical(ref_translation_ptr, ref);
- }
- }
- realm::util::terminate("Invalid ref translation entry", __FILE__, __LINE__, txl.cookie, 0x1234567890);
- return nullptr;
- }
- inline char* Allocator::translate(ref_type ref) const noexcept
- {
- auto ref_translation_ptr = m_ref_translation_ptr.load(std::memory_order_acquire);
- if (REALM_LIKELY(ref_translation_ptr)) {
- return translate_critical(ref_translation_ptr, ref);
- }
- else {
- return do_translate(ref);
- }
- }
- }
- #endif
|