1 /*
2  * Locality.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 FLOW_LOCALITY_H
22 #define FLOW_LOCALITY_H
23 #pragma once
24 
25 #include "flow/flow.h"
26 
27 struct ProcessClass {
28 	// This enum is stored in restartInfo.ini for upgrade tests, so be very careful about changing the existing items!
29 	enum ClassType { UnsetClass, StorageClass, TransactionClass, ResolutionClass, TesterClass, ProxyClass, MasterClass, StatelessClass, LogClass, ClusterControllerClass, LogRouterClass, DataDistributorClass, CoordinatorClass, RatekeeperClass, InvalidClass = -1 };
30 	enum Fitness { BestFit, GoodFit, UnsetFit, OkayFit, WorstFit, ExcludeFit, NeverAssign }; //cannot be larger than 7 because of leader election mask
31 	enum ClusterRole { Storage, TLog, Proxy, Master, Resolver, LogRouter, ClusterController, DataDistributor, Ratekeeper, NoRole };
32 	enum ClassSource { CommandLineSource, AutoSource, DBSource, InvalidSource = -1 };
33 	int16_t _class;
34 	int16_t _source;
35 
36 public:
ProcessClassProcessClass37 	ProcessClass() : _class( UnsetClass ), _source( CommandLineSource ) {}
ProcessClassProcessClass38 	ProcessClass( ClassType type, ClassSource source ) : _class( type ), _source( source ) {}
ProcessClassProcessClass39 	explicit ProcessClass( std::string s, ClassSource source ) : _source( source ) {
40 		if (s=="storage") _class = StorageClass;
41 		else if (s=="transaction") _class = TransactionClass;
42 		else if (s=="resolution") _class = ResolutionClass;
43 		else if (s=="proxy") _class = ProxyClass;
44 		else if (s=="master") _class = MasterClass;
45 		else if (s=="test") _class = TesterClass;
46 		else if (s=="unset") _class = UnsetClass;
47 		else if (s=="stateless") _class = StatelessClass;
48 		else if (s=="log") _class = LogClass;
49 		else if (s=="router") _class = LogRouterClass;
50 		else if (s=="cluster_controller") _class = ClusterControllerClass;
51 		else if (s=="data_distributor") _class = DataDistributorClass;
52 		else if (s=="coordinator") _class = CoordinatorClass;
53 		else if (s=="ratekeeper") _class = RatekeeperClass;
54 		else _class = InvalidClass;
55 	}
56 
ProcessClassProcessClass57 	ProcessClass( std::string classStr, std::string sourceStr ) {
58 		if (classStr=="storage") _class = StorageClass;
59 		else if (classStr=="transaction") _class = TransactionClass;
60 		else if (classStr=="resolution") _class = ResolutionClass;
61 		else if (classStr=="proxy") _class = ProxyClass;
62 		else if (classStr=="master") _class = MasterClass;
63 		else if (classStr=="test") _class = TesterClass;
64 		else if (classStr=="unset") _class = UnsetClass;
65 		else if (classStr=="stateless") _class = StatelessClass;
66 		else if (classStr=="log") _class = LogClass;
67 		else if (classStr=="router") _class = LogRouterClass;
68 		else if (classStr=="cluster_controller") _class = ClusterControllerClass;
69 		else if (classStr=="data_distributor") _class = DataDistributorClass;
70 		else if (classStr=="coordinator") _class = CoordinatorClass;
71 		else if (classStr=="ratekeeper") _class = RatekeeperClass;
72 		else _class = InvalidClass;
73 
74 		if (sourceStr=="command_line") _source = CommandLineSource;
75 		else if (sourceStr=="configure_auto") _source = AutoSource;
76 		else if (sourceStr=="set_class") _source = DBSource;
77 		else _source = InvalidSource;
78 	}
79 
classTypeProcessClass80 	ClassType classType() const { return (ClassType)_class; }
classSourceProcessClass81 	ClassSource classSource() const { return (ClassSource)_source; }
82 
83 	bool operator == ( const ClassType& rhs ) const { return _class == rhs; }
84 	bool operator != ( const ClassType& rhs ) const { return _class != rhs; }
85 
86 	bool operator == ( const ProcessClass& rhs ) const { return _class == rhs._class && _source == rhs._source; }
87 	bool operator != ( const ProcessClass& rhs ) const { return _class != rhs._class || _source != rhs._source; }
88 
toStringProcessClass89 	std::string toString() const {
90 		switch (_class) {
91 			case UnsetClass: return "unset";
92 			case StorageClass: return "storage";
93 			case TransactionClass: return "transaction";
94 			case ResolutionClass: return "resolution";
95 			case ProxyClass: return "proxy";
96 			case MasterClass: return "master";
97 			case TesterClass: return "test";
98 			case StatelessClass: return "stateless";
99 			case LogClass: return "log";
100 			case LogRouterClass: return "router";
101 			case ClusterControllerClass: return "cluster_controller";
102 			case DataDistributorClass: return "data_distributor";
103 			case CoordinatorClass: return "coordinator";
104 			case RatekeeperClass: return "ratekeeper";
105 			default: return "invalid";
106 		}
107 	}
108 
sourceStringProcessClass109 	std::string sourceString() const {
110 		switch (_source) {
111 			case CommandLineSource: return "command_line";
112 			case AutoSource: return "configure_auto";
113 			case DBSource: return "set_class";
114 			default: return "invalid";
115 		}
116 	}
117 
118 	Fitness machineClassFitness( ClusterRole role ) const ;
119 
120 	template <class Ar>
serializeProcessClass121 	void serialize(Ar& ar) {
122 		serializer(ar, _class, _source);
123 	}
124 };
125 
126 struct LocalityData {
127 	std::map<Standalone<StringRef>, Optional<Standalone<StringRef>>>	_data;
128 
129 	static const StringRef	keyProcessId;
130 	static const StringRef	keyZoneId;
131 	static const StringRef	keyDcId;
132 	static const StringRef	keyMachineId;
133 	static const StringRef	keyDataHallId;
134 
135 public:
LocalityDataLocalityData136 	LocalityData() {}
137 
LocalityDataLocalityData138 	LocalityData(Optional<Standalone<StringRef>> processID, Optional<Standalone<StringRef>> zoneID, Optional<Standalone<StringRef>> MachineID, Optional<Standalone<StringRef>> dcID ) {
139 		_data[keyProcessId] = processID;
140 		_data[keyZoneId] = zoneID;
141 		_data[keyMachineId] = MachineID;
142 		_data[keyDcId] = dcID;
143 	}
144 
145 	bool operator == (LocalityData const& rhs) const {
146 		return ((_data.size() == rhs._data.size())													&&
147 					  (std::equal(_data.begin(), _data.end(), rhs._data.begin())));
148 	}
149 
getLocalityData150 	Optional<Standalone<StringRef>>	get(StringRef key) const {
151 		auto pos = _data.find(key);
152 		return (pos == _data.end()) ? Optional<Standalone<StringRef>>() : pos->second;
153 	}
154 
setLocalityData155 	void set(StringRef key, Optional<Standalone<StringRef>> value) {
156 		_data[key] = value;
157 	}
158 
isPresentLocalityData159 	bool	isPresent(StringRef key) const { return (_data.find(key) != _data.end()); }
isPresentLocalityData160 	bool	isPresent(StringRef key, Optional<Standalone<StringRef>> value) const {
161 		auto pos = _data.find(key);
162 		return (pos != _data.end()) ? false : (pos->second == value);
163 	}
164 
describeValueLocalityData165 	std::string describeValue(StringRef key) const {
166 		auto value = get(key);
167 		return (value.present()) ? value.get().toString() : "[unset]";
168 	}
169 
describeZoneLocalityData170 	std::string describeZone() const { return describeValue(keyZoneId); }
describeDataHallLocalityData171 	std::string describeDataHall() const { return describeValue(keyDataHallId); }
describeDcIdLocalityData172 	std::string describeDcId() const { return describeValue(keyDcId); }
describeMachineIdLocalityData173 	std::string describeMachineId() const { return describeValue(keyMachineId); }
describeProcessIdLocalityData174 	std::string describeProcessId() const { return describeValue(keyProcessId); }
175 
processIdLocalityData176 	Optional<Standalone<StringRef>> processId() const { return get(keyProcessId); }
zoneIdLocalityData177 	Optional<Standalone<StringRef>> zoneId() const { return get(keyZoneId); }
machineIdLocalityData178 	Optional<Standalone<StringRef>> machineId() const { return get(keyMachineId); } // default is ""
dcIdLocalityData179 	Optional<Standalone<StringRef>> dcId() const { return get(keyDcId); }
dataHallIdLocalityData180 	Optional<Standalone<StringRef>> dataHallId() const { return get(keyDataHallId); }
181 
toStringLocalityData182 	std::string toString() const {
183 		std::string	infoString;
184 		for (auto it = _data.rbegin(); !(it == _data.rend()); ++it) {
185 			if (infoString.length()) { infoString += " "; }
186 			infoString += it->first.printable() + "=";
187 			infoString += (it->second.present()) ? it->second.get().printable() : "[unset]";
188 		}
189 		return infoString;
190 	}
191 
192 	template <class Ar>
serializeLocalityData193 	void serialize(Ar& ar) {
194 		// Locality is persisted in the database inside StorageServerInterface, so changes here have to be
195 		// versioned carefully!
196 		if (ar.protocolVersion() >= 0x0FDB00A446020001LL) {
197 			Standalone<StringRef> key;
198 			Optional<Standalone<StringRef>> value;
199 			uint64_t mapSize = (uint64_t)_data.size();
200 			serializer(ar, mapSize);
201 			if (ar.isDeserializing) {
202 				for (size_t i = 0; i < mapSize; i++) {
203 					serializer(ar, key, value);
204 					_data[key] = value;
205 				}
206 			}
207 			else {
208 				for (auto it = _data.begin(); it != _data.end(); it++) {
209 					key = it->first;
210 					value = it->second;
211 					serializer(ar, key, value);
212 				}
213 			}
214 		}
215 		else {
216 			ASSERT(ar.isDeserializing);
217 			UID	zoneId, dcId, processId;
218 			serializer(ar, zoneId, dcId);
219 			set(keyZoneId, Standalone<StringRef>(zoneId.toString()));
220 			set(keyDcId, Standalone<StringRef>(dcId.toString()));
221 
222 			if (ar.protocolVersion() >= 0x0FDB00A340000001LL) {
223 				serializer(ar, processId);
224 				set(keyProcessId, Standalone<StringRef>(processId.toString()));
225 			}
226 			else {
227 				int _machineClass = ProcessClass::UnsetClass;
228 				serializer(ar, _machineClass);
229 			}
230 		}
231 	}
232 
233 	static const UID UNSET_ID;
234 };
235 
236 static std::string describe(
237 		std::vector<LocalityData> const& items,
238 		StringRef const key,
239 		int max_items = -1 )
240 {
241 	if(!items.size())
242 		return "[no items]";
243 	std::string s;
244 	int count = 0;
245 	for(auto const& item : items) {
246 		if( ++count > max_items && max_items >= 0)
247 			break;
248 		if (count > 1) s += ",";
249 		s += item.describeValue(key);
250 	}
251 	return s;
252 }
253 static 	std::string describeZones( std::vector<LocalityData> const& items, int max_items = -1 ) {
254 	return describe(items, LocalityData::keyZoneId, max_items);
255 }
256 static 	std::string describeDataHalls( std::vector<LocalityData> const& items, int max_items = -1 ) {
257 	return describe(items, LocalityData::keyDataHallId, max_items);
258 }
259 
260 struct ProcessData {
261 	LocalityData locality;
262 	ProcessClass processClass;
263 	NetworkAddress address;
264 
ProcessDataProcessData265 	ProcessData() {}
ProcessDataProcessData266 	ProcessData( LocalityData locality, ProcessClass processClass, NetworkAddress address ) : locality(locality), processClass(processClass), address(address) {}
267 
268 	template <class Ar>
serializeProcessData269 	void serialize(Ar& ar) {
270 		serializer(ar, locality, processClass, address);
271 	}
272 
273 	struct sort_by_address {
operatorProcessData::sort_by_address274 		bool operator ()(ProcessData const&a, ProcessData const& b) const { return a.address < b.address; }
275 	};
276 };
277 
278 template <class Interface, class Enable = void>
279 struct LBLocalityData {
280 	enum { Present = 0 };
getLocalityLBLocalityData281 	static LocalityData getLocality( Interface const& ) { return LocalityData(); }
getAddressLBLocalityData282 	static NetworkAddress getAddress( Interface const& ) { return NetworkAddress(); }
alwaysFreshLBLocalityData283 	static bool alwaysFresh() { return true; }
284 };
285 
286 // Template specialization that only works for interfaces with a .locality member.
287 //   If an interface has a .locality it must also have a .address()
288 template <class Interface>
289 struct LBLocalityData<Interface, typename std::enable_if< Interface::LocationAwareLoadBalance >::type> {
290 	enum { Present = 1 };
291 	static LocalityData getLocality( Interface const& i ) { return i.locality; }
292 	static NetworkAddress getAddress( Interface const& i ) { return i.address(); }
293 	static bool alwaysFresh() { return Interface::AlwaysFresh; }
294 };
295 
296 struct LBDistance {
297 	enum Type {
298 		SAME_MACHINE = 0,
299 		SAME_DC = 1,
300 		DISTANT = 2
301 	};
302 };
303 
304 LBDistance::Type loadBalanceDistance( LocalityData const& localLoc, LocalityData const& otherLoc, NetworkAddress const& otherAddr );
305 
306 #endif
307