/* * CoordinationInterface.h * * This source file is part of the FoundationDB open source project * * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 FDBCLIENT_COORDINATIONINTERFACE_H #define FDBCLIENT_COORDINATIONINTERFACE_H #pragma once #include "fdbclient/FDBTypes.h" #include "fdbrpc/fdbrpc.h" #include "fdbrpc/Locality.h" #include "fdbclient/CommitProxyInterface.h" #include "fdbclient/ClusterInterface.h" const int MAX_CLUSTER_FILE_BYTES = 60000; constexpr UID WLTOKEN_CLIENTLEADERREG_GETLEADER(-1, 2); constexpr UID WLTOKEN_CLIENTLEADERREG_OPENDATABASE(-1, 3); constexpr UID WLTOKEN_PROTOCOL_INFO(-1, 10); constexpr UID WLTOKEN_CONFIGTXN_GETVERSION(-1, 11); constexpr UID WLTOKEN_CONFIGTXN_GET(-1, 12); constexpr UID WLTOKEN_CONFIGTXN_GETRANGE(-1, 13); constexpr UID WLTOKEN_CONFIGTXN_COMMIT(-1, 14); struct ClientLeaderRegInterface { RequestStream getLeader; RequestStream openDatabase; ClientLeaderRegInterface() {} ClientLeaderRegInterface(NetworkAddress remote); ClientLeaderRegInterface(INetwork* local); }; class ClusterConnectionString { public: ClusterConnectionString() {} ClusterConnectionString(std::string const& connectionString); ClusterConnectionString(vector, Key); vector const& coordinators() const { return coord; } Key clusterKey() const { return key; } Key clusterKeyName() const { return keyDesc; } // Returns the "name" or "description" part of the clusterKey (the part before the ':') std::string toString() const; static std::string getErrorString(std::string const& source, Error const& e); private: void parseKey(std::string const& key); vector coord; Key key, keyDesc; }; class ClusterConnectionFile : NonCopyable, public ReferenceCounted { public: ClusterConnectionFile() {} // Loads and parses the file at 'path', throwing errors if the file cannot be read or the format is invalid. // // The format of the file is: description:id@[addrs]+ // The description and id together are called the "key" // // The following is enforced about the format of the file: // - The key must contain one (and only one) ':' character // - The description contains only allowed characters (a-z, A-Z, 0-9, _) // - The ID contains only allowed characters (a-z, A-Z, 0-9) // - At least one address is specified // - There is no address present more than once explicit ClusterConnectionFile(std::string const& path); explicit ClusterConnectionFile(ClusterConnectionString const& cs) : cs(cs), setConn(false) {} explicit ClusterConnectionFile(std::string const& filename, ClusterConnectionString const& contents); // returns static std::pair lookupClusterFileName(std::string const& filename); // get a human readable error message describing the error returned from the constructor static std::string getErrorString(std::pair const& resolvedFile, Error const& e); ClusterConnectionString const& getConnectionString() const; bool writeFile(); void setConnectionString(ClusterConnectionString const&); std::string const& getFilename() const { ASSERT(filename.size()); return filename; } bool canGetFilename() const { return filename.size() != 0; } bool fileContentsUpToDate() const; bool fileContentsUpToDate(ClusterConnectionString& fileConnectionString) const; void notifyConnected(); private: ClusterConnectionString cs; std::string filename; bool setConn; }; struct LeaderInfo { constexpr static FileIdentifier file_identifier = 8338794; UID changeID; static const uint64_t mask = ~(127ll << 57); Value serializedInfo; bool forward; // If true, serializedInfo is a connection string instead! LeaderInfo() : forward(false) {} LeaderInfo(UID changeID) : changeID(changeID), forward(false) {} bool operator<(LeaderInfo const& r) const { return changeID < r.changeID; } bool operator>(LeaderInfo const& r) const { return r < *this; } bool operator<=(LeaderInfo const& r) const { return !(*this > r); } bool operator>=(LeaderInfo const& r) const { return !(*this < r); } bool operator==(LeaderInfo const& r) const { return changeID == r.changeID; } bool operator!=(LeaderInfo const& r) const { return !(*this == r); } // The first 7 bits of ChangeID represent cluster controller process class fitness, the lower the better void updateChangeID(ClusterControllerPriorityInfo info) { changeID = UID(((uint64_t)info.processClassFitness << 57) | ((uint64_t)info.isExcluded << 60) | ((uint64_t)info.dcFitness << 61) | (changeID.first() & mask), changeID.second()); } // All but the first 7 bits are used to represent process id bool equalInternalId(LeaderInfo const& leaderInfo) const { return ((changeID.first() & mask) == (leaderInfo.changeID.first() & mask)) && changeID.second() == leaderInfo.changeID.second(); } // Change leader only if // 1. the candidate has better process class fitness and the candidate is not the leader // 2. the leader process class fitness becomes worse bool leaderChangeRequired(LeaderInfo const& candidate) const { return ((changeID.first() & ~mask) > (candidate.changeID.first() & ~mask) && !equalInternalId(candidate)) || ((changeID.first() & ~mask) < (candidate.changeID.first() & ~mask) && equalInternalId(candidate)); } ClusterControllerPriorityInfo getPriorityInfo() const { ClusterControllerPriorityInfo info; info.processClassFitness = (changeID.first() >> 57) & 7; info.isExcluded = (changeID.first() >> 60) & 1; info.dcFitness = (changeID.first() >> 61) & 7; return info; } template void serialize(Ar& ar) { serializer(ar, changeID, serializedInfo, forward); } }; struct GetLeaderRequest { constexpr static FileIdentifier file_identifier = 214727; Key key; UID knownLeader; ReplyPromise> reply; GetLeaderRequest() {} explicit GetLeaderRequest(Key key, UID kl) : key(key), knownLeader(kl) {} template void serialize(Ar& ar) { serializer(ar, key, knownLeader, reply); } }; struct OpenDatabaseCoordRequest { constexpr static FileIdentifier file_identifier = 214728; // Sent by the native API to the coordinator to open a database and track client // info changes. Returns immediately if the current client info id is different from // knownClientInfoID; otherwise returns when it next changes (or perhaps after a long interval) Key traceLogGroup; Standalone> issues; Standalone> supportedVersions; UID knownClientInfoID; Key clusterKey; vector coordinators; ReplyPromise> reply; template void serialize(Ar& ar) { serializer(ar, issues, supportedVersions, traceLogGroup, knownClientInfoID, clusterKey, coordinators, reply); } }; class ClientCoordinators { public: vector clientLeaderServers; Key clusterKey; Reference ccf; explicit ClientCoordinators(Reference ccf); explicit ClientCoordinators(Key clusterKey, std::vector coordinators); ClientCoordinators() {} }; struct ProtocolInfoReply { constexpr static FileIdentifier file_identifier = 7784298; ProtocolVersion version; template void serialize(Ar& ar) { uint64_t version_ = 0; if (Ar::isSerializing) { version_ = version.versionWithFlags(); } serializer(ar, version_); if (Ar::isDeserializing) { version = ProtocolVersion(version_); } } }; struct ProtocolInfoRequest { constexpr static FileIdentifier file_identifier = 13261233; ReplyPromise reply{ PeerCompatibilityPolicy{ RequirePeer::AtLeast, ProtocolVersion::withStableInterfaces() } }; template void serialize(Ar& ar) { serializer(ar, reply); } }; #endif