mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-26 19:35:12 +00:00
There can be multiple sends underway when first one detects an error and destroys rpc client, but the rpc client is still in use by other sends. Fix this by making rpc client pointer shared and hold on it for each send operation.
522 lines
20 KiB
C++
522 lines
20 KiB
C++
/*
|
|
* 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 <unordered_map>
|
|
#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,
|
|
PREPARE_DONE_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<net::messaging_verb> {
|
|
public:
|
|
size_t operator()(const net::messaging_verb& x) const {
|
|
return hash<int32_t>()(int32_t(x));
|
|
}
|
|
};
|
|
} // namespace std
|
|
|
|
namespace net {
|
|
|
|
// NOTE: operator(input_stream<char>&, T&) takes a reference to uninitialized
|
|
// T object and should use placement new in case T is non POD
|
|
struct serializer {
|
|
template <typename T, typename Input>
|
|
inline T read_integral(Input& input) const {
|
|
static_assert(std::is_integral<T>::value, "T should be integral");
|
|
T data;
|
|
input.read(reinterpret_cast<char*>(&data), sizeof(T));
|
|
return net::ntoh(data);
|
|
}
|
|
|
|
template <typename T, typename Output>
|
|
inline void write_integral(Output& output, T data) const {
|
|
static_assert(std::is_integral<T>::value, "T should be integral");
|
|
data = net::hton(data);
|
|
output.write(reinterpret_cast<const char*>(&data), sizeof(T));
|
|
}
|
|
|
|
// Adaptor for writing objects having db::serializer<>
|
|
template <typename Serializable, typename Output>
|
|
inline void write_serializable(Output& out, const Serializable& v) const {
|
|
db::serializer<Serializable> ser(v);
|
|
bytes b(bytes::initialized_later(), ser.size() + data_output::serialized_size<uint32_t>());
|
|
data_output d_out(b);
|
|
d_out.write<uint32_t>(ser.size());
|
|
ser.write(d_out);
|
|
return out.write(reinterpret_cast<const char*>(b.c_str()), b.size());
|
|
}
|
|
|
|
// Adaptor for reading objects having db::serializer<>
|
|
template <typename Serializable, typename Input>
|
|
inline Serializable read_serializable(Input& in) const {
|
|
auto sz = read_integral<uint32_t>(in);
|
|
bytes data(bytes::initialized_later(), sz);
|
|
in.read(reinterpret_cast<char*>(data.begin()), sz);
|
|
data_input din(data);
|
|
return db::serializer<Serializable>::read(din);
|
|
}
|
|
|
|
// For integer type
|
|
template <typename Input>
|
|
bool read(Input& input, rpc::type<bool>) const { return read(input, rpc::type<uint8_t>()); }
|
|
template <typename Input>
|
|
int8_t read(Input& input, rpc::type<int8_t>) const { return read_integral<int8_t>(input); }
|
|
template <typename Input>
|
|
uint8_t read(Input& input, rpc::type<uint8_t>) const { return read_integral<uint8_t>(input); }
|
|
template <typename Input>
|
|
int16_t read(Input& input, rpc::type<int16_t>) const { return read_integral<int16_t>(input); }
|
|
template <typename Input>
|
|
uint16_t read(Input& input, rpc::type<uint16_t>) const { return read_integral<uint16_t>(input); }
|
|
template <typename Input>
|
|
int32_t read(Input& input, rpc::type<int32_t>) const { return read_integral<int32_t>(input); }
|
|
template <typename Input>
|
|
uint32_t read(Input& input, rpc::type<uint32_t>) const { return read_integral<uint32_t>(input); }
|
|
template <typename Input>
|
|
int64_t read(Input& input, rpc::type<int64_t>) const { return read_integral<int64_t>(input); }
|
|
template <typename Input>
|
|
uint64_t read(Input& input, rpc::type<uint64_t>) const { return read_integral<uint64_t>(input); }
|
|
template <typename Output>
|
|
void write(Output& output, bool data) const { write(output, uint8_t(data)); }
|
|
template <typename Output>
|
|
void write(Output& output, int8_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, uint8_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, int16_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, uint16_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, int32_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, uint32_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, int64_t data) const { write_integral(output, data); }
|
|
template <typename Output>
|
|
void write(Output& output, uint64_t data) const { write_integral(output, data); }
|
|
|
|
// For vectors
|
|
template <typename T, typename Output>
|
|
inline void write(Output& out, const std::vector<T>& v) const {
|
|
write(out, uint32_t(v.size()));
|
|
for (auto&& e : v) {
|
|
write(out, e);
|
|
}
|
|
}
|
|
template <typename T, typename Input>
|
|
inline std::vector<T> read(Input& in, rpc::type<std::vector<T>>) const {
|
|
auto sz = read(in, rpc::type<uint32_t>());
|
|
std::vector<T> v;
|
|
v.reserve(sz);
|
|
while (sz--) {
|
|
v.push_back(read(in, rpc::type<T>()));
|
|
}
|
|
return v;
|
|
}
|
|
|
|
// For messaging_verb
|
|
template <typename Output>
|
|
void write(Output& out, messaging_verb v) const {
|
|
return write(out, std::underlying_type_t<messaging_verb>(v));
|
|
}
|
|
template <typename Input>
|
|
messaging_verb operator()(Input& in, rpc::type<messaging_verb>) const {
|
|
return messaging_verb(read(in, rpc::type<std::underlying_type_t<messaging_verb>>()));
|
|
}
|
|
|
|
// For sstring
|
|
template <typename Output>
|
|
void write(Output& out, const sstring& v) const {
|
|
write(out, uint32_t(v.size()));
|
|
out.write(v.begin(), v.size());
|
|
}
|
|
template <typename Input>
|
|
sstring read(Input& in, rpc::type<sstring>) const {
|
|
auto sz = read(in, rpc::type<uint32_t>());
|
|
sstring v(sstring::initialized_later(), sz);
|
|
in.read(v.begin(), sz);
|
|
return v;
|
|
}
|
|
|
|
// For frozen_mutation
|
|
template <typename Output>
|
|
void write(Output& out, const frozen_mutation& v) const{
|
|
return write_serializable(out, v);
|
|
}
|
|
template <typename Input>
|
|
frozen_mutation read(Input& in, rpc::type<frozen_mutation>) const {
|
|
return read_serializable<frozen_mutation>(in);
|
|
}
|
|
|
|
// For reconcilable_result
|
|
template <typename Output>
|
|
void write(Output& out, const reconcilable_result& v) const{
|
|
return write_serializable(out, v);
|
|
}
|
|
template <typename Input>
|
|
reconcilable_result read(Input& in, rpc::type<reconcilable_result>) const {
|
|
return read_serializable<reconcilable_result>(in);
|
|
}
|
|
|
|
// For complex types which have serialize()/deserialize(), e.g. gms::gossip_digest_syn, gms::gossip_digest_ack2
|
|
template <typename T, typename Output>
|
|
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<const char*>(b.c_str()), sz);
|
|
}
|
|
template <typename T, typename Input>
|
|
T read_gms(Input& in) const {
|
|
auto sz = read(in, rpc::type<uint32_t>());
|
|
bytes b(bytes::initialized_later(), sz);
|
|
in.read(reinterpret_cast<char*>(b.begin()), sz);
|
|
bytes_view bv(b);
|
|
return T::deserialize(bv);
|
|
}
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const gms::gossip_digest_syn& v) const;
|
|
template <typename Input>
|
|
gms::gossip_digest_syn read(Input& in, rpc::type<gms::gossip_digest_syn>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const gms::gossip_digest_ack2& v) const;
|
|
template <typename Input>
|
|
gms::gossip_digest_ack2 read(Input& in, rpc::type<gms::gossip_digest_ack2>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const streaming::messages::stream_init_message& v) const;
|
|
template <typename Input>
|
|
streaming::messages::stream_init_message read(Input& in, rpc::type<streaming::messages::stream_init_message>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const streaming::messages::prepare_message& v) const;
|
|
template <typename Input>
|
|
streaming::messages::prepare_message read(Input& in, rpc::type<streaming::messages::prepare_message>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const gms::inet_address& v) const;
|
|
template <typename Input>
|
|
gms::inet_address read(Input& in, rpc::type<gms::inet_address>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const gms::gossip_digest_ack& v) const;
|
|
template <typename Input>
|
|
gms::gossip_digest_ack read(Input& in, rpc::type<gms::gossip_digest_ack>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const query::read_command& v) const;
|
|
template <typename Input>
|
|
query::read_command read(Input& in, rpc::type<query::read_command>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const query::result& v) const;
|
|
template <typename Input>
|
|
query::result read(Input& in, rpc::type<query::result>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const query::result_digest& v) const;
|
|
template <typename Input>
|
|
query::result_digest read(Input& in, rpc::type<query::result_digest>) const;
|
|
|
|
template <typename Output>
|
|
void write(Output& out, const utils::UUID& v) const;
|
|
template <typename Input>
|
|
utils::UUID read(Input& in, rpc::type<utils::UUID>) const;
|
|
|
|
// for query::range<T>
|
|
template <typename Output, typename T>
|
|
void write(Output& out, const query::range<T>& v) const;
|
|
template <typename Input, typename T>
|
|
query::range<T> read(Input& input, rpc::type<query::range<T>>) const;
|
|
|
|
template <typename Output, typename T>
|
|
void write(Output& out, const foreign_ptr<T>& v) const {
|
|
return write(out, *v);
|
|
}
|
|
template <typename Input, typename T>
|
|
foreign_ptr<T> read(Input& in, rpc::type<foreign_ptr<T>>) const {
|
|
return make_foreign(read(in, rpc::type<T>()));
|
|
}
|
|
|
|
template <typename Output, typename T>
|
|
void write(Output& out, const lw_shared_ptr<T>& v) const {
|
|
return write(out, *v);
|
|
}
|
|
template <typename Input, typename T>
|
|
lw_shared_ptr<T> read(Input& in, rpc::type<lw_shared_ptr<T>>) const {
|
|
return make_lw_shared(read(in, rpc::type<T>()));
|
|
}
|
|
};
|
|
|
|
// thunk from new-style free function serialization to old-style member function
|
|
template <typename Output, typename T>
|
|
inline
|
|
void
|
|
write(serializer s, Output& out, const T& data) {
|
|
s.write(out, data);
|
|
}
|
|
|
|
template <typename Input, typename T>
|
|
inline
|
|
T
|
|
read(serializer s, Input& in, rpc::type<T> 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(shared_ptr<rpc_protocol_client_wrapper>&& client);
|
|
shared_ptr<rpc_protocol_client_wrapper> rpc_client;
|
|
rpc::stats get_stats() const;
|
|
};
|
|
|
|
void foreach_client(std::function<void(const shard_id& id, const shard_info& info)> 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_protocol_wrapper> _rpc;
|
|
std::unique_ptr<rpc_protocol_server_wrapper> _server;
|
|
std::unordered_map<shard_id, shard_info, shard_id::hash> _clients;
|
|
uint64_t _dropped_messages[static_cast<int32_t>(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<future<unsigned> (streaming::messages::stream_init_message msg, unsigned src_cpu_id)>&& func);
|
|
future<unsigned> 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<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);
|
|
future<streaming::messages::prepare_message> 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 PREPARE_DONE_MESSAGE verb
|
|
void register_prepare_done_message(std::function<future<> (UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id)>&& func);
|
|
future<> send_prepare_done_message(shard_id id, UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id);
|
|
|
|
// Wrapper for STREAM_MUTATION verb
|
|
void register_stream_mutation(std::function<future<> (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<future<> (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<rpc::no_wait_type (UUID plan_id, inet_address from, inet_address connecting, unsigned dst_cpu_id)>&& 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<future<> ()>&& func);
|
|
future<> send_echo(shard_id id);
|
|
|
|
// Wrapper for GOSSIP_SHUTDOWN
|
|
void register_gossip_shutdown(std::function<rpc::no_wait_type (inet_address from)>&& func);
|
|
future<> send_gossip_shutdown(shard_id id, inet_address from);
|
|
|
|
// Wrapper for GOSSIP_DIGEST_SYN
|
|
void register_gossip_digest_syn(std::function<future<gms::gossip_digest_ack> (gms::gossip_digest_syn)>&& func);
|
|
future<gms::gossip_digest_ack> send_gossip_digest_syn(shard_id id, gms::gossip_digest_syn msg);
|
|
|
|
// Wrapper for GOSSIP_DIGEST_ACK2
|
|
void register_gossip_digest_ack2(std::function<rpc::no_wait_type (gms::gossip_digest_ack2)>&& func);
|
|
future<> send_gossip_digest_ack2(shard_id id, gms::gossip_digest_ack2 msg);
|
|
|
|
// Wrapper for DEFINITIONS_UPDATE
|
|
void register_definitions_update(std::function<rpc::no_wait_type (std::vector<frozen_mutation> fm)>&& func);
|
|
future<> send_definitions_update(shard_id id, std::vector<frozen_mutation> fm);
|
|
|
|
// Wrapper for MIGRATION_REQUEST
|
|
void register_migration_request(std::function<future<std::vector<frozen_mutation>> (gms::inet_address reply_to, unsigned shard)>&& func);
|
|
future<std::vector<frozen_mutation>> 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<rpc::no_wait_type (frozen_mutation fm, std::vector<inet_address> 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<inet_address> forward,
|
|
inet_address reply_to, unsigned shard, response_id_type response_id);
|
|
|
|
// Wrapper for MUTATION_DONE
|
|
void register_mutation_done(std::function<rpc::no_wait_type (const rpc::client_info& cinfo, unsigned shard, response_id_type response_id)>&& func);
|
|
future<> send_mutation_done(shard_id id, unsigned shard, response_id_type response_id);
|
|
|
|
// Wrapper for READ_DATA
|
|
// Note: WTH is future<foreign_ptr<lw_shared_ptr<query::result>>
|
|
void register_read_data(std::function<future<foreign_ptr<lw_shared_ptr<query::result>>> (query::read_command cmd, query::partition_range pr)>&& func);
|
|
future<query::result> 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<future<foreign_ptr<lw_shared_ptr<reconcilable_result>>> (query::read_command cmd, query::partition_range pr)>&& func);
|
|
future<reconcilable_result> 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<future<query::result_digest> (query::read_command cmd, query::partition_range pr)>&& func);
|
|
future<query::result_digest> 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.
|
|
shared_ptr<rpc_protocol_client_wrapper> get_rpc_client(shard_id id);
|
|
void remove_rpc_client(shard_id id);
|
|
std::unique_ptr<rpc_protocol_wrapper>& rpc();
|
|
};
|
|
|
|
extern distributed<messaging_service> _the_messaging_service;
|
|
|
|
inline distributed<messaging_service>& 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
|