Compare commits

...

7 Commits

Author SHA1 Message Date
Kevin Heifner 1b71f4f8a4 Used named_thread instead of named_thread_pool 2023-02-04 10:14:52 -06:00
Kevin Heifner 9dba153514 Merge branch 'desc-thread-pool' into named-thread-strand 2023-02-04 10:07:13 -06:00
Kevin Heifner 38e88449ee Merge remote-tracking branch 'origin/main' into desc-thread-pool 2023-02-04 10:06:45 -06:00
Kevin Heifner 8352c683f5 Add a named_thread class that includes a strand 2023-02-04 09:59:26 -06:00
Kevin Heifner eeb293c8d3 Use eosio:chain::name for named_thread_pool name 2023-02-04 09:32:22 -06:00
Kevin Heifner 03e183a18d Improve comment 2023-02-03 07:48:32 -06:00
Kevin Heifner de3a8594a7 Add description to lambda so that you can determine which thread pool is active for a given thread stack trace. 2023-02-03 07:15:52 -06:00
9 changed files with 107 additions and 25 deletions
+1 -1
View File
@@ -301,7 +301,7 @@ struct controller_impl {
conf( cfg ),
chain_id( chain_id ),
read_mode( cfg.read_mode ),
thread_pool( "chain" )
thread_pool( "chain"_n )
{
fork_db.open( [this]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
@@ -1,7 +1,9 @@
#pragma once
#include <eosio/chain/name.hpp>
#include <fc/exception/exception.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/post.hpp>
#include <future>
#include <memory>
@@ -21,12 +23,12 @@ namespace eosio { namespace chain {
/// @param name_prefix is name appended with -## of thread.
/// A short name_prefix (6 chars or under) is recommended as console_appender uses 9 chars
/// for the thread name.
explicit named_thread_pool( std::string name_prefix );
explicit named_thread_pool( eosio::chain::name name_prefix );
/// calls stop()
~named_thread_pool();
boost::asio::io_context& get_executor() { return _ioc; }
auto& get_executor() { return _ioc; }
/// Spawn threads, can be re-started after stop().
/// Assumes start()/stop() called from the same thread or externally protected.
@@ -42,12 +44,40 @@ namespace eosio { namespace chain {
private:
using ioc_work_t = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
std::string _name_prefix;
eosio::chain::name _name_prefix;
boost::asio::io_context _ioc;
std::vector<std::thread> _thread_pool;
std::optional<ioc_work_t> _ioc_work;
};
class named_thread {
public:
/// @param name_prefix is name appended with -1 for thread name.
/// A short name_prefix (6 chars or under) is recommended as console_appender uses 9 chars
/// for the thread name.
explicit named_thread( eosio::chain::name name_prefix )
: _pool( name_prefix ) {}
/// stop before destroying strand
~named_thread() { stop(); }
auto& get_executor() { return _strand; }
/// Spawn thread, can be re-started after stop().
/// Assumes start()/stop() called from the same thread or externally protected.
/// @param on_except is the function to call if io_context throws an exception, is called from thread pool thread.
/// if an empty function then logs and rethrows exception on thread which will terminate.
/// @throw assert_exception if already started and not stopped.
void start( named_thread_pool::on_except_t on_except ) { _pool.start( 1, std::move(on_except) ); }
/// destroy work guard, stop io_context, join thread_pool
void stop() { _pool.stop(); }
private:
named_thread_pool _pool;
boost::asio::io_context::strand _strand{_pool.get_executor()};
};
// async on io_context and return future
template<typename F>
+7 -4
View File
@@ -1,11 +1,12 @@
#include <eosio/chain/thread_utils.hpp>
#include <eosio/chain/name.hpp>
#include <fc/log/logger_config.hpp>
#include <fc/exception/exception.hpp>
namespace eosio { namespace chain {
named_thread_pool::named_thread_pool( std::string name_prefix )
: _name_prefix( std::move(name_prefix) )
named_thread_pool::named_thread_pool( eosio::chain::name name_prefix )
: _name_prefix( name_prefix )
, _ioc()
{
}
@@ -19,9 +20,11 @@ void named_thread_pool::start( size_t num_threads, on_except_t on_except ) {
_ioc_work.emplace( boost::asio::make_work_guard( _ioc ) );
_ioc.restart();
_thread_pool.reserve( num_threads );
for( size_t i = 0; i < num_threads; ++i ) {
_thread_pool.emplace_back( [&ioc = _ioc, &name_prefix = _name_prefix, on_except, i]() {
std::string tn = name_prefix + "-" + std::to_string( i );
// capture eosio::name so it is available in the stack for debugger, use abieos/tools/num2name to get string name
_thread_pool.emplace_back( [name_prefix = _name_prefix, &ioc = _ioc, on_except, i]() {
std::string tn = name_prefix.to_string() + "-" + std::to_string( i );
try {
fc::set_os_thread_name( tn );
ioc.run();
@@ -115,7 +115,7 @@ BOOST_FIXTURE_TEST_CASE(updateauth_test_multi_threaded, TESTER) { try {
produce_block();
create_account(tester_account);
named_thread_pool thread_pool( "test" );
named_thread_pool thread_pool( "test"_n );
thread_pool.start( 5, {} );
for( size_t i = 0; i < 100; ++i ) {
@@ -129,7 +129,7 @@ struct http_plugin_state {
bool keep_alive = false;
uint16_t thread_pool_size = 2;
eosio::chain::named_thread_pool thread_pool{ "http" };
eosio::chain::named_thread_pool thread_pool{ eosio::chain::name("http") };
fc::logger& logger;
+1 -1
View File
@@ -281,7 +281,7 @@ namespace eosio {
compat::channels::transaction_ack::channel_type::handle incoming_transaction_ack_subscription;
uint16_t thread_pool_size = 4;
eosio::chain::named_thread_pool thread_pool{ "net" };
eosio::chain::named_thread_pool thread_pool{ "net"_n };
boost::asio::deadline_timer accept_error_timer{thread_pool.get_executor()};
+1 -1
View File
@@ -307,7 +307,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
pending_block_mode _pending_block_mode = pending_block_mode::speculating;
unapplied_transaction_queue _unapplied_transactions;
size_t _thread_pool_size = config::default_controller_thread_pool_size;
named_thread_pool _thread_pool{ "prod" };
named_thread_pool _thread_pool{ "prod"_n };
std::atomic<int32_t> _max_transaction_time_ms; // modified by app thread, read by net_plugin thread pool
std::atomic<bool> _received_block{false}; // modified by net_plugin thread pool and app thread
@@ -87,7 +87,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
template <class ACCEPTOR>
struct generic_acceptor {
using socket_type = typename ACCEPTOR::protocol_type::socket;
generic_acceptor(boost::asio::io_context& ioc) : acceptor_(ioc), socket_(ioc), error_timer_(ioc) {}
generic_acceptor(boost::asio::io_context::strand& s) : acceptor_(s), socket_(s), error_timer_(s) {}
ACCEPTOR acceptor_;
socket_type socket_;
boost::asio::deadline_timer error_timer_;
@@ -99,7 +99,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
using acceptor_type = std::variant<std::unique_ptr<tcp_acceptor>, std::unique_ptr<unix_acceptor>>;
std::set<acceptor_type> acceptors;
named_thread_pool thread_pool{"SHiP"};
named_thread ship_thread{"ship"_n};
static void get_log_entry(state_history_log& log, uint32_t block_num, std::optional<bytes>& result) {
if (block_num < log.begin_block() || block_num >= log.end_block())
@@ -224,7 +224,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
template <typename T>
void send(T obj) {
boost::asio::post(this->plugin->thread_pool.get_executor(), [self = this->shared_from_this(), obj = std::move(obj) ]() mutable {
boost::asio::post(this->plugin->ship_thread.get_executor(), [self = this->shared_from_this(), obj = std::move(obj) ]() mutable {
self->send_queue.emplace_back(fc::raw::pack(state_result{std::move(obj)}));
self->send();
});
@@ -405,7 +405,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
}
void close() override {
boost::asio::post(plugin->thread_pool.get_executor(), [self = this->shared_from_this()]() {
boost::asio::post(plugin->ship_thread.get_executor(), [self = this->shared_from_this()]() {
self->close_i();
});
}
@@ -434,7 +434,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
FC_THROW_EXCEPTION(plugin_exception, "unable to open listen socket");
};
auto init_tcp_acceptor = [&]() { acceptors.insert(std::make_unique<tcp_acceptor>(thread_pool.get_executor())); };
auto init_tcp_acceptor = [&]() { acceptors.insert(std::make_unique<tcp_acceptor>(ship_thread.get_executor())); };
auto init_unix_acceptor = [&]() {
// take a sniff and see if anything is already listening at the given socket path, or if the socket path exists
// but nothing is listening
@@ -453,7 +453,7 @@ struct state_history_plugin_impl : std::enable_shared_from_this<state_history_pl
ec = test_ec;
}
check_ec("open");
acceptors.insert(std::make_unique<unix_acceptor>(thread_pool.get_executor()));
acceptors.insert(std::make_unique<unix_acceptor>(ship_thread.get_executor()));
};
// create and configure acceptors, can be both
@@ -727,8 +727,7 @@ void state_history_plugin::plugin_startup() {
fc_ilog( _log, "Done storing initial state on startup" );
}
my->listen();
// use of executor assumes only one thread
my->thread_pool.start( 1, [](const fc::exception& e) {
my->ship_thread.start( [](const fc::exception& e) {
fc_elog( _log, "Exception in SHiP thread pool, exiting: ${e}", ("e", e.to_detail_string()) );
app().quit();
} );
@@ -745,7 +744,7 @@ void state_history_plugin::plugin_shutdown() {
my->stopping = true;
my->trace_log->stop();
my->chain_state_log->stop();
my->thread_pool.stop();
my->ship_thread.stop();
}
void state_history_plugin::handle_sighup() { fc::logger::update(logger_name, _log); }
+54 -4
View File
@@ -910,7 +910,7 @@ BOOST_AUTO_TEST_CASE(transaction_metadata_test) { try {
BOOST_CHECK_EQUAL(trx.id(), ptrx->id());
BOOST_CHECK_EQUAL(trx.id(), ptrx2->id());
named_thread_pool thread_pool( "misc" );
named_thread_pool thread_pool( "misc"_n );
thread_pool.start( 5, {} );
auto fut = transaction_metadata::start_recover_keys( ptrx, thread_pool.get_executor(), test.control->get_chain_id(), fc::microseconds::maximum(), transaction_metadata::trx_type::input );
@@ -1202,7 +1202,7 @@ BOOST_AUTO_TEST_CASE(bad_alloc_test) {
BOOST_AUTO_TEST_CASE(named_thread_pool_test) {
{
named_thread_pool thread_pool( "misc" );
named_thread_pool thread_pool( "misc"_n );
thread_pool.start( 5, {} );
std::promise<void> p;
@@ -1213,7 +1213,7 @@ BOOST_AUTO_TEST_CASE(named_thread_pool_test) {
BOOST_TEST( (f.wait_for( 100ms ) == std::future_status::ready) );
}
{ // delayed start
named_thread_pool thread_pool( "misc" );
named_thread_pool thread_pool( "misc"_n );
std::promise<void> p;
auto f = p.get_future();
@@ -1227,7 +1227,7 @@ BOOST_AUTO_TEST_CASE(named_thread_pool_test) {
{ // exception
std::promise<fc::exception> ep;
auto ef = ep.get_future();
named_thread_pool thread_pool( "misc" );
named_thread_pool thread_pool( "misc"_n );
thread_pool.start( 5, [&ep](const fc::exception& e) { ep.set_value(e); } );
boost::asio::post( thread_pool.get_executor(), [](){
@@ -1250,6 +1250,56 @@ BOOST_AUTO_TEST_CASE(named_thread_pool_test) {
}
}
BOOST_AUTO_TEST_CASE(named_thread_test) {
{
named_thread thread( "misc"_n );
thread.start( {} );
std::promise<void> p;
auto f = p.get_future();
boost::asio::post( thread.get_executor(), [&p](){
p.set_value();
});
BOOST_TEST( (f.wait_for( 100ms ) == std::future_status::ready) );
}
{ // delayed start
named_thread thread( "misc"_n );
std::promise<void> p;
auto f = p.get_future();
boost::asio::post( thread.get_executor(), [&p](){
p.set_value();
});
BOOST_TEST( (f.wait_for( 10ms ) == std::future_status::timeout) );
thread.start( {} );
BOOST_TEST( (f.wait_for( 100ms ) == std::future_status::ready) );
}
{ // exception
std::promise<fc::exception> ep;
auto ef = ep.get_future();
named_thread thread( "misc"_n );
thread.start( [&ep](const fc::exception& e) { ep.set_value(e); } );
boost::asio::post( thread.get_executor(), [](){
FC_ASSERT( false, "oops throw on thread" );
});
BOOST_TEST( (ef.wait_for( 100ms ) == std::future_status::ready) );
BOOST_TEST( ef.get().to_detail_string().find("oops throw on thread") != std::string::npos );
// we can restart, after a stop
BOOST_REQUIRE_THROW( thread.start( [&ep](const fc::exception& e) { ep.set_value(e); } ), fc::assert_exception );
thread.stop();
std::promise<void> p;
auto f = p.get_future();
boost::asio::post( thread.get_executor(), [&p](){
p.set_value();
});
thread.start( [&ep](const fc::exception& e) { ep.set_value(e); } );
BOOST_TEST( (f.wait_for( 100ms ) == std::future_status::ready) );
}
}
BOOST_AUTO_TEST_CASE(public_key_from_hash) {
auto private_key_string = std::string("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3");
auto expected_public_key = std::string("EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV");