Commit 681e3f04 authored by Dominik Charousset's avatar Dominik Charousset

Tweak new BASP features to be downward compatible

parent 86df0d19
No preview for this file type
doc/basp_header.png

39.3 KB | W: | H:

doc/basp_header.png

76.8 KB | W: | H:

doc/basp_header.png
doc/basp_header.png
doc/basp_header.png
doc/basp_header.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -51,7 +51,7 @@ template <class Result, ...@@ -51,7 +51,7 @@ template <class Result,
local_actor, local_actor,
typename std::remove_pointer<FirstArg>::type typename std::remove_pointer<FirstArg>::type
>::value> >::value>
struct infer_handle_from_fun_ { struct infer_handle_from_fun_impl {
using type = actor; using type = actor;
using impl = event_based_actor; using impl = event_based_actor;
using behavior_type = behavior; using behavior_type = behavior;
...@@ -60,7 +60,7 @@ struct infer_handle_from_fun_ { ...@@ -60,7 +60,7 @@ struct infer_handle_from_fun_ {
// dynamically typed actor returning a behavior // dynamically typed actor returning a behavior
template <class Impl> template <class Impl>
struct infer_handle_from_fun_<void, Impl*, true> { struct infer_handle_from_fun_impl<void, Impl*, true> {
using type = actor; using type = actor;
using impl = Impl; using impl = Impl;
using behavior_type = behavior; using behavior_type = behavior;
...@@ -69,7 +69,7 @@ struct infer_handle_from_fun_<void, Impl*, true> { ...@@ -69,7 +69,7 @@ struct infer_handle_from_fun_<void, Impl*, true> {
// dynamically typed actor with self pointer // dynamically typed actor with self pointer
template <class Impl> template <class Impl>
struct infer_handle_from_fun_<behavior, Impl*, true> { struct infer_handle_from_fun_impl<behavior, Impl*, true> {
using type = actor; using type = actor;
using impl = Impl; using impl = Impl;
using behavior_type = behavior; using behavior_type = behavior;
...@@ -78,7 +78,7 @@ struct infer_handle_from_fun_<behavior, Impl*, true> { ...@@ -78,7 +78,7 @@ struct infer_handle_from_fun_<behavior, Impl*, true> {
// statically typed actor returning a behavior // statically typed actor returning a behavior
template <class... Sigs, class FirstArg> template <class... Sigs, class FirstArg>
struct infer_handle_from_fun_<typed_behavior<Sigs...>, FirstArg, false> { struct infer_handle_from_fun_impl<typed_behavior<Sigs...>, FirstArg, false> {
using type = typed_actor<Sigs...>; using type = typed_actor<Sigs...>;
using impl = typed_event_based_actor<Sigs...>; using impl = typed_event_based_actor<Sigs...>;
using behavior_type = typed_behavior<Sigs...>; using behavior_type = typed_behavior<Sigs...>;
...@@ -87,7 +87,7 @@ struct infer_handle_from_fun_<typed_behavior<Sigs...>, FirstArg, false> { ...@@ -87,7 +87,7 @@ struct infer_handle_from_fun_<typed_behavior<Sigs...>, FirstArg, false> {
// statically typed actor with self pointer // statically typed actor with self pointer
template <class Result, class... Sigs> template <class Result, class... Sigs>
struct infer_handle_from_fun_<Result, typed_event_based_actor<Sigs...>*, true> { struct infer_handle_from_fun_impl<Result, typed_event_based_actor<Sigs...>*, true> {
using type = typed_actor<Sigs...>; using type = typed_actor<Sigs...>;
using impl = typed_event_based_actor<Sigs...>; using impl = typed_event_based_actor<Sigs...>;
using behavior_type = typed_behavior<Sigs...>; using behavior_type = typed_behavior<Sigs...>;
...@@ -99,7 +99,7 @@ struct infer_handle_from_fun { ...@@ -99,7 +99,7 @@ struct infer_handle_from_fun {
using result_type = typename Trait::result_type; using result_type = typename Trait::result_type;
using arg_types = typename Trait::arg_types; using arg_types = typename Trait::arg_types;
using first_arg = typename detail::tl_head<arg_types>::type; using first_arg = typename detail::tl_head<arg_types>::type;
using delegate = infer_handle_from_fun_<result_type, first_arg>; using delegate = infer_handle_from_fun_impl<result_type, first_arg>;
using type = typename delegate::type; using type = typename delegate::type;
using impl = typename delegate::impl; using impl = typename delegate::impl;
using behavior_type = typename delegate::behavior_type; using behavior_type = typename delegate::behavior_type;
......
...@@ -222,7 +222,7 @@ struct infer_typed_actor_base<Result, T*, true> { ...@@ -222,7 +222,7 @@ struct infer_typed_actor_base<Result, T*, true> {
/// constructor arguments. /// constructor arguments.
template <class C, spawn_options Os = no_spawn_options, class... Ts> template <class C, spawn_options Os = no_spawn_options, class... Ts>
typename actor_handle_from_signature_list<typename C::signatures>::type typename actor_handle_from_signature_list<typename C::signatures>::type
spawn_typed(Ts&&... xs) { CAF_DEPRECATED spawn_typed(Ts&&... xs) {
return spawn_class<C, Os>(nullptr, empty_before_launch_callback{}, return spawn_class<C, Os>(nullptr, empty_before_launch_callback{},
std::forward<Ts>(xs)...); std::forward<Ts>(xs)...);
} }
......
...@@ -187,6 +187,7 @@ void actor_registry::initialize() { ...@@ -187,6 +187,7 @@ void actor_registry::initialize() {
using topic_set = std::unordered_set<std::string>; using topic_set = std::unordered_set<std::string>;
std::unordered_map<key_type, std::pair<mapped_type, subscriber_set>> data; std::unordered_map<key_type, std::pair<mapped_type, subscriber_set>> data;
std::unordered_map<actor,topic_set> subscribers; std::unordered_map<actor,topic_set> subscribers;
const char* name = "caf.config_server";
}; };
auto kvstore = [](stateful_actor<kvstate>* self) -> behavior { auto kvstore = [](stateful_actor<kvstate>* self) -> behavior {
return { return {
......
...@@ -265,6 +265,23 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) { ...@@ -265,6 +265,23 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) {
ok_atom::value, self->address()), ok_atom::value, self->address()),
self->host()); self->host());
}, },
[&](sys_atom, get_atom, std::string& what) {
CAF_LOGF_TRACE(CAF_ARG(what));
if (what == "info") {
CAF_LOGF_DEBUG("reply to 'info' message");
node.sender->enqueue(
mailbox_element::make_joint(self->address(), node.mid.response_id(),
ok_atom::value, std::move(what),
self->address(), self->name()),
self->host());
return;
}
node.sender->enqueue(
mailbox_element::make_joint(self->address(), node.mid.response_id(),
error_atom::value,
"unknown key: " + std::move(what)),
self->host());
},
others >> [&] { others >> [&] {
mismatch = true; mismatch = true;
} }
......
...@@ -165,7 +165,7 @@ namespace basp { ...@@ -165,7 +165,7 @@ namespace basp {
/// The current BASP version. Different BASP versions will not /// The current BASP version. Different BASP versions will not
/// be able to exchange messages. /// be able to exchange messages.
constexpr uint64_t version = 2; constexpr uint64_t version = 1;
/// Storage type for raw bytes. /// Storage type for raw bytes.
using buffer_type = std::vector<char>; using buffer_type = std::vector<char>;
...@@ -203,13 +203,7 @@ enum class message_type : uint32_t { ...@@ -203,13 +203,7 @@ enum class message_type : uint32_t {
/// that has been terminated. /// that has been terminated.
/// ///
/// ![](kill_proxy_instance.png) /// ![](kill_proxy_instance.png)
kill_proxy_instance = 0x04, kill_proxy_instance = 0x04
/// Looks up a particular named actor in the registry
/// of the receiving node, which replies with a `dispatch_message`.
///
/// ![](name_lookup.png)
name_lookup = 0x05
}; };
/// @relates message_type /// @relates message_type
...@@ -337,8 +331,9 @@ public: ...@@ -337,8 +331,9 @@ public:
/// including the node that is assigned as direct path for `hdl`. /// including the node that is assigned as direct path for `hdl`.
void erase_direct(const connection_handle& hdl, erase_callback& cb); void erase_direct(const connection_handle& hdl, erase_callback& cb);
/// Removes any entry for indirect connection to `dest`. /// Removes any entry for indirect connection to `dest` and returns
void erase_indirect(const node_id& dest); /// `true` if `dest` had an indirect route, otherwise `false`.
bool erase_indirect(const node_id& dest);
/// Queries whether `dest` is reachable. /// Queries whether `dest` is reachable.
bool reachable(const node_id& dest); bool reachable(const node_id& dest);
...@@ -406,6 +401,11 @@ public: ...@@ -406,6 +401,11 @@ public:
const node_id& dest_node, actor_id dest_actor, const node_id& dest_node, actor_id dest_actor,
message& msg, message_id mid) = 0; message& msg, message_id mid) = 0;
/// Called whenever BASP learns the ID of a remote node
/// to which it does not have a direct connection.
virtual void learned_new_node_directly(const node_id& nid,
bool was_known_indirectly) = 0;
/// Called whenever BASP learns the ID of a remote node /// Called whenever BASP learns the ID of a remote node
/// to which it does not have a direct connection. /// to which it does not have a direct connection.
virtual void learned_new_node_indirectly(const node_id& nid) = 0; virtual void learned_new_node_indirectly(const node_id& nid) = 0;
...@@ -514,7 +514,7 @@ public: ...@@ -514,7 +514,7 @@ public:
void write_server_handshake(buffer_type& buf, optional<uint16_t> port); void write_server_handshake(buffer_type& buf, optional<uint16_t> port);
/// Writes the client handshake to `buf`. /// Writes the client handshake to `buf`.
void write_client_handshake(buffer_type& buf); void write_client_handshake(buffer_type& buf, const node_id& remote_side);
/// Writes a `dispatch_error` to `buf`. /// Writes a `dispatch_error` to `buf`.
void write_dispatch_error(buffer_type& buf, void write_dispatch_error(buffer_type& buf,
...@@ -530,32 +530,15 @@ public: ...@@ -530,32 +530,15 @@ public:
actor_id aid, actor_id aid,
uint32_t rsn); uint32_t rsn);
/// Writes a name lookup request to `buf`.
void write_name_lookup(buffer_type& buf,
atom_value requested_name,
const node_id& dest_node,
actor_id source_actor);
const node_id& this_node() const { const node_id& this_node() const {
return this_node_; return this_node_;
} }
using named_actors_map = std::unordered_map<atom_value, actor>;
/// Returns the named actors for this node.
named_actors_map named_actors();
/// Returns the named actors for `nid`.
optional<const named_actors_map&> named_actors(const node_id& nid);
private: private:
void read_named_actors(binary_deserializer& source, const node_id& nid);
routing_table tbl_; routing_table tbl_;
published_actor_map published_actors_; published_actor_map published_actors_;
node_id this_node_; node_id this_node_;
callee& callee_; callee& callee_;
std::unordered_map<node_id, named_actors_map> named_actors_;
}; };
/// Checks whether given header contains a handshake. /// Checks whether given header contains a handshake.
......
...@@ -60,10 +60,19 @@ struct basp_broker_state : actor_namespace::backend, basp::instance::callee { ...@@ -60,10 +60,19 @@ struct basp_broker_state : actor_namespace::backend, basp::instance::callee {
// inherited from basp::instance::listener // inherited from basp::instance::listener
void kill_proxy(const node_id& nid, actor_id aid, uint32_t rsn) override; void kill_proxy(const node_id& nid, actor_id aid, uint32_t rsn) override;
// inherited from basp::instance::listener
void deliver(const node_id& source_node, actor_id source_actor, void deliver(const node_id& source_node, actor_id source_actor,
const node_id& dest_node, actor_id dest_actor, const node_id& dest_node, actor_id dest_actor,
message& msg, message_id mid) override; message& msg, message_id mid) override;
// performs bookkeeping such as managing `spawn_servers`
void learned_new_node(const node_id& nid);
// inherited from basp::instance::listener
void learned_new_node_directly(const node_id& nid,
bool was_known_indirectly_before) override;
// inherited from basp::instance::listener
void learned_new_node_indirectly(const node_id& nid) override; void learned_new_node_indirectly(const node_id& nid) override;
struct connection_context { struct connection_context {
...@@ -95,6 +104,11 @@ struct basp_broker_state : actor_namespace::backend, basp::instance::callee { ...@@ -95,6 +104,11 @@ struct basp_broker_state : actor_namespace::backend, basp::instance::callee {
// keeps the associated proxies alive to work around subtle bugs // keeps the associated proxies alive to work around subtle bugs
std::unordered_map<node_id, std::pair<uint16_t, actor_addr>> known_remotes; std::unordered_map<node_id, std::pair<uint16_t, actor_addr>> known_remotes;
// stores handles to spawn servers for other nodes; these servers
// are spawned whenever the broker learns a new node ID and try to
// get a 'SpawnServ' instance on the remote side
std::unordered_map<node_id, actor> spawn_servers;
// can be enabled by the user to let CAF automatically try // can be enabled by the user to let CAF automatically try
// to establish new connections at runtime to optimize // to establish new connections at runtime to optimize
// routing paths by forming a mesh between all nodes // routing paths by forming a mesh between all nodes
......
...@@ -49,8 +49,6 @@ std::string to_string(message_type x) { ...@@ -49,8 +49,6 @@ std::string to_string(message_type x) {
return "announce_proxy_instance"; return "announce_proxy_instance";
case message_type::kill_proxy_instance: case message_type::kill_proxy_instance:
return "kill_proxy_instance"; return "kill_proxy_instance";
case message_type::name_lookup:
return "name_lookup";
default: default:
return "???"; return "???";
} }
...@@ -115,12 +113,21 @@ bool zero(T val) { ...@@ -115,12 +113,21 @@ bool zero(T val) {
bool server_handshake_valid(const header& hdr) { bool server_handshake_valid(const header& hdr) {
return valid(hdr.source_node) return valid(hdr.source_node)
&& ! valid(hdr.dest_node)
&& zero(hdr.dest_actor)
&& ! zero(hdr.operation_data) && ! zero(hdr.operation_data)
&& ! zero(hdr.payload_len); && ( (! zero(hdr.source_actor) && ! zero(hdr.payload_len))
|| (zero(hdr.source_actor) && zero(hdr.payload_len)));
} }
bool client_handshake_valid(const header& hdr) { bool client_handshake_valid(const header& hdr) {
return valid(hdr.source_node); return valid(hdr.source_node)
&& valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node
&& zero(hdr.source_actor)
&& zero(hdr.dest_actor)
&& zero(hdr.payload_len)
&& zero(hdr.operation_data);
} }
bool dispatch_message_valid(const header& hdr) { bool dispatch_message_valid(const header& hdr) {
...@@ -133,7 +140,10 @@ bool announce_proxy_instance_valid(const header& hdr) { ...@@ -133,7 +140,10 @@ bool announce_proxy_instance_valid(const header& hdr) {
return valid(hdr.source_node) return valid(hdr.source_node)
&& valid(hdr.dest_node) && valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node && hdr.source_node != hdr.dest_node
&& ! zero(hdr.dest_actor); && zero(hdr.source_actor)
&& ! zero(hdr.dest_actor)
&& zero(hdr.payload_len)
&& zero(hdr.operation_data);
} }
bool kill_proxy_instance_valid(const header& hdr) { bool kill_proxy_instance_valid(const header& hdr) {
...@@ -141,16 +151,11 @@ bool kill_proxy_instance_valid(const header& hdr) { ...@@ -141,16 +151,11 @@ bool kill_proxy_instance_valid(const header& hdr) {
&& valid(hdr.dest_node) && valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node && hdr.source_node != hdr.dest_node
&& ! zero(hdr.source_actor) && ! zero(hdr.source_actor)
&& zero(hdr.dest_actor)
&& zero(hdr.payload_len)
&& ! zero(hdr.operation_data); && ! zero(hdr.operation_data);
} }
bool name_lookup_valid(const header& hdr) {
return valid(hdr.source_node)
&& valid(hdr.dest_node)
&& hdr.source_node != hdr.dest_node
&& ! zero(hdr.source_actor);
}
} // namespace <anonymous> } // namespace <anonymous>
bool valid(const header& hdr) { bool valid(const header& hdr) {
...@@ -167,8 +172,6 @@ bool valid(const header& hdr) { ...@@ -167,8 +172,6 @@ bool valid(const header& hdr) {
return announce_proxy_instance_valid(hdr); return announce_proxy_instance_valid(hdr);
case message_type::kill_proxy_instance: case message_type::kill_proxy_instance:
return kill_proxy_instance_valid(hdr); return kill_proxy_instance_valid(hdr);
case message_type::name_lookup:
return name_lookup_valid(hdr);
} }
} }
...@@ -247,8 +250,8 @@ void routing_table::erase_direct(const connection_handle& hdl, ...@@ -247,8 +250,8 @@ void routing_table::erase_direct(const connection_handle& hdl,
direct_by_hdl_.erase(i); direct_by_hdl_.erase(i);
} }
void routing_table::erase_indirect(const node_id& dest) { bool routing_table::erase_indirect(const node_id& dest) {
indirect_.erase(dest); return indirect_.erase(dest) > 0;
} }
void routing_table::add_direct(const connection_handle& hdl, void routing_table::add_direct(const connection_handle& hdl,
...@@ -390,7 +393,7 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr, ...@@ -390,7 +393,7 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr,
std::set<std::string> sigs; std::set<std::string> sigs;
binary_deserializer bd{payload->data(), payload->size(), binary_deserializer bd{payload->data(), payload->size(),
&get_namespace()}; &get_namespace()};
// read first half of payload (ID and interface of published actor) // read payload (ID and interface of published actor)
bd >> aid >> sigs; bd >> aid >> sigs;
// close self connection after handshake is done // close self connection after handshake is done
if (hdr.source_node == this_node_) { if (hdr.source_node == this_node_) {
...@@ -408,37 +411,32 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr, ...@@ -408,37 +411,32 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr,
// add direct route to this node and remove any indirect entry // add direct route to this node and remove any indirect entry
CAF_LOG_INFO("new direct connection: " << to_string(hdr.source_node)); CAF_LOG_INFO("new direct connection: " << to_string(hdr.source_node));
tbl_.add_direct(dm.handle, hdr.source_node); tbl_.add_direct(dm.handle, hdr.source_node);
tbl_.erase_indirect(hdr.source_node); auto was_indirect = tbl_.erase_indirect(hdr.source_node);
// write handshake as client in response // write handshake as client in response
auto path = tbl_.lookup(hdr.source_node); auto path = tbl_.lookup(hdr.source_node);
if (!path) { if (!path) {
CAF_LOG_ERROR("no route to host after server handshake"); CAF_LOG_ERROR("no route to host after server handshake");
return err(); return err();
} }
// read remainig payload write_client_handshake(path->wr_buf, hdr.source_node);
read_named_actors(bd, hdr.source_node); callee_.learned_new_node_directly(hdr.source_node, was_indirect);
write_client_handshake(path->wr_buf);
// tell client to create proxy etc.
callee_.finalize_handshake(hdr.source_node, aid, sigs); callee_.finalize_handshake(hdr.source_node, aid, sigs);
flush(*path); flush(*path);
break; break;
} }
case message_type::client_handshake: case message_type::client_handshake: {
if (tbl_.lookup_direct(hdr.source_node) != invalid_connection_handle) { if (tbl_.lookup_direct(hdr.source_node) != invalid_connection_handle) {
CAF_LOG_INFO("received second client handshake for " CAF_LOG_INFO("received second client handshake for "
<< to_string(hdr.source_node) << ", close connection"); << to_string(hdr.source_node) << " (ignored)");
return err(); break;
} }
// add direct route to this node and remove any indirect entry // add direct route to this node and remove any indirect entry
CAF_LOG_INFO("new direct connection: " << to_string(hdr.source_node)); CAF_LOG_INFO("new direct connection: " << to_string(hdr.source_node));
tbl_.add_direct(dm.handle, hdr.source_node); tbl_.add_direct(dm.handle, hdr.source_node);
tbl_.erase_indirect(hdr.source_node); auto was_indirect = tbl_.erase_indirect(hdr.source_node);
if (payload_valid()) { callee_.learned_new_node_directly(hdr.source_node, was_indirect);
binary_deserializer bd{payload->data(), payload->size(),
&get_namespace()};
read_named_actors(bd, hdr.source_node);
}
break; break;
}
case message_type::dispatch_message: { case message_type::dispatch_message: {
if (! payload_valid()) if (! payload_valid())
return err(); return err();
...@@ -467,25 +465,6 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr, ...@@ -467,25 +465,6 @@ connection_state instance::handle(const new_data_msg& dm, header& hdr,
callee_.kill_proxy(hdr.source_node, hdr.source_actor, callee_.kill_proxy(hdr.source_node, hdr.source_actor,
static_cast<uint32_t>(hdr.operation_data)); static_cast<uint32_t>(hdr.operation_data));
break; break;
case message_type::name_lookup: {
if (hdr.source_node == this_node())
return err();
auto path = tbl_.lookup(hdr.source_node);
if (! path) {
CAF_LOG_INFO("cannot reply to name lookup: no route to source");
return await_header;
}
auto atm = static_cast<atom_value>(hdr.operation_data);
auto res = detail::singletons::get_actor_registry()->get_named(atm);
auto msg = make_message(ok_atom::value, std::move(res));
auto writer = make_callback([&](serializer& sink) {
msg.serialize(sink);
});
write(path->wr_buf, message_type::dispatch_message, nullptr, 0,
this_node(), hdr.source_node, res.id(), hdr.source_actor, &writer);
flush(*path);
break;
}
default: default:
CAF_LOG_ERROR("invalid operation"); CAF_LOG_ERROR("invalid operation");
return err(); return err();
...@@ -652,10 +631,6 @@ void instance::write_server_handshake(buffer_type& out_buf, ...@@ -652,10 +631,6 @@ void instance::write_server_handshake(buffer_type& out_buf,
auto writer = make_callback([&](serializer& sink) { auto writer = make_callback([&](serializer& sink) {
if (pa) if (pa)
sink << pa->first.id() << pa->second; sink << pa->first.id() << pa->second;
else
sink << invalid_actor_id << std::set<std::string>{};
sink << atom("SpawnServ")
<< singletons::get_actor_registry()->get_named(atom("SpawnServ"));
}); });
header hdr{message_type::server_handshake, 0, version, header hdr{message_type::server_handshake, 0, version,
this_node_, invalid_node_id, this_node_, invalid_node_id,
...@@ -663,17 +638,12 @@ void instance::write_server_handshake(buffer_type& out_buf, ...@@ -663,17 +638,12 @@ void instance::write_server_handshake(buffer_type& out_buf,
write(out_buf, hdr, &writer); write(out_buf, hdr, &writer);
} }
void instance::write_client_handshake(buffer_type& buf) { void instance::write_client_handshake(buffer_type& buf,
using namespace detail; const node_id& remote_side) {
auto writer = make_callback([&](serializer& sink) {
sink << atom("SpawnServ")
<< singletons::get_actor_registry()->get_named(atom("SpawnServ"));
});
write(buf, write(buf,
message_type::client_handshake, nullptr, 0, message_type::client_handshake, nullptr, 0,
this_node_, invalid_node_id, this_node_, remote_side,
invalid_actor_id, invalid_actor_id, invalid_actor_id, invalid_actor_id);
&writer);
} }
void instance::write_dispatch_error(buffer_type& buf, void instance::write_dispatch_error(buffer_type& buf,
...@@ -704,39 +674,6 @@ void instance::write_kill_proxy_instance(buffer_type& buf, ...@@ -704,39 +674,6 @@ void instance::write_kill_proxy_instance(buffer_type& buf,
write(buf, hdr); write(buf, hdr);
} }
void instance::write_name_lookup(buffer_type& buf,
atom_value requested_name,
const node_id& dest_node,
actor_id source_actor) {
write(buf, message_type::name_lookup, nullptr,
static_cast<uint64_t>(requested_name), this_node_, dest_node,
source_actor, invalid_actor_id);
}
auto instance::named_actors() -> named_actors_map {
return detail::singletons::get_actor_registry()->named_actors();
}
auto instance::named_actors(const node_id& nid)
-> optional<const named_actors_map&> {
auto i = named_actors_.find(nid);
if (i == named_actors_.end())
return none;
return i->second;
}
void instance::read_named_actors(binary_deserializer& bd, const node_id& nid) {
auto& storage = named_actors_[nid];
CAF_ASSERT(storage.empty());
while (! bd.at_end()) {
atom_value key;
actor value;
bd >> key >> value;
storage.emplace(key, std::move(value));
}
}
} // namespace basp } // namespace basp
} // namespace io } // namespace io
} // namespace caf } // namespace caf
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "caf/io/basp_broker.hpp" #include "caf/io/basp_broker.hpp"
#include <limits>
#include "caf/exception.hpp" #include "caf/exception.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/event_based_actor.hpp" #include "caf/event_based_actor.hpp"
...@@ -208,10 +210,20 @@ void basp_broker_state::deliver(const node_id& source_node, ...@@ -208,10 +210,20 @@ void basp_broker_state::deliver(const node_id& source_node,
} }
abstract_actor_ptr dest; abstract_actor_ptr dest;
uint32_t rsn = exit_reason::remote_link_unreachable; uint32_t rsn = exit_reason::remote_link_unreachable;
if (dest_node == this_node()) if (dest_node != this_node())
std::tie(dest, rsn) = registry->get_entry(dest_actor);
else
dest = get_namespace().get_or_put(dest_node, dest_actor); dest = get_namespace().get_or_put(dest_node, dest_actor);
else
if (dest_actor == std::numeric_limits<actor_id>::max()) {
// this hack allows CAF to talk to older CAF versions; CAF <= 0.14 will
// discard this message silently as the receiver is not found, while
// CAF >= 0.14.1 will use the operation data to identify named actors
auto dest_name = static_cast<atom_value>(mid.integer_value());
CAF_LOG_DEBUG("dest_name = " << to_string(dest_name));
mid = message_id::make(); // override this since the message is async
dest = actor_cast<abstract_actor_ptr>(registry->get_named(dest_name));
} else {
std::tie(dest, rsn) = registry->get_entry(dest_actor);
}
if (! dest) { if (! dest) {
CAF_LOG_INFO("cannot deliver message, destination not found"); CAF_LOG_INFO("cannot deliver message, destination not found");
if (mid.valid() && src != invalid_actor_addr) { if (mid.valid() && src != invalid_actor_addr) {
...@@ -223,9 +235,73 @@ void basp_broker_state::deliver(const node_id& source_node, ...@@ -223,9 +235,73 @@ void basp_broker_state::deliver(const node_id& source_node,
dest->enqueue(src, mid, std::move(msg), nullptr); dest->enqueue(src, mid, std::move(msg), nullptr);
} }
void basp_broker_state::learned_new_node(const node_id& nid) {
CAF_LOG_TRACE(CAF_TSARG(nid));
auto& tmp = spawn_servers[nid];
tmp = spawn<hidden>([=](event_based_actor* this_actor) -> behavior {
return {
[=](ok_atom, const std::string& /* key == "info" */,
const actor_addr& config_serv_addr, const std::string& /* name */) {
auto config_serv = actor_cast<actor>(config_serv_addr);
this_actor->monitor(config_serv);
this_actor->become(
[=](spawn_atom, std::string& type, message& args)
-> delegated<either<ok_atom, actor_addr, std::set<std::string>>
::or_else<error_atom, std::string>> {
this_actor->delegate(config_serv, get_atom::value,
std::move(type), std::move(args));
return {};
},
[=](const down_msg& dm) {
this_actor->quit(dm.reason);
},
others >> [=] {
CAF_LOGF_ERROR("spawn server has received unexpected message: "
<< to_string(this_actor->current_message()));
}
);
},
after(std::chrono::minutes(5)) >> [=] {
CAF_LOGF_INFO("no spawn server on node " << to_string(nid));
this_actor->quit();
}
};
});
using namespace detail;
singletons::get_actor_registry()->put(tmp.id(),
actor_cast<abstract_actor_ptr>(tmp));
auto writer = make_callback([](serializer& sink) {
auto msg = make_message(sys_atom::value, get_atom::value, "info");
msg.serialize(sink);
});
auto path = instance.tbl().lookup(nid);
if (! path) {
CAF_LOG_ERROR("learned_new_node called, but no route to nid");
return;
}
// writing std::numeric_limits<actor_id>::max() is a hack to get
// this send-to-named-actor feature working with older CAF releases
instance.write(path->wr_buf,
basp::message_type::dispatch_message,
nullptr, static_cast<uint64_t>(atom("SpawnServ")),
this_node(), nid,
tmp.id(), std::numeric_limits<actor_id>::max(),
&writer);
instance.flush(*path);
}
void basp_broker_state::learned_new_node_directly(const node_id& nid,
bool was_indirectly_before) {
CAF_ASSERT(this_context != nullptr);
CAF_LOG_TRACE(CAF_TSARG(nid));
if (! was_indirectly_before)
learned_new_node(nid);
}
void basp_broker_state::learned_new_node_indirectly(const node_id& nid) { void basp_broker_state::learned_new_node_indirectly(const node_id& nid) {
CAF_ASSERT(this_context != nullptr); CAF_ASSERT(this_context != nullptr);
CAF_LOG_TRACE(CAF_TSARG(nid)); CAF_LOG_TRACE(CAF_TSARG(nid));
learned_new_node(nid);
if (! enable_automatic_connections) if (! enable_automatic_connections)
return; return;
actor bb = self; // a handle for our helper back to this BASP broker actor bb = self; // a handle for our helper back to this BASP broker
...@@ -236,14 +312,7 @@ void basp_broker_state::learned_new_node_indirectly(const node_id& nid) { ...@@ -236,14 +312,7 @@ void basp_broker_state::learned_new_node_indirectly(const node_id& nid) {
auto connection_helper = [=](event_based_actor* helper, actor s) -> behavior { auto connection_helper = [=](event_based_actor* helper, actor s) -> behavior {
helper->monitor(s); helper->monitor(s);
return { return {
// this is the result of the name lookup we initiate via BASP // this config is send from the remote `ConfigServ`
[=](ok_atom, actor remote_config_server) {
CAF_LOGF_DEBUG("received remote config server: "
<< to_string(remote_config_server));
helper->send(remote_config_server,
get_atom::value, "basp.default-connectivity");
},
// this is the message we are actually waiting for
[=](ok_atom, const std::string&, message& msg) { [=](ok_atom, const std::string&, message& msg) {
CAF_LOGF_DEBUG("received requested config: " << to_string(msg)); CAF_LOGF_DEBUG("received requested config: " << to_string(msg));
// whatever happens, we are done afterwards // whatever happens, we are done afterwards
...@@ -290,10 +359,22 @@ void basp_broker_state::learned_new_node_indirectly(const node_id& nid) { ...@@ -290,10 +359,22 @@ void basp_broker_state::learned_new_node_indirectly(const node_id& nid) {
return; return;
} }
using namespace detail; using namespace detail;
auto tmp = spawn<detached + hidden + lazy_init>(connection_helper, self); auto tmp = spawn<detached + hidden>(connection_helper, self);
singletons::get_actor_registry()->put(tmp.id(), singletons::get_actor_registry()->put(tmp.id(),
actor_cast<abstract_actor_ptr>(tmp)); actor_cast<abstract_actor_ptr>(tmp));
instance.write_name_lookup(path->wr_buf, atom("ConfigServ"), nid, tmp.id()); auto writer = make_callback([](serializer& sink) {
auto msg = make_message(get_atom::value, "basp.default-connectivity");
msg.serialize(sink);
});
// writing std::numeric_limits<actor_id>::max() is a hack to get
// this send-to-named-actor feature working with older CAF releases
instance.write(path->wr_buf,
basp::message_type::dispatch_message,
nullptr, static_cast<uint64_t>(atom("ConfigServ")),
this_node(), nid,
tmp.id(), std::numeric_limits<actor_id>::max(),
&writer);
instance.flush(*path);
} }
void basp_broker_state::set_context(connection_handle hdl) { void basp_broker_state::set_context(connection_handle hdl) {
...@@ -491,17 +572,12 @@ behavior basp_broker::make_behavior() { ...@@ -491,17 +572,12 @@ behavior basp_broker::make_behavior() {
auto rp = make_response_promise(); auto rp = make_response_promise();
rp.deliver(error_atom::value, std::move(errmsg)); rp.deliver(error_atom::value, std::move(errmsg));
}; };
auto na = state.instance.named_actors(nid); auto i = state.spawn_servers.find(nid);
if (! na) { if (i == state.spawn_servers.end()) {
err("no connection to requested node"); err("no connection to requested node");
return {}; return {};
}
auto i = na->find(atom("SpawnServ"));
if (i == na->end()) {
err("no spawn server on requested node");
return {};
} }
delegate(i->second, get_atom::value, std::move(type), std::move(args)); delegate(i->second, spawn_atom::value, std::move(type), std::move(args));
return {}; return {};
}, },
[=](ok_atom, const std::string& key, message& value) { [=](ok_atom, const std::string& key, message& value) {
......
...@@ -258,7 +258,7 @@ void middleman::initialize() { ...@@ -258,7 +258,7 @@ void middleman::initialize() {
} }
// announce io-related types // announce io-related types
announce<network::protocol>("caf::io::network::protocol"); announce<network::protocol>("caf::io::network::protocol");
announce<network::address_listing>("caf::network::address_listing"); announce<network::address_listing>("caf::io::network::address_listing");
do_announce<new_data_msg>("caf::io::new_data_msg"); do_announce<new_data_msg>("caf::io::new_data_msg");
do_announce<new_connection_msg>("caf::io::new_connection_msg"); do_announce<new_connection_msg>("caf::io::new_connection_msg");
do_announce<acceptor_closed_msg>("caf::io::acceptor_closed_msg"); do_announce<acceptor_closed_msg>("caf::io::acceptor_closed_msg");
......
This diff is collapsed.
...@@ -111,10 +111,11 @@ CAF_TEST(remote_spawn) { ...@@ -111,10 +111,11 @@ CAF_TEST(remote_spawn) {
announce_actor_type("mirror", mirror); announce_actor_type("mirror", mirror);
auto argv = caf::test::engine::argv(); auto argv = caf::test::engine::argv();
auto argc = caf::test::engine::argc(); auto argc = caf::test::engine::argc();
uint16_t port; uint16_t port = 0;
auto r = message_builder(argv, argv + argc).extract_opts({ auto r = message_builder(argv, argv + argc).extract_opts({
{"server,s", "run as server (don't run client"}, {"server,s", "run as server (don't run client"},
{"client,c", "add client port (two needed)", port}, {"client,c", "add client port (two needed)", port},
{"port,p", "force a port in server mode", port},
{"use-asio", "use ASIO network backend (if available)"} {"use-asio", "use ASIO network backend (if available)"}
}); });
if (! r.error.empty() || r.opts.count("help") > 0 || ! r.remainder.empty()) { if (! r.error.empty() || r.opts.count("help") > 0 || ! r.remainder.empty()) {
...@@ -135,7 +136,7 @@ CAF_TEST(remote_spawn) { ...@@ -135,7 +136,7 @@ CAF_TEST(remote_spawn) {
return; return;
} }
auto serv = spawn(server); auto serv = spawn(server);
port = io::publish(serv, 0); port = io::publish(serv, port);
CAF_TEST_INFO("published server at port " << port); CAF_TEST_INFO("published server at port " << port);
if (r.opts.count("server") == 0) { if (r.opts.count("server") == 0) {
auto child = detail::run_program(invalid_actor, argv[0], "-n", "-s", auto child = detail::run_program(invalid_actor, argv[0], "-n", "-s",
......
...@@ -219,7 +219,8 @@ CAF_TEST(test_uniform_type) { ...@@ -219,7 +219,8 @@ CAF_TEST(test_uniform_type) {
"caf::io::connection_closed_msg", "caf::io::connection_closed_msg",
"caf::io::network::protocol", "caf::io::network::protocol",
"caf::io::new_connection_msg", "caf::io::new_connection_msg",
"caf::io::new_data_msg")); "caf::io::new_data_msg",
"caf::io::network::address_listing"));
CAF_MESSAGE("io types checked"); CAF_MESSAGE("io types checked");
} }
// check whether enums can be announced as members // check whether enums can be announced as members
......
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