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