From 8dbd152f536400de4a0dd999d74de6d82909806a Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 19 Aug 2024 17:05:16 -0400 Subject: [PATCH 1/4] Forward allocated blocks to populator strand. --- src/protocols/protocol_block_in_31800.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/protocol_block_in_31800.cpp b/src/protocols/protocol_block_in_31800.cpp index bec5df3a..c4e27d9d 100644 --- a/src/protocols/protocol_block_in_31800.cpp +++ b/src/protocols/protocol_block_in_31800.cpp @@ -370,9 +370,9 @@ bool protocol_block_in_31800::handle_receive_block(const code& ec, LOGP("Downloaded block [" << encode_hash(hash) << ":" << height << "] from [" << authority() << "]."); - ////populate(block, link, height, BIND(complete, _1, block, height)); - notify(ec, chase::checked, height); - fire(events::block_archived, height); + populate(block, link, height, BIND(complete, _1, block, height)); + ////notify(ec, chase::checked, height); + ////fire(events::block_archived, height); count(size); map_->erase(it); @@ -390,9 +390,11 @@ void protocol_block_in_31800::complete(const code& ec, { if (block->is_valid()) { + ////const auto wire = block->serialized_size(true); + ////const auto allocated = block->get_allocation(); + ////const auto ratio = static_cast((100.0 * allocated) / wire); notify(ec, chase::checked, height); fire(events::block_archived, height); - ////const auto bytes = block->get_allocation(); } } From c493a6fc104bba2042fbb7ace4f355315dfa5ff9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 19 Aug 2024 17:05:25 -0400 Subject: [PATCH 2/4] Comments. --- include/bitcoin/node/block_memory.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index 4d437277..06664fb1 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -27,14 +27,14 @@ namespace libbitcoin { namespace node { -/// Thread SAFE linear memory allocation and tracking. +/// Thread SAFE linear arena allocator. class BCN_API block_memory final : public network::memory { public: DELETE_COPY_MOVE_DESTRUCT(block_memory); - /// Default allocate each arena to preclude allcation and locking. + /// Default allocate each arena to preclude locking. block_memory(size_t bytes, size_t threads) NOEXCEPT; /// Each thread obtains an arena of the same size. From 14ced6df07c96324856d5978d482b7608c0eee28 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 19 Aug 2024 18:12:27 -0400 Subject: [PATCH 3/4] Implement linked-linear memory arena. --- include/bitcoin/node/block_arena.hpp | 56 +++++++--- src/block_arena.cpp | 153 +++++++++++++++++---------- 2 files changed, 143 insertions(+), 66 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index 6d0ce658..abf4ffac 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -26,8 +26,7 @@ namespace libbitcoin { namespace node { -/// Thread UNSAFE linear memory arena. -/// Caller must manage capacity to ensure buffer is not overflowed. +/// Thread UNSAFE linked-linear memory arena. class BCN_API block_arena final : public arena { @@ -40,24 +39,57 @@ class BCN_API block_arena final block_arena& operator=(block_arena&& other) NOEXCEPT; - void* start() NOEXCEPT override; - size_t detach() NOEXCEPT override; - void release(void* ptr, size_t bytes) NOEXCEPT override; + /// Start an allocation of linked chunks. + void* start() THROWS override; + + /// Finalize allocation and reset allocator, return total allocation. + size_t detach() THROWS override; + + /// Release all chunks chained to the address. + void release(void* address) NOEXCEPT override; + +protected: + struct record{ void* next; size_t size; }; + + /// Attach a memory chunk to the allocated list. + void* attach(size_t minimum) THROWS; + + /// Trim chunk to offset_, invalidates capacity. + void trim_to_offset() THROWS; + + /// Close out chunk with link to next. + void set_record(uint8_t* next_address, size_t own_size) NOEXCEPT; + + /// Get size of address chunk and address of next chunk (or nullptr). + record get_record(uint8_t* address) const NOEXCEPT; + + /// Number of bytes remaining to be allocated. + size_t capacity() const NOEXCEPT; + + /// Reset members (does not free). + size_t reset() NOEXCEPT; private: + static constexpr size_t record_size = sizeof(record); + constexpr size_t to_aligned(size_t value, size_t align) NOEXCEPT + { + using namespace system; + BC_ASSERT_MSG(is_nonzero(align), "align zero"); + BC_ASSERT_MSG(!is_add_overflow(value, sub1(align)), "overflow"); + BC_ASSERT_MSG(power2(floored_log2(align)) == align, "align power"); + BC_ASSERT_MSG(align <= alignof(std::max_align_t), "align overflow"); + return (value + sub1(align)) & ~sub1(align); + } + void* do_allocate(size_t bytes, size_t align) THROWS override; void do_deallocate(void* ptr, size_t bytes, size_t align) NOEXCEPT override; bool do_is_equal(const arena& other) const NOEXCEPT override; - // Number of bytes remaining to be allocated. - size_t capacity() const NOEXCEPT; - - // These are thread safe (set only construct). - uint8_t* memory_map_{ nullptr }; + // This are unprotected, caller must guard. + uint8_t* memory_map_; size_t size_; - - // This is unprotected, caller must guard. size_t offset_; + size_t total_; }; diff --git a/src/block_arena.cpp b/src/block_arena.cpp index 03c24cca..fa68c3d8 100644 --- a/src/block_arena.cpp +++ b/src/block_arena.cpp @@ -18,41 +18,33 @@ */ #include +#include #include #include namespace libbitcoin { - -BC_DEBUG_ONLY(constexpr auto max_align = alignof(std::max_align_t);) - -template = true> -constexpr Type to_aligned(Type value, Type alignment) NOEXCEPT -{ - return (value + sub1(alignment)) & ~sub1(alignment); -} - namespace node { BC_PUSH_WARNING(NO_MALLOC_OR_FREE) +BC_PUSH_WARNING(NO_REINTERPRET_CAST) BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) -BC_PUSH_WARNING(THROW_FROM_NOEXCEPT) -// "If size is zero, the behavior of malloc is implementation-defined. For -// example, a null pointer may be returned. Alternatively, a non-null pointer -// may be returned; but such a pointer should not be dereferenced, and should -// be passed to free to avoid memory leaks." -// en.cppreference.com/w/c/memory/malloc +// construct/destruct/assign +// ---------------------------------------------------------------------------- block_arena::block_arena(size_t size) NOEXCEPT - : size_{ size }, - offset_{ size } + : memory_map_{ nullptr }, + size_{ std::max(size, record_size) }, + offset_{ size_ }, + total_{ zero } { } block_arena::block_arena(block_arena&& other) NOEXCEPT : memory_map_{ other.memory_map_ }, size_{ other.size_ }, - offset_{ other.offset_ } + offset_{ other.offset_ }, + total_{ other.total_ } { // Prevents free(memory_map_) as responsibility is passed to this object. other.memory_map_ = nullptr; @@ -60,7 +52,7 @@ block_arena::block_arena(block_arena&& other) NOEXCEPT block_arena::~block_arena() NOEXCEPT { - release(memory_map_, offset_); + release(memory_map_); } block_arena& block_arena::operator=(block_arena&& other) NOEXCEPT @@ -68,62 +60,121 @@ block_arena& block_arena::operator=(block_arena&& other) NOEXCEPT memory_map_ = other.memory_map_; size_ = other.size_; offset_ = other.offset_; + total_ = other.total_; // Prevents free(memory_map_) as responsibility is passed to this object. other.memory_map_ = nullptr; return *this; } -void* block_arena::start() NOEXCEPT +// public +// ---------------------------------------------------------------------------- + +void* block_arena::start() THROWS { - release(memory_map_, offset_); - memory_map_ = system::pointer_cast(std::malloc(size_)); - if (is_null(memory_map_)) - throw allocation_exception{}; + release(memory_map_); + reset(); + return attach(zero); +} - offset_ = zero; - return memory_map_; +size_t block_arena::detach() THROWS +{ + trim_to_offset(); + set_record(nullptr, offset_); + return reset(); } -size_t block_arena::detach() NOEXCEPT +void block_arena::release(void* address) NOEXCEPT { - const auto size = offset_; - const auto map = std::realloc(memory_map_, size); + while (!is_null(address)) + { + const auto value = get_record(system::pointer_cast(address)); + std::free(address/*, value.size */); + address = value.next; + } +} + +// protected +// ---------------------------------------------------------------------------- - // Memory map must not move. +void* block_arena::attach(size_t minimum) THROWS +{ + using namespace system; + + // Ensure next allocation accomodates record plus request (expandable). + BC_ASSERT(!is_add_overflow(minimum, record_size)); + size_ = std::max(size_, minimum + record_size); + + // Allocate size to temporary. + const auto map = pointer_cast(std::malloc(size_)); + if (is_null(map)) + throw allocation_exception{}; + + // Set previous chunk record pointer to new allocation and own size. + set_record(map, offset_); + offset_ = record_size; + return memory_map_ = map; +} + +void block_arena::trim_to_offset() THROWS +{ + // Memory map must not move. Move by realloc is allowed but not expected + // for truncation. If moves then this should drop into mmap/munmap/mremap. + const auto map = std::realloc(memory_map_, offset_); if (map != memory_map_) throw allocation_exception{}; +} - memory_map_ = nullptr; - offset_ = size_; - return size; +void block_arena::set_record(uint8_t* next_address, size_t own_size) NOEXCEPT +{ + // Don't set previous when current is the first chunk. + if (is_null(memory_map_)) + return; + + reinterpret_cast(*memory_map_) = { next_address, own_size }; + total_ += own_size; } -void block_arena::release(void* ptr, size_t) NOEXCEPT +block_arena::record block_arena::get_record(uint8_t* address) const NOEXCEPT { - // Does not affect member state. - if (!is_null(ptr)) - std::free(ptr); + return reinterpret_cast(*address); } -void* block_arena::do_allocate(size_t bytes, size_t align) THROWS +size_t block_arena::capacity() const NOEXCEPT { - using namespace system; - BC_ASSERT_MSG(is_nonzero(align), "align zero"); - BC_ASSERT_MSG(align <= max_align, "align overflow"); - BC_ASSERT_MSG(power2(floored_log2(align)) == align, "align power"); - BC_ASSERT_MSG(!is_add_overflow(bytes, sub1(align)), "alignment overflow"); + return system::floored_subtract(size_, offset_); +} +size_t block_arena::reset() NOEXCEPT +{ + const auto total = total_; + memory_map_ = nullptr; + offset_ = size_; + total_ = zero; + return total; +} + +// protected interface +// ---------------------------------------------------------------------------- + +void* block_arena::do_allocate(size_t bytes, size_t align) THROWS +{ const auto aligned_offset = to_aligned(offset_, align); const auto padding = aligned_offset - offset_; const auto allocation = padding + bytes; + BC_ASSERT(!system::is_add_overflow(padding, bytes)); - ////BC_ASSERT_MSG(allocation <= capacity(), "buffer overflow"); if (allocation > capacity()) - throw allocation_exception{}; - - offset_ += allocation; - return memory_map_ + aligned_offset; + { + trim_to_offset(); + attach(allocation); + return do_allocate(bytes, align); + } + else + { + offset_ += allocation; + return memory_map_ + aligned_offset; + } } void block_arena::do_deallocate(void*, size_t, size_t) NOEXCEPT @@ -136,12 +187,6 @@ bool block_arena::do_is_equal(const arena& other) const NOEXCEPT return &other == this; } -// private -size_t block_arena::capacity() const NOEXCEPT -{ - return system::floored_subtract(size_, offset_); -} - BC_POP_WARNING() BC_POP_WARNING() BC_POP_WARNING() From 61403aec2c9f88238fad574f3c0d32d0afb55670 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 19 Aug 2024 20:50:55 -0400 Subject: [PATCH 4/4] Use allocation_multiple, disable realloc(). --- include/bitcoin/node/block_arena.hpp | 15 +++---- include/bitcoin/node/block_memory.hpp | 8 ++-- include/bitcoin/node/settings.hpp | 3 +- src/block_arena.cpp | 57 ++++++++++++++++----------- src/block_memory.cpp | 4 +- src/full_node.cpp | 3 +- src/parser.cpp | 6 +-- src/settings.cpp | 7 +--- test/settings.cpp | 4 +- 9 files changed, 55 insertions(+), 52 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index abf4ffac..d0ad096a 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -33,14 +33,14 @@ class BCN_API block_arena final public: DELETE_COPY(block_arena); - block_arena(size_t size=zero) NOEXCEPT; + block_arena(size_t multiple) NOEXCEPT; block_arena(block_arena&& other) NOEXCEPT; ~block_arena() NOEXCEPT; block_arena& operator=(block_arena&& other) NOEXCEPT; /// Start an allocation of linked chunks. - void* start() THROWS override; + void* start(size_t wire_size) THROWS override; /// Finalize allocation and reset allocator, return total allocation. size_t detach() THROWS override; @@ -51,8 +51,8 @@ class BCN_API block_arena final protected: struct record{ void* next; size_t size; }; - /// Attach a memory chunk to the allocated list. - void* attach(size_t minimum) THROWS; + /// Link a memory chunk to the allocated list. + void* link_new_chunk(size_t minimum=zero) THROWS; /// Trim chunk to offset_, invalidates capacity. void trim_to_offset() THROWS; @@ -67,7 +67,7 @@ class BCN_API block_arena final size_t capacity() const NOEXCEPT; /// Reset members (does not free). - size_t reset() NOEXCEPT; + size_t reset(size_t chunk_size=zero) NOEXCEPT; private: static constexpr size_t record_size = sizeof(record); @@ -85,11 +85,12 @@ class BCN_API block_arena final void do_deallocate(void* ptr, size_t bytes, size_t align) NOEXCEPT override; bool do_is_equal(const arena& other) const NOEXCEPT override; - // This are unprotected, caller must guard. + // These are unprotected, caller must guard. uint8_t* memory_map_; - size_t size_; + size_t multiple_; size_t offset_; size_t total_; + size_t size_; }; diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index 06664fb1..98178b58 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -27,17 +27,17 @@ namespace libbitcoin { namespace node { -/// Thread SAFE linear arena allocator. +/// Thread SAFE linked-linear arena allocator. class BCN_API block_memory final : public network::memory { public: DELETE_COPY_MOVE_DESTRUCT(block_memory); - /// Default allocate each arena to preclude locking. - block_memory(size_t bytes, size_t threads) NOEXCEPT; + /// Per thread multiple of wire size for each linear allocation chunk. + block_memory(size_t multiple, size_t threads) NOEXCEPT; - /// Each thread obtains an arena of the same size. + /// Each thread obtains an arena. arena* get_arena() NOEXCEPT override; protected: diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index 799242f8..dcd67236 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -74,7 +74,7 @@ class BCN_API settings /// Properties. bool headers_first; float allowed_deviation; - uint64_t allocation_bytes; + uint16_t allocation_multiple; uint64_t snapshot_bytes; uint32_t snapshot_valid; uint32_t maximum_height; @@ -84,7 +84,6 @@ class BCN_API settings uint32_t threads; /// Helpers. - virtual size_t allocation() const NOEXCEPT; virtual size_t maximum_height_() const NOEXCEPT; virtual size_t maximum_concurrency_() const NOEXCEPT; virtual network::steady_clock::duration sample_period() const NOEXCEPT; diff --git a/src/block_arena.cpp b/src/block_arena.cpp index fa68c3d8..33911e72 100644 --- a/src/block_arena.cpp +++ b/src/block_arena.cpp @@ -25,6 +25,8 @@ namespace libbitcoin { namespace node { +using namespace system; + BC_PUSH_WARNING(NO_MALLOC_OR_FREE) BC_PUSH_WARNING(NO_REINTERPRET_CAST) BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) @@ -32,19 +34,21 @@ BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) // construct/destruct/assign // ---------------------------------------------------------------------------- -block_arena::block_arena(size_t size) NOEXCEPT +block_arena::block_arena(size_t multiple) NOEXCEPT : memory_map_{ nullptr }, - size_{ std::max(size, record_size) }, - offset_{ size_ }, - total_{ zero } + multiple_{ multiple }, + offset_{ zero }, + total_{ zero }, + size_{ zero } { } block_arena::block_arena(block_arena&& other) NOEXCEPT : memory_map_{ other.memory_map_ }, - size_{ other.size_ }, + multiple_{ other.multiple_ }, offset_{ other.offset_ }, - total_{ other.total_ } + total_{ other.total_ }, + size_{ other.size_ } { // Prevents free(memory_map_) as responsibility is passed to this object. other.memory_map_ = nullptr; @@ -58,9 +62,10 @@ block_arena::~block_arena() NOEXCEPT block_arena& block_arena::operator=(block_arena&& other) NOEXCEPT { memory_map_ = other.memory_map_; - size_ = other.size_; + multiple_ = other.multiple_; offset_ = other.offset_; total_ = other.total_; + size_ = other.size_; // Prevents free(memory_map_) as responsibility is passed to this object. other.memory_map_ = nullptr; @@ -70,11 +75,14 @@ block_arena& block_arena::operator=(block_arena&& other) NOEXCEPT // public // ---------------------------------------------------------------------------- -void* block_arena::start() THROWS +void* block_arena::start(size_t wire_size) THROWS { + if (is_multiply_overflow(wire_size, multiple_)) + throw allocation_exception{}; + release(memory_map_); - reset(); - return attach(zero); + reset(multiple_ * wire_size); + return link_new_chunk(); } size_t block_arena::detach() THROWS @@ -88,20 +96,18 @@ void block_arena::release(void* address) NOEXCEPT { while (!is_null(address)) { - const auto value = get_record(system::pointer_cast(address)); + const auto value = get_record(pointer_cast(address)); std::free(address/*, value.size */); address = value.next; - } + } } // protected // ---------------------------------------------------------------------------- -void* block_arena::attach(size_t minimum) THROWS +void* block_arena::link_new_chunk(size_t minimum) THROWS { - using namespace system; - - // Ensure next allocation accomodates record plus request (expandable). + // Ensure next allocation accomodates record plus current request. BC_ASSERT(!is_add_overflow(minimum, record_size)); size_ = std::max(size_, minimum + record_size); @@ -120,9 +126,9 @@ void block_arena::trim_to_offset() THROWS { // Memory map must not move. Move by realloc is allowed but not expected // for truncation. If moves then this should drop into mmap/munmap/mremap. - const auto map = std::realloc(memory_map_, offset_); - if (map != memory_map_) - throw allocation_exception{}; + ////const auto map = std::realloc(memory_map_, offset_); + ////if (map != memory_map_) + //// throw allocation_exception{}; } void block_arena::set_record(uint8_t* next_address, size_t own_size) NOEXCEPT @@ -142,14 +148,16 @@ block_arena::record block_arena::get_record(uint8_t* address) const NOEXCEPT size_t block_arena::capacity() const NOEXCEPT { - return system::floored_subtract(size_, offset_); + return floored_subtract(size_, offset_); } -size_t block_arena::reset() NOEXCEPT +size_t block_arena::reset(size_t chunk_size) NOEXCEPT { + // Chunk resets to nullptr/full with no total allocation. const auto total = total_; memory_map_ = nullptr; - offset_ = size_; + offset_ = chunk_size; + size_ = chunk_size; total_ = zero; return total; } @@ -161,13 +169,14 @@ void* block_arena::do_allocate(size_t bytes, size_t align) THROWS { const auto aligned_offset = to_aligned(offset_, align); const auto padding = aligned_offset - offset_; - const auto allocation = padding + bytes; + BC_ASSERT(!system::is_add_overflow(padding, bytes)); + const auto allocation = padding + bytes; if (allocation > capacity()) { trim_to_offset(); - attach(allocation); + link_new_chunk(allocation); return do_allocate(bytes, align); } else diff --git a/src/block_memory.cpp b/src/block_memory.cpp index fbf7f10a..b1e7b203 100644 --- a/src/block_memory.cpp +++ b/src/block_memory.cpp @@ -27,12 +27,12 @@ namespace node { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) -block_memory::block_memory(size_t bytes, size_t threads) NOEXCEPT +block_memory::block_memory(size_t multiple, size_t threads) NOEXCEPT : count_{}, arenas_{} { arenas_.reserve(threads); for (auto index = zero; index < threads; ++index) - arenas_.emplace_back(bytes); + arenas_.emplace_back(multiple); } arena* block_memory::get_arena() NOEXCEPT diff --git a/src/full_node.cpp b/src/full_node.cpp index 73e71ff3..6a9d1f5d 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -41,7 +41,8 @@ full_node::full_node(query& query, const configuration& configuration, : p2p(configuration.network, log), config_(configuration), query_(query), - memory_(configuration.node.allocation(), configuration.network.threads), + memory_(configuration.node.allocation_multiple, + configuration.network.threads), chaser_block_(*this), chaser_header_(*this), chaser_check_(*this), diff --git a/src/parser.cpp b/src/parser.cpp index d2283133..ee0874fb 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -898,9 +898,9 @@ options_metadata parser::load_settings() THROWS "Allowable underperformance standard deviation, defaults to 1.5 (0 disables)." ) ( - "node.allocation_bytes", - value(&configured.node.allocation_bytes), - "Preallocated block buffer for each network thread, defaults to 52000000." + "node.allocation_multiple", + value(&configured.node.allocation_multiple), + "Per thread block deserialization buffer multiple of wire size, defaults to 20." ) ( "node.maximum_height", diff --git a/src/settings.cpp b/src/settings.cpp index ac521ba8..67d5fee8 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -77,7 +77,7 @@ namespace node { settings::settings() NOEXCEPT : headers_first{ true }, allowed_deviation{ 1.5 }, - allocation_bytes{ 52'000'000 }, + allocation_multiple{ 20 }, snapshot_bytes{ 107'374'182'400 }, snapshot_valid{ 100'000 }, maximum_height{ 0 }, @@ -94,11 +94,6 @@ settings::settings(chain::selection) NOEXCEPT // TODO: testnet, etc. maximum_concurrency, snapshot_bytes. } -size_t settings::allocation() const NOEXCEPT -{ - return system::limit(allocation_bytes); -} - size_t settings::maximum_height_() const NOEXCEPT { return to_bool(maximum_height) ? maximum_height : max_size_t; diff --git a/test/settings.cpp b/test/settings.cpp index f555c127..2341a1c4 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -59,9 +59,7 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.snapshot_bytes, 107'374'182'400_u64); BOOST_REQUIRE_EQUAL(node.snapshot_valid, 100'000_u32); BOOST_REQUIRE_EQUAL(node.maximum_height, 0_u32); - - BOOST_REQUIRE_EQUAL(node.allocation(), system::limit(52'000'000_u64)); - BOOST_REQUIRE_EQUAL(node.allocation_bytes, 52'000'000_u64); + BOOST_REQUIRE_EQUAL(node.allocation_multiple, 20_u16); BOOST_REQUIRE_EQUAL(node.maximum_height_(), max_size_t); BOOST_REQUIRE_EQUAL(node.maximum_concurrency, 50000_u32);