Unverified Commit b63f959c authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #664

Remove indirect routing
parents 1ba9006e 97272b36
...@@ -45,11 +45,12 @@ namespace basp { ...@@ -45,11 +45,12 @@ namespace basp {
/// Describes a protocol instance managing multiple connections. /// Describes a protocol instance managing multiple connections.
class instance { class instance {
public: public:
using endpoint_handle = routing_table::endpoint_handle;
/// Provides a callback-based interface for certain BASP events. /// Provides a callback-based interface for certain BASP events.
class callee { class callee {
protected: protected:
using buffer_type = std::vector<char>; using buffer_type = std::vector<char>;
using endpoint_handle = variant<connection_handle, datagram_handle>; using endpoint_handle = instance::endpoint_handle;
public: public:
explicit callee(actor_system& sys, proxy_registry::backend& backend); explicit callee(actor_system& sys, proxy_registry::backend& backend);
...@@ -83,14 +84,8 @@ public: ...@@ -83,14 +84,8 @@ public:
std::vector<strong_actor_ptr>& forwarding_stack, std::vector<strong_actor_ptr>& forwarding_stack,
message& msg) = 0; message& msg) = 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. virtual void learned_new_node(const node_id& nid) = 0;
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
/// to which it does not have a direct connection.
virtual void learned_new_node_indirectly(const node_id& nid) = 0;
/// Called if a heartbeat was received from `nid` /// Called if a heartbeat was received from `nid`
virtual void handle_heartbeat(const node_id& nid) = 0; virtual void handle_heartbeat(const node_id& nid) = 0;
...@@ -176,15 +171,15 @@ public: ...@@ -176,15 +171,15 @@ public:
/// Sends heartbeat messages to all valid nodes those are directly connected. /// Sends heartbeat messages to all valid nodes those are directly connected.
void handle_heartbeat(execution_unit* ctx); void handle_heartbeat(execution_unit* ctx);
/// Returns a route to `target` or `none` on error. /// Returns the handle for communication with `target` or `none` on error.
optional<routing_table::route> lookup(const node_id& target); optional<endpoint_handle> lookup(const node_id& target);
/// Flushes the underlying buffer of `path`. /// Flushes the underlying buffer of `hdl`.
void flush(const routing_table::route& path); void flush(endpoint_handle hdl);
/// Sends a BASP message and implicitly flushes the output buffer of `r`. /// Sends a BASP message and implicitly flushes the output buffer of `hdl`.
/// This function will update `hdr.payload_len` if a payload was written. /// This function will update `hdr.payload_len` if a payload was written.
void write(execution_unit* ctx, const routing_table::route& r, void write(execution_unit* ctx, endpoint_handle hdl,
header& hdr, payload_writer* writer = nullptr); header& hdr, payload_writer* writer = nullptr);
/// Adds a new actor to the map of published actors. /// Adds a new actor to the map of published actors.
...@@ -294,11 +289,11 @@ public: ...@@ -294,11 +289,11 @@ public:
bool handle(execution_unit* ctx, const Handle& hdl, header& hdr, bool handle(execution_unit* ctx, const Handle& hdl, header& hdr,
std::vector<char>* payload, bool tcp_based, std::vector<char>* payload, bool tcp_based,
optional<endpoint_context&> ep, optional<uint16_t> port) { optional<endpoint_context&> ep, optional<uint16_t> port) {
// function object for checking payload validity // Function object for checking payload validity.
auto payload_valid = [&]() -> bool { auto payload_valid = [&]() -> bool {
return payload != nullptr && payload->size() == hdr.payload_len; return payload != nullptr && payload->size() == hdr.payload_len;
}; };
// handle message to ourselves // Handle message to ourselves.
switch (hdr.operation) { switch (hdr.operation) {
case message_type::server_handshake: { case message_type::server_handshake: {
actor_id aid = invalid_actor_id; actor_id aid = invalid_actor_id;
...@@ -320,37 +315,31 @@ public: ...@@ -320,37 +315,31 @@ public:
if (e) if (e)
return false; return false;
} }
// 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_) {
CAF_LOG_INFO("close connection to self immediately"); CAF_LOG_INFO("close connection to self immediately");
callee_.finalize_handshake(hdr.source_node, aid, sigs); callee_.finalize_handshake(hdr.source_node, aid, sigs);
return false; return false;
} }
// close this connection if we already have a direct connection // Close this connection if we already established communication.
if (tbl_.lookup_direct(hdr.source_node)) { // TODO: Should we allow multiple "connections" over different
// transport protocols?
if (tbl_.lookup(hdr.source_node)) {
CAF_LOG_INFO("close connection since we already have a " CAF_LOG_INFO("close connection since we already have a "
"direct connection: " << CAF_ARG(hdr.source_node)); "connection: " << CAF_ARG(hdr.source_node));
callee_.finalize_handshake(hdr.source_node, aid, sigs); callee_.finalize_handshake(hdr.source_node, aid, sigs);
return false; return false;
} }
// add direct route to this node and remove any indirect entry // Add this node to our contacts.
CAF_LOG_INFO("new direct connection:" << CAF_ARG(hdr.source_node)); CAF_LOG_INFO("new endpoint:" << CAF_ARG(hdr.source_node));
tbl_.add_direct(hdl, hdr.source_node); tbl_.add(hdl, hdr.source_node);
auto was_indirect = tbl_.erase_indirect(hdr.source_node); // TODO: Add status, addresses, ... ?
// write handshake as client in response // Write handshake as client in response.
auto path = tbl_.lookup(hdr.source_node); if (tcp_based)
if (!path) { write_client_handshake(ctx, callee_.get_buffer(hdl), hdr.source_node);
CAF_LOG_ERROR("no route to host after server handshake"); callee_.learned_new_node(hdr.source_node);
return false;
}
if (tcp_based) {
auto ch = get<connection_handle>(path->hdl);
write_client_handshake(ctx, callee_.get_buffer(ch),
hdr.source_node);
}
callee_.learned_new_node_directly(hdr.source_node, was_indirect);
callee_.finalize_handshake(hdr.source_node, aid, sigs); callee_.finalize_handshake(hdr.source_node, aid, sigs);
flush(*path); flush(hdl);
break; break;
} }
case message_type::client_handshake: { case message_type::client_handshake: {
...@@ -368,49 +357,35 @@ public: ...@@ -368,49 +357,35 @@ public:
return false; return false;
} }
} }
auto new_node = (this_node() != hdr.source_node
&& !tbl_.lookup(hdr.source_node));
if (!new_node) {
if (tcp_based) { if (tcp_based) {
if (tbl_.lookup_direct(hdr.source_node)) {
CAF_LOG_INFO("received second client handshake:" CAF_LOG_INFO("received second client handshake:"
<< CAF_ARG(hdr.source_node)); << CAF_ARG(hdr.source_node));
break; break;
} }
// add direct route to this node and remove any indirect entry
CAF_LOG_INFO("new direct connection:" << CAF_ARG(hdr.source_node));
tbl_.add_direct(hdl, hdr.source_node);
auto was_indirect = tbl_.erase_indirect(hdr.source_node);
callee_.learned_new_node_directly(hdr.source_node, was_indirect);
} else { } else {
auto new_node = (this_node() != hdr.source_node // Add this node to our contacts.
&& !tbl_.lookup_direct(hdr.source_node)); CAF_LOG_INFO("new endpoint:" << CAF_ARG(hdr.source_node));
if (new_node) { tbl_.add(hdl, hdr.source_node);
// add direct route to this node and remove any indirect entry // TODO: Add status, addresses, ... ?
CAF_LOG_INFO("new direct connection:" << CAF_ARG(hdr.source_node));
tbl_.add_direct(hdl, hdr.source_node);
} }
// Since udp is unreliable we answer, maybe our message was lost.
if (!tcp_based) {
uint16_t seq = (ep && ep->requires_ordering) ? ep->seq_outgoing++ : 0; uint16_t seq = (ep && ep->requires_ordering) ? ep->seq_outgoing++ : 0;
write_server_handshake(ctx, write_server_handshake(ctx, callee_.get_buffer(hdl), port, seq);
callee_.get_buffer(hdl),
port, seq);
callee_.flush(hdl); callee_.flush(hdl);
if (new_node) {
auto was_indirect = tbl_.erase_indirect(hdr.source_node);
callee_.learned_new_node_directly(hdr.source_node, was_indirect);
}
} }
// We have to call this after `write_server_handshake` because
// `learned_new_node` expects there to be an entry in the routing table.
if (new_node)
callee_.learned_new_node(hdr.source_node);
break; break;
} }
case message_type::dispatch_message: { case message_type::dispatch_message: {
if (!payload_valid()) if (!payload_valid())
return false; return false;
// in case the sender of this message was received via a third node,
// we assume that that node to offers a route to the original source
auto last_hop = tbl_.lookup_direct(hdl);
if (hdr.source_node != none
&& hdr.source_node != this_node_
&& last_hop != hdr.source_node
&& !tbl_.lookup_direct(hdr.source_node)
&& tbl_.add_indirect(last_hop, hdr.source_node))
callee_.learned_new_node_indirectly(hdr.source_node);
binary_deserializer bd{ctx, *payload}; binary_deserializer bd{ctx, *payload};
auto receiver_name = static_cast<atom_value>(0); auto receiver_name = static_cast<atom_value>(0);
std::vector<strong_actor_ptr> forwarding_stack; std::vector<strong_actor_ptr> forwarding_stack;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "caf/io/basp/buffer_type.hpp" #include "caf/io/basp/buffer_type.hpp"
#include "caf/io/network/interfaces.hpp"
namespace std { namespace std {
template<> template<>
...@@ -58,59 +60,30 @@ public: ...@@ -58,59 +60,30 @@ public:
virtual ~routing_table(); virtual ~routing_table();
/// Describes a routing path to a node.
struct route {
const node_id& next_hop;
endpoint_handle hdl;
};
/// Describes a function object for erase operations that /// Describes a function object for erase operations that
/// is called for each indirectly lost connection. /// is called for each indirectly lost connection.
using erase_callback = callback<const node_id&>; using erase_callback = callback<const node_id&>;
/// Returns a route to `target` or `none` on error. /// Returns the ID of the peer reachable via `hdl` or
optional<route> lookup(const node_id& target);
/// Returns the ID of the peer connected via `hdl` or
/// `none` if `hdl` is unknown. /// `none` if `hdl` is unknown.
node_id lookup_direct(const endpoint_handle& hdl) const; node_id lookup(const endpoint_handle& hdl) const;
/// Returns the handle offering a direct connection to `nid` or /// Returns the handle for communication with `nid` or
/// `invalid_connection_handle` if no direct connection to `nid` exists. /// `none` if `nid` is unknown.
optional<endpoint_handle> lookup_direct(const node_id& nid) const; optional<endpoint_handle> lookup(const node_id& nid) const;
/// Returns the next hop that would be chosen for `nid`
/// or `none` if there's no indirect route to `nid`.
node_id lookup_indirect(const node_id& nid) const;
/// Adds a new direct route to the table. /// Adds a new direct route to the table.
/// @pre `hdl != invalid_connection_handle && nid != none` /// @pre `hdl != invalid_connection_handle && nid != none`
void add_direct(const endpoint_handle& hdl, const node_id& nid); void add(const endpoint_handle& hdl, const node_id& nid);
/// Adds a new indirect route to the table.
bool add_indirect(const node_id& hop, const node_id& dest);
/// Blacklist the route to `dest` via `hop`.
void blacklist(const node_id& hop, const node_id& dest);
/// Removes a direct connection and calls `cb` for any node /// Removes a direct connection and calls `cb` for any node
/// that became unreachable as a result of this operation, /// that became unreachable as a result of this operation,
/// 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 endpoint_handle& hdl, erase_callback& cb); void erase(const endpoint_handle& hdl, erase_callback& cb);
/// Removes any entry for indirect connection to `dest` and returns
/// `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);
/// Removes all direct and indirect routes to `dest` and calls
/// `cb` for any node that became unreachable as a result of this
/// operation, including `dest`.
/// @returns the number of removed routes (direct and indirect)
size_t erase(const node_id& dest, erase_callback& cb);
/// Returns the parent broker. /// Returns the parent broker.
inline abstract_broker* parent() { inline abstract_broker* parent() {
return parent_; return parent_;
...@@ -126,16 +99,11 @@ public: ...@@ -126,16 +99,11 @@ public:
return std::forward<Fallback>(x); return std::forward<Fallback>(x);
} }
using node_id_set = std::unordered_set<node_id>;
using indirect_entries = std::unordered_map<node_id, // dest
node_id_set>; // hop
abstract_broker* parent_; abstract_broker* parent_;
std::unordered_map<endpoint_handle, node_id> direct_by_hdl_; std::unordered_map<endpoint_handle, node_id> direct_by_hdl_;
// TODO: Do we need a list as a second argument as there could be
// multiple handles for different technologies?
std::unordered_map<node_id, endpoint_handle> direct_by_nid_; std::unordered_map<node_id, endpoint_handle> direct_by_nid_;
indirect_entries indirect_;
indirect_entries blacklist_;
}; };
/// @} /// @}
......
...@@ -81,14 +81,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee { ...@@ -81,14 +81,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
std::vector<strong_actor_ptr>& stages, message& msg); std::vector<strong_actor_ptr>& stages, message& msg);
// performs bookkeeping such as managing `spawn_servers` // performs bookkeeping such as managing `spawn_servers`
void learned_new_node(const node_id& nid); void learned_new_node(const node_id& nid) override;
// inherited from basp::instance::callee
void learned_new_node_directly(const node_id& nid,
bool was_indirectly_before) override;
// inherited from basp::instance::callee
void learned_new_node_indirectly(const node_id& nid) override;
// inherited from basp::instance::callee // inherited from basp::instance::callee
uint16_t next_sequence_number(connection_handle hdl) override; uint16_t next_sequence_number(connection_handle hdl) override;
......
This diff is collapsed.
...@@ -63,13 +63,13 @@ connection_state instance::handle(execution_unit* ctx, ...@@ -63,13 +63,13 @@ connection_state instance::handle(execution_unit* ctx,
new_data_msg& dm, header& hdr, new_data_msg& dm, header& hdr,
bool is_payload) { bool is_payload) {
CAF_LOG_TRACE(CAF_ARG(dm) << CAF_ARG(is_payload)); CAF_LOG_TRACE(CAF_ARG(dm) << CAF_ARG(is_payload));
// function object providing cleanup code on errors // Function object providing cleanup code on errors.
auto err = [&]() -> connection_state { auto err = [&]() -> connection_state {
auto cb = make_callback([&](const node_id& nid) -> error { auto cb = make_callback([&](const node_id& nid) -> error {
callee_.purge_state(nid); callee_.purge_state(nid);
return none; return none;
}); });
tbl_.erase_direct(dm.handle, cb); tbl_.erase(dm.handle, cb);
return close_connection; return close_connection;
}; };
std::vector<char>* payload = nullptr; std::vector<char>* payload = nullptr;
...@@ -93,23 +93,23 @@ connection_state instance::handle(execution_unit* ctx, ...@@ -93,23 +93,23 @@ connection_state instance::handle(execution_unit* ctx,
} }
} }
CAF_LOG_DEBUG(CAF_ARG(hdr)); CAF_LOG_DEBUG(CAF_ARG(hdr));
// needs forwarding? // Needs forwarding?
if (!is_handshake(hdr) && !is_heartbeat(hdr) && hdr.dest_node != this_node_) { if (!is_handshake(hdr) && !is_heartbeat(hdr) && hdr.dest_node != this_node_) {
CAF_LOG_DEBUG("forward message"); CAF_LOG_DEBUG("forward message");
auto path = lookup(hdr.dest_node); auto ehdl = lookup(hdr.dest_node);
if (path) { if (ehdl) {
binary_serializer bs{ctx, callee_.get_buffer(path->hdl)}; binary_serializer bs{ctx, callee_.get_buffer(*ehdl)};
auto e = bs(hdr); auto e = bs(hdr);
if (e) if (e)
return err(); return err();
if (payload != nullptr) if (payload != nullptr)
bs.apply_raw(payload->size(), payload->data()); bs.apply_raw(payload->size(), payload->data());
flush(*path); flush(*ehdl);
notify<hook::message_forwarded>(hdr, payload); notify<hook::message_forwarded>(hdr, payload);
} else { } else {
CAF_LOG_INFO("cannot forward message, no route to destination"); CAF_LOG_INFO("cannot forward message, no route to destination");
if (hdr.source_node != this_node_) { if (hdr.source_node != this_node_) {
// TODO: signalize error back to sending node // TODO: Signalize error back to sending node.
auto reverse_path = lookup(hdr.source_node); auto reverse_path = lookup(hdr.source_node);
if (!reverse_path) { if (!reverse_path) {
CAF_LOG_WARNING("cannot send error message: no route to source"); CAF_LOG_WARNING("cannot send error message: no route to source");
...@@ -131,22 +131,22 @@ connection_state instance::handle(execution_unit* ctx, ...@@ -131,22 +131,22 @@ connection_state instance::handle(execution_unit* ctx,
bool instance::handle(execution_unit* ctx, new_datagram_msg& dm, bool instance::handle(execution_unit* ctx, new_datagram_msg& dm,
endpoint_context& ep) { endpoint_context& ep) {
using itr_t = network::receive_buffer::iterator; using itr_t = network::receive_buffer::iterator;
// function object providing cleanup code on errors // Function object providing cleanup code on errors.
auto err = [&]() -> bool { auto err = [&]() -> bool {
auto cb = make_callback([&](const node_id& nid) -> error { auto cb = make_callback([&](const node_id& nid) -> error {
callee_.purge_state(nid); callee_.purge_state(nid);
return none; return none;
}); });
tbl_.erase_direct(dm.handle, cb); tbl_.erase(dm.handle, cb);
return false; return false;
}; };
// extract payload // Extract payload.
std::vector<char> pl_buf{std::move_iterator<itr_t>(std::begin(dm.buf) + std::vector<char> pl_buf{std::move_iterator<itr_t>(std::begin(dm.buf) +
basp::header_size), basp::header_size),
std::move_iterator<itr_t>(std::end(dm.buf))}; std::move_iterator<itr_t>(std::end(dm.buf))};
// resize header // Resize header.
dm.buf.resize(basp::header_size); dm.buf.resize(basp::header_size);
// extract header // Extract header.
binary_deserializer bd{ctx, dm.buf}; binary_deserializer bd{ctx, dm.buf};
auto e = bd(ep.hdr); auto e = bd(ep.hdr);
if (e || !valid(ep.hdr)) { if (e || !valid(ep.hdr)) {
...@@ -175,24 +175,24 @@ bool instance::handle(execution_unit* ctx, new_datagram_msg& dm, ...@@ -175,24 +175,24 @@ bool instance::handle(execution_unit* ctx, new_datagram_msg& dm,
} }
// This is the expected message. // This is the expected message.
ep.seq_incoming += 1; ep.seq_incoming += 1;
// TODO: add optional reliability here // TODO: Add optional reliability here.
if (!is_handshake(ep.hdr) && !is_heartbeat(ep.hdr) if (!is_handshake(ep.hdr) && !is_heartbeat(ep.hdr)
&& ep.hdr.dest_node != this_node_) { && ep.hdr.dest_node != this_node_) {
CAF_LOG_DEBUG("forward message"); CAF_LOG_DEBUG("forward message");
auto path = lookup(ep.hdr.dest_node); auto ehdl = lookup(ep.hdr.dest_node);
if (path) { if (ehdl) {
binary_serializer bs{ctx, callee_.get_buffer(path->hdl)}; binary_serializer bs{ctx, callee_.get_buffer(*ehdl)};
auto ex = bs(ep.hdr); auto ex = bs(ep.hdr);
if (ex) if (ex)
return err(); return err();
if (payload != nullptr) if (payload != nullptr)
bs.apply_raw(payload->size(), payload->data()); bs.apply_raw(payload->size(), payload->data());
flush(*path); flush(*ehdl);
notify<hook::message_forwarded>(ep.hdr, payload); notify<hook::message_forwarded>(ep.hdr, payload);
} else { } else {
CAF_LOG_INFO("cannot forward message, no route to destination"); CAF_LOG_INFO("cannot forward message, no route to destination");
if (ep.hdr.source_node != this_node_) { if (ep.hdr.source_node != this_node_) {
// TODO: signalize error back to sending node // TODO: Signalize error back to sending node.
auto reverse_path = lookup(ep.hdr.source_node); auto reverse_path = lookup(ep.hdr.source_node);
if (!reverse_path) { if (!reverse_path) {
CAF_LOG_WARNING("cannot send error message: no route to source"); CAF_LOG_WARNING("cannot send error message: no route to source");
...@@ -224,20 +224,20 @@ void instance::handle_heartbeat(execution_unit* ctx) { ...@@ -224,20 +224,20 @@ void instance::handle_heartbeat(execution_unit* ctx) {
} }
} }
optional<routing_table::route> instance::lookup(const node_id& target) { optional<instance::endpoint_handle> instance::lookup(const node_id& target) {
return tbl_.lookup(target); return tbl_.lookup(target);
} }
void instance::flush(const routing_table::route& path) { void instance::flush(endpoint_handle hdl) {
callee_.flush(path.hdl); callee_.flush(hdl);
} }
void instance::write(execution_unit* ctx, const routing_table::route& r, void instance::write(execution_unit* ctx, instance::endpoint_handle hdl,
header& hdr, payload_writer* writer) { header& hdr, payload_writer* writer) {
CAF_LOG_TRACE(CAF_ARG(hdr)); CAF_LOG_TRACE(CAF_ARG(hdr));
CAF_ASSERT(hdr.payload_len == 0 || writer != nullptr); CAF_ASSERT(hdr.payload_len == 0 || writer != nullptr);
write(ctx, callee_.get_buffer(r.hdl), hdr, writer); write(ctx, callee_.get_buffer(hdl), hdr, writer);
flush(r); flush(hdl);
} }
void instance::add_published_actor(uint16_t port, void instance::add_published_actor(uint16_t port,
...@@ -295,7 +295,7 @@ size_t instance::remove_published_actor(const actor_addr& whom, ...@@ -295,7 +295,7 @@ size_t instance::remove_published_actor(const actor_addr& whom,
bool instance::is_greater(sequence_type lhs, sequence_type rhs, bool instance::is_greater(sequence_type lhs, sequence_type rhs,
sequence_type max_distance) { sequence_type max_distance) {
// distance between lhs and rhs is smaller than max_distance. // Distance between lhs and rhs is smaller than max_distance.
return ((lhs > rhs) && (lhs - rhs <= max_distance)) || return ((lhs > rhs) && (lhs - rhs <= max_distance)) ||
((lhs < rhs) && (rhs - lhs > max_distance)); ((lhs < rhs) && (rhs - lhs > max_distance));
} }
...@@ -307,8 +307,8 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender, ...@@ -307,8 +307,8 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(receiver) CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(receiver)
<< CAF_ARG(mid) << CAF_ARG(msg)); << CAF_ARG(mid) << CAF_ARG(msg));
CAF_ASSERT(receiver && system().node() != receiver->node()); CAF_ASSERT(receiver && system().node() != receiver->node());
auto path = lookup(receiver->node()); auto ehdl = lookup(receiver->node());
if (!path) { if (!ehdl) {
notify<hook::message_sending_failed>(sender, receiver, mid, msg); notify<hook::message_sending_failed>(sender, receiver, mid, msg);
return false; return false;
} }
...@@ -319,10 +319,10 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender, ...@@ -319,10 +319,10 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
header hdr{message_type::dispatch_message, 0, 0, mid.integer_value(), header hdr{message_type::dispatch_message, 0, 0, mid.integer_value(),
sender ? sender->node() : this_node(), receiver->node(), sender ? sender->node() : this_node(), receiver->node(),
sender ? sender->id() : invalid_actor_id, receiver->id(), sender ? sender->id() : invalid_actor_id, receiver->id(),
visit(seq_num_visitor{callee_}, path->hdl)}; visit(seq_num_visitor{callee_}, *ehdl)};
write(ctx, callee_.get_buffer(path->hdl), hdr, &writer); write(ctx, callee_.get_buffer(*ehdl), hdr, &writer);
flush(*path); flush(*ehdl);
notify<hook::message_sent>(sender, path->next_hop, receiver, mid, msg); notify<hook::message_sent>(sender, receiver->node(), receiver, mid, msg);
return true; return true;
} }
...@@ -332,7 +332,7 @@ void instance::write(execution_unit* ctx, buffer_type& buf, ...@@ -332,7 +332,7 @@ void instance::write(execution_unit* ctx, buffer_type& buf,
error err; error err;
if (pw != nullptr) { if (pw != nullptr) {
auto pos = buf.size(); auto pos = buf.size();
// write payload first (skip first 72 bytes and write header later) // Write payload first (skip first 72 bytes and write header later).
char placeholder[basp::header_size]; char placeholder[basp::header_size];
buf.insert(buf.end(), std::begin(placeholder), std::end(placeholder)); buf.insert(buf.end(), std::begin(placeholder), std::end(placeholder));
binary_serializer bs{ctx, buf}; binary_serializer bs{ctx, buf};
......
...@@ -33,58 +33,19 @@ routing_table::~routing_table() { ...@@ -33,58 +33,19 @@ routing_table::~routing_table() {
// nop // nop
} }
optional<routing_table::route> routing_table::lookup(const node_id& target) { node_id routing_table::lookup(const endpoint_handle& hdl) const {
auto hdl = lookup_direct(target);
if (hdl)
return route{target, *hdl};
// pick first available indirect route
auto i = indirect_.find(target);
if (i != indirect_.end()) {
auto& hops = i->second;
while (!hops.empty()) {
auto& hop = *hops.begin();
hdl = lookup_direct(hop);
if (hdl)
return route{hop, *hdl};
hops.erase(hops.begin());
}
}
return none;
}
node_id routing_table::lookup_direct(const endpoint_handle& hdl) const {
return get_opt(direct_by_hdl_, hdl, none); return get_opt(direct_by_hdl_, hdl, none);
} }
optional<routing_table::endpoint_handle> optional<routing_table::endpoint_handle>
routing_table::lookup_direct(const node_id& nid) const { routing_table::lookup(const node_id& nid) const {
auto i = direct_by_nid_.find(nid); auto i = direct_by_nid_.find(nid);
if (i != direct_by_nid_.end()) if (i != direct_by_nid_.end())
return i->second; return i->second;
return none; return none;
} }
node_id routing_table::lookup_indirect(const node_id& nid) const { void routing_table::erase(const endpoint_handle& hdl, erase_callback& cb) {
auto i = indirect_.find(nid);
if (i == indirect_.end())
return none;
if (i->second.empty())
return none;
return *i->second.begin();
}
void routing_table::blacklist(const node_id& hop, const node_id& dest) {
blacklist_[dest].emplace(hop);
auto i = indirect_.find(dest);
if (i == indirect_.end())
return;
i->second.erase(hop);
if (i->second.empty())
indirect_.erase(i);
}
void routing_table::erase_direct(const endpoint_handle& hdl,
erase_callback& cb) {
auto i = direct_by_hdl_.find(hdl); auto i = direct_by_hdl_.find(hdl);
if (i == direct_by_hdl_.end()) if (i == direct_by_hdl_.end())
return; return;
...@@ -94,19 +55,7 @@ void routing_table::erase_direct(const endpoint_handle& hdl, ...@@ -94,19 +55,7 @@ void routing_table::erase_direct(const endpoint_handle& hdl,
direct_by_hdl_.erase(i->first); direct_by_hdl_.erase(i->first);
} }
bool routing_table::erase_indirect(const node_id& dest) { void routing_table::add(const endpoint_handle& hdl, const node_id& nid) {
auto i = indirect_.find(dest);
if (i == indirect_.end())
return false;
if (parent_->parent().has_hook())
for (auto& nid : i->second)
parent_->parent().notify<hook::route_lost>(nid, dest);
indirect_.erase(i);
return true;
}
void routing_table::add_direct(const endpoint_handle& hdl,
const node_id& nid) {
CAF_ASSERT(direct_by_hdl_.count(hdl) == 0); CAF_ASSERT(direct_by_hdl_.count(hdl) == 0);
CAF_ASSERT(direct_by_nid_.count(nid) == 0); CAF_ASSERT(direct_by_nid_.count(nid) == 0);
direct_by_hdl_.emplace(hdl, nid); direct_by_hdl_.emplace(hdl, nid);
...@@ -114,42 +63,8 @@ void routing_table::add_direct(const endpoint_handle& hdl, ...@@ -114,42 +63,8 @@ void routing_table::add_direct(const endpoint_handle& hdl,
parent_->parent().notify<hook::new_connection_established>(nid); parent_->parent().notify<hook::new_connection_established>(nid);
} }
bool routing_table::add_indirect(const node_id& hop, const node_id& dest) {
auto i = blacklist_.find(dest);
if (i == blacklist_.end() || i->second.count(hop) == 0) {
auto& hops = indirect_[dest];
auto added_first = hops.empty();
hops.emplace(hop);
parent_->parent().notify<hook::new_route_added>(hop, dest);
return added_first;
}
return false; // blacklisted
}
bool routing_table::reachable(const node_id& dest) { bool routing_table::reachable(const node_id& dest) {
return direct_by_nid_.count(dest) > 0 || indirect_.count(dest) > 0; return direct_by_nid_.count(dest) > 0;
}
size_t routing_table::erase(const node_id& dest, erase_callback& cb) {
cb(dest);
size_t res = 0;
auto i = indirect_.find(dest);
if (i != indirect_.end()) {
res = i->second.size();
for (auto& nid : i->second) {
cb(nid);
parent_->parent().notify<hook::route_lost>(nid, dest);
}
indirect_.erase(i);
}
auto hdl = lookup_direct(dest);
if (hdl) {
direct_by_hdl_.erase(*hdl);
direct_by_nid_.erase(dest);
parent_->parent().notify<hook::connection_lost>(dest);
++res;
}
return res;
} }
} // namespace basp } // namespace basp
......
...@@ -52,7 +52,7 @@ constexpr uint64_t no_operation_data = 0; ...@@ -52,7 +52,7 @@ constexpr uint64_t no_operation_data = 0;
constexpr auto basp_atom = caf::atom("BASP"); constexpr auto basp_atom = caf::atom("BASP");
constexpr auto spawn_serv_atom = caf::atom("SpawnServ"); constexpr auto spawn_serv_atom = caf::atom("SpawnServ");
constexpr auto config_serv_atom = caf::atom("ConfigServ"); // constexpr auto config_serv_atom = caf::atom("ConfigServ");
} // namespace <anonymous> } // namespace <anonymous>
...@@ -310,10 +310,9 @@ public: ...@@ -310,10 +310,9 @@ public:
make_message(sys_atom::value, get_atom::value, "info")); make_message(sys_atom::value, get_atom::value, "info"));
// test whether basp instance correctly updates the // test whether basp instance correctly updates the
// routing table upon receiving client handshakes // routing table upon receiving client handshakes
auto path = tbl().lookup(n.id); auto ehdl = tbl().lookup(n.id);
CAF_REQUIRE(path); CAF_REQUIRE(ehdl);
CAF_CHECK_EQUAL(path->hdl, n.connection); CAF_CHECK_EQUAL(*ehdl, n.connection);
CAF_CHECK_EQUAL(path->next_hop, n.id);
} }
std::pair<basp::header, buffer> read_from_out_buf(connection_handle hdl) { std::pair<basp::header, buffer> read_from_out_buf(connection_handle hdl) {
...@@ -723,6 +722,7 @@ CAF_TEST(actor_serialize_and_deserialize) { ...@@ -723,6 +722,7 @@ CAF_TEST(actor_serialize_and_deserialize) {
std::vector<actor_id>{}, msg); std::vector<actor_id>{}, msg);
} }
/*
CAF_TEST(indirect_connections) { CAF_TEST(indirect_connections) {
// this node receives a message from jupiter via mars and responds via mars // this node receives a message from jupiter via mars and responds via mars
// and any ad-hoc automatic connection requests are ignored // and any ad-hoc automatic connection requests are ignored
...@@ -772,11 +772,13 @@ CAF_TEST(indirect_connections) { ...@@ -772,11 +772,13 @@ CAF_TEST(indirect_connections) {
std::vector<actor_id>{}, std::vector<actor_id>{},
make_message("hello from earth!")); make_message("hello from earth!"));
} }
*/
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
CAF_TEST_FIXTURE_SCOPE(basp_tests_with_autoconn, autoconn_enabled_fixture) CAF_TEST_FIXTURE_SCOPE(basp_tests_with_autoconn, autoconn_enabled_fixture)
/*
CAF_TEST(automatic_connection) { CAF_TEST(automatic_connection) {
// this tells our BASP broker to enable the automatic connection feature // this tells our BASP broker to enable the automatic connection feature
//anon_send(aut(), ok_atom::value, //anon_send(aut(), ok_atom::value,
...@@ -787,9 +789,9 @@ CAF_TEST(automatic_connection) { ...@@ -787,9 +789,9 @@ CAF_TEST(automatic_connection) {
// but then also establishes a connection to jupiter directly) // but then also establishes a connection to jupiter directly)
auto check_node_in_tbl = [&](node& n) { auto check_node_in_tbl = [&](node& n) {
io::id_visitor id_vis; io::id_visitor id_vis;
auto hdl = tbl().lookup_direct(n.id); auto ehdl = tbl().lookup(n.id);
CAF_REQUIRE(hdl); CAF_REQUIRE(ehdl);
CAF_CHECK_EQUAL(visit(id_vis, *hdl), n.connection.id()); CAF_CHECK_EQUAL(visit(id_vis, *ehdl), n.connection.id());
}; };
mpx()->provide_scribe("jupiter", 8080, jupiter().connection); mpx()->provide_scribe("jupiter", 8080, jupiter().connection);
CAF_CHECK(mpx()->has_pending_scribe("jupiter", 8080)); CAF_CHECK(mpx()->has_pending_scribe("jupiter", 8080));
...@@ -831,8 +833,8 @@ CAF_TEST(automatic_connection) { ...@@ -831,8 +833,8 @@ CAF_TEST(automatic_connection) {
no_operation_data, this_node(), jupiter().id, no_operation_data, this_node(), jupiter().id,
invalid_actor_id, jupiter().dummy_actor->id()); invalid_actor_id, jupiter().dummy_actor->id());
CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u); CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u);
CAF_CHECK_EQUAL(tbl().lookup_indirect(jupiter().id), mars().id); CAF_CHECK_EQUAL(tbl().lookup(jupiter().id), mars().id);
CAF_CHECK_EQUAL(tbl().lookup_indirect(mars().id), none); CAF_CHECK_EQUAL(tbl().lookup(mars().id), none);
auto connection_helper_actor = sys.latest_actor_id(); auto connection_helper_actor = sys.latest_actor_id();
CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u); CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u);
// create a dummy config server and respond to the name lookup // create a dummy config server and respond to the name lookup
...@@ -887,5 +889,6 @@ CAF_TEST(automatic_connection) { ...@@ -887,5 +889,6 @@ CAF_TEST(automatic_connection) {
make_message("hello from earth!")); make_message("hello from earth!"));
CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u); CAF_CHECK_EQUAL(mpx()->output_buffer(mars().connection).size(), 0u);
} }
*/
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
...@@ -56,7 +56,7 @@ constexpr uint64_t no_operation_data = 0; ...@@ -56,7 +56,7 @@ constexpr uint64_t no_operation_data = 0;
constexpr auto basp_atom = caf::atom("BASP"); constexpr auto basp_atom = caf::atom("BASP");
constexpr auto spawn_serv_atom = caf::atom("SpawnServ"); constexpr auto spawn_serv_atom = caf::atom("SpawnServ");
constexpr auto config_serv_atom = caf::atom("ConfigServ"); // constexpr auto config_serv_atom = caf::atom("ConfigServ");
} // namespace <anonymous> } // namespace <anonymous>
...@@ -309,10 +309,9 @@ public: ...@@ -309,10 +309,9 @@ public:
make_message(sys_atom::value, get_atom::value, "info")); make_message(sys_atom::value, get_atom::value, "info"));
// test whether basp instance correctly updates the // test whether basp instance correctly updates the
// routing table upon receiving client handshakes // routing table upon receiving client handshakes
auto path = tbl().lookup(n.id); auto ehdl= tbl().lookup(n.id);
CAF_REQUIRE(path); CAF_REQUIRE(ehdl);
CAF_CHECK_EQUAL(path->hdl, n.endpoint); CAF_CHECK_EQUAL(*ehdl, n.endpoint);
CAF_CHECK_EQUAL(path->next_hop, n.id);
} }
std::pair<basp::header, buffer> read_from_out_buf(datagram_handle hdl) { std::pair<basp::header, buffer> read_from_out_buf(datagram_handle hdl) {
...@@ -829,6 +828,7 @@ CAF_TEST(actor_serialize_and_deserialize_udp) { ...@@ -829,6 +828,7 @@ CAF_TEST(actor_serialize_and_deserialize_udp) {
std::vector<actor_id>{}, msg); std::vector<actor_id>{}, msg);
} }
/*
CAF_TEST(indirect_connections_udp) { CAF_TEST(indirect_connections_udp) {
// this node receives a message from jupiter via mars and responds via mars // this node receives a message from jupiter via mars and responds via mars
// and any ad-hoc automatic connection requests are ignored // and any ad-hoc automatic connection requests are ignored
...@@ -878,6 +878,7 @@ CAF_TEST(indirect_connections_udp) { ...@@ -878,6 +878,7 @@ CAF_TEST(indirect_connections_udp) {
std::vector<actor_id>{}, std::vector<actor_id>{},
make_message("hello from earth!")); make_message("hello from earth!"));
} }
*/
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
...@@ -1023,6 +1024,7 @@ CAF_TEST_FIXTURE_SCOPE_END() ...@@ -1023,6 +1024,7 @@ CAF_TEST_FIXTURE_SCOPE_END()
CAF_TEST_FIXTURE_SCOPE(basp_udp_tests_with_autoconn, autoconn_enabled_fixture) CAF_TEST_FIXTURE_SCOPE(basp_udp_tests_with_autoconn, autoconn_enabled_fixture)
/*
CAF_TEST(automatic_connection_udp) { CAF_TEST(automatic_connection_udp) {
// this tells our BASP broker to enable the automatic connection feature // this tells our BASP broker to enable the automatic connection feature
//anon_send(aut(), ok_atom::value, //anon_send(aut(), ok_atom::value,
...@@ -1033,9 +1035,9 @@ CAF_TEST(automatic_connection_udp) { ...@@ -1033,9 +1035,9 @@ CAF_TEST(automatic_connection_udp) {
// but then also establishes a connection to jupiter directly) // but then also establishes a connection to jupiter directly)
auto check_node_in_tbl = [&](node& n) { auto check_node_in_tbl = [&](node& n) {
io::id_visitor id_vis; io::id_visitor id_vis;
auto hdl = tbl().lookup_direct(n.id); auto ehdl = tbl().lookup(n.id);
CAF_REQUIRE(hdl); CAF_REQUIRE(ehdl);
CAF_CHECK_EQUAL(visit(id_vis, *hdl), n.endpoint.id()); CAF_CHECK_EQUAL(visit(id_vis, *ehdl), n.endpoint.id());
}; };
mpx()->provide_datagram_servant("jupiter", 8080, jupiter().endpoint); mpx()->provide_datagram_servant("jupiter", 8080, jupiter().endpoint);
CAF_CHECK(mpx()->has_pending_remote_endpoint("jupiter", 8080)); CAF_CHECK(mpx()->has_pending_remote_endpoint("jupiter", 8080));
...@@ -1142,5 +1144,6 @@ CAF_TEST(automatic_connection_udp) { ...@@ -1142,5 +1144,6 @@ CAF_TEST(automatic_connection_udp) {
make_message("hello from earth!")); make_message("hello from earth!"));
CAF_CHECK_EQUAL(mpx()->output_queue(mars().endpoint).size(), 0u); CAF_CHECK_EQUAL(mpx()->output_queue(mars().endpoint).size(), 0u);
} }
*/
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
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