Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change default max-transaction-time #1655

Merged
merged 20 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ae1a89c
GH-1639 Change default max-transaction-time from 30 to 499
heifner Sep 15, 2023
494fbae
GH-1639 Execute read-only trxs only on read-only threads
heifner Sep 18, 2023
fd232b2
GH-1639 Add <optional> include
heifner Sep 18, 2023
2749256
GH-1639 Add <optional> include
heifner Sep 18, 2023
f038d65
GH-1639 Enable contracts-console on all nodes
heifner Sep 18, 2023
3e40394
GH-1639 Revert changes to test
heifner Sep 18, 2023
1a6631a
GH-1639 read-only trxs only allowed when read-only-threads > 0
heifner Sep 18, 2023
7a7aa58
GH-1639 Remove unneeded dependency on producer_plugin
heifner Sep 18, 2023
1368ecd
GH-1639 Fix producer_plugin shutdown of read only threads to prevent …
heifner Sep 18, 2023
11df9d1
GH-1639 Decrease read-only-threads from 128 to 16 since ci/cd was tim…
heifner Sep 19, 2023
36be3f7
GH-1639 Favor this over rhs for queue comparison. Also use C++20 spac…
heifner Sep 19, 2023
d2cd84c
GH-1639 Use canonical spaceship operator
heifner Sep 19, 2023
6394011
GH-1639 Revert using of spaceship operator as it appears to not work …
heifner Sep 19, 2023
e6b8493
GH-1639 Use same ec for both cancel calls
heifner Sep 19, 2023
8d221a7
GH-1639 Modify exec_pri_queue to manage the 3 priority queues instead…
heifner Sep 20, 2023
ae2424d
GH-1639 More simplification
heifner Sep 20, 2023
e6bbaaf
GH-1639 fix gcc warning
heifner Sep 20, 2023
a6465e6
GH-1639 Additional test
heifner Sep 21, 2023
b077dc3
GH-1639 Update max-transaction-time help description
heifner Sep 22, 2023
b012cce
GH-1639 Add init_read_threads
heifner Sep 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/01_nodeos/03_plugins/producer_plugin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ Config Options for eosio::producer_plugin:
chain is stale.
-x [ --pause-on-startup ] Start this node in a state where
production is paused
--max-transaction-time arg (=30) Limits the maximum time (in
milliseconds) that is allowed a pushed
transaction's code to execute before
being considered invalid
--max-transaction-time arg (=499) Setting this value (in milliseconds)
will restrict the allowed transaction
execution time to a value potentially
lower than the on-chain consensus
max_transaction_cpu_usage value.
--max-irreversible-block-age arg (=-1)
Limits the maximum age (in seconds) of
the DPOS Irreversible Block for a chain
Expand Down
82 changes: 37 additions & 45 deletions libraries/custom_appbase/include/eosio/chain/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <appbase/application_base.hpp>
#include <eosio/chain/exec_pri_queue.hpp>
#include <chrono>
#include <optional>
#include <mutex>

/*
Expand All @@ -21,73 +22,62 @@ enum class exec_window {
// the main app thread is active.
};

enum class exec_queue {
read_only, // the queue storing tasks which are safe to execute
// in parallel with other read-only tasks in the read-only
// thread pool as well as on the main app thread.
// Multi-thread safe as long as nothing is executed from the read_write queue.
read_write // the queue storing tasks which can be only executed
// on the app thread while read-only tasks are
// not being executed in read-only threads. Single threaded.
};

class two_queue_executor {
class priority_queue_executor {
public:

// Trade off on returning to appbase exec() loop as the overhead of poll/run can be measurable for small running tasks.
// This adds to the total time that the main thread can be busy when a high priority task is waiting.
static constexpr uint16_t minimum_runtime_ms = 3;

// inform how many read_threads will be calling read_only/read_exclusive queues
// Currently only used to assert if exec_queue::read_exclusive is used without any read threads
void init_read_threads(size_t num_read_threads) {
pri_queue_.init_read_threads(num_read_threads);
}

template <typename Func>
auto post( int priority, exec_queue q, Func&& func ) {
if ( q == exec_queue::read_write )
return boost::asio::post(io_serv_, read_write_queue_.wrap(priority, --order_, std::forward<Func>(func)));
else
return boost::asio::post( io_serv_, read_only_queue_.wrap( priority, --order_, std::forward<Func>( func)));
return boost::asio::post( io_serv_, pri_queue_.wrap( priority, q, --order_, std::forward<Func>(func)));
}

// Legacy and deprecated. To be removed after cleaning up its uses in base appbase
template <typename Func>
auto post( int priority, Func&& func ) {
// safer to use read_write queue for unknown type of operation since operations
// from read_write queue are not executed in parallel with read-only operations
return boost::asio::post(io_serv_, read_write_queue_.wrap(priority, --order_, std::forward<Func>(func)));
return boost::asio::post(io_serv_, pri_queue_.wrap(priority, exec_queue::read_write, --order_, std::forward<Func>(func)));
}

boost::asio::io_service& get_io_service() { return io_serv_; }

// called from main thread, highest read_only and read_write
bool execute_highest() {
// execute for at least minimum runtime
const auto end = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(minimum_runtime_ms);

bool more = false;
while (true) {
if ( exec_window_ == exec_window::write ) {
// During write window only main thread is accessing anything in two_queue_executor, no locking required
if( !read_write_queue_.empty() && (read_only_queue_.empty() || *read_only_queue_.top() < *read_write_queue_.top()) ) {
// read_write_queue_'s top function's priority greater than read_only_queue_'s top function's, or read_only_queue_ empty
read_write_queue_.execute_highest();
} else if( !read_only_queue_.empty() ) {
read_only_queue_.execute_highest();
}
more = !read_only_queue_.empty() || !read_write_queue_.empty();
// During write window only main thread is accessing anything in priority_queue_executor, no locking required
more = pri_queue_.execute_highest(exec_queue::read_write, exec_queue::read_only);
} else {
// When in read window, multiple threads including main app thread are accessing two_queue_executor, locking required
more = read_only_queue_.execute_highest_locked(false);
// When in read window, multiple threads including main app thread are accessing priority_queue_executor, locking required
more = pri_queue_.execute_highest_locked(exec_queue::read_only);
}
if (!more || std::chrono::high_resolution_clock::now() > end)
break;
}
return more;
}

bool execute_highest_read_only() {
bool execute_highest_read() {
// execute for at least minimum runtime
const auto end = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(minimum_runtime_ms);

bool more = false;
while (true) {
more = read_only_queue_.execute_highest_locked( true );
get_io_service().poll(); // schedule any queued
more = pri_queue_.execute_highest_blocking_locked(exec_queue::read_only, exec_queue::read_exclusive);
if (!more || std::chrono::high_resolution_clock::now() > end)
break;
}
Expand All @@ -97,25 +87,25 @@ class two_queue_executor {
template <typename Function>
boost::asio::executor_binder<Function, appbase::exec_pri_queue::executor>
wrap(int priority, exec_queue q, Function&& func ) {
if ( q == exec_queue::read_write )
return read_write_queue_.wrap(priority, --order_, std::forward<Function>(func));
else
return read_only_queue_.wrap( priority, --order_, std::forward<Function>( func));
return pri_queue_.wrap(priority, q, --order_, std::forward<Function>(func));
}

void stop() {
pri_queue_.stop();
}

void clear() {
read_only_queue_.clear();
read_write_queue_.clear();
pri_queue_.clear();
}

void set_to_read_window(uint32_t num_threads, std::function<bool()> should_exit) {
void set_to_read_window(std::function<bool()> should_exit) {
exec_window_ = exec_window::read;
read_only_queue_.enable_locking(num_threads, std::move(should_exit));
pri_queue_.enable_locking(std::move(should_exit));
}

void set_to_write_window() {
exec_window_ = exec_window::write;
read_only_queue_.disable_locking();
pri_queue_.disable_locking();
}

bool is_read_window() const {
Expand All @@ -126,20 +116,22 @@ class two_queue_executor {
return exec_window_ == exec_window::write;
}

auto& read_only_queue() { return read_only_queue_; }

auto& read_write_queue() { return read_write_queue_; }
size_t read_only_queue_size() { return pri_queue_.size(exec_queue::read_only); }
size_t read_write_queue_size() { return pri_queue_.size(exec_queue::read_write); }
size_t read_exclusive_queue_size() { return pri_queue_.size(exec_queue::read_exclusive); }
bool read_only_queue_empty() { return pri_queue_.empty(exec_queue::read_only); }
bool read_write_queue_empty() { return pri_queue_.empty(exec_queue::read_write); }
bool read_exclusive_queue_empty() { return pri_queue_.empty(exec_queue::read_exclusive); }

// members are ordered taking into account that the last one is destructed first
private:
boost::asio::io_service io_serv_;
appbase::exec_pri_queue read_only_queue_;
appbase::exec_pri_queue read_write_queue_;
std::atomic<std::size_t> order_ { std::numeric_limits<size_t>::max() }; // to maintain FIFO ordering in both queues within priority
exec_window exec_window_ { exec_window::write };
appbase::exec_pri_queue pri_queue_;
std::atomic<std::size_t> order_{ std::numeric_limits<size_t>::max() }; // to maintain FIFO ordering in all queues within priority
exec_window exec_window_{ exec_window::write };
};

using application = application_t<two_queue_executor>;
using application = application_t<priority_queue_executor>;
}

#include <appbase/application_instance.hpp>
Loading