/* * Copyright (C) 2015 Cloudius Systems, Ltd. */ #pragma once #include "core/reactor.hh" #include "core/iostream.hh" #include "core/distributed.hh" #include "core/print.hh" #include "core/sstring.hh" #include "core/do_with.hh" #include "net/api.hh" #include "utils/serialization.hh" #include "gms/inet_address.hh" #include "rpc/rpc_types.hh" #include #include "frozen_mutation.hh" #include "query-request.hh" #include "db/serializer.hh" #include "mutation_query.hh" // forward declarations namespace streaming { namespace messages { class stream_init_message; class prepare_message; }} namespace gms { class gossip_digest_syn; class gossip_digest_ack; class gossip_digest_ack2; } class frozen_mutation; namespace utils { class UUID; } namespace db { class seed_provider_type; } namespace net { /* All verb handler identifiers */ enum class messaging_verb : int32_t { MUTATION, MUTATION_DONE, BINARY, // Deprecated READ_REPAIR, READ, READ_DATA, READ_MUTATION_DATA, // urchin-only READ_DIGEST, REQUEST_RESPONSE, // client-initiated reads and writes STREAM_INITIATE, // Deprecated STREAM_INITIATE_DONE, // Deprecated STREAM_REPLY, // Deprecated STREAM_REQUEST, // Deprecated RANGE_SLICE, BOOTSTRAP_TOKEN, // Deprecated TREE_REQUEST, // Deprecated TREE_RESPONSE, // Deprecated JOIN, // Deprecated GOSSIP_DIGEST_SYN, GOSSIP_DIGEST_ACK, GOSSIP_DIGEST_ACK2, DEFINITIONS_ANNOUNCE, // Deprecated DEFINITIONS_UPDATE, TRUNCATE, SCHEMA_CHECK, INDEX_SCAN, // Deprecated REPLICATION_FINISHED, INTERNAL_RESPONSE, // responses to internal calls COUNTER_MUTATION, STREAMING_REPAIR_REQUEST, // Deprecated STREAMING_REPAIR_RESPONSE, // Deprecated SNAPSHOT, // Similar to nt snapshot MIGRATION_REQUEST, GOSSIP_SHUTDOWN, _TRACE, ECHO, REPAIR_MESSAGE, PAXOS_PREPARE, PAXOS_PROPOSE, PAXOS_COMMIT, PAGED_RANGE, UNUSED_1, UNUSED_2, UNUSED_3, // Used by streaming STREAM_INIT_MESSAGE, PREPARE_MESSAGE, STREAM_MUTATION, STREAM_MUTATION_DONE, INCOMING_FILE_MESSAGE, OUTGOING_FILE_MESSAGE, RECEIVED_MESSAGE, RETRY_MESSAGE, COMPLETE_MESSAGE, SESSION_FAILED_MESSAGE, LAST, }; } // namespace net namespace std { template <> class hash { public: size_t operator()(const net::messaging_verb& x) const { return hash()(int32_t(x)); } }; } // namespace std namespace net { // NOTE: operator(input_stream&, T&) takes a reference to uninitialized // T object and should use placement new in case T is non POD struct serializer { template inline T read_integral(Input& input) const { static_assert(std::is_integral::value, "T should be integral"); T data; input.read(reinterpret_cast(&data), sizeof(T)); return net::ntoh(data); } template inline void write_integral(Output& output, T data) const { static_assert(std::is_integral::value, "T should be integral"); data = net::hton(data); output.write(reinterpret_cast(&data), sizeof(T)); } // Adaptor for writing objects having db::serializer<> template inline void write_serializable(Output& out, const Serializable& v) const { db::serializer ser(v); bytes b(bytes::initialized_later(), ser.size() + data_output::serialized_size()); data_output d_out(b); d_out.write(ser.size()); ser.write(d_out); return out.write(reinterpret_cast(b.c_str()), b.size()); } // Adaptor for reading objects having db::serializer<> template inline Serializable read_serializable(Input& in) const { auto sz = read_integral(in); bytes data(bytes::initialized_later(), sz); in.read(reinterpret_cast(data.begin()), sz); data_input din(data); return db::serializer::read(din); } // For integer type template bool read(Input& input, rpc::type) const { return read(input, rpc::type()); } template int8_t read(Input& input, rpc::type) const { return read_integral(input); } template uint8_t read(Input& input, rpc::type) const { return read_integral(input); } template int16_t read(Input& input, rpc::type) const { return read_integral(input); } template uint16_t read(Input& input, rpc::type) const { return read_integral(input); } template int32_t read(Input& input, rpc::type) const { return read_integral(input); } template uint32_t read(Input& input, rpc::type) const { return read_integral(input); } template int64_t read(Input& input, rpc::type) const { return read_integral(input); } template uint64_t read(Input& input, rpc::type) const { return read_integral(input); } template void write(Output& output, bool data) const { write(output, uint8_t(data)); } template void write(Output& output, int8_t data) const { write_integral(output, data); } template void write(Output& output, uint8_t data) const { write_integral(output, data); } template void write(Output& output, int16_t data) const { write_integral(output, data); } template void write(Output& output, uint16_t data) const { write_integral(output, data); } template void write(Output& output, int32_t data) const { write_integral(output, data); } template void write(Output& output, uint32_t data) const { write_integral(output, data); } template void write(Output& output, int64_t data) const { write_integral(output, data); } template void write(Output& output, uint64_t data) const { write_integral(output, data); } // For vectors template inline void write(Output& out, const std::vector& v) const { write(out, uint32_t(v.size())); for (auto&& e : v) { write(out, e); } } template inline std::vector read(Input& in, rpc::type>) const { auto sz = read(in, rpc::type()); std::vector v; v.reserve(sz); while (sz--) { v.push_back(read(in, rpc::type())); } return v; } // For messaging_verb template void write(Output& out, messaging_verb v) const { return write(out, std::underlying_type_t(v)); } template messaging_verb operator()(Input& in, rpc::type) const { return messaging_verb(read(in, rpc::type>())); } // For sstring template void write(Output& out, const sstring& v) const { write(out, uint32_t(v.size())); out.write(v.begin(), v.size()); } template void read(Input& in, rpc::type) const { auto sz = read(in, rpc::type()); sstring v(sstring::initialized_later(), sz); in.read(v.begin(), sz); return v; } // For frozen_mutation template void write(Output& out, const frozen_mutation& v) const{ return write_serializable(out, v); } template frozen_mutation read(Input& in, rpc::type) const { return read_serializable(in); } // For reconcilable_result template void write(Output& out, const reconcilable_result& v) const{ return write_serializable(out, v); } template reconcilable_result read(Input& in, rpc::type) const { return read_serializable(in); } // For complex types which have serialize()/deserialize(), e.g. gms::gossip_digest_syn, gms::gossip_digest_ack2 template void write_gms(Output& out, const T& v) const { uint32_t sz = v.serialized_size(); write(out, sz); bytes b(bytes::initialized_later(), sz); auto _out = b.begin(); v.serialize(_out); out.write(reinterpret_cast(b.c_str()), sz); } template T read_gms(Input& in) const { auto sz = read(in, rpc::type()); bytes b(bytes::initialized_later(), sz); in.read(reinterpret_cast(b.begin()), sz); bytes_view bv(b); return T::deserialize(bv); } template void write(Output& out, const gms::gossip_digest_syn& v) const; template gms::gossip_digest_syn read(Input& in, rpc::type) const; template void write(Output& out, const gms::gossip_digest_ack2& v) const; template gms::gossip_digest_ack2 read(Input& in, rpc::type) const; template void write(Output& out, const streaming::messages::stream_init_message& v) const; template streaming::messages::stream_init_message read(Input& in, rpc::type) const; template void write(Output& out, const streaming::messages::prepare_message& v) const; template streaming::messages::prepare_message read(Input& in, rpc::type) const; template void write(Output& out, const gms::inet_address& v) const; template gms::inet_address read(Input& in, rpc::type) const; template void write(Output& out, const gms::gossip_digest_ack& v) const; template gms::gossip_digest_ack read(Input& in, rpc::type) const; template void write(Output& out, const query::read_command& v) const; template query::read_command read(Input& in, rpc::type) const; template void write(Output& out, const query::result& v) const; template query::result read(Input& in, rpc::type) const; template void write(Output& out, const query::result_digest& v) const; template query::result_digest read(Input& in, rpc::type) const; template void write(Output& out, const utils::UUID& v) const; template utils::UUID read(Input& in, rpc::type) const; // for query::range template void write(Output& out, const query::range& v) const; template query::range read(Input& input, rpc::type>) const; template void write(Output& out, const foreign_ptr& v) const { return write(out, *v); } template foreign_ptr read(Input& in, rpc::type>) const { return make_foreign(read(in, rpc::type())); } template void write(Output& out, const lw_shared_ptr& v) const { return write(out, *v); } template lw_shared_ptr read(Input& in, rpc::type>) const { return make_lw_shared(read(in, rpc::type())); } }; // thunk from new-style free function serialization to old-style member function template inline void write(serializer s, Output& out, const T& data) { s.write(out, data); } template inline T read(serializer s, Input& in, rpc::type type) { return s.read(in, type); } struct shard_id { gms::inet_address addr; uint32_t cpu_id; friend bool operator==(const shard_id& x, const shard_id& y); friend bool operator<(const shard_id& x, const shard_id& y); friend std::ostream& operator<<(std::ostream& os, const shard_id& x); struct hash { size_t operator()(const shard_id& id) const; }; }; class messaging_service { public: using shard_id = net::shard_id; using inet_address = gms::inet_address; using UUID = utils::UUID; struct rpc_protocol_wrapper; struct rpc_protocol_client_wrapper; struct rpc_protocol_server_wrapper; // FIXME: messaging service versioning static constexpr int32_t current_version = 0; struct shard_info { shard_info(std::unique_ptr&& client); std::unique_ptr rpc_client; rpc::stats get_stats() const; }; void foreach_client(std::function f) const; void increment_dropped_messages(messaging_verb verb); uint64_t get_dropped_messages(messaging_verb verb) const; const uint64_t* get_dropped_messages() const; int32_t get_raw_version(const gms::inet_address& endpoint) const; bool knows_version(const gms::inet_address& endpoint) const; private: static constexpr uint16_t _default_port = 7000; gms::inet_address _listen_address; uint16_t _port; std::unique_ptr _rpc; std::unique_ptr _server; std::unordered_map _clients; uint64_t _dropped_messages[static_cast(messaging_verb::LAST)] = {}; public: messaging_service(gms::inet_address ip = gms::inet_address("0.0.0.0")); ~messaging_service(); public: uint16_t port(); gms::inet_address listen_address(); future<> stop(); static rpc::no_wait_type no_wait(); public: // Wrapper for STREAM_INIT_MESSAGE verb void register_stream_init_message(std::function (streaming::messages::stream_init_message msg, unsigned src_cpu_id)>&& func); future send_stream_init_message(shard_id id, streaming::messages::stream_init_message msg, unsigned src_cpu_id); // Wrapper for PREPARE_MESSAGE verb void register_prepare_message(std::function (streaming::messages::prepare_message msg, UUID plan_id, inet_address from, inet_address connecting, unsigned src_cpu_id, unsigned dst_cpu_id)>&& func); future 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); // Wrapper for STREAM_MUTATION verb void register_stream_mutation(std::function (UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id)>&& func); future<> send_stream_mutation(shard_id id, UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id); void register_stream_mutation_done(std::function (UUID plan_id, UUID cf_id, inet_address from, inet_address connecting, unsigned dst_cpu_id)>&& func); future<> send_stream_mutation_done(shard_id id, UUID plan_id, UUID cf_id, inet_address from, inet_address connecting, unsigned dst_cpu_id); void register_complete_message(std::function&& func); future<> send_complete_message(shard_id id, UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id); // Wrapper for ECHO verb void register_echo(std::function ()>&& func); future<> send_echo(shard_id id); // Wrapper for GOSSIP_SHUTDOWN void register_gossip_shutdown(std::function&& func); future<> send_gossip_shutdown(shard_id id, inet_address from); // Wrapper for GOSSIP_DIGEST_SYN void register_gossip_digest_syn(std::function (gms::gossip_digest_syn)>&& func); future send_gossip_digest_syn(shard_id id, gms::gossip_digest_syn msg); // Wrapper for GOSSIP_DIGEST_ACK2 void register_gossip_digest_ack2(std::function&& func); future<> send_gossip_digest_ack2(shard_id id, gms::gossip_digest_ack2 msg); // Wrapper for DEFINITIONS_UPDATE void register_definitions_update(std::function fm)>&& func); future<> send_definitions_update(shard_id id, std::vector fm); // Wrapper for MIGRATION_REQUEST void register_migration_request(std::function> (gms::inet_address reply_to, unsigned shard)>&& func); future> send_migration_request(shard_id id, gms::inet_address reply_to, unsigned shard); // FIXME: response_id_type is an alias in service::storage_proxy::response_id_type using response_id_type = uint64_t; // Wrapper for MUTATION void register_mutation(std::function forward, inet_address reply_to, unsigned shard, response_id_type response_id)>&& func); future<> send_mutation(shard_id id, const frozen_mutation& fm, std::vector forward, inet_address reply_to, unsigned shard, response_id_type response_id); // Wrapper for MUTATION_DONE void register_mutation_done(std::function&& func); future<> send_mutation_done(shard_id id, unsigned shard, response_id_type response_id); // Wrapper for READ_DATA // Note: WTH is future> void register_read_data(std::function>> (query::read_command cmd, query::partition_range pr)>&& func); future send_read_data(shard_id id, query::read_command& cmd, query::partition_range& pr); // Wrapper for READ_MUTATION_DATA void register_read_mutation_data(std::function>> (query::read_command cmd, query::partition_range pr)>&& func); future send_read_mutation_data(shard_id id, query::read_command& cmd, query::partition_range& pr); // Wrapper for READ_DIGEST void register_read_digest(std::function (query::read_command cmd, query::partition_range pr)>&& func); future send_read_digest(shard_id id, query::read_command& cmd, query::partition_range& pr); public: // Return rpc::protocol::client for a shard which is a ip + cpuid pair. rpc_protocol_client_wrapper& get_rpc_client(shard_id id); void remove_rpc_client(shard_id id); std::unique_ptr& rpc(); }; extern distributed _the_messaging_service; inline distributed& get_messaging_service() { return _the_messaging_service; } inline messaging_service& get_local_messaging_service() { return _the_messaging_service.local(); } future<> init_messaging_service(sstring listen_address, db::seed_provider_type seed_provider); } // namespace net