448 lines
19 KiB
C++
448 lines
19 KiB
C++
/*
|
|
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#include "message/messaging_service.hh"
|
|
#include "core/distributed.hh"
|
|
#include "gms/failure_detector.hh"
|
|
#include "gms/gossiper.hh"
|
|
#include "service/storage_service.hh"
|
|
#include "streaming/messages/stream_init_message.hh"
|
|
#include "streaming/messages/prepare_message.hh"
|
|
#include "gms/gossip_digest_syn.hh"
|
|
#include "gms/gossip_digest_ack.hh"
|
|
#include "gms/gossip_digest_ack2.hh"
|
|
#include "query-request.hh"
|
|
#include "query-result.hh"
|
|
#include "rpc/rpc.hh"
|
|
#include "db/config.hh"
|
|
|
|
namespace net {
|
|
|
|
using inet_address = gms::inet_address;
|
|
using gossip_digest_syn = gms::gossip_digest_syn;
|
|
using gossip_digest_ack = gms::gossip_digest_ack;
|
|
using gossip_digest_ack2 = gms::gossip_digest_ack2;
|
|
using rpc_protocol = rpc::protocol<serializer, messaging_verb>;
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const gms::gossip_digest_syn& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
gms::gossip_digest_syn net::serializer::read(Input& in, rpc::type<gms::gossip_digest_syn>) const {
|
|
return read_gms<gms::gossip_digest_syn>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const gms::gossip_digest_ack2& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
gms::gossip_digest_ack2 net::serializer::read(Input& in, rpc::type<gms::gossip_digest_ack2>) const {
|
|
return read_gms<gms::gossip_digest_ack2>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const streaming::messages::stream_init_message& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
streaming::messages::stream_init_message net::serializer::read(Input& in, rpc::type<streaming::messages::stream_init_message>) const {
|
|
return read_gms<streaming::messages::stream_init_message>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const streaming::messages::prepare_message& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
streaming::messages::prepare_message net::serializer::read(Input& in, rpc::type<streaming::messages::prepare_message>) const {
|
|
return read_gms<streaming::messages::prepare_message>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const gms::inet_address& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
gms::inet_address net::serializer::read(Input& in, rpc::type<gms::inet_address>) const {
|
|
return read_gms<gms::inet_address>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const gms::gossip_digest_ack& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
gms::gossip_digest_ack net::serializer::read(Input& in, rpc::type<gms::gossip_digest_ack>) const {
|
|
return read_gms<gms::gossip_digest_ack>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const query::read_command& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
query::read_command net::serializer::read(Input& in, rpc::type<query::read_command>) const {
|
|
return read_gms<query::read_command>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const query::result& v) const {
|
|
// FIXME: allow const call to query::result::serialize()
|
|
uint32_t sz = v.serialized_size();
|
|
write(out, sz);
|
|
bytes b(bytes::initialized_later(), sz);
|
|
auto _out = b.begin();
|
|
const_cast<query::result&>(v).serialize(_out);
|
|
out.write(reinterpret_cast<const char*>(b.c_str()), sz);
|
|
}
|
|
template <typename Input>
|
|
query::result net::serializer::read(Input& in, rpc::type<query::result>) const {
|
|
return read_gms<query::result>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const query::result_digest& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
query::result_digest net::serializer::read(Input& in, rpc::type<query::result_digest>) const {
|
|
return read_gms<query::result_digest>(in);
|
|
}
|
|
|
|
template <typename Output>
|
|
void net::serializer::write(Output& out, const utils::UUID& v) const {
|
|
return write_gms(out, v);
|
|
}
|
|
template <typename Input>
|
|
utils::UUID net::serializer::read(Input& in, rpc::type<utils::UUID>) const {
|
|
return read_gms<utils::UUID>(in);
|
|
}
|
|
|
|
// for query::range<T>
|
|
template <typename Output, typename T>
|
|
void net::serializer::write(Output& out, const query::range<T>& v) const {
|
|
write_gms(out, v);
|
|
}
|
|
template <typename Input, typename T>
|
|
query::range<T> net::serializer::read(Input& in, rpc::type<query::range<T>>) const {
|
|
return read_gms<query::range<T>>(in);
|
|
}
|
|
|
|
struct messaging_service::rpc_protocol_wrapper : public rpc_protocol { using rpc_protocol::rpc_protocol; };
|
|
struct messaging_service::rpc_protocol_client_wrapper : public rpc_protocol::client { using rpc_protocol::client::client; };
|
|
struct messaging_service::rpc_protocol_server_wrapper : public rpc_protocol::server { using rpc_protocol::server::server; };
|
|
|
|
|
|
constexpr int32_t messaging_service::current_version;
|
|
|
|
distributed<messaging_service> _the_messaging_service;
|
|
|
|
future<> deinit_messaging_service() {
|
|
return gms::get_gossiper().stop().then([] {
|
|
return gms::get_failure_detector().stop();
|
|
}).then([] {
|
|
return net::get_messaging_service().stop();
|
|
}).then([]{
|
|
return service::deinit_storage_service();
|
|
});
|
|
}
|
|
|
|
future<> init_messaging_service(sstring listen_address, db::seed_provider_type seed_provider) {
|
|
const gms::inet_address listen(listen_address);
|
|
std::set<gms::inet_address> seeds;
|
|
if (seed_provider.parameters.count("seeds") > 0) {
|
|
size_t begin = 0;
|
|
size_t next = 0;
|
|
sstring& seeds_str = seed_provider.parameters.find("seeds")->second;
|
|
while (begin < seeds_str.length() && begin != (next=seeds_str.find(",",begin))) {
|
|
seeds.emplace(gms::inet_address(seeds_str.substr(begin,next-begin)));
|
|
begin = next+1;
|
|
}
|
|
}
|
|
if (seeds.empty()) {
|
|
seeds.emplace(gms::inet_address("127.0.0.1"));
|
|
}
|
|
|
|
engine().at_exit([]{
|
|
return deinit_messaging_service();
|
|
});
|
|
|
|
return net::get_messaging_service().start(listen).then([seeds] {
|
|
auto& ms = net::get_local_messaging_service();
|
|
print("Messaging server listening on ip %s port %d ...\n", ms.listen_address(), ms.port());
|
|
return gms::get_failure_detector().start().then([seeds] {
|
|
return gms::get_gossiper().start().then([seeds] {
|
|
auto& gossiper = gms::get_local_gossiper();
|
|
gossiper.set_seeds(seeds);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
bool operator==(const shard_id& x, const shard_id& y) {
|
|
return x.addr == y.addr && x.cpu_id == y.cpu_id ;
|
|
}
|
|
|
|
bool operator<(const shard_id& x, const shard_id& y) {
|
|
if (x.addr < y.addr) {
|
|
return true;
|
|
} else if (y.addr < x.addr) {
|
|
return false;
|
|
} else {
|
|
return x.cpu_id < y.cpu_id;
|
|
}
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const shard_id& x) {
|
|
return os << x.addr << ":" << x.cpu_id;
|
|
}
|
|
|
|
size_t shard_id::hash::operator()(const shard_id& id) const {
|
|
return std::hash<uint32_t>()(id.cpu_id) + std::hash<uint32_t>()(id.addr.raw_addr());
|
|
}
|
|
|
|
messaging_service::shard_info::shard_info(std::unique_ptr<rpc_protocol_client_wrapper>&& client)
|
|
: rpc_client(std::move(client)) {
|
|
}
|
|
|
|
rpc::stats messaging_service::shard_info::get_stats() const {
|
|
return rpc_client->get_stats();
|
|
}
|
|
|
|
void messaging_service::foreach_client(std::function<void(const shard_id& id, const shard_info& info)> f) const {
|
|
for (auto i = _clients.cbegin(); i != _clients.cend(); i++) {
|
|
f(i->first, i->second);
|
|
}
|
|
}
|
|
|
|
void messaging_service::increment_dropped_messages(messaging_verb verb) {
|
|
_dropped_messages[static_cast<int32_t>(verb)]++;
|
|
}
|
|
|
|
uint64_t messaging_service::get_dropped_messages(messaging_verb verb) const {
|
|
return _dropped_messages[static_cast<int32_t>(verb)];
|
|
}
|
|
|
|
const uint64_t* messaging_service::get_dropped_messages() const {
|
|
return _dropped_messages;
|
|
}
|
|
|
|
int32_t messaging_service::get_raw_version(const gms::inet_address& endpoint) const {
|
|
// FIXME: messaging service versioning
|
|
return current_version;
|
|
}
|
|
|
|
bool messaging_service::knows_version(const gms::inet_address& endpoint) const {
|
|
// FIXME: messaging service versioning
|
|
return true;
|
|
}
|
|
|
|
messaging_service::messaging_service(gms::inet_address ip)
|
|
: _listen_address(ip)
|
|
, _port(_default_port)
|
|
, _rpc(new rpc_protocol_wrapper(serializer{}))
|
|
, _server(new rpc_protocol_server_wrapper(*_rpc, ipv4_addr{_listen_address.raw_addr(), _port})) {
|
|
}
|
|
|
|
messaging_service::~messaging_service() = default;
|
|
|
|
uint16_t messaging_service::port() {
|
|
return _port;
|
|
}
|
|
|
|
gms::inet_address messaging_service::listen_address() {
|
|
return _listen_address;
|
|
}
|
|
|
|
future<> messaging_service::stop() {
|
|
return when_all(_server->stop(),
|
|
parallel_for_each(_clients, [](std::pair<const shard_id, shard_info>& c) {
|
|
return c.second.rpc_client->stop();
|
|
})
|
|
).discard_result();
|
|
}
|
|
|
|
rpc::no_wait_type messaging_service::no_wait() {
|
|
return rpc::no_wait;
|
|
}
|
|
|
|
messaging_service::rpc_protocol_client_wrapper& messaging_service::get_rpc_client(shard_id id) {
|
|
auto it = _clients.find(id);
|
|
if (it == _clients.end()) {
|
|
auto remote_addr = ipv4_addr(id.addr.raw_addr(), _port);
|
|
auto client = std::make_unique<rpc_protocol_client_wrapper>(*_rpc, remote_addr, ipv4_addr{_listen_address.raw_addr(), 0});
|
|
it = _clients.emplace(id, shard_info(std::move(client))).first;
|
|
return *it->second.rpc_client;
|
|
} else {
|
|
return *it->second.rpc_client;
|
|
}
|
|
}
|
|
|
|
void messaging_service::remove_rpc_client(shard_id id) {
|
|
_clients.erase(id);
|
|
}
|
|
|
|
std::unique_ptr<messaging_service::rpc_protocol_wrapper>& messaging_service::rpc() {
|
|
return _rpc;
|
|
}
|
|
|
|
// Register a handler (a callback lambda) for verb
|
|
template <typename Func>
|
|
void register_handler(messaging_service* ms, messaging_verb verb, Func&& func) {
|
|
ms->rpc()->register_handler(verb, std::move(func));
|
|
}
|
|
|
|
// Send a message for verb
|
|
template <typename MsgIn, typename... MsgOut>
|
|
auto send_message(messaging_service* ms, messaging_verb verb, shard_id id, MsgOut&&... msg) {
|
|
auto& rpc_client = ms->get_rpc_client(id);
|
|
auto rpc_handler = ms->rpc()->make_client<MsgIn(MsgOut...)>(verb);
|
|
return rpc_handler(rpc_client, std::forward<MsgOut>(msg)...).then_wrapped([ms, id, verb] (auto&& f) {
|
|
try {
|
|
if (f.failed()) {
|
|
ms->increment_dropped_messages(verb);
|
|
f.get();
|
|
assert(false); // never reached
|
|
}
|
|
return std::move(f);
|
|
} catch (rpc::closed_error) {
|
|
// This is a transport error
|
|
ms->remove_rpc_client(id);
|
|
throw;
|
|
} catch (...) {
|
|
// This is expected to be a rpc server error, e.g., the rpc handler throws a std::runtime_error.
|
|
throw;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Send one way message for verb
|
|
template <typename... MsgOut>
|
|
auto send_message_oneway(messaging_service* ms, messaging_verb verb, shard_id id, MsgOut&&... msg) {
|
|
return send_message<rpc::no_wait_type>(ms, std::move(verb), std::move(id), std::forward<MsgOut>(msg)...);
|
|
}
|
|
|
|
// Wrappers for verbs
|
|
void messaging_service::register_stream_init_message(std::function<future<unsigned> (streaming::messages::stream_init_message msg, unsigned src_cpu_id)>&& func) {
|
|
register_handler(this, messaging_verb::STREAM_INIT_MESSAGE, std::move(func));
|
|
}
|
|
future<unsigned> messaging_service::send_stream_init_message(shard_id id, streaming::messages::stream_init_message msg, unsigned src_cpu_id) {
|
|
return send_message<unsigned>(this, messaging_verb::STREAM_INIT_MESSAGE, std::move(id), std::move(msg), std::move(src_cpu_id));
|
|
}
|
|
|
|
void messaging_service::register_prepare_message(std::function<future<streaming::messages::prepare_message> (streaming::messages::prepare_message msg, UUID plan_id,
|
|
inet_address from, inet_address connecting, unsigned src_cpu_id, unsigned dst_cpu_id)>&& func) {
|
|
register_handler(this, messaging_verb::PREPARE_MESSAGE, std::move(func));
|
|
}
|
|
future<streaming::messages::prepare_message> messaging_service::send_prepare_message(shard_id id, streaming::messages::prepare_message msg, UUID plan_id,
|
|
inet_address from, inet_address connecting, unsigned src_cpu_id, unsigned dst_cpu_id) {
|
|
return send_message<streaming::messages::prepare_message>(this, messaging_verb::PREPARE_MESSAGE, std::move(id), std::move(msg),
|
|
std::move(plan_id), std::move(from), std::move(connecting), std::move(src_cpu_id), std::move(dst_cpu_id));
|
|
}
|
|
|
|
void messaging_service::register_stream_mutation(std::function<future<> (UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id)>&& func) {
|
|
register_handler(this, messaging_verb::STREAM_MUTATION, std::move(func));
|
|
}
|
|
future<> messaging_service::send_stream_mutation(shard_id id, UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id) {
|
|
return send_message<void>(this, messaging_verb::STREAM_MUTATION, std::move(id), std::move(plan_id), std::move(fm), std::move(dst_cpu_id));
|
|
}
|
|
|
|
void messaging_service::register_stream_mutation_done(std::function<future<> (UUID plan_id, UUID cf_id, inet_address from, inet_address connecting, unsigned dst_cpu_id)>&& func) {
|
|
register_handler(this, messaging_verb::STREAM_MUTATION_DONE, std::move(func));
|
|
}
|
|
future<> messaging_service::send_stream_mutation_done(shard_id id, UUID plan_id, UUID cf_id, inet_address from, inet_address connecting, unsigned dst_cpu_id) {
|
|
return send_message<void>(this, messaging_verb::STREAM_MUTATION_DONE, std::move(id), std::move(plan_id), std::move(cf_id), std::move(from), std::move(connecting), std::move(dst_cpu_id));
|
|
}
|
|
|
|
void messaging_service::register_complete_message(std::function<rpc::no_wait_type (UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id)>&& func) {
|
|
register_handler(this, messaging_verb::COMPLETE_MESSAGE, std::move(func));
|
|
}
|
|
future<> messaging_service::send_complete_message(shard_id id, UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id) {
|
|
return send_message_oneway(this, messaging_verb::COMPLETE_MESSAGE, std::move(id), std::move(plan_id), std::move(from), std::move(connecting), std::move(dst_cpu_id));
|
|
}
|
|
|
|
void messaging_service::register_echo(std::function<future<> ()>&& func) {
|
|
register_handler(this, messaging_verb::ECHO, std::move(func));
|
|
}
|
|
future<> messaging_service::send_echo(shard_id id) {
|
|
return send_message<void>(this, messaging_verb::ECHO, std::move(id));
|
|
}
|
|
|
|
void messaging_service::register_gossip_shutdown(std::function<rpc::no_wait_type (inet_address from)>&& func) {
|
|
register_handler(this, messaging_verb::GOSSIP_SHUTDOWN, std::move(func));
|
|
}
|
|
future<> messaging_service::send_gossip_shutdown(shard_id id, inet_address from) {
|
|
return send_message_oneway(this, messaging_verb::GOSSIP_SHUTDOWN, std::move(id), std::move(from));
|
|
}
|
|
|
|
void messaging_service::register_gossip_digest_syn(std::function<future<gossip_digest_ack> (gossip_digest_syn)>&& func) {
|
|
register_handler(this, messaging_verb::GOSSIP_DIGEST_SYN, std::move(func));
|
|
}
|
|
future<gossip_digest_ack> messaging_service::send_gossip_digest_syn(shard_id id, gossip_digest_syn msg) {
|
|
return send_message<gossip_digest_ack>(this, messaging_verb::GOSSIP_DIGEST_SYN, std::move(id), std::move(msg));
|
|
}
|
|
|
|
void messaging_service::register_gossip_digest_ack2(std::function<rpc::no_wait_type (gossip_digest_ack2)>&& func) {
|
|
register_handler(this, messaging_verb::GOSSIP_DIGEST_ACK2, std::move(func));
|
|
}
|
|
future<> messaging_service::send_gossip_digest_ack2(shard_id id, gossip_digest_ack2 msg) {
|
|
return send_message_oneway(this, messaging_verb::GOSSIP_DIGEST_ACK2, std::move(id), std::move(msg));
|
|
}
|
|
|
|
void messaging_service::register_definitions_update(std::function<rpc::no_wait_type (std::vector<frozen_mutation> fm)>&& func) {
|
|
register_handler(this, net::messaging_verb::DEFINITIONS_UPDATE, std::move(func));
|
|
}
|
|
future<> messaging_service::send_definitions_update(shard_id id, std::vector<frozen_mutation> fm) {
|
|
return send_message_oneway(this, messaging_verb::DEFINITIONS_UPDATE, std::move(id), std::move(fm));
|
|
}
|
|
|
|
void messaging_service::register_migration_request(std::function<future<std::vector<frozen_mutation>> (gms::inet_address reply_to, unsigned shard)>&& func) {
|
|
register_handler(this, net::messaging_verb::MIGRATION_REQUEST, std::move(func));
|
|
}
|
|
future<std::vector<frozen_mutation>> messaging_service::send_migration_request(shard_id id, gms::inet_address reply_to, unsigned shard) {
|
|
return send_message<std::vector<frozen_mutation>>(this, messaging_verb::MIGRATION_REQUEST, std::move(id), std::move(reply_to), std::move(shard));
|
|
}
|
|
|
|
void messaging_service::register_mutation(std::function<rpc::no_wait_type (frozen_mutation fm, std::vector<inet_address> forward,
|
|
inet_address reply_to, unsigned shard, response_id_type response_id)>&& func) {
|
|
register_handler(this, net::messaging_verb::MUTATION, std::move(func));
|
|
}
|
|
future<> messaging_service::send_mutation(shard_id id, const frozen_mutation& fm, std::vector<inet_address> forward,
|
|
inet_address reply_to, unsigned shard, response_id_type response_id) {
|
|
return send_message_oneway(this, messaging_verb::MUTATION, std::move(id), fm, std::move(forward),
|
|
std::move(reply_to), std::move(shard), std::move(response_id));
|
|
}
|
|
|
|
void messaging_service::register_mutation_done(std::function<rpc::no_wait_type (const rpc::client_info& cinfo, unsigned shard, response_id_type response_id)>&& func) {
|
|
register_handler(this, net::messaging_verb::MUTATION_DONE, std::move(func));
|
|
}
|
|
future<> messaging_service::send_mutation_done(shard_id id, unsigned shard, response_id_type response_id) {
|
|
return send_message_oneway(this, messaging_verb::MUTATION_DONE, std::move(id), std::move(shard), std::move(response_id));
|
|
}
|
|
|
|
void messaging_service::register_read_data(std::function<future<foreign_ptr<lw_shared_ptr<query::result>>> (query::read_command cmd, query::partition_range pr)>&& func) {
|
|
register_handler(this, net::messaging_verb::READ_DATA, std::move(func));
|
|
}
|
|
future<query::result> messaging_service::send_read_data(shard_id id, query::read_command& cmd, query::partition_range& pr) {
|
|
return send_message<query::result>(this, messaging_verb::READ_DATA, std::move(id), cmd, pr);
|
|
}
|
|
|
|
void messaging_service::register_read_mutation_data(std::function<future<foreign_ptr<lw_shared_ptr<reconcilable_result>>> (query::read_command cmd, query::partition_range pr)>&& func) {
|
|
register_handler(this, net::messaging_verb::READ_MUTATION_DATA, std::move(func));
|
|
}
|
|
future<reconcilable_result> messaging_service::send_read_mutation_data(shard_id id, query::read_command& cmd, query::partition_range& pr) {
|
|
return send_message<reconcilable_result>(this, messaging_verb::READ_MUTATION_DATA, std::move(id), cmd, pr);
|
|
}
|
|
|
|
void messaging_service::register_read_digest(std::function<future<query::result_digest> (query::read_command cmd, query::partition_range pr)>&& func) {
|
|
register_handler(this, net::messaging_verb::READ_DIGEST, std::move(func));
|
|
}
|
|
future<query::result_digest> messaging_service::send_read_digest(shard_id id, query::read_command& cmd, query::partition_range& pr) {
|
|
return send_message<query::result_digest>(this, net::messaging_verb::READ_DIGEST, std::move(id), cmd, pr);
|
|
}
|
|
|
|
} // namespace net
|