1 /*
2  * CoordinationInterface.h
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef FDBCLIENT_COORDINATIONINTERFACE_H
22 #define FDBCLIENT_COORDINATIONINTERFACE_H
23 #pragma once
24 
25 #include "fdbclient/FDBTypes.h"
26 #include "fdbrpc/fdbrpc.h"
27 #include "fdbrpc/Locality.h"
28 
29 const int MAX_CLUSTER_FILE_BYTES = 60000;
30 
31 struct ClientLeaderRegInterface {
32 	RequestStream< struct GetLeaderRequest > getLeader;
33 
ClientLeaderRegInterfaceClientLeaderRegInterface34 	ClientLeaderRegInterface() {}
35 	ClientLeaderRegInterface( NetworkAddress remote );
36 	ClientLeaderRegInterface( INetwork* local );
37 };
38 
39 class ClusterConnectionString {
40 public:
ClusterConnectionString()41 	ClusterConnectionString() {}
42 	ClusterConnectionString( std::string const& connectionString );
43 	ClusterConnectionString( vector<NetworkAddress>, Key );
coordinators()44 	vector<NetworkAddress> const& coordinators() const { return coord; }
clusterKey()45 	Key clusterKey() const { return key; }
clusterKeyName()46 	Key clusterKeyName() const { return keyDesc; }  // Returns the "name" or "description" part of the clusterKey (the part before the ':')
47 	std::string toString() const;
48 	static std::string getErrorString(std::string const& source, Error const& e);
49 private:
50 	void parseKey( std::string const& key );
51 
52 	vector<NetworkAddress> coord;
53 	Key key, keyDesc;
54 };
55 
56 class ClusterConnectionFile : NonCopyable, public ReferenceCounted<ClusterConnectionFile> {
57 public:
ClusterConnectionFile()58 	ClusterConnectionFile() {}
59 	// Loads and parses the file at 'path', throwing errors if the file cannot be read or the format is invalid.
60 	//
61 	// The format of the file is: description:id@[addrs]+
62 	//  The description and id together are called the "key"
63 	//
64 	// The following is enforced about the format of the file:
65 	//  - The key must contain one (and only one) ':' character
66 	//  - The description contains only allowed characters (a-z, A-Z, 0-9, _)
67 	//  - The ID contains only allowed characters (a-z, A-Z, 0-9)
68 	//  - At least one address is specified
69 	//  - There is no address present more than once
70 	explicit ClusterConnectionFile( std::string const& path );
ClusterConnectionFile(ClusterConnectionString const & cs)71 	explicit ClusterConnectionFile(ClusterConnectionString const& cs) : cs(cs), setConn(false) {}
72 	explicit ClusterConnectionFile(std::string const& filename, ClusterConnectionString const& contents);
73 
74 	// returns <resolved name, was default file>
75 	static std::pair<std::string, bool> lookupClusterFileName( std::string const& filename );
76 	// get a human readable error message describing the error returned from the constructor
77 	static std::string getErrorString( std::pair<std::string, bool> const& resolvedFile, Error const& e );
78 
79 	ClusterConnectionString const& getConnectionString() const;
80 	bool writeFile();
81 	void setConnectionString( ClusterConnectionString const& );
getFilename()82 	std::string const& getFilename() const { ASSERT( filename.size() ); return filename; }
canGetFilename()83 	bool canGetFilename() const { return filename.size() != 0; }
84 	bool fileContentsUpToDate() const;
85 	bool fileContentsUpToDate(ClusterConnectionString &fileConnectionString) const;
86 	void notifyConnected();
87 private:
88 	ClusterConnectionString cs;
89 	std::string filename;
90 	bool setConn;
91 };
92 
93 struct LeaderInfo {
94 	UID changeID;
95 	static const uint64_t mask = ~(127ll << 57);
96 	Value serializedInfo;
97 	bool forward;  // If true, serializedInfo is a connection string instead!
98 
LeaderInfoLeaderInfo99 	LeaderInfo() : forward(false) {}
LeaderInfoLeaderInfo100 	LeaderInfo(UID changeID) : changeID(changeID), forward(false) {}
101 
102 	bool operator < (LeaderInfo const& r) const { return changeID < r.changeID; }
103 	bool operator == (LeaderInfo const& r) const { return changeID == r.changeID; }
104 
105 	// The first 7 bits of ChangeID represent cluster controller process class fitness, the lower the better
updateChangeIDLeaderInfo106 	void updateChangeID(ClusterControllerPriorityInfo info) {
107 		changeID = UID( ((uint64_t)info.processClassFitness << 57) | ((uint64_t)info.isExcluded << 60) | ((uint64_t)info.dcFitness << 61) | (changeID.first() & mask), changeID.second() );
108 	}
109 
110 	// All but the first 7 bits are used to represent process id
equalInternalIdLeaderInfo111 	bool equalInternalId(LeaderInfo const& leaderInfo) const {
112 		return ((changeID.first() & mask) == (leaderInfo.changeID.first() & mask)) && changeID.second() == leaderInfo.changeID.second();
113 	}
114 
115 	// Change leader only if
116 	// 1. the candidate has better process class fitness and the candidate is not the leader
117 	// 2. the leader process class fitness becomes worse
leaderChangeRequiredLeaderInfo118 	bool leaderChangeRequired(LeaderInfo const& candidate) const {
119 		return ((changeID.first() & ~mask) > (candidate.changeID.first() & ~mask) && !equalInternalId(candidate)) || ((changeID.first() & ~mask) < (candidate.changeID.first() & ~mask) && equalInternalId(candidate));
120 	}
121 
122 	template <class Ar>
serializeLeaderInfo123 	void serialize(Ar& ar) {
124 		serializer(ar, changeID, serializedInfo, forward);
125 	}
126 };
127 
128 struct GetLeaderRequest {
129 	Key key;
130 	UID knownLeader;
131 	ReplyPromise< Optional<LeaderInfo> > reply;
132 
GetLeaderRequestGetLeaderRequest133 	GetLeaderRequest() {}
GetLeaderRequestGetLeaderRequest134 	explicit GetLeaderRequest(Key key, UID kl) : key(key), knownLeader(kl) {}
135 
136 	template <class Ar>
serializeGetLeaderRequest137 	void serialize(Ar& ar) {
138 		serializer(ar, key, knownLeader, reply);
139 	}
140 };
141 
142 class ClientCoordinators {
143 public:
144 	vector< ClientLeaderRegInterface > clientLeaderServers;
145 	Key clusterKey;
146 	Reference<ClusterConnectionFile> ccf;
147 
148 	explicit ClientCoordinators( Reference<ClusterConnectionFile> ccf );
ClientCoordinators()149 	ClientCoordinators() {}
150 };
151 
152 #endif
153