Update boost::asio usage to conform to newer standards: (#144)

* Convert boost::asio::io_service to boost::asio::io_context
  * Convert strand.wrap(...) to boost::asio::bind_executor(strand, ...)
  * Convert strand.dispatch(...) to boost::asio::dispatch(strand, ...)
  * Convert io_context.reset() to io_context.restart()
  * Convert null_buffers() usage to socket.async_wait(...)
  * Drop usage of GET_IO_SERVICE macro from monero
  * Refactor REST server to manage resources better
This commit is contained in:
Lee *!* Clagett
2024-11-20 10:53:40 -05:00
committed by Lee *!* Clagett
parent 5796dad3b8
commit 66b7497a34
17 changed files with 259 additions and 197 deletions

View File

@@ -399,7 +399,7 @@ namespace rpc
return {lws::error::bad_daemon_response};
}
expect<net::zmq::async_client> client::make_async_client(boost::asio::io_service& io) const
expect<net::zmq::async_client> client::make_async_client(boost::asio::io_context& io) const
{
MONERO_PRECOND(ctx != nullptr);

View File

@@ -26,7 +26,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/optional/optional.hpp>
#include <chrono>
#include <memory>
@@ -139,7 +139,7 @@ namespace rpc
}
//! \return `async_client` to daemon. Thread safe.
expect<net::zmq::async_client> make_async_client(boost::asio::io_service& io) const;
expect<net::zmq::async_client> make_async_client(boost::asio::io_context& io) const;
/*!
Queue `message` for sending to daemon. If the queue is full, wait a

View File

@@ -27,14 +27,15 @@
#include "client.h"
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <chrono>
#include "common/expect.h" // monero/src
#include "misc_log_ex.h" // monero/contrib/epee/include
#include "net/net_utils_base.h" // monero/contrib/epee/include
#include "rpc/scanner/commands.h"
#include "rpc/scanner/connection.h"
#include "rpc/scanner/read_commands.h"
@@ -121,9 +122,13 @@ namespace lws { namespace rpc { namespace scanner
{
MINFO("Attempting connection to " << self_->server_address_);
self_->connect_timer_.expires_from_now(connect_timeout);
self_->connect_timer_.async_wait(self_->strand_.wrap(close{self_}));
self_->connect_timer_.async_wait(
boost::asio::bind_executor(self_->strand_, close{self_})
);
BOOST_ASIO_CORO_YIELD self_->sock_.async_connect(self_->server_address_, self_->strand_.wrap(*this));
BOOST_ASIO_CORO_YIELD self_->sock_.async_connect(
self_->server_address_, boost::asio::bind_executor(self_->strand_, *this)
);
if (!self_->connect_timer_.cancel() || error)
{
@@ -135,7 +140,9 @@ namespace lws { namespace rpc { namespace scanner
MINFO("Retrying connection in " << std::chrono::seconds{reconnect_interval}.count() << " seconds");
self_->connect_timer_.expires_from_now(reconnect_interval);
BOOST_ASIO_CORO_YIELD self_->connect_timer_.async_wait(self_->strand_.wrap(*this));
BOOST_ASIO_CORO_YIELD self_->connect_timer_.async_wait(
boost::asio::bind_executor(self_->strand_, *this)
);
}
MINFO("Connection made to " << self_->server_address_);
@@ -147,7 +154,7 @@ namespace lws { namespace rpc { namespace scanner
}
};
client::client(boost::asio::io_service& io, const std::string& address, std::string pass, std::vector<std::shared_ptr<queue>> local)
client::client(boost::asio::io_context& io, const std::string& address, std::string pass, std::vector<std::shared_ptr<queue>> local)
: connection(io),
local_(std::move(local)),
pass_(std::move(pass)),
@@ -182,11 +189,14 @@ namespace lws { namespace rpc { namespace scanner
{
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch([self] ()
boost::asio::dispatch(
self->strand_,
[self] ()
{
if (!self->sock_.is_open())
connector{self}();
});
}
);
}
void client::push_accounts(const std::shared_ptr<client>& self, std::vector<lws::account> users)
@@ -194,7 +204,9 @@ namespace lws { namespace rpc { namespace scanner
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch([self, users = std::move(users)] () mutable
boost::asio::dispatch(
self->strand_,
[self, users = std::move(users)] () mutable
{
/* Keep this algorithm simple, one user at a time. A little more difficult
to do multiples at once */
@@ -207,7 +219,8 @@ namespace lws { namespace rpc { namespace scanner
);
self->next_push_ %= self->local_.size();
}
});
}
);
}
void client::replace_accounts(const std::shared_ptr<client>& self, std::vector<lws::account> users)
@@ -215,7 +228,9 @@ namespace lws { namespace rpc { namespace scanner
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch([self, users = std::move(users)] () mutable
boost::asio::dispatch(
self->strand_,
[self, users = std::move(users)] () mutable
{
MINFO("Received " << users.size() << " accounts as new workload");
for (std::size_t i = 0; i < self->local_.size(); ++i)
@@ -230,7 +245,8 @@ namespace lws { namespace rpc { namespace scanner
self->local_[i]->replace_accounts(std::move(next));
}
self->next_push_ = 0;
});
}
);
}
void client::send_update(const std::shared_ptr<client>& self, std::vector<lws::account> users, std::vector<crypto::hash> blocks)
@@ -238,17 +254,20 @@ namespace lws { namespace rpc { namespace scanner
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch([self, users = std::move(users), blocks = std::move(blocks)] () mutable
boost::asio::dispatch(
self->strand_,
[self, users = std::move(users), blocks = std::move(blocks)] () mutable
{
if (!self->connected_)
MONERO_THROW(common_error::kInvalidArgument, "not connected");
write_command(self, update_accounts{std::move(users), std::move(blocks)});
});
}
);
}
void client::cleanup()
{
base_cleanup();
GET_IO_SERVICE(sock_).stop();
context().stop();
}
}}} // lws // rpc // scanner

View File

@@ -26,7 +26,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/steady_timer.hpp>
#include <cstddef>
@@ -81,7 +81,7 @@ namespace lws { namespace rpc { namespace scanner
//! Send `users` upstream for disk storage
static void send_update(const std::shared_ptr<client>& self, std::vector<lws::account> users, std::vector<crypto::hash> blocks);
//! Closes socket and calls stop on `io_service`.
//! Closes socket and calls stop on `io_context`.
void cleanup();
};
}}} // lws // rpc // scanner

View File

@@ -31,7 +31,7 @@
namespace lws { namespace rpc { namespace scanner
{
connection::connection(boost::asio::io_service& io)
connection::connection(boost::asio::io_context& io)
: read_buf_(),
write_bufs_(),
sock_(io),

View File

@@ -28,7 +28,7 @@
#include <atomic>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/strand.hpp>
@@ -50,13 +50,15 @@ namespace lws { namespace rpc { namespace scanner
std::deque<epee::byte_slice> write_bufs_;
boost::asio::ip::tcp::socket sock_;
boost::asio::steady_timer write_timeout_;
boost::asio::io_service::strand strand_;
boost::asio::io_context::strand strand_;
header next_;
bool cleanup_;
explicit connection(boost::asio::io_service& io);
explicit connection(boost::asio::io_context& io);
~connection();
boost::asio::io_context& context() const { return strand_.context(); }
boost::asio::ip::tcp::endpoint remote_endpoint();
//! \return ASIO compatible read buffer of `size`.

View File

@@ -26,7 +26,9 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/read.hpp>
#include <cstring>
#include <limits>
@@ -120,11 +122,15 @@ namespace lws { namespace rpc { namespace scanner
for (;;) // multiple commands
{
// indefinite read timeout (waiting for next command)
BOOST_ASIO_CORO_YIELD boost::asio::async_read(self_->sock_, self_->read_buffer(sizeof(self_->next_)), self_->strand_.wrap(*this));
BOOST_ASIO_CORO_YIELD boost::asio::async_read(
self_->sock_, self_->read_buffer(sizeof(self_->next_)), boost::asio::bind_executor(self_->strand_, *this)
);
std::memcpy(std::addressof(self_->next_), self_->read_buf_.data(), sizeof(self_->next_));
static_assert(std::numeric_limits<header::length_type::value_type>::max() <= std::numeric_limits<std::size_t>::max());
BOOST_ASIO_CORO_YIELD boost::asio::async_read(self_->sock_, self_->read_buffer(self_->next_.length.value()), self_->strand_.wrap(*this));
BOOST_ASIO_CORO_YIELD boost::asio::async_read(
self_->sock_, self_->read_buffer(self_->next_.length.value()), boost::asio::bind_executor(self_->strand_, *this)
);
const auto& commands = T::commands();
if (commands.size() <= self_->next_.id || !commands[self_->next_.id](self_))
@@ -142,7 +148,7 @@ namespace lws { namespace rpc { namespace scanner
{
if (!self)
return false;
self->strand_.dispatch(do_read_commands{self});
boost::asio::dispatch(self->strand_, do_read_commands{self});
return true;
}
}}} // lws // rpc // scanner

View File

@@ -27,6 +27,7 @@
#include "server.h"
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/lexical_cast.hpp>
@@ -39,7 +40,6 @@
#include "common/expect.h" // monero/src/
#include "error.h"
#include "misc_log_ex.h" // monero/contrib/epee/include
#include "net/net_utils_base.h" // monero/contrib/epee/include
#include "rpc/scanner/commands.h"
#include "rpc/scanner/connection.h"
#include "rpc/scanner/read_commands.h"
@@ -80,7 +80,7 @@ namespace lws { namespace rpc { namespace scanner
std::size_t threads_; //!< Number of scan threads at remote process
public:
explicit server_connection(std::shared_ptr<server> parent, boost::asio::io_service& io)
explicit server_connection(std::shared_ptr<server> parent, boost::asio::io_context& io)
: connection(io),
parent_(std::move(parent)),
threads_(0)
@@ -179,8 +179,10 @@ namespace lws { namespace rpc { namespace scanner
{
for (;;)
{
next_ = std::make_shared<server_connection>(self_, GET_IO_SERVICE(self_->check_timer_));
BOOST_ASIO_CORO_YIELD self_->acceptor_.async_accept(next_->sock_, self_->strand_.wrap(*this));
next_ = std::make_shared<server_connection>(self_, self_->strand_.context());
BOOST_ASIO_CORO_YIELD self_->acceptor_.async_accept(
next_->sock_, boost::asio::bind_executor(self_->strand_, *this)
);
MINFO("New connection to " << next_->remote_endpoint() << " / " << next_.get());
@@ -202,7 +204,7 @@ namespace lws { namespace rpc { namespace scanner
assert(self_->strand_.running_in_this_thread());
self_->check_timer_.expires_from_now(account_poll_interval);
self_->check_timer_.async_wait(self_->strand_.wrap(*this));
self_->check_timer_.async_wait(boost::asio::bind_executor(self_->strand_, *this));
std::size_t total_threads = self_->local_.size();
std::vector<std::shared_ptr<server_connection>> remotes{};
@@ -456,7 +458,7 @@ namespace lws { namespace rpc { namespace scanner
};
}
server::server(boost::asio::io_service& io, db::storage disk, rpc::client zclient, std::vector<std::shared_ptr<queue>> local, std::vector<db::account_id> active, ssl_verification_t webhook_verify)
server::server(boost::asio::io_context& io, db::storage disk, rpc::client zclient, std::vector<std::shared_ptr<queue>> local, std::vector<db::account_id> active, ssl_verification_t webhook_verify)
: strand_(io),
check_timer_(io),
acceptor_(io),
@@ -517,7 +519,9 @@ namespace lws { namespace rpc { namespace scanner
return;
auto endpoint = get_endpoint(address);
self->strand_.dispatch([self, endpoint = std::move(endpoint), pass = std::move(pass)] ()
boost::asio::dispatch(
self->strand_,
[self, endpoint = std::move(endpoint), pass = std::move(pass)] ()
{
self->acceptor_.close();
self->acceptor_.open(endpoint.protocol());
@@ -531,21 +535,22 @@ namespace lws { namespace rpc { namespace scanner
self->compute_hash(self->pass_hashed_, pass);
acceptor{std::move(self)}();
});
}
);
}
void server::start_user_checking(const std::shared_ptr<server>& self)
{
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch(check_users{self});
boost::asio::dispatch(self->strand_, check_users{self});
}
void server::replace_users(const std::shared_ptr<server>& self)
{
if (!self)
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
self->strand_.dispatch([self] () { self->do_replace_users(); });
boost::asio::dispatch(self->strand_, [self] () { self->do_replace_users(); });
}
void server::store(const std::shared_ptr<server>& self, std::vector<lws::account> users, std::vector<crypto::hash> blocks)
@@ -554,7 +559,9 @@ namespace lws { namespace rpc { namespace scanner
MONERO_THROW(common_error::kInvalidArgument, "nullptr self");
std::sort(users.begin(), users.end(), by_height{});
self->strand_.dispatch([self, users = std::move(users), blocks = std::move(blocks)] ()
boost::asio::dispatch(
self->strand_,
[self, users = std::move(users), blocks = std::move(blocks)] ()
{
const lws::scanner_options opts{self->webhook_verify_, false, false};
if (!lws::user_data::store(self->disk_, self->zclient_, epee::to_span(blocks), epee::to_span(users), nullptr, opts))

View File

@@ -27,7 +27,7 @@
#pragma once
#include <array>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/steady_timer.hpp>
@@ -57,7 +57,7 @@ namespace lws { namespace rpc { namespace scanner
needed (basically a REST server on either end). */
class server
{
boost::asio::io_service::strand strand_;
boost::asio::io_context::strand strand_;
boost::asio::steady_timer check_timer_;
boost::asio::ip::tcp::acceptor acceptor_;
std::set<std::weak_ptr<server_connection>, std::owner_less<std::weak_ptr<server_connection>>> remote_;
@@ -85,7 +85,7 @@ namespace lws { namespace rpc { namespace scanner
public:
static boost::asio::ip::tcp::endpoint get_endpoint(const std::string& address);
explicit server(boost::asio::io_service& io, db::storage disk, rpc::client zclient, std::vector<std::shared_ptr<queue>> local, std::vector<db::account_id> active, ssl_verification_t webhook_verify);
explicit server(boost::asio::io_context& io, db::storage disk, rpc::client zclient, std::vector<std::shared_ptr<queue>> local, std::vector<db::account_id> active, ssl_verification_t webhook_verify);
server(const server&) = delete;
server(server&&) = delete;

View File

@@ -26,6 +26,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/write.hpp>
@@ -118,8 +119,10 @@ namespace lws { namespace rpc { namespace scanner
while (!self_->write_bufs_.empty())
{
self_->write_timeout_.expires_from_now(std::chrono::seconds{10});
self_->write_timeout_.async_wait(self_->strand_.wrap(timeout<T>{self_}));
BOOST_ASIO_CORO_YIELD boost::asio::async_write(self_->sock_, self_->write_buffer(), self_->strand_.wrap(*this));
self_->write_timeout_.async_wait(boost::asio::bind_executor(self_->strand_, timeout<T>{self_}));
BOOST_ASIO_CORO_YIELD boost::asio::async_write(
self_->sock_, self_->write_buffer(), boost::asio::bind_executor(self_->strand_, *this)
);
self_->write_timeout_.cancel();
self_->write_bufs_.pop_front();
}
@@ -205,6 +208,6 @@ namespace lws { namespace rpc { namespace scanner
}
};
self->strand_.dispatch(queue_slice{self, std::move(msg)});
boost::asio::dispatch(self->strand_, queue_slice{self, std::move(msg)});
}
}}} // lws // rpc // scanner