1 /*
2  * MultiInterface.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_MULTIINTERFACE_H
22 #define FLOW_MULTIINTERFACE_H
23 #pragma once
24 
25 extern uint64_t debug_lastLoadBalanceResultEndpointToken;
26 
27 template <class K, class V>
28 struct KVPair {
29 	// KVPair<K,V> is ordered only by K and described by V
30 	K k;
31 	V v;
KVPairKVPair32 	KVPair() {}
KVPairKVPair33 	KVPair( K const& k, V const& v ) : k(k), v(v) {}
KVPairKVPair34 	KVPair(K && k, V && v) : k(std::move(k)), v(std::move(v)) {}
35 };
36 template <class K, class V> bool operator < ( KVPair<K,V> const& l, KVPair<K,V> const& r ) { return l.k < r.k; }
37 template <class K, class V> bool operator < ( KVPair<K,V> const& l, K const& r ) { return l.k < r; }
38 template <class K, class V> bool operator < ( K const& l, KVPair<K,V> const& r ) { return l < r.k; }
39 
40 template <class K, class V>
describe(KVPair<K,V> const & p)41 std::string describe( KVPair<K,V> const& p ) { return format("%d ", p.k) + describe(p.v); }
42 
43 template <class T>
44 struct ReferencedInterface : public ReferenceCounted<ReferencedInterface<T>> {
45 	T interf;
46 	int8_t distance;
toStringReferencedInterface47 	std::string toString() const {
48 		return interf.toString();
49 	}
interfReferencedInterface50 	ReferencedInterface(T const& interf, LocalityData const& locality = LocalityData()) : interf(interf) {
51 		distance = LBLocalityData<T>::Present ? loadBalanceDistance( locality, LBLocalityData<T>::getLocality( interf ), LBLocalityData<T>::getAddress( interf ) ) : LBDistance::DISTANT;
52 	}
~ReferencedInterfaceReferencedInterface53 	virtual ~ReferencedInterface() {}
54 
sort_by_distanceReferencedInterface55 	static bool sort_by_distance(Reference<ReferencedInterface<T>> r1, Reference<ReferencedInterface<T>> r2) {
56 		return r1->distance < r2->distance;
57 	}
58 };
59 
60 template <class T>
61 class MultiInterface : public ReferenceCounted<MultiInterface<T>> {
62 public:
63 	MultiInterface( const vector<T>& v, LocalityData const& locality = LocalityData() ) : bestCount(0) {
64 		for(int i=0; i<v.size(); i++)
65 			alternatives.push_back(KVPair<int,T>(LBDistance::DISTANT,v[i]));
66 		g_random->randomShuffle(alternatives);
67 		if ( LBLocalityData<T>::Present ) {
68 			for(int a=0; a<alternatives.size(); a++)
69 				alternatives[a].k = loadBalanceDistance( locality, LBLocalityData<T>::getLocality( alternatives[a].v ), LBLocalityData<T>::getAddress( alternatives[a].v ) );
70 			std::stable_sort( alternatives.begin(), alternatives.end() );
71 		}
72 		if(size())
73 			bestCount = std::lower_bound( alternatives.begin()+1, alternatives.end(), alternatives[0].k+1 ) - alternatives.begin();
74 	}
75 
size()76 	int size() const { return alternatives.size(); }
countBest()77 	int countBest() const {
78 		return bestCount;
79 	}
bestDistance()80 	LBDistance::Type bestDistance() const {
81 		if( !size() )
82 			return LBDistance::DISTANT;
83 		return (LBDistance::Type) alternatives[0].k;
84 	}
alwaysFresh()85 	bool alwaysFresh() const {
86 		return LBLocalityData<T>::alwaysFresh();
87 	}
88 
89 	template <class F>
get(int index,F T::* member)90 	F const& get( int index, F T::*member ) const {
91 		return alternatives[index].v.*member;
92 	}
93 
getInterface(int index)94 	T const& getInterface(int index) { return alternatives[index].v; }
getId(int index)95 	UID getId( int index ) const { return alternatives[index].v.id(); }
96 
~MultiInterface()97 	virtual ~MultiInterface() {}
98 
description()99 	std::string description() {
100 		return describe( alternatives );
101 	}
102 private:
103 	vector<KVPair<int,T>> alternatives;
104 	int16_t bestCount;
105 };
106 
107 template <class T>
108 class MultiInterface<ReferencedInterface<T>> : public ReferenceCounted<MultiInterface<ReferencedInterface<T>>> {
109 public:
MultiInterface(const vector<Reference<ReferencedInterface<T>>> & v)110 	MultiInterface( const vector<Reference<ReferencedInterface<T>>>& v ) : alternatives(v), bestCount(0) {
111 		g_random->randomShuffle(alternatives);
112 		if ( LBLocalityData<T>::Present ) {
113 			std::stable_sort( alternatives.begin(), alternatives.end(), ReferencedInterface<T>::sort_by_distance );
114 		}
115 		if(size()) {
116 			for(int i = 1; i < alternatives.size(); i++) {
117 				if(alternatives[i]->distance > alternatives[0]->distance) {
118 					bestCount = i;
119 					return;
120 				}
121 			}
122 			bestCount = size();
123 		}
124 	}
125 
size()126 	int size() const { return alternatives.size(); }
countBest()127 	int countBest() const {
128 		return bestCount;
129 	}
bestDistance()130 	LBDistance::Type bestDistance() const {
131 		if( !size() )
132 			return LBDistance::DISTANT;
133 		return (LBDistance::Type) alternatives[0]->distance;
134 	}
alwaysFresh()135 	bool alwaysFresh() const {
136 		return LBLocalityData<T>::alwaysFresh();
137 	}
138 
139 	template <class F>
get(int index,F T::* member)140 	F const& get( int index, F T::*member ) const {
141 		return alternatives[index]->interf.*member;
142 	}
143 
getInterface(int index)144 	T const& getInterface(int index) { return alternatives[index]->interf; }
getId(int index)145 	UID getId( int index ) const { return alternatives[index]->interf.id(); }
146 
~MultiInterface()147 	virtual ~MultiInterface() {}
148 
description()149 	std::string description() {
150 		return describe( alternatives );
151 	}
152 private:
153 	vector<Reference<ReferencedInterface<T>>> alternatives;
154 	int16_t bestCount;
155 };
156 
load(Ar & ar,Reference<MultiInterface<T>> &)157 template <class Ar, class T> void load(Ar& ar, Reference<MultiInterface<T>>&) { ASSERT(false); }	//< required for Future<T>
158 
159 #endif
160