Commit 546bb80c authored by Dominik Charousset's avatar Dominik Charousset

Track requests and delegated messages

parent 2239586b
......@@ -403,20 +403,8 @@ public:
detail::implicit_conversions_t<
typename std::decay<Ts>::type>...>::delegated_type
delegate(const Handle& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "nothing to delegate");
using token = detail::type_list<typename detail::implicit_conversions<
typename std::decay<Ts>::type>::type...>;
static_assert(response_type_unbox<signatures_of_t<Handle>, token>::valid,
"receiver does not accept given message");
auto mid = current_element_->mid;
current_element_->mid = P == message_priority::high
? mid.with_high_priority()
: mid.with_normal_priority();
dest->enqueue(make_mailbox_element(std::move(current_element_->sender), mid,
std::move(current_element_->stages),
std::forward<Ts>(xs)...),
context());
return {};
auto rp = make_response_promise();
return rp.template delegate<P>(dest, std::forward<Ts>(xs)...);
}
virtual void initialize();
......
......@@ -21,15 +21,16 @@
#include <tuple>
#include <chrono>
#include "caf/fwd.hpp"
#include "caf/actor.hpp"
#include "caf/message.hpp"
#include "caf/check_typed_input.hpp"
#include "caf/detail/profiled_send.hpp"
#include "caf/duration.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
#include "caf/message_id.hpp"
#include "caf/response_type.hpp"
#include "caf/response_handle.hpp"
#include "caf/message_priority.hpp"
#include "caf/check_typed_input.hpp"
#include "caf/response_handle.hpp"
#include "caf/response_type.hpp"
namespace caf {
namespace mixin {
......@@ -77,17 +78,17 @@ public:
>::type...>;
static_assert(response_type_unbox<signatures_of_t<Handle>, token>::valid,
"receiver does not accept given message");
auto dptr = static_cast<Subtype*>(this);
auto req_id = dptr->new_request_id(P);
auto self = static_cast<Subtype*>(this);
auto req_id = self->new_request_id(P);
if (dest) {
dest->eq_impl(req_id, dptr->ctrl(), dptr->context(),
std::forward<Ts>(xs)...);
dptr->request_response_timeout(timeout, req_id);
detail::profiled_send(self, self->ctrl(), dest, req_id, {},
self->context(), std::forward<Ts>(xs)...);
self->request_response_timeout(timeout, req_id);
} else {
dptr->eq_impl(req_id.response_id(), dptr->ctrl(), dptr->context(),
self->eq_impl(req_id.response_id(), self->ctrl(), self->context(),
make_error(sec::invalid_argument));
}
return {req_id.response_id(), dptr};
return {req_id.response_id(), self};
}
/// Sends `{xs...}` as a synchronous message to `dest` with priority `mp`.
......
......@@ -21,11 +21,12 @@
#include <vector>
#include "caf/actor.hpp"
#include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_cast.hpp"
#include "caf/check_typed_input.hpp"
#include "caf/message.hpp"
#include "caf/message_id.hpp"
#include "caf/response_type.hpp"
#include "caf/check_typed_input.hpp"
namespace caf {
......@@ -63,8 +64,8 @@ public:
"it is not possible to deliver objects of type result<T>");
static_assert(!detail::tl_exists<ts, detail::is_expected>::value,
"mixing expected<T> with regular values is not supported");
return deliver_impl(make_message(std::forward<T>(x),
std::forward<Ts>(xs)...));
return deliver_impl(
make_message(std::forward<T>(x), std::forward<Ts>(xs)...));
}
template <class T>
......@@ -75,28 +76,22 @@ public:
}
/// Satisfies the promise by delegating to another actor.
template <message_priority P = message_priority::normal,
class Handle = actor, class... Ts>
typename response_type<
typename Handle::signatures,
detail::implicit_conversions_t<typename std::decay<Ts>::type>...
>::delegated_type
template <message_priority P = message_priority::normal, class Handle = actor,
class... Ts>
typename response_type<typename Handle::signatures,
detail::implicit_conversions_t<
typename std::decay<Ts>::type>...>::delegated_type
delegate(const Handle& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "nothing to delegate");
using token =
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
using token = detail::type_list<typename detail::implicit_conversions<
typename std::decay<Ts>::type>::type...>;
static_assert(response_type_unbox<signatures_of_t<Handle>, token>::valid,
"receiver does not accept given message");
if (dest) {
auto mid = P == message_priority::high ? id_.with_high_priority() : id_;
dest->enqueue(make_mailbox_element(std::move(source_), mid,
std::move(stages_),
std::forward<Ts>(xs)...),
context());
}
// TODO: use `if constexpr` when switching to C++17
if (P == message_priority::high)
id_ = id_.with_high_priority();
delegate_impl(actor_cast<abstract_actor*>(dest),
make_message(std::forward<Ts>(xs)...));
return {};
}
......@@ -143,6 +138,8 @@ private:
void deliver_impl(message msg);
void delegate_impl(abstract_actor* receiver, message msg);
strong_actor_ptr self_;
strong_actor_ptr source_;
forwarding_stack stages_;
......
......@@ -108,4 +108,20 @@ void response_promise::deliver_impl(message msg) {
CAF_LOG_WARNING("malformed response promise: self != nullptr && !pending()");
}
void response_promise::delegate_impl(abstract_actor* receiver, message msg) {
CAF_LOG_TRACE(CAF_ARG(msg));
if (receiver == nullptr) {
CAF_LOG_DEBUG("drop response: invalid delegation target");
return;
}
if (self_ == nullptr) {
CAF_LOG_DEBUG("drop response: invalid promise");
return;
}
auto self = self_ptr();
detail::profiled_send(self, std::move(source_), receiver, id_,
std::move(stages_), self->context(), std::move(msg));
self_.reset();
}
} // namespace caf
......@@ -110,19 +110,22 @@ struct fixture {
scheduler_type& sched;
};
struct foo_state {
const char* name = "foo";
};
# define NAMED_ACTOR_STATE(type) \
struct type##_state { \
const char* name = #type; \
}
struct bar_state {
const char* name = "bar";
};
NAMED_ACTOR_STATE(bar);
NAMED_ACTOR_STATE(client);
NAMED_ACTOR_STATE(foo);
NAMED_ACTOR_STATE(server);
NAMED_ACTOR_STATE(worker);
} // namespace
CAF_TEST_FIXTURE_SCOPE(actor_profiler_tests, fixture)
CAF_TEST(record actor construction) {
CAF_TEST(profilers record actor construction) {
CAF_MESSAGE("fully initialize CAF, ignore system-internal actors");
run();
rec.log.clear();
......@@ -141,7 +144,7 @@ CAF_TEST(record actor construction) {
rec.log);
}
CAF_TEST(record actor messaging) {
CAF_TEST(profilers record asynchronous messaging) {
CAF_MESSAGE("fully initialize CAF, ignore system-internal actors");
run();
rec.log.clear();
......@@ -178,6 +181,51 @@ CAF_TEST(record actor messaging) {
rec.log);
}
CAF_TEST(profilers record request / response messaging) {
CAF_MESSAGE("fully initialize CAF, ignore system-internal actors");
run();
rec.log.clear();
CAF_MESSAGE("spawn a client and a server with one worker");
auto worker = [](stateful_actor<worker_state>*) -> behavior {
return {
[](int x, int y) { return x + y; },
};
};
auto server = [](stateful_actor<server_state>* self, actor work) -> behavior {
return {
[=](int x, int y) { return self->delegate(work, x, y); },
};
};
auto client = [](stateful_actor<client_state>* self, actor serv) {
self->request(serv, infinite, 19, 23).then([](int result) {
CAF_CHECK_EQUAL(result, 42);
});
};
sys.spawn(client, sys.spawn(server, sys.spawn(worker)));
run();
for (const auto& line : rec.log) {
CAF_MESSAGE(line);
}
CAF_CHECK_EQUAL(string_list({
"new: worker",
"new: server",
"new: client",
"client sends: (19, 23)",
"server got: (19, 23)",
"server sends: (19, 23)",
"server consumed the message",
"delete: server",
"worker got: (19, 23)",
"worker sends: (42)",
"worker consumed the message",
"client got: (42)",
"client consumed the message",
"delete: worker",
"delete: client",
}),
rec.log);
}
CAF_TEST_FIXTURE_SCOPE_END()
#endif // CAF_ENABLE_ACTOR_PROFILER
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment