mirror of
https://github.com/boostorg/mysql.git
synced 2025-05-12 14:11:41 +00:00
Connections now support immediate executors
Immediate completions in connection and any_connection are now correctly dispatched to the token's immediate executor using asio::async_immediate instead of plain asio::post. Added a section on executors in the reference docs of async functions in connection and any_connection Disabled TSAN connection_pool_cancel_get_connection for libc++ builds close #301
This commit is contained in:
parent
7ef6ff8773
commit
268aa33a84
@ -389,6 +389,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
@ -751,6 +761,16 @@ public:
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code, std::size_t)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*
|
||||
* \par Object lifetimes
|
||||
* The storage that `output` references must be kept alive until the operation completes.
|
||||
*/
|
||||
@ -799,6 +819,16 @@ public:
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code, std::size_t)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*
|
||||
* \par Object lifetimes
|
||||
* The storage that `output` references must be kept alive until the operation completes.
|
||||
*/
|
||||
@ -903,6 +933,16 @@ public:
|
||||
* \n
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
@ -1017,6 +1057,16 @@ public:
|
||||
* \n
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
@ -1076,6 +1126,16 @@ public:
|
||||
* \details
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
@ -1143,6 +1203,16 @@ public:
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*
|
||||
* \par Object lifetimes
|
||||
* The request and response objects must be kept alive and should not be modified
|
||||
* until the operation completes.
|
||||
|
@ -247,6 +247,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
typename EndpointType,
|
||||
@ -322,6 +332,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -393,6 +413,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
@ -495,6 +525,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,
|
||||
@ -576,6 +616,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code, boost::mysql::statement)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -633,6 +683,16 @@ public:
|
||||
*
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -693,6 +753,16 @@ public:
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code, boost::mysql::rows_view)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -828,6 +898,16 @@ public:
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code, std::size_t)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*
|
||||
* \par Object lifetimes
|
||||
* The storage that `output` references must be kept alive until the operation completes.
|
||||
*/
|
||||
@ -878,6 +958,16 @@ public:
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code, std::size_t)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*
|
||||
* \par Object lifetimes
|
||||
* The storage that `output` references must be kept alive until the operation completes.
|
||||
*/
|
||||
@ -943,6 +1033,16 @@ public:
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is
|
||||
* `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <
|
||||
BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,
|
||||
@ -999,6 +1099,16 @@ public:
|
||||
* \n
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -1071,6 +1181,16 @@ public:
|
||||
* \n
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -1128,6 +1248,16 @@ public:
|
||||
* \details
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
@ -1186,6 +1316,16 @@ public:
|
||||
* \details
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*
|
||||
* \par Executor
|
||||
* Intermediate completion handlers, as well as the final handler, are executed using
|
||||
* `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated
|
||||
* executor.
|
||||
*
|
||||
* If the final handler has an associated immediate executor, and the operation
|
||||
* completes immediately, the final handler is dispatched to it.
|
||||
* Otherwise, the final handler is called as if it was submitted using `asio::post`,
|
||||
* and is never be called inline from within this function.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/compose.hpp>
|
||||
#include <boost/asio/immediate.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@ -66,7 +67,7 @@ struct run_algo_op
|
||||
BOOST_MYSQL_YIELD(
|
||||
resume_point_,
|
||||
1,
|
||||
asio::post(stream_.get_executor(), std::move(self))
|
||||
asio::async_immediate(stream_.get_executor(), std::move(self))
|
||||
)
|
||||
}
|
||||
self.complete(stored_ec_);
|
||||
|
@ -53,6 +53,11 @@ struct BOOST_ATTRIBUTE_NODISCARD network_result_base
|
||||
{
|
||||
error_code err;
|
||||
diagnostics diag;
|
||||
bool was_immediate{};
|
||||
|
||||
network_result_base(error_code ec = {}, diagnostics d = {}) noexcept : err(ec), diag(std::move(d)) {}
|
||||
|
||||
void validate_immediate(bool expect_immediate, source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;
|
||||
|
||||
void validate_no_error(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;
|
||||
|
||||
@ -100,6 +105,16 @@ struct BOOST_ATTRIBUTE_NODISCARD network_result : network_result_base
|
||||
{
|
||||
}
|
||||
|
||||
// Allow chaining
|
||||
network_result<R>& validate_immediate(
|
||||
bool expect_immediate,
|
||||
source_location loc = BOOST_MYSQL_CURRENT_LOCATION
|
||||
)
|
||||
{
|
||||
network_result_base::validate_immediate(expect_immediate, loc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_ATTRIBUTE_NODISCARD
|
||||
value_type get(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&
|
||||
{
|
||||
@ -127,6 +142,7 @@ struct BOOST_ATTRIBUTE_NODISCARD runnable_network_result
|
||||
create_server_diag("network_result_v2 - diagnostics not cleared")
|
||||
};
|
||||
bool done{false};
|
||||
bool was_immediate{false};
|
||||
|
||||
impl_t(asio::io_context& ctx) : ctx(ctx) {}
|
||||
};
|
||||
|
@ -28,6 +28,13 @@ void poll_until(
|
||||
source_location loc = BOOST_MYSQL_CURRENT_LOCATION
|
||||
);
|
||||
|
||||
// run fn() in ctx, then poll until it completes
|
||||
void run_in_context(
|
||||
asio::io_context& ctx,
|
||||
const std::function<void()>& fn,
|
||||
source_location loc = BOOST_MYSQL_CURRENT_LOCATION
|
||||
);
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <boost/mysql/detail/access.hpp>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/execution/blocking.hpp>
|
||||
#include <boost/asio/execution/relationship.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
@ -414,6 +416,20 @@ void boost::mysql::test::poll_until(
|
||||
}
|
||||
}
|
||||
|
||||
void boost::mysql::test::run_in_context(
|
||||
asio::io_context& ctx,
|
||||
const std::function<void()>& fn,
|
||||
source_location loc
|
||||
)
|
||||
{
|
||||
bool finished = false;
|
||||
asio::dispatch(asio::bind_executor(ctx.get_executor(), [fn, &finished]() {
|
||||
fn();
|
||||
finished = true;
|
||||
}));
|
||||
poll_until(ctx, &finished, loc);
|
||||
}
|
||||
|
||||
//
|
||||
// io_context_fixture.hpp
|
||||
//
|
||||
@ -427,6 +443,13 @@ boost::mysql::test::io_context_fixture::~io_context_fixture()
|
||||
//
|
||||
// network_result.hpp
|
||||
//
|
||||
|
||||
void boost::mysql::test::network_result_base::validate_immediate(bool expect_immediate, source_location loc)
|
||||
const
|
||||
{
|
||||
BOOST_TEST_CONTEXT("Called from " << loc) { BOOST_TEST(was_immediate == expect_immediate); }
|
||||
}
|
||||
|
||||
void boost::mysql::test::network_result_base::validate_no_error(source_location loc) const
|
||||
{
|
||||
validate_error(error_code(), diagnostics(), loc);
|
||||
@ -503,6 +526,9 @@ void boost::mysql::test::test_detail::as_netres_handler_base::complete_base(
|
||||
network_result_base& netres
|
||||
) const
|
||||
{
|
||||
// Are we in an immediate completion?
|
||||
bool is_immediate = is_initiation_function();
|
||||
|
||||
// Check executor. The passed executor must be the top one in all cases.
|
||||
// Immediate completions must be dispatched through the immediate executor, too.
|
||||
// In all cases, we may encounter a bigger stack because of previous immediate completions.
|
||||
@ -512,9 +538,8 @@ void boost::mysql::test::test_detail::as_netres_handler_base::complete_base(
|
||||
};
|
||||
|
||||
// Expected top of the executor stack
|
||||
boost::span<const int> expected_stack_top = is_initiation_function()
|
||||
? boost::span<const int>(stack_data_immediate)
|
||||
: boost::span<const int>(stack_data_regular);
|
||||
boost::span<const int> expected_stack_top = is_immediate ? boost::span<const int>(stack_data_immediate)
|
||||
: boost::span<const int>(stack_data_regular);
|
||||
|
||||
// Actual top of the executor stack
|
||||
auto actual_stack_top = executor_stack().last(
|
||||
@ -530,4 +555,7 @@ void boost::mysql::test::test_detail::as_netres_handler_base::complete_base(
|
||||
netres.diag = *diag_ptr;
|
||||
else
|
||||
netres.diag = create_server_diag("<diagnostics unavailable>");
|
||||
|
||||
// Record immediate-ness
|
||||
netres.was_immediate = is_immediate;
|
||||
}
|
@ -35,8 +35,8 @@
|
||||
#include "test_common/create_basic.hpp"
|
||||
#include "test_common/create_diagnostics.hpp"
|
||||
#include "test_common/network_result.hpp"
|
||||
#include "test_common/poll_until.hpp"
|
||||
#include "test_common/printing.hpp"
|
||||
#include "test_common/tracker_executor.hpp"
|
||||
#include "test_integration/any_connection_fixture.hpp"
|
||||
#include "test_integration/connect_params_builder.hpp"
|
||||
#include "test_integration/run_coro.hpp"
|
||||
@ -317,6 +317,25 @@ BOOST_FIXTURE_TEST_CASE(default_token_cancel_after, any_connection_fixture)
|
||||
});
|
||||
}
|
||||
|
||||
// Spotcheck: immediate completions dispatched to the immediate executor
|
||||
BOOST_FIXTURE_TEST_CASE(immediate_completions, any_connection_fixture)
|
||||
{
|
||||
run_in_context(ctx, [this]() {
|
||||
// Setup
|
||||
connect();
|
||||
results r;
|
||||
|
||||
// Prepare a statement
|
||||
auto stmt = conn.async_prepare_statement("SELECT 1", as_netresult).get();
|
||||
|
||||
// Executing with the wrong number of params is an immediate error
|
||||
conn.async_execute(stmt.bind(0), r, as_netresult)
|
||||
.run()
|
||||
.validate_immediate(true)
|
||||
.validate_error(client_errc::wrong_num_params);
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -24,6 +24,12 @@ local tests =
|
||||
|
||||
for test in $(tests)
|
||||
{
|
||||
# TSAN seems to raise a false positive with libc++ shared_ptr/weak_ptr, used in this test
|
||||
local libcpp_exclusion ;
|
||||
if $(test) = "connection_pool_cancel_get_connection" {
|
||||
libcpp_exclusion = <stdlib>libc++:<build>no ;
|
||||
}
|
||||
|
||||
# In OSX, tsan reports a race condition in Asio's kqueue reactor. Ignore this for now.
|
||||
# Net TS executors use std::atomic_thread_fence, unsupported by TSAN, which yields false positives.
|
||||
# gcc-5 seems to emit incorrect tsan instrumentation code for static initializations
|
||||
@ -36,6 +42,7 @@ for test in $(tests)
|
||||
<target-os>darwin:<build>no
|
||||
<boost.mysql.use-ts-executor>on:<build>no
|
||||
<toolset>gcc-5:<build>no
|
||||
$(libcpp_exclusion)
|
||||
<thread-sanitizer>norecover
|
||||
: target-name $(test)
|
||||
;
|
||||
|
@ -16,9 +16,11 @@
|
||||
#include <boost/asio/any_completion_handler.hpp>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/deferred.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@ -32,6 +34,7 @@
|
||||
#include "test_common/io_context_fixture.hpp"
|
||||
#include "test_common/netfun_maker.hpp"
|
||||
#include "test_common/network_result.hpp"
|
||||
#include "test_common/poll_until.hpp"
|
||||
#include "test_unit/printing.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
@ -417,18 +420,15 @@ BOOST_AUTO_TEST_CASE(stream_errors)
|
||||
}
|
||||
|
||||
// Returning an error or next_action() from resume in the first call works correctly
|
||||
BOOST_AUTO_TEST_CASE(resume_error_immediate)
|
||||
BOOST_AUTO_TEST_CASE(resume_error_immediate_sync)
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
signature_t fn;
|
||||
error_code ec;
|
||||
} test_cases[] = {
|
||||
{"success_sync", sync_fn, error_code() },
|
||||
{"success_async", async_fn, error_code() },
|
||||
{"error_sync", sync_fn, asio::error::no_data},
|
||||
{"error_async", async_fn, asio::error::no_data},
|
||||
{"success", error_code() },
|
||||
{"error", asio::error::no_data},
|
||||
};
|
||||
|
||||
for (const auto& tc : test_cases)
|
||||
@ -440,13 +440,51 @@ BOOST_AUTO_TEST_CASE(resume_error_immediate)
|
||||
mock_algo algo(next_action(tc.ec));
|
||||
test_engine eng{fix.ctx.get_executor()};
|
||||
|
||||
tc.fn(eng, any_resumable_ref(algo))
|
||||
sync_fn(eng, any_resumable_ref(algo))
|
||||
.validate_error(tc.ec, create_server_diag("<diagnostics unavailable>"));
|
||||
BOOST_TEST(eng.value.stream().calls.size() == 0u);
|
||||
algo.check_calls({
|
||||
{error_code(), 0u}
|
||||
});
|
||||
// Note: the testing infrastructure already checks that we post correctly in the async versions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(resume_error_immediate_async)
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
error_code ec;
|
||||
} test_cases[] = {
|
||||
{"success", error_code() },
|
||||
{"error", asio::error::no_data},
|
||||
};
|
||||
|
||||
for (const auto& tc : test_cases)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(tc.name)
|
||||
{
|
||||
// We need to call the initiation function from a context thread
|
||||
// to get immediate completions
|
||||
io_context_fixture fix;
|
||||
run_in_context(fix.ctx, [&]() {
|
||||
// Setup
|
||||
mock_algo algo(next_action(tc.ec));
|
||||
test_engine eng{fix.ctx.get_executor()};
|
||||
|
||||
// Run the function
|
||||
eng.async_run(any_resumable_ref(algo), as_netresult)
|
||||
.run()
|
||||
.validate_immediate(true)
|
||||
.validate_error(tc.ec, create_server_diag("<diagnostics unavailable>"));
|
||||
|
||||
// Check
|
||||
BOOST_TEST(eng.value.stream().calls.size() == 0u);
|
||||
algo.check_calls({
|
||||
{error_code(), 0u}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user