From 45cf5719387a9df2e0d7d9cd53b840e9566e4d3a Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 3 Aug 2024 10:36:28 -0400 Subject: [PATCH 1/7] Disable stranded assert (called on start). --- src/chasers/chaser_check.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chasers/chaser_check.cpp b/src/chasers/chaser_check.cpp index dabc233d..3c52fd2b 100644 --- a/src/chasers/chaser_check.cpp +++ b/src/chasers/chaser_check.cpp @@ -298,7 +298,8 @@ map_ptr chaser_check::get_map() NOEXCEPT bool chaser_check::set_map(const map_ptr& map) NOEXCEPT { - BC_ASSERT(stranded()); + // Called from start. + ////BC_ASSERT(stranded()); BC_ASSERT(map->size() <= messages::max_inventory); if (map->empty()) From 04991a4bf862a77912023df431772511f7b1db4e Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 3 Aug 2024 12:04:32 -0400 Subject: [PATCH 2/7] Implement naive and fixed buffer block_arena. --- include/bitcoin/node/block_arena.hpp | 16 +++++-- include/bitcoin/node/block_memory.hpp | 2 +- src/block_arena.cpp | 64 +++++++++++++++++++++------ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index 7bdc7779..2c93696e 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -35,10 +35,10 @@ class BCN_API block_arena final inline std::shared_mutex& get_mutex() NOEXCEPT { - return mutex_; + return remap_mutex_; } - block_arena() NOEXCEPT; + block_arena(size_t size) NOEXCEPT; ~block_arena() NOEXCEPT; private: @@ -46,9 +46,17 @@ 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 is thread safe. - std::shared_mutex mutex_{}; + // These are thread safe. + const uint64_t capacity_; + std::shared_mutex field_mutex_{}; + std::shared_mutex remap_mutex_{}; + + // These are protected by mutex. + uint8_t* memory_map_; + uint64_t offset_{}; + }; + } // namespace node } // namespace libbitcoin diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index a7481af4..76039039 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -36,7 +36,7 @@ class BCN_API block_memory final retainer::ptr get_retainer() NOEXCEPT override; private: - block_arena arena_{}; + block_arena arena_{ system::power2(34_size) }; }; } // namespace node diff --git a/src/block_arena.cpp b/src/block_arena.cpp index b1009468..b723fac0 100644 --- a/src/block_arena.cpp +++ b/src/block_arena.cpp @@ -18,36 +18,71 @@ */ #include +#include #include #include namespace libbitcoin { + +template = true> +constexpr Type to_aligned(Type value, Type alignment) NOEXCEPT +{ + return (value + sub1(alignment)) & ~sub1(alignment); +} + namespace node { -// TODO: initialize memory. -block_arena::block_arena() NOEXCEPT +BC_PUSH_WARNING(NO_MALLOC_OR_FREE) +BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) + +// "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 + +block_arena::block_arena(size_t size) NOEXCEPT + : capacity_{ size }, + memory_map_{ system::pointer_cast(malloc(size)) } { } -// TODO: block on mutex until exclusive and then free memory. block_arena::~block_arena() NOEXCEPT { + if (!is_null(memory_map_)) + { + std::unique_lock remap_lock(remap_mutex_); + free(memory_map_); + } } -// TODO: if aligned size is insufficient block on mutex until memory remapped. -void* block_arena::do_allocate(size_t bytes, size_t) THROWS +void* block_arena::do_allocate(size_t bytes, size_t align) THROWS { - BC_PUSH_WARNING(NO_NEW_OR_DELETE) - return ::operator new(bytes); - BC_POP_WARNING() + using namespace system; + BC_ASSERT_MSG(is_nonzero(align), "align zero"); + BC_ASSERT_MSG(align <= alignof(std::max_align_t), "align overflow"); + BC_ASSERT_MSG(power2(floored_log2(align)) == align, "align power"); + BC_ASSERT_MSG(!is_add_overflow(bytes, sub1(align)), "align overflow"); + + std::unique_lock field_lock(field_mutex_); + + auto aligned = to_aligned(offset_, align); + if (bytes > system::floored_subtract(capacity_, aligned)) + { + // TODO: Could loop over a try lock here and log deadlock warning. + std::unique_lock remap_lock(remap_mutex_); + aligned = offset_ = zero; + + if (bytes > capacity_) + throw allocation_exception(); + } + + offset_ = aligned + bytes; + return memory_map_ + aligned; } -// TODO: change to nop. -void block_arena::do_deallocate(void* ptr, size_t, size_t) NOEXCEPT +void block_arena::do_deallocate(void*, size_t, size_t) NOEXCEPT { - BC_PUSH_WARNING(NO_NEW_OR_DELETE) - ::operator delete(ptr); - BC_POP_WARNING() } bool block_arena::do_is_equal(const arena& other) const NOEXCEPT @@ -56,5 +91,8 @@ bool block_arena::do_is_equal(const arena& other) const NOEXCEPT return &other == this; } +BC_POP_WARNING() +BC_POP_WARNING() + } // namespace node } // namespace libbitcoin From 8afd73b3b8b7ae1deb6f4b9d98a6ecf022371c18 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 3 Aug 2024 13:07:44 -0400 Subject: [PATCH 3/7] Use correct BC_PUSH_WARNING. --- src/block_memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block_memory.cpp b/src/block_memory.cpp index 413a15dc..9196e8c8 100644 --- a/src/block_memory.cpp +++ b/src/block_memory.cpp @@ -31,7 +31,7 @@ arena* block_memory::get_arena() NOEXCEPT retainer::ptr block_memory::get_retainer() NOEXCEPT { - BC_PUSH_WARNING(NO_NEW_OR_DELETE) + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return std::make_shared(arena_.get_mutex()); BC_POP_WARNING() } From d2fbb429f5f66c3de7e9f82400b6c8f1e88d4557 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 3 Aug 2024 13:08:09 -0400 Subject: [PATCH 4/7] Make block_memory size configurable. --- include/bitcoin/node/block_arena.hpp | 4 ++-- include/bitcoin/node/block_memory.hpp | 6 +++++- include/bitcoin/node/settings.hpp | 2 ++ src/block_memory.cpp | 5 +++++ src/full_node.cpp | 2 +- src/parser.cpp | 5 +++++ src/settings.cpp | 6 ++++++ test/settings.cpp | 5 +++++ 8 files changed, 31 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index 2c93696e..407db374 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -47,13 +47,13 @@ class BCN_API block_arena final bool do_is_equal(const arena& other) const NOEXCEPT override; // These are thread safe. - const uint64_t capacity_; + const size_t capacity_; std::shared_mutex field_mutex_{}; std::shared_mutex remap_mutex_{}; // These are protected by mutex. uint8_t* memory_map_; - uint64_t offset_{}; + size_t offset_{}; }; diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index 76039039..24ed223a 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -32,11 +32,15 @@ class BCN_API block_memory final : public network::memory { public: + DELETE_COPY_MOVE_DESTRUCT(block_memory); + + block_memory(size_t size) NOEXCEPT; + arena* get_arena() NOEXCEPT override; retainer::ptr get_retainer() NOEXCEPT override; private: - block_arena arena_{ system::power2(34_size) }; + block_arena arena_; }; } // namespace node diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index a9a7fd5a..799242f8 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -74,6 +74,7 @@ class BCN_API settings /// Properties. bool headers_first; float allowed_deviation; + uint64_t allocation_bytes; uint64_t snapshot_bytes; uint32_t snapshot_valid; uint32_t maximum_height; @@ -83,6 +84,7 @@ 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_memory.cpp b/src/block_memory.cpp index 9196e8c8..f0eb72b6 100644 --- a/src/block_memory.cpp +++ b/src/block_memory.cpp @@ -24,6 +24,11 @@ namespace libbitcoin { namespace node { +block_memory::block_memory(size_t size) NOEXCEPT + : arena_{ size } +{ +} + arena* block_memory::get_arena() NOEXCEPT { return &arena_; diff --git a/src/full_node.cpp b/src/full_node.cpp index cfcf1994..62100ae5 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -40,7 +40,7 @@ full_node::full_node(query& query, const configuration& configuration, const logger& log) NOEXCEPT : p2p(configuration.network, log), config_(configuration), - memory_(), + memory_(configuration.node.allocation()), query_(query), chaser_block_(*this), chaser_header_(*this), diff --git a/src/parser.cpp b/src/parser.cpp index 9ae0ca9c..2e0d2499 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -897,6 +897,11 @@ options_metadata parser::load_settings() THROWS value(&configured.node.allowed_deviation), "Allowable underperformance standard deviation, defaults to 1.5 (0 disables)." ) + ( + "node.allocation_bytes", + value(&configured.node.allocation_bytes), + "Blocks preallocated memory buffer, defaults to 1'073'741'824." + ) ( "node.maximum_height", value(&configured.node.maximum_height), diff --git a/src/settings.cpp b/src/settings.cpp index 90056ee8..31c01ab1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -77,6 +77,7 @@ namespace node { settings::settings() NOEXCEPT : headers_first{ true }, allowed_deviation{ 1.5 }, + allocation_bytes{ 1'073'741'824 }, snapshot_bytes{ 107'374'182'400 }, snapshot_valid{ 100'000 }, maximum_height{ 0 }, @@ -93,6 +94,11 @@ 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 576542f7..3d54b417 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -59,10 +59,15 @@ 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(1'073'741'824_u64)); + BOOST_REQUIRE_EQUAL(node.allocation_bytes, 1'073'741'824_u64); + BOOST_REQUIRE_EQUAL(node.maximum_height_(), max_size_t); BOOST_REQUIRE_EQUAL(node.maximum_concurrency, 50000_u32); BOOST_REQUIRE_EQUAL(node.maximum_concurrency_(), 50000_size); BOOST_REQUIRE_EQUAL(node.sample_period_seconds, 10_u16); + BOOST_REQUIRE(node.sample_period() == steady_clock::duration(seconds(10))); BOOST_REQUIRE_EQUAL(node.currency_window_minutes, 60_u32); BOOST_REQUIRE(node.currency_window() == steady_clock::duration(minutes(60))); From 29f0a3185c6a574270a8011a34f1a3bf3e589cc7 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 3 Aug 2024 15:18:02 -0400 Subject: [PATCH 5/7] Make memory_map_ const. --- include/bitcoin/node/block_arena.hpp | 4 ++-- src/block_arena.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index 407db374..3e5a7a56 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -48,11 +48,11 @@ class BCN_API block_arena final // These are thread safe. const size_t capacity_; + const uint8_t* memory_map_; std::shared_mutex field_mutex_{}; std::shared_mutex remap_mutex_{}; - // These are protected by mutex. - uint8_t* memory_map_; + // This is protected by mutex. size_t offset_{}; }; diff --git a/src/block_arena.cpp b/src/block_arena.cpp index b723fac0..1f231b56 100644 --- a/src/block_arena.cpp +++ b/src/block_arena.cpp @@ -52,7 +52,7 @@ block_arena::~block_arena() NOEXCEPT if (!is_null(memory_map_)) { std::unique_lock remap_lock(remap_mutex_); - free(memory_map_); + free(const_cast(memory_map_)); } } @@ -78,7 +78,7 @@ void* block_arena::do_allocate(size_t bytes, size_t align) THROWS } offset_ = aligned + bytes; - return memory_map_ + aligned; + return const_cast(memory_map_ + aligned); } void block_arena::do_deallocate(void*, size_t, size_t) NOEXCEPT From 3aebc3b86af535e06f2e2c9cdd4f253d68776370 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 4 Aug 2024 00:08:07 -0400 Subject: [PATCH 6/7] Use thread_local block_arenas in block_memory. --- include/bitcoin/node/block_arena.hpp | 26 ++++++++++--------- include/bitcoin/node/block_memory.hpp | 20 ++++++++++++--- src/block_arena.cpp | 36 ++++++++++++++++++++------- src/block_memory.cpp | 24 +++++++++++++++--- src/full_node.cpp | 2 +- 5 files changed, 79 insertions(+), 29 deletions(-) diff --git a/include/bitcoin/node/block_arena.hpp b/include/bitcoin/node/block_arena.hpp index 3e5a7a56..7a1ceec8 100644 --- a/include/bitcoin/node/block_arena.hpp +++ b/include/bitcoin/node/block_arena.hpp @@ -26,34 +26,36 @@ namespace libbitcoin { namespace node { -/// Thread safe block memory arena. +/// Thread UNSAFE linear memory arena. class BCN_API block_arena final : public arena { public: - DELETE_COPY_MOVE(block_arena); + DELETE_COPY(block_arena); + + block_arena(size_t size=zero) NOEXCEPT; + block_arena(block_arena&& other) NOEXCEPT; + ~block_arena() NOEXCEPT; + + block_arena& operator=(block_arena&& other) NOEXCEPT; inline std::shared_mutex& get_mutex() NOEXCEPT { - return remap_mutex_; + return mutex_; } - block_arena(size_t size) NOEXCEPT; - ~block_arena() NOEXCEPT; - private: 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; // These are thread safe. - const size_t capacity_; - const uint8_t* memory_map_; - std::shared_mutex field_mutex_{}; - std::shared_mutex remap_mutex_{}; + std::shared_mutex mutex_{}; + uint8_t* memory_map_; + size_t capacity_; - // This is protected by mutex. - size_t offset_{}; + // This is unprotected, caller must guard. + size_t offset_; }; diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index 24ed223a..83d8b7fe 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -19,7 +19,9 @@ #ifndef LIBBITCOIN_NODE_BLOCK_MEMORY_HPP #define LIBBITCOIN_NODE_BLOCK_MEMORY_HPP +#include #include +#include #include #include #include @@ -27,20 +29,32 @@ namespace libbitcoin { namespace node { -/// Thread safe block memory. +/// Thread SAFE linear memory allocation and tracking. class BCN_API block_memory final : public network::memory { public: DELETE_COPY_MOVE_DESTRUCT(block_memory); - block_memory(size_t size) NOEXCEPT; + /// Store the size for each thread's arena initilization. + /// Default allocate each arena to preclude allcation and locking. + block_memory(size_t size, size_t threads) NOEXCEPT; + /// Each thread obtains an arena of the same size. arena* get_arena() NOEXCEPT override; + + /// Each thread obtains its arena's retainer. retainer::ptr get_retainer() NOEXCEPT override; +protected: + block_arena* get_block_arena() NOEXCEPT; + private: - block_arena arena_; + // These are thread safe. + std::atomic_size_t count_; + + // This is protected by thread_local member. + std::vector arenas_; }; } // namespace node diff --git a/src/block_arena.cpp b/src/block_arena.cpp index 1f231b56..d9ebaa21 100644 --- a/src/block_arena.cpp +++ b/src/block_arena.cpp @@ -42,20 +42,41 @@ BC_PUSH_WARNING(NO_POINTER_ARITHMETIC) // en.cppreference.com/w/c/memory/malloc block_arena::block_arena(size_t size) NOEXCEPT - : capacity_{ size }, - memory_map_{ system::pointer_cast(malloc(size)) } + : memory_map_{ system::pointer_cast(malloc(size)) }, + capacity_{ size }, + offset_{} { } +block_arena::block_arena(block_arena&& other) NOEXCEPT + : memory_map_{ other.memory_map_ }, + capacity_{ other.capacity_ }, + offset_{ other.offset_ } +{ + // Prevents free(memory_map_) as responsibility is passed to this object. + other.memory_map_ = nullptr; +} + block_arena::~block_arena() NOEXCEPT { if (!is_null(memory_map_)) { - std::unique_lock remap_lock(remap_mutex_); - free(const_cast(memory_map_)); + std::unique_lock lock(mutex_); + free(memory_map_); } } +block_arena& block_arena::operator=(block_arena&& other) NOEXCEPT +{ + memory_map_ = other.memory_map_; + capacity_ = other.capacity_; + offset_ = other.offset_; + + // Prevents free(memory_map_) as responsibility is passed to this object. + other.memory_map_ = nullptr; + return *this; +} + void* block_arena::do_allocate(size_t bytes, size_t align) THROWS { using namespace system; @@ -64,13 +85,10 @@ void* block_arena::do_allocate(size_t bytes, size_t align) THROWS BC_ASSERT_MSG(power2(floored_log2(align)) == align, "align power"); BC_ASSERT_MSG(!is_add_overflow(bytes, sub1(align)), "align overflow"); - std::unique_lock field_lock(field_mutex_); - auto aligned = to_aligned(offset_, align); if (bytes > system::floored_subtract(capacity_, aligned)) { - // TODO: Could loop over a try lock here and log deadlock warning. - std::unique_lock remap_lock(remap_mutex_); + std::unique_lock lock(mutex_); aligned = offset_ = zero; if (bytes > capacity_) @@ -78,7 +96,7 @@ void* block_arena::do_allocate(size_t bytes, size_t align) THROWS } offset_ = aligned + bytes; - return const_cast(memory_map_ + aligned); + return memory_map_ + aligned; } void block_arena::do_deallocate(void*, size_t, size_t) NOEXCEPT diff --git a/src/block_memory.cpp b/src/block_memory.cpp index f0eb72b6..49641e5a 100644 --- a/src/block_memory.cpp +++ b/src/block_memory.cpp @@ -19,27 +19,43 @@ #include #include +#include #include namespace libbitcoin { namespace node { -block_memory::block_memory(size_t size) NOEXCEPT - : arena_{ size } +block_memory::block_memory(size_t size, size_t threads) NOEXCEPT + : count_{}, arenas_{} { + arenas_.reserve(threads); + for (auto index = zero; index < threads; ++index) + arenas_.emplace_back(size); } arena* block_memory::get_arena() NOEXCEPT { - return &arena_; + return get_block_arena(); } retainer::ptr block_memory::get_retainer() NOEXCEPT { BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) - return std::make_shared(arena_.get_mutex()); + return std::make_shared(get_block_arena()->get_mutex()); BC_POP_WARNING() } +// protected + +block_arena* block_memory::get_block_arena() NOEXCEPT +{ + static thread_local auto index = count_.fetch_add(one); + + if (index >= arenas_.size()) + return nullptr; + + return &arenas_.at(index); +} + } // namespace node } // namespace libbitcoin diff --git a/src/full_node.cpp b/src/full_node.cpp index 62100ae5..6332de7c 100644 --- a/src/full_node.cpp +++ b/src/full_node.cpp @@ -40,7 +40,7 @@ full_node::full_node(query& query, const configuration& configuration, const logger& log) NOEXCEPT : p2p(configuration.network, log), config_(configuration), - memory_(configuration.node.allocation()), + memory_(configuration.node.allocation(), configuration.network.threads), query_(query), chaser_block_(*this), chaser_header_(*this), From f13518acde9944a704f90808020bbd8edb89906b Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 4 Aug 2024 00:57:01 -0400 Subject: [PATCH 7/7] Style, comments, throw on over-requested block arenas. --- include/bitcoin/node/block_memory.hpp | 9 ++++----- src/block_memory.cpp | 11 +++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/bitcoin/node/block_memory.hpp b/include/bitcoin/node/block_memory.hpp index 83d8b7fe..21f77173 100644 --- a/include/bitcoin/node/block_memory.hpp +++ b/include/bitcoin/node/block_memory.hpp @@ -36,9 +36,8 @@ class BCN_API block_memory final public: DELETE_COPY_MOVE_DESTRUCT(block_memory); - /// Store the size for each thread's arena initilization. /// Default allocate each arena to preclude allcation and locking. - block_memory(size_t size, size_t threads) NOEXCEPT; + block_memory(size_t bytes, size_t threads) NOEXCEPT; /// Each thread obtains an arena of the same size. arena* get_arena() NOEXCEPT override; @@ -47,13 +46,13 @@ class BCN_API block_memory final retainer::ptr get_retainer() NOEXCEPT override; protected: - block_arena* get_block_arena() NOEXCEPT; + block_arena* get_block_arena() THROWS; private: - // These are thread safe. + // This is thread safe. std::atomic_size_t count_; - // This is protected by thread_local member. + // This is protected by constructor init and thread_local indexation. std::vector arenas_; }; diff --git a/src/block_memory.cpp b/src/block_memory.cpp index 49641e5a..6fdf29e7 100644 --- a/src/block_memory.cpp +++ b/src/block_memory.cpp @@ -25,17 +25,19 @@ namespace libbitcoin { namespace node { -block_memory::block_memory(size_t size, size_t threads) NOEXCEPT +block_memory::block_memory(size_t bytes, size_t threads) NOEXCEPT : count_{}, arenas_{} { arenas_.reserve(threads); for (auto index = zero; index < threads; ++index) - arenas_.emplace_back(size); + arenas_.emplace_back(bytes); } arena* block_memory::get_arena() NOEXCEPT { + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return get_block_arena(); + BC_POP_WARNING() } retainer::ptr block_memory::get_retainer() NOEXCEPT @@ -47,12 +49,13 @@ retainer::ptr block_memory::get_retainer() NOEXCEPT // protected -block_arena* block_memory::get_block_arena() NOEXCEPT +block_arena* block_memory::get_block_arena() THROWS { static thread_local auto index = count_.fetch_add(one); + // More threads are requesting an arena than specified at construct. if (index >= arenas_.size()) - return nullptr; + throw allocation_exception(); return &arenas_.at(index); }