2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* FlowTransport.h
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef FLOW_TRANSPORT_H
|
|
|
|
#define FLOW_TRANSPORT_H
|
|
|
|
#pragma once
|
|
|
|
|
2018-10-25 05:59:50 +08:00
|
|
|
#include <algorithm>
|
2020-02-18 13:54:05 +08:00
|
|
|
#include "fdbrpc/HealthMonitor.h"
|
2019-06-25 06:19:33 +08:00
|
|
|
#include "flow/genericactors.actor.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
#include "flow/network.h"
|
2019-01-31 05:53:23 +08:00
|
|
|
#include "flow/FileIdentifier.h"
|
2020-10-24 05:23:28 +08:00
|
|
|
#include "flow/ProtocolVersion.h"
|
2019-08-30 07:49:57 +08:00
|
|
|
#include "flow/Net2Packet.h"
|
2020-10-07 08:01:13 +08:00
|
|
|
#include "fdbrpc/ContinuousSample.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-09-21 00:46:34 +08:00
|
|
|
enum { WLTOKEN_ENDPOINT_NOT_FOUND = 0, WLTOKEN_PING_PACKET, WLTOKEN_FIRST_AVAILABLE };
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
#pragma pack(push, 4)
|
|
|
|
class Endpoint {
|
|
|
|
public:
|
|
|
|
// Endpoint represents a particular service (e.g. a serialized Promise<T> or PromiseStream<T>)
|
|
|
|
// An endpoint is either "local" (used for receiving data) or "remote" (used for sending data)
|
2019-01-31 05:53:23 +08:00
|
|
|
constexpr static FileIdentifier file_identifier = 10618805;
|
2017-05-26 04:48:44 +08:00
|
|
|
typedef UID Token;
|
2018-10-31 04:44:37 +08:00
|
|
|
NetworkAddressList addresses;
|
2017-05-26 04:48:44 +08:00
|
|
|
Token token;
|
|
|
|
|
2019-03-24 08:54:46 +08:00
|
|
|
Endpoint() {}
|
2018-10-31 04:44:37 +08:00
|
|
|
Endpoint(const NetworkAddressList& addresses, Token token) : addresses(addresses), token(token) {
|
2019-02-01 10:20:14 +08:00
|
|
|
choosePrimaryAddress();
|
|
|
|
}
|
|
|
|
|
2021-09-21 00:46:34 +08:00
|
|
|
static Token wellKnownToken(int wlTokenID) { return UID(-1, wlTokenID); }
|
|
|
|
|
|
|
|
static Endpoint wellKnown(const NetworkAddressList& addresses, int wlTokenID) {
|
|
|
|
return Endpoint(addresses, wellKnownToken(wlTokenID));
|
|
|
|
}
|
|
|
|
|
2019-02-01 10:20:14 +08:00
|
|
|
void choosePrimaryAddress() {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (addresses.secondaryAddress.present() &&
|
|
|
|
((!g_network->getLocalAddresses().secondaryAddress.present() &&
|
|
|
|
(addresses.address.isTLS() != g_network->getLocalAddresses().address.isTLS())) ||
|
|
|
|
(g_network->getLocalAddresses().secondaryAddress.present() && !addresses.address.isTLS()))) {
|
2019-03-24 08:54:46 +08:00
|
|
|
std::swap(addresses.address, addresses.secondaryAddress.get());
|
2020-03-11 06:05:13 +08:00
|
|
|
}
|
2018-10-31 04:44:37 +08:00
|
|
|
}
|
2018-10-25 05:59:50 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
bool isValid() const { return token.isValid(); }
|
|
|
|
bool isLocal() const;
|
|
|
|
|
2018-10-31 04:44:37 +08:00
|
|
|
// Return the primary network address, which is the first network address among
|
|
|
|
// all addresses this endpoint listens to.
|
2021-03-11 02:06:03 +08:00
|
|
|
const NetworkAddress& getPrimaryAddress() const { return addresses.address; }
|
2018-10-31 04:44:37 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
NetworkAddress getStableAddress() const { return addresses.getTLSAddress(); }
|
2020-04-11 04:45:16 +08:00
|
|
|
|
2021-06-20 00:47:13 +08:00
|
|
|
Endpoint getAdjustedEndpoint(uint32_t index) const {
|
2020-04-13 13:18:51 +08:00
|
|
|
uint32_t newIndex = token.second();
|
|
|
|
newIndex += index;
|
2021-03-11 02:06:03 +08:00
|
|
|
return Endpoint(
|
|
|
|
addresses,
|
|
|
|
UID(token.first() + (uint64_t(index) << 32), (token.second() & 0xffffffff00000000LL) | newIndex));
|
2020-04-13 07:04:48 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator==(Endpoint const& r) const {
|
2020-05-20 11:41:56 +08:00
|
|
|
return token == r.token && getPrimaryAddress() == r.getPrimaryAddress();
|
2018-10-25 05:59:50 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator!=(Endpoint const& r) const { return !(*this == r); }
|
|
|
|
bool operator<(Endpoint const& r) const {
|
2020-05-20 15:00:06 +08:00
|
|
|
return addresses.address < r.addresses.address || (addresses.address == r.addresses.address && token < r.token);
|
2018-10-25 05:59:50 +08:00
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <class Ar>
|
|
|
|
void serialize(Ar& ar) {
|
2019-02-21 03:52:47 +08:00
|
|
|
if constexpr (is_fb_function<Ar>) {
|
2019-02-01 10:20:14 +08:00
|
|
|
serializer(ar, addresses, token);
|
2019-02-21 03:52:47 +08:00
|
|
|
if constexpr (Ar::isDeserializing) {
|
2019-02-01 10:20:14 +08:00
|
|
|
choosePrimaryAddress();
|
|
|
|
}
|
2019-02-21 03:52:47 +08:00
|
|
|
} else {
|
2019-06-19 08:55:27 +08:00
|
|
|
if (ar.isDeserializing && !ar.protocolVersion().hasEndpointAddrList()) {
|
2019-04-10 05:29:21 +08:00
|
|
|
addresses.secondaryAddress = Optional<NetworkAddress>();
|
|
|
|
serializer(ar, addresses.address, token);
|
2019-02-21 03:52:47 +08:00
|
|
|
} else {
|
|
|
|
serializer(ar, addresses, token);
|
|
|
|
if (ar.isDeserializing) {
|
|
|
|
choosePrimaryAddress();
|
|
|
|
}
|
|
|
|
}
|
2019-02-01 10:20:14 +08:00
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
#pragma pack(pop)
|
2018-10-25 05:59:50 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
namespace std {
|
|
|
|
template <>
|
|
|
|
struct hash<Endpoint> {
|
|
|
|
size_t operator()(const Endpoint& ep) const { return ep.token.hash() + ep.addresses.address.hash(); }
|
|
|
|
};
|
|
|
|
} // namespace std
|
2020-05-21 03:21:57 +08:00
|
|
|
|
2020-09-19 09:32:32 +08:00
|
|
|
enum class RequirePeer { Exactly, AtLeast };
|
|
|
|
|
|
|
|
struct PeerCompatibilityPolicy {
|
|
|
|
RequirePeer requirement;
|
|
|
|
ProtocolVersion version;
|
|
|
|
};
|
|
|
|
|
2019-01-26 07:10:20 +08:00
|
|
|
class ArenaObjectReader;
|
2017-05-26 04:48:44 +08:00
|
|
|
class NetworkMessageReceiver {
|
|
|
|
public:
|
2019-01-26 07:10:20 +08:00
|
|
|
virtual void receive(ArenaObjectReader&) = 0;
|
2017-05-26 04:48:44 +08:00
|
|
|
virtual bool isStream() const { return false; }
|
2020-09-19 09:32:32 +08:00
|
|
|
virtual PeerCompatibilityPolicy peerCompatibilityPolicy() const {
|
2020-09-29 01:58:49 +08:00
|
|
|
return { RequirePeer::Exactly, g_network->protocolVersion() };
|
2020-09-19 09:32:32 +08:00
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
2019-08-30 07:49:57 +08:00
|
|
|
struct TransportData;
|
|
|
|
|
|
|
|
struct Peer : public ReferenceCounted<Peer> {
|
|
|
|
TransportData* transport;
|
|
|
|
NetworkAddress destination;
|
|
|
|
UnsentPacketQueue unsent;
|
|
|
|
ReliablePacketList reliable;
|
2021-03-11 02:06:03 +08:00
|
|
|
AsyncTrigger dataToSend; // Triggered when unsent.empty() becomes false
|
2019-08-30 07:49:57 +08:00
|
|
|
Future<Void> connect;
|
|
|
|
AsyncTrigger resetPing;
|
2020-07-10 13:50:47 +08:00
|
|
|
AsyncTrigger resetConnection;
|
2019-08-30 07:49:57 +08:00
|
|
|
bool compatible;
|
2021-03-11 02:06:03 +08:00
|
|
|
bool outgoingConnectionIdle; // We don't actually have a connection open and aren't trying to open one because we
|
|
|
|
// don't have anything to send
|
2019-08-30 07:49:57 +08:00
|
|
|
double lastConnectTime;
|
|
|
|
double reconnectionDelay;
|
|
|
|
int peerReferences;
|
|
|
|
bool incompatibleProtocolVersionNewer;
|
|
|
|
int64_t bytesReceived;
|
2020-10-12 14:05:21 +08:00
|
|
|
int64_t bytesSent;
|
2019-08-30 07:49:57 +08:00
|
|
|
double lastDataPacketSentTime;
|
|
|
|
int outstandingReplies;
|
2020-10-07 07:55:35 +08:00
|
|
|
ContinuousSample<double> pingLatencies;
|
2020-11-03 07:59:38 +08:00
|
|
|
double lastLoggedTime;
|
2020-10-07 07:07:35 +08:00
|
|
|
int64_t lastLoggedBytesReceived;
|
2020-10-12 14:05:21 +08:00
|
|
|
int64_t lastLoggedBytesSent;
|
2021-06-16 08:36:56 +08:00
|
|
|
int timeoutCount;
|
2021-04-16 02:45:14 +08:00
|
|
|
|
|
|
|
Reference<AsyncVar<Optional<ProtocolVersion>>> protocolVersion;
|
|
|
|
|
2020-11-03 07:59:38 +08:00
|
|
|
// Cleared every time stats are logged for this peer.
|
|
|
|
int connectOutgoingCount;
|
|
|
|
int connectIncomingCount;
|
|
|
|
int connectFailedCount;
|
2020-11-06 04:14:35 +08:00
|
|
|
ContinuousSample<double> connectLatencies;
|
2019-08-30 07:49:57 +08:00
|
|
|
|
2020-04-23 10:38:01 +08:00
|
|
|
explicit Peer(TransportData* transport, NetworkAddress const& destination);
|
2019-08-30 07:49:57 +08:00
|
|
|
|
|
|
|
void send(PacketBuffer* pb, ReliablePacket* rp, bool firstUnsent);
|
|
|
|
|
|
|
|
void prependConnectPacket();
|
|
|
|
|
|
|
|
void discardUnreliablePackets();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void onIncomingConnection(Reference<Peer> self, Reference<IConnection> conn, Future<Void> reader);
|
2019-08-30 07:49:57 +08:00
|
|
|
};
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
class FlowTransport {
|
|
|
|
public:
|
2021-09-21 00:46:34 +08:00
|
|
|
FlowTransport(uint64_t transportId, int maxWellKnownEndpoints);
|
2017-05-26 04:48:44 +08:00
|
|
|
~FlowTransport();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Creates a new FlowTransport and makes FlowTransport::transport() return it. This uses g_network->global()
|
|
|
|
// variables, so it will be private to a simulation.
|
2021-09-21 00:46:34 +08:00
|
|
|
static void createInstance(bool isClient, uint64_t transportId, int maxWellKnownEndpoints);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-05-30 04:43:21 +08:00
|
|
|
static bool isClient() { return g_network->global(INetwork::enClientFailureMonitor) != nullptr; }
|
2019-04-19 05:12:45 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// Metrics must be initialized after FlowTransport::createInstance has been called
|
2021-04-16 02:45:14 +08:00
|
|
|
void initMetrics();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Starts a server listening on the given listenAddress, and sets publicAddress to be the public
|
|
|
|
// address of this server. Returns only errors.
|
2021-04-16 02:45:14 +08:00
|
|
|
Future<Void> bind(NetworkAddress publicAddress, NetworkAddress listenAddress);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2018-10-31 04:44:37 +08:00
|
|
|
// Returns first local NetworkAddress.
|
2021-04-16 02:45:14 +08:00
|
|
|
NetworkAddress getLocalAddress() const;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-02-01 10:20:14 +08:00
|
|
|
// Returns all local NetworkAddress.
|
2021-04-16 02:45:14 +08:00
|
|
|
NetworkAddressList getLocalAddresses() const;
|
2019-02-01 10:20:14 +08:00
|
|
|
|
2021-06-16 08:36:56 +08:00
|
|
|
// Returns all peers that the FlowTransport is monitoring.
|
2021-06-18 01:13:08 +08:00
|
|
|
const std::unordered_map<NetworkAddress, Reference<Peer>>& getAllPeers() const;
|
2021-06-16 08:36:56 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// Returns the same of all peers that have attempted to connect, but have incompatible protocol versions
|
2021-04-16 02:45:14 +08:00
|
|
|
std::map<NetworkAddress, std::pair<uint64_t, double>>* getIncompatiblePeers();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-04-06 14:09:36 +08:00
|
|
|
// Returns when getIncompatiblePeers has at least one peer which is incompatible.
|
2021-04-16 02:45:14 +08:00
|
|
|
Future<Void> onIncompatibleChanged();
|
2020-04-06 14:09:36 +08:00
|
|
|
|
2018-07-11 04:10:29 +08:00
|
|
|
// Signal that a peer connection is being used, even if no messages are currently being sent to the peer
|
2021-04-16 02:45:14 +08:00
|
|
|
void addPeerReference(const Endpoint&, bool isStream);
|
2018-07-11 04:10:29 +08:00
|
|
|
|
|
|
|
// Signal that a peer connection is no longer being used
|
2021-04-16 02:45:14 +08:00
|
|
|
void removePeerReference(const Endpoint&, bool isStream);
|
2018-07-11 04:10:29 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// Sets endpoint to be a new local endpoint which delivers messages to the given receiver
|
2021-04-16 02:45:14 +08:00
|
|
|
void addEndpoint(Endpoint& endpoint, NetworkMessageReceiver*, TaskPriority taskID);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void addEndpoints(std::vector<std::pair<struct FlowReceiver*, TaskPriority>> const& streams);
|
2020-04-13 13:18:51 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// The given local endpoint no longer delivers messages to the given receiver or uses resources
|
2021-04-16 02:45:14 +08:00
|
|
|
void removeEndpoint(const Endpoint&, NetworkMessageReceiver*);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Sets endpoint to a new local endpoint (without changing its token) which delivers messages to the given receiver
|
|
|
|
// Implementations may have limitations on when this function is called and what endpoint.token may be!
|
2021-04-16 02:45:14 +08:00
|
|
|
void addWellKnownEndpoint(Endpoint& endpoint, NetworkMessageReceiver*, TaskPriority taskID);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-04-16 02:45:14 +08:00
|
|
|
// sendReliable will keep trying to deliver the data to the destination until cancelReliable is called. It will
|
|
|
|
// retry sending if the connection is closed or the failure manager reports the destination become available (edge
|
|
|
|
// triggered).
|
2021-03-11 02:06:03 +08:00
|
|
|
ReliablePacket* sendReliable(ISerializeSource const& what, const Endpoint& destination);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-04-16 02:45:14 +08:00
|
|
|
// Makes Packet "unreliable" (either the data or a connection close event will be delivered eventually). It can
|
|
|
|
// still be used safely to send a reply to a "reliable" request.
|
2021-03-11 02:06:03 +08:00
|
|
|
void cancelReliable(ReliablePacket*);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// This async var will be set to true when the process cannot connect to a public network address that the failure
|
|
|
|
// monitor thinks is healthy.
|
2021-04-16 02:45:14 +08:00
|
|
|
Reference<AsyncVar<bool>> getDegraded();
|
2019-04-05 05:11:12 +08:00
|
|
|
|
2020-07-10 13:50:47 +08:00
|
|
|
// Forces the connection with this address to be reset
|
2021-04-16 02:45:14 +08:00
|
|
|
void resetConnection(NetworkAddress address);
|
2020-07-10 13:50:47 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Reference<Peer> sendUnreliable(ISerializeSource const& what,
|
|
|
|
const Endpoint& destination,
|
|
|
|
bool openConnection); // { cancelReliable(sendReliable(what,destination)); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2017-11-10 03:20:35 +08:00
|
|
|
bool incompatibleOutgoingConnectionsPresent();
|
|
|
|
|
2021-04-16 02:45:14 +08:00
|
|
|
// Returns the protocol version of the peer at the specified address. The result is returned as an AsyncVar that
|
|
|
|
// can be used to monitor for changes of a peer's protocol. The protocol version will be unset in the event that
|
|
|
|
// there is no connection established to the peer.
|
|
|
|
//
|
|
|
|
// Note that this function does not establish a connection to the peer. In order to obtain a peer's protocol
|
|
|
|
// version, some other mechanism should be used to connect to that peer.
|
2021-07-13 12:28:38 +08:00
|
|
|
Reference<AsyncVar<Optional<ProtocolVersion>> const> getPeerProtocolAsyncVar(NetworkAddress addr);
|
2021-04-16 02:45:14 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
static FlowTransport& transport() {
|
|
|
|
return *static_cast<FlowTransport*>((void*)g_network->global(INetwork::enFlowTransport));
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
static NetworkAddress getGlobalLocalAddress() { return transport().getLocalAddress(); }
|
2019-02-01 10:20:14 +08:00
|
|
|
static NetworkAddressList getGlobalLocalAddresses() { return transport().getLocalAddresses(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-03-27 03:05:43 +08:00
|
|
|
Endpoint loadedEndpoint(const UID& token);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-02-18 13:54:05 +08:00
|
|
|
HealthMonitor* healthMonitor();
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
|
|
|
class TransportData* self;
|
|
|
|
};
|
|
|
|
|
2019-01-07 19:38:35 +08:00
|
|
|
inline bool Endpoint::isLocal() const {
|
2019-03-24 08:54:46 +08:00
|
|
|
const auto& localAddrs = FlowTransport::transport().getLocalAddresses();
|
2021-03-11 02:06:03 +08:00
|
|
|
return addresses.address == localAddrs.address ||
|
|
|
|
(localAddrs.secondaryAddress.present() && addresses.address == localAddrs.secondaryAddress.get());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2017-10-17 07:46:52 +08:00
|
|
|
#endif
|