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