/* * Copyright (C) 2015 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #pragma once #include "messaging_service_fwd.hh" #include "core/reactor.hh" #include "core/distributed.hh" #include "core/sstring.hh" #include "gms/inet_address.hh" #include "rpc/rpc_types.hh" #include #include "query-request.hh" #include "mutation_query.hh" #include "range.hh" #include "repair/repair.hh" #include "tracing/tracing.hh" #include "digest_algorithm.hh" #include // forward declarations namespace streaming { class prepare_message; } namespace gms { class gossip_digest_syn; class gossip_digest_ack; class gossip_digest_ack2; } namespace utils { class UUID; } namespace db { class seed_provider_type; } class frozen_mutation; class frozen_schema; class partition_checksum; namespace dht { class token; } namespace query { using partition_range = dht::partition_range; class read_command; class result; } namespace compat { using wrapping_partition_range = wrapping_range; } namespace netw { /* All verb handler identifiers */ enum class messaging_verb : int32_t { CLIENT_ID = 0, MUTATION = 1, MUTATION_DONE = 2, READ_DATA = 3, READ_MUTATION_DATA = 4, READ_DIGEST = 5, // Used by gossip GOSSIP_DIGEST_SYN = 6, GOSSIP_DIGEST_ACK = 7, GOSSIP_DIGEST_ACK2 = 8, GOSSIP_ECHO = 9, GOSSIP_SHUTDOWN = 10, // end of gossip verb DEFINITIONS_UPDATE = 11, TRUNCATE = 12, REPLICATION_FINISHED = 13, MIGRATION_REQUEST = 14, // Used by streaming PREPARE_MESSAGE = 15, PREPARE_DONE_MESSAGE = 16, STREAM_MUTATION = 17, STREAM_MUTATION_DONE = 18, COMPLETE_MESSAGE = 19, // end of streaming verbs REPAIR_CHECKSUM_RANGE = 20, GET_SCHEMA_VERSION = 21, SCHEMA_CHECK = 22, COUNTER_MUTATION = 23, LAST = 24, }; } // namespace netw namespace std { template <> class hash { public: size_t operator()(const netw::messaging_verb& x) const { return hash()(int32_t(x)); } }; } // namespace std namespace netw { struct serializer {}; struct msg_addr { gms::inet_address addr; uint32_t cpu_id; friend bool operator==(const msg_addr& x, const msg_addr& y); friend bool operator<(const msg_addr& x, const msg_addr& y); friend std::ostream& operator<<(std::ostream& os, const msg_addr& x); struct hash { size_t operator()(const msg_addr& id) const; }; }; class messaging_service : public seastar::async_sharded_service { public: struct rpc_protocol_wrapper; struct rpc_protocol_client_wrapper; struct rpc_protocol_server_wrapper; struct shard_info; using msg_addr = netw::msg_addr; using inet_address = gms::inet_address; using UUID = utils::UUID; using clients_map = std::unordered_map; // This should change only if serialization format changes static constexpr int32_t current_version = 0; struct shard_info { shard_info(shared_ptr&& client); shared_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; enum class encrypt_what { none, rack, dc, all, }; enum class compress_what { none, dc, all, }; enum class tcp_nodelay_what { local, all, }; private: gms::inet_address _listen_address; uint16_t _port; uint16_t _ssl_port; encrypt_what _encrypt_what; compress_what _compress_what; tcp_nodelay_what _tcp_nodelay_what; bool _should_listen_to_broadcast_address; // map: Node broadcast address -> Node internal IP for communication within the same data center std::unordered_map _preferred_ip_cache; std::unique_ptr _rpc; std::array, 2> _server; ::shared_ptr _credentials; std::array, 2> _server_tls; std::array _clients; uint64_t _dropped_messages[static_cast(messaging_verb::LAST)] = {}; bool _stopping = false; std::list> _connection_drop_notifiers; public: using clock_type = lowres_clock; public: messaging_service(gms::inet_address ip = gms::inet_address("0.0.0.0"), uint16_t port = 7000, bool listen_now = true); messaging_service(gms::inet_address ip, uint16_t port, encrypt_what, compress_what, tcp_nodelay_what, uint16_t ssl_port, std::shared_ptr, bool sltba = false, bool listen_now = true); ~messaging_service(); public: void start_listen(); uint16_t port(); gms::inet_address listen_address(); future<> stop_tls_server(); future<> stop_nontls_server(); future<> stop_client(); future<> stop(); static rpc::no_wait_type no_wait(); bool is_stopping() { return _stopping; } public: gms::inet_address get_preferred_ip(gms::inet_address ep); future<> init_local_preferred_ip_cache(); void cache_preferred_ip(gms::inet_address ep, gms::inet_address ip); // Wrapper for PREPARE_MESSAGE verb void register_prepare_message(std::function (const rpc::client_info& cinfo, streaming::prepare_message msg, UUID plan_id, sstring description)>&& func); future send_prepare_message(msg_addr id, streaming::prepare_message msg, UUID plan_id, sstring description); // Wrapper for PREPARE_DONE_MESSAGE verb void register_prepare_done_message(std::function (const rpc::client_info& cinfo, UUID plan_id, unsigned dst_cpu_id)>&& func); future<> send_prepare_done_message(msg_addr id, UUID plan_id, unsigned dst_cpu_id); // Wrapper for STREAM_MUTATION verb void register_stream_mutation(std::function (const rpc::client_info& cinfo, UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id, rpc::optional)>&& func); future<> send_stream_mutation(msg_addr id, UUID plan_id, frozen_mutation fm, unsigned dst_cpu_id, bool fragmented); void register_stream_mutation_done(std::function (const rpc::client_info& cinfo, UUID plan_id, dht::token_range_vector ranges, UUID cf_id, unsigned dst_cpu_id)>&& func); future<> send_stream_mutation_done(msg_addr id, UUID plan_id, dht::token_range_vector ranges, UUID cf_id, unsigned dst_cpu_id); void register_complete_message(std::function (const rpc::client_info& cinfo, UUID plan_id, unsigned dst_cpu_id, rpc::optional failed)>&& func); future<> send_complete_message(msg_addr id, UUID plan_id, unsigned dst_cpu_id, bool failed = false); // Wrapper for REPAIR_CHECKSUM_RANGE verb void register_repair_checksum_range(std::function (sstring keyspace, sstring cf, dht::token_range range, rpc::optional hash_version)>&& func); void unregister_repair_checksum_range(); future send_repair_checksum_range(msg_addr id, sstring keyspace, sstring cf, dht::token_range range, repair_checksum hash_version); // Wrapper for GOSSIP_ECHO verb void register_gossip_echo(std::function ()>&& func); void unregister_gossip_echo(); future<> send_gossip_echo(msg_addr id); // Wrapper for GOSSIP_SHUTDOWN void register_gossip_shutdown(std::function&& func); void unregister_gossip_shutdown(); future<> send_gossip_shutdown(msg_addr id, inet_address from); // Wrapper for GOSSIP_DIGEST_SYN void register_gossip_digest_syn(std::function&& func); void unregister_gossip_digest_syn(); future<> send_gossip_digest_syn(msg_addr id, gms::gossip_digest_syn msg); // Wrapper for GOSSIP_DIGEST_ACK void register_gossip_digest_ack(std::function&& func); void unregister_gossip_digest_ack(); future<> send_gossip_digest_ack(msg_addr id, gms::gossip_digest_ack msg); // Wrapper for GOSSIP_DIGEST_ACK2 void register_gossip_digest_ack2(std::function&& func); void unregister_gossip_digest_ack2(); future<> send_gossip_digest_ack2(msg_addr id, gms::gossip_digest_ack2 msg); // Wrapper for DEFINITIONS_UPDATE void register_definitions_update(std::function fm)>&& func); void unregister_definitions_update(); future<> send_definitions_update(msg_addr id, std::vector fm); // Wrapper for MIGRATION_REQUEST void register_migration_request(std::function> (const rpc::client_info&)>&& func); void unregister_migration_request(); future> send_migration_request(msg_addr id); // 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 (const rpc::client_info&, rpc::opt_time_point, frozen_mutation fm, std::vector forward, inet_address reply_to, unsigned shard, response_id_type response_id, rpc::optional> trace_info)>&& func); void unregister_mutation(); future<> send_mutation(msg_addr id, clock_type::time_point timeout, const frozen_mutation& fm, std::vector forward, inet_address reply_to, unsigned shard, response_id_type response_id, std::experimental::optional trace_info = std::experimental::nullopt); // Wrapper for COUNTER_MUTATION void register_counter_mutation(std::function (const rpc::client_info&, rpc::opt_time_point, std::vector fms, db::consistency_level cl, stdx::optional trace_info)>&& func); void unregister_counter_mutation(); future<> send_counter_mutation(msg_addr id, clock_type::time_point timeout, std::vector fms, db::consistency_level cl, stdx::optional trace_info = std::experimental::nullopt); // Wrapper for MUTATION_DONE void register_mutation_done(std::function (const rpc::client_info& cinfo, unsigned shard, response_id_type response_id)>&& func); void unregister_mutation_done(); future<> send_mutation_done(msg_addr id, unsigned shard, response_id_type response_id); // Wrapper for READ_DATA // Note: WTH is future> void register_read_data(std::function>, cache_temperature> (const rpc::client_info&, query::read_command cmd, compat::wrapping_partition_range pr, rpc::optional digest)>&& func); void unregister_read_data(); future> send_read_data(msg_addr id, clock_type::time_point timeout, const query::read_command& cmd, const dht::partition_range& pr, query::digest_algorithm da); // Wrapper for GET_SCHEMA_VERSION void register_get_schema_version(std::function(unsigned, table_schema_version)>&& func); void unregister_get_schema_version(); future send_get_schema_version(msg_addr, table_schema_version); // Wrapper for SCHEMA_CHECK void register_schema_check(std::function()>&& func); void unregister_schema_check(); future send_schema_check(msg_addr); // Wrapper for READ_MUTATION_DATA void register_read_mutation_data(std::function>, cache_temperature> (const rpc::client_info&, query::read_command cmd, compat::wrapping_partition_range pr)>&& func); void unregister_read_mutation_data(); future> send_read_mutation_data(msg_addr id, clock_type::time_point timeout, const query::read_command& cmd, const dht::partition_range& pr); // Wrapper for READ_DIGEST void register_read_digest(std::function (const rpc::client_info&, query::read_command cmd, compat::wrapping_partition_range pr)>&& func); void unregister_read_digest(); future, rpc::optional> send_read_digest(msg_addr id, clock_type::time_point timeout, const query::read_command& cmd, const dht::partition_range& pr); // Wrapper for TRUNCATE void register_truncate(std::function(sstring, sstring)>&& func); void unregister_truncate(); future<> send_truncate(msg_addr, std::chrono::milliseconds, sstring, sstring); // Wrapper for REPLICATION_FINISHED verb void register_replication_finished(std::function (inet_address from)>&& func); void unregister_replication_finished(); future<> send_replication_finished(msg_addr id, inet_address from); void foreach_server_connection_stats(std::function&& f) const; private: bool remove_rpc_client_one(clients_map& clients, msg_addr id, bool dead_only); public: // Return rpc::protocol::client for a shard which is a ip + cpuid pair. shared_ptr get_rpc_client(messaging_verb verb, msg_addr id); void remove_error_rpc_client(messaging_verb verb, msg_addr id); void remove_rpc_client(msg_addr id); using drop_notifier_handler = decltype(_connection_drop_notifiers)::iterator; drop_notifier_handler register_connection_drop_notifier(std::function cb); void unregister_connection_drop_notifier(drop_notifier_handler h); std::unique_ptr& rpc(); static msg_addr get_source(const rpc::client_info& client); }; 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(); } } // namespace netw