Line data Source code
1 : #pragma once
2 :
3 : #include <algorithm>
4 : #include <bitset>
5 : #include <cstdint>
6 : #include <functional>
7 : #include <map>
8 : #include <memory>
9 : #include <string>
10 :
11 : #include "envoy/common/optref.h"
12 : #include "envoy/config/cluster/v3/cluster.pb.h"
13 : #include "envoy/extensions/load_balancing_policies/subset/v3/subset.pb.h"
14 : #include "envoy/extensions/load_balancing_policies/subset/v3/subset.pb.validate.h"
15 : #include "envoy/runtime/runtime.h"
16 : #include "envoy/stats/scope.h"
17 : #include "envoy/stream_info/stream_info.h"
18 : #include "envoy/upstream/load_balancer.h"
19 :
20 : #include "source/common/common/macros.h"
21 : #include "source/common/protobuf/protobuf.h"
22 : #include "source/common/protobuf/utility.h"
23 : #include "source/common/upstream/load_balancer_impl.h"
24 : #include "source/common/upstream/upstream_impl.h"
25 :
26 : #include "absl/container/node_hash_map.h"
27 : #include "absl/types/optional.h"
28 :
29 : namespace Envoy {
30 : namespace Upstream {
31 :
32 : class ChildLoadBalancerCreator {
33 : public:
34 0 : virtual ~ChildLoadBalancerCreator() = default;
35 :
36 : virtual std::pair<ThreadAwareLoadBalancerPtr, LoadBalancerPtr>
37 : createLoadBalancer(const PrioritySet& child_priority_set, const PrioritySet* local_priority_set,
38 : ClusterLbStats& stats, Stats::Scope& scope, Runtime::Loader& runtime,
39 : Random::RandomGenerator& random, TimeSource& time_source) PURE;
40 : };
41 : using ChildLoadBalancerCreatorPtr = std::unique_ptr<ChildLoadBalancerCreator>;
42 :
43 : class LegacyChildLoadBalancerCreatorImpl : public Upstream::ChildLoadBalancerCreator {
44 : public:
45 : LegacyChildLoadBalancerCreatorImpl(
46 : LoadBalancerType lb_type,
47 : OptRef<const envoy::config::cluster::v3::Cluster::RingHashLbConfig> lb_ring_hash_config,
48 : OptRef<const envoy::config::cluster::v3::Cluster::MaglevLbConfig> lb_maglev_config,
49 : OptRef<const envoy::config::cluster::v3::Cluster::RoundRobinLbConfig> round_robin_config,
50 : OptRef<const envoy::config::cluster::v3::Cluster::LeastRequestLbConfig> least_request_config,
51 : const envoy::config::cluster::v3::Cluster::CommonLbConfig& common_config);
52 :
53 : std::pair<Upstream::ThreadAwareLoadBalancerPtr, Upstream::LoadBalancerPtr>
54 : createLoadBalancer(const Upstream::PrioritySet& child_priority_set,
55 : const Upstream::PrioritySet* local_priority_set, ClusterLbStats& stats,
56 : Stats::Scope& scope, Runtime::Loader& runtime, Random::RandomGenerator& random,
57 : TimeSource& time_source) override;
58 :
59 0 : OptRef<const envoy::config::cluster::v3::Cluster::RoundRobinLbConfig> lbRoundRobinConfig() const {
60 0 : if (round_robin_config_ != nullptr) {
61 0 : return *round_robin_config_;
62 0 : }
63 0 : return absl::nullopt;
64 0 : }
65 :
66 0 : LoadBalancerType lbType() const { return lb_type_; }
67 :
68 : OptRef<const envoy::config::cluster::v3::Cluster::LeastRequestLbConfig>
69 0 : lbLeastRequestConfig() const {
70 0 : if (least_request_config_ != nullptr) {
71 0 : return *least_request_config_;
72 0 : }
73 0 : return absl::nullopt;
74 0 : }
75 :
76 0 : OptRef<const envoy::config::cluster::v3::Cluster::MaglevLbConfig> lbMaglevConfig() const {
77 0 : if (lb_maglev_config_ != nullptr) {
78 0 : return *lb_maglev_config_;
79 0 : }
80 0 : return absl::nullopt;
81 0 : }
82 :
83 0 : OptRef<const envoy::config::cluster::v3::Cluster::RingHashLbConfig> lbRingHashConfig() const {
84 0 : if (lb_ring_hash_config_ != nullptr) {
85 0 : return *lb_ring_hash_config_;
86 0 : }
87 0 : return absl::nullopt;
88 0 : }
89 :
90 : private:
91 : const LoadBalancerType lb_type_;
92 : const std::unique_ptr<const envoy::config::cluster::v3::Cluster::RingHashLbConfig>
93 : lb_ring_hash_config_;
94 : const std::unique_ptr<const envoy::config::cluster::v3::Cluster::MaglevLbConfig>
95 : lb_maglev_config_;
96 : const std::unique_ptr<const envoy::config::cluster::v3::Cluster::RoundRobinLbConfig>
97 : round_robin_config_;
98 : const std::unique_ptr<const envoy::config::cluster::v3::Cluster::LeastRequestLbConfig>
99 : least_request_config_;
100 : const envoy::config::cluster::v3::Cluster::CommonLbConfig common_config_;
101 : };
102 :
103 : using HostHashSet = absl::flat_hash_set<HostSharedPtr>;
104 :
105 : class SubsetLoadBalancerConfig : public Upstream::LoadBalancerConfig {
106 : public:
107 : SubsetLoadBalancerConfig(const SubsetLoadbalancingPolicyProto& subset_config,
108 : ProtobufMessage::ValidationVisitor& visitor);
109 :
110 : SubsetLoadBalancerConfig(const LegacySubsetLoadbalancingPolicyProto& subset_config,
111 : Upstream::LoadBalancerConfigPtr sub_load_balancer_config,
112 : Upstream::TypedLoadBalancerFactory* sub_load_balancer_factory)
113 : : subset_info_(subset_config), sub_load_balancer_config_(std::move(sub_load_balancer_config)),
114 0 : sub_load_balancer_factory_(sub_load_balancer_factory) {
115 0 : ASSERT(sub_load_balancer_factory_ != nullptr, "sub_load_balancer_factory_ must not be nullptr");
116 0 : }
117 :
118 : Upstream::ThreadAwareLoadBalancerPtr
119 : createLoadBalancer(const Upstream::ClusterInfo& cluster_info,
120 : const Upstream::PrioritySet& child_priority_set, Runtime::Loader& runtime,
121 0 : Random::RandomGenerator& random, TimeSource& time_source) const {
122 0 : return sub_load_balancer_factory_->create(*sub_load_balancer_config_, cluster_info,
123 0 : child_priority_set, runtime, random, time_source);
124 0 : }
125 :
126 0 : const Upstream::LoadBalancerSubsetInfo& subsetInfo() const { return subset_info_; }
127 :
128 : private:
129 : LoadBalancerSubsetInfoImpl subset_info_;
130 :
131 : Upstream::LoadBalancerConfigPtr sub_load_balancer_config_;
132 : Upstream::TypedLoadBalancerFactory* sub_load_balancer_factory_{};
133 : };
134 :
135 : class SubsetLoadBalancer : public LoadBalancer, Logger::Loggable<Logger::Id::upstream> {
136 : public:
137 : SubsetLoadBalancer(const LoadBalancerSubsetInfo& subsets, ChildLoadBalancerCreatorPtr child_lb,
138 : const PrioritySet& priority_set, const PrioritySet* local_priority_set,
139 : ClusterLbStats& stats, Stats::Scope& scope, Runtime::Loader& runtime,
140 : Random::RandomGenerator& random, TimeSource& time_source);
141 : ~SubsetLoadBalancer() override;
142 :
143 : // Upstream::LoadBalancer
144 : HostConstSharedPtr chooseHost(LoadBalancerContext* context) override;
145 : // TODO(alyssawilk) implement for non-metadata match.
146 0 : HostConstSharedPtr peekAnotherHost(LoadBalancerContext*) override { return nullptr; }
147 : // Pool selection not implemented.
148 : absl::optional<Upstream::SelectedPoolAndConnection>
149 : selectExistingConnection(Upstream::LoadBalancerContext* /*context*/,
150 : const Upstream::Host& /*host*/,
151 0 : std::vector<uint8_t>& /*hash_key*/) override {
152 0 : return absl::nullopt;
153 0 : }
154 : // Lifetime tracking not implemented.
155 0 : OptRef<Envoy::Http::ConnectionPool::ConnectionLifetimeCallbacks> lifetimeCallbacks() override {
156 0 : return {};
157 0 : }
158 :
159 : private:
160 : struct SubsetSelectorFallbackParams;
161 :
162 : void initSubsetAnyOnce();
163 : void initSubsetDefaultOnce();
164 : void initSubsetSelectorMap();
165 : void initSelectorFallbackSubset(const envoy::config::cluster::v3::Cluster::LbSubsetConfig::
166 : LbSubsetSelector::LbSubsetSelectorFallbackPolicy&);
167 : HostConstSharedPtr
168 : chooseHostForSelectorFallbackPolicy(const SubsetSelectorFallbackParams& fallback_params,
169 : LoadBalancerContext* context);
170 :
171 : HostConstSharedPtr chooseHostIteration(LoadBalancerContext* context);
172 :
173 : // Represents a subset of an original HostSet.
174 : class HostSubsetImpl : public HostSetImpl {
175 : public:
176 : HostSubsetImpl(const HostSet& original_host_set, bool locality_weight_aware,
177 : bool scale_locality_weight)
178 : : HostSetImpl(original_host_set.priority(), original_host_set.weightedPriorityHealth(),
179 : original_host_set.overprovisioningFactor()),
180 : original_host_set_(original_host_set), locality_weight_aware_(locality_weight_aware),
181 0 : scale_locality_weight_(scale_locality_weight) {}
182 :
183 : void update(const HostHashSet& matching_hosts, const HostVector& hosts_added,
184 : const HostVector& hosts_removed);
185 : LocalityWeightsConstSharedPtr
186 : determineLocalityWeights(const HostsPerLocality& hosts_per_locality) const;
187 :
188 : private:
189 : const HostSet& original_host_set_;
190 : const bool locality_weight_aware_;
191 : const bool scale_locality_weight_;
192 : };
193 :
194 : // Represents a subset of an original PrioritySet.
195 : class PrioritySubsetImpl : public PrioritySetImpl {
196 : public:
197 : PrioritySubsetImpl(const SubsetLoadBalancer& subset_lb, bool locality_weight_aware,
198 : bool scale_locality_weight);
199 :
200 : void update(uint32_t priority, const HostHashSet& matching_hosts, const HostVector& hosts_added,
201 : const HostVector& hosts_removed);
202 :
203 0 : bool empty() const { return empty_; }
204 :
205 0 : void triggerCallbacks() {
206 0 : for (size_t i = 0; i < hostSetsPerPriority().size(); ++i) {
207 0 : runReferenceUpdateCallbacks(i, {}, {});
208 0 : }
209 0 : }
210 :
211 : void updateSubset(uint32_t priority, const HostHashSet& matching_hosts,
212 0 : const HostVector& hosts_added, const HostVector& hosts_removed) {
213 0 : reinterpret_cast<HostSubsetImpl*>(host_sets_[priority].get())
214 0 : ->update(matching_hosts, hosts_added, hosts_removed);
215 0 : runUpdateCallbacks(hosts_added, hosts_removed);
216 0 : }
217 :
218 : // Thread aware LB if applicable.
219 : ThreadAwareLoadBalancerPtr thread_aware_lb_;
220 : // Current active LB.
221 : LoadBalancerPtr lb_;
222 :
223 : protected:
224 : HostSetImplPtr createHostSet(uint32_t priority, absl::optional<bool> weighted_priority_health,
225 : absl::optional<uint32_t> overprovisioning_factor) override;
226 :
227 : private:
228 : const PrioritySet& original_priority_set_;
229 : const PrioritySet* original_local_priority_set_{};
230 : const bool locality_weight_aware_;
231 : const bool scale_locality_weight_;
232 : bool empty_ = true;
233 : };
234 :
235 : using HostSubsetImplPtr = std::unique_ptr<HostSubsetImpl>;
236 : using PrioritySubsetImplPtr = std::unique_ptr<PrioritySubsetImpl>;
237 :
238 : using SubsetMetadata = std::vector<std::pair<std::string, ProtobufWkt::Value>>;
239 :
240 : class LbSubsetEntry;
241 : struct SubsetSelectorMap;
242 :
243 : using LbSubsetEntryPtr = std::shared_ptr<LbSubsetEntry>;
244 : using SubsetSelectorMapPtr = std::shared_ptr<SubsetSelectorMap>;
245 : using ValueSubsetMap = absl::node_hash_map<HashedValue, LbSubsetEntryPtr>;
246 : using LbSubsetMap = absl::node_hash_map<std::string, ValueSubsetMap>;
247 : using SubsetSelectorFallbackParamsRef = std::reference_wrapper<SubsetSelectorFallbackParams>;
248 : using MetadataFallbacks = ProtobufWkt::RepeatedPtrField<ProtobufWkt::Value>;
249 :
250 : public:
251 : class LoadBalancerContextWrapper : public LoadBalancerContext {
252 : public:
253 : LoadBalancerContextWrapper(LoadBalancerContext* wrapped,
254 : const std::set<std::string>& filtered_metadata_match_criteria_names);
255 :
256 : LoadBalancerContextWrapper(LoadBalancerContext* wrapped,
257 : Router::MetadataMatchCriteriaConstPtr metadata_match_criteria)
258 0 : : wrapped_(wrapped), metadata_match_(std::move(metadata_match_criteria)) {}
259 :
260 : LoadBalancerContextWrapper(LoadBalancerContext* wrapped,
261 : const ProtobufWkt::Struct& metadata_match_criteria_override);
262 : // LoadBalancerContext
263 0 : absl::optional<uint64_t> computeHashKey() override { return wrapped_->computeHashKey(); }
264 0 : const Router::MetadataMatchCriteria* metadataMatchCriteria() override {
265 0 : return metadata_match_.get();
266 0 : }
267 0 : const Network::Connection* downstreamConnection() const override {
268 0 : return wrapped_->downstreamConnection();
269 0 : }
270 0 : const StreamInfo::StreamInfo* requestStreamInfo() const override {
271 0 : return wrapped_->requestStreamInfo();
272 0 : }
273 0 : const Http::RequestHeaderMap* downstreamHeaders() const override {
274 0 : return wrapped_->downstreamHeaders();
275 0 : }
276 : const HealthyAndDegradedLoad& determinePriorityLoad(
277 : const PrioritySet& priority_set, const HealthyAndDegradedLoad& original_priority_load,
278 0 : const Upstream::RetryPriority::PriorityMappingFunc& priority_mapping_func) override {
279 0 : return wrapped_->determinePriorityLoad(priority_set, original_priority_load,
280 0 : priority_mapping_func);
281 0 : }
282 0 : bool shouldSelectAnotherHost(const Host& host) override {
283 0 : return wrapped_->shouldSelectAnotherHost(host);
284 0 : }
285 0 : uint32_t hostSelectionRetryCount() const override {
286 0 : return wrapped_->hostSelectionRetryCount();
287 0 : }
288 0 : Network::Socket::OptionsSharedPtr upstreamSocketOptions() const override {
289 0 : return wrapped_->upstreamSocketOptions();
290 0 : }
291 0 : Network::TransportSocketOptionsConstSharedPtr upstreamTransportSocketOptions() const override {
292 0 : return wrapped_->upstreamTransportSocketOptions();
293 0 : }
294 :
295 0 : absl::optional<OverrideHost> overrideHostToSelect() const override {
296 0 : return wrapped_->overrideHostToSelect();
297 0 : }
298 :
299 : private:
300 : LoadBalancerContext* wrapped_;
301 : Router::MetadataMatchCriteriaConstPtr metadata_match_;
302 : };
303 :
304 : private:
305 : struct SubsetSelectorFallbackParams {
306 : envoy::config::cluster::v3::Cluster::LbSubsetConfig::LbSubsetSelector::
307 : LbSubsetSelectorFallbackPolicy fallback_policy_;
308 : const std::set<std::string>* fallback_keys_subset_ = nullptr;
309 : };
310 :
311 : struct SubsetSelectorMap {
312 : absl::node_hash_map<std::string, SubsetSelectorMapPtr> subset_keys_;
313 : SubsetSelectorFallbackParams fallback_params_;
314 : };
315 :
316 : class LbSubset {
317 : public:
318 0 : virtual ~LbSubset() = default;
319 : virtual HostConstSharedPtr chooseHost(LoadBalancerContext* context) const PURE;
320 : virtual void pushHost(uint32_t priority, HostSharedPtr host) PURE;
321 : virtual void finalize(uint32_t priority) PURE;
322 : virtual bool active() const PURE;
323 : };
324 : using LbSubsetPtr = std::unique_ptr<LbSubset>;
325 :
326 : class PriorityLbSubset : public LbSubset {
327 : public:
328 : PriorityLbSubset(const SubsetLoadBalancer& subset_lb, bool locality_weight_aware,
329 : bool scale_locality_weight)
330 0 : : subset_(subset_lb, locality_weight_aware, scale_locality_weight) {}
331 :
332 : // Subset
333 0 : HostConstSharedPtr chooseHost(LoadBalancerContext* context) const override {
334 0 : return subset_.lb_->chooseHost(context);
335 0 : }
336 0 : void pushHost(uint32_t priority, HostSharedPtr host) override {
337 0 : while (host_sets_.size() <= priority) {
338 0 : host_sets_.push_back({HostHashSet(), HostHashSet()});
339 0 : }
340 0 : host_sets_[priority].second.emplace(std::move(host));
341 0 : }
342 : // Called after pushHost. Update subset by the hosts that pushed in the pushHost. If no any host
343 : // is pushed then subset_ will be set to empty.
344 0 : void finalize(uint32_t priority) override {
345 0 : while (host_sets_.size() <= priority) {
346 0 : host_sets_.push_back({HostHashSet(), HostHashSet()});
347 0 : }
348 0 : auto& [old_hosts, new_hosts] = host_sets_[priority];
349 :
350 0 : HostVector added;
351 0 : HostVector removed;
352 :
353 0 : for (const auto& host : old_hosts) {
354 0 : if (new_hosts.count(host) == 0) {
355 0 : removed.emplace_back(host);
356 0 : }
357 0 : }
358 :
359 0 : for (const auto& host : new_hosts) {
360 0 : if (old_hosts.count(host) == 0) {
361 0 : added.emplace_back(host);
362 0 : }
363 0 : }
364 :
365 0 : subset_.update(priority, new_hosts, added, removed);
366 :
367 0 : old_hosts.swap(new_hosts);
368 0 : new_hosts.clear();
369 0 : }
370 :
371 0 : bool active() const override { return !subset_.empty(); }
372 :
373 : std::vector<std::pair<HostHashSet, HostHashSet>> host_sets_;
374 : PrioritySubsetImpl subset_;
375 : };
376 :
377 : class SingleHostLbSubset : public LbSubset {
378 : // Subset
379 0 : HostConstSharedPtr chooseHost(LoadBalancerContext*) const override { return subset_; }
380 : // This is called at most once for every update for single host subset.
381 0 : void pushHost(uint32_t priority, HostSharedPtr host) override {
382 0 : new_hosts_[priority] = std::move(host);
383 0 : }
384 : // Called after pushHost. Update subset by the host that pushed in the pushHost. If no any host
385 : // is pushed then subset_ will be set to nullptr.
386 0 : void finalize(uint32_t priority) override {
387 0 : if (auto iter = new_hosts_.find(priority); iter == new_hosts_.end()) {
388 : // No any host for current subset and priority. Try remove record in the hosts_.
389 0 : hosts_.erase(priority);
390 0 : } else {
391 : // Single host is set for current subset and priority.
392 0 : hosts_[priority] = std::move(iter->second);
393 0 : new_hosts_.erase(priority);
394 0 : }
395 :
396 0 : if (hosts_.empty()) {
397 0 : subset_ = nullptr;
398 0 : return;
399 0 : }
400 :
401 0 : subset_ = hosts_.begin()->second;
402 0 : }
403 0 : bool active() const override { return subset_ != nullptr; }
404 :
405 : // We will update subsets for every priority separately and these simple map can help us
406 : // to ensure which priority has valid host quickly.
407 : std::map<uint32_t, HostSharedPtr> hosts_;
408 : std::map<uint32_t, HostSharedPtr> new_hosts_;
409 : HostConstSharedPtr subset_;
410 : };
411 :
412 : // Entry in the subset hierarchy.
413 : class LbSubsetEntry {
414 : public:
415 0 : LbSubsetEntry() = default;
416 :
417 0 : bool initialized() const { return lb_subset_ != nullptr; }
418 0 : bool active() const { return initialized() && lb_subset_->active(); }
419 0 : bool hasChildren() const { return !children_.empty(); }
420 :
421 : LbSubsetMap children_;
422 :
423 : // Only initialized if a match exists at this level.
424 : LbSubsetPtr lb_subset_;
425 :
426 : // Used to quick check if entry is single host subset entry or not.
427 : bool single_host_subset_{};
428 : };
429 :
430 : void initLbSubsetEntryOnce(LbSubsetEntryPtr& entry, bool single_host_subset);
431 :
432 : // Create filtered default subset (if necessary) and other subsets based on current hosts.
433 : void refreshSubsets();
434 : void refreshSubsets(uint32_t priority);
435 :
436 : // Called by HostSet::MemberUpdateCb
437 : void update(uint32_t priority, const HostVector& all_hosts);
438 :
439 : void updateFallbackSubset(uint32_t priority, const HostVector& all_hosts);
440 : void processSubsets(uint32_t priority, const HostVector& all_hosts);
441 :
442 : HostConstSharedPtr tryChooseHostFromContext(LoadBalancerContext* context, bool& host_chosen);
443 :
444 : absl::optional<SubsetSelectorFallbackParamsRef>
445 : tryFindSelectorFallbackParams(LoadBalancerContext* context);
446 :
447 : bool hostMatches(const SubsetMetadata& kvs, const Host& host);
448 :
449 : LbSubsetEntryPtr
450 : findSubset(const std::vector<Router::MetadataMatchCriterionConstSharedPtr>& matches);
451 :
452 : LbSubsetEntryPtr findOrCreateLbSubsetEntry(LbSubsetMap& subsets, const SubsetMetadata& kvs,
453 : uint32_t idx);
454 : void forEachSubset(LbSubsetMap& subsets, std::function<void(LbSubsetEntryPtr&)> cb);
455 : void purgeEmptySubsets(LbSubsetMap& subsets);
456 :
457 : std::vector<SubsetMetadata> extractSubsetMetadata(const std::set<std::string>& subset_keys,
458 : const Host& host);
459 : std::string describeMetadata(const SubsetMetadata& kvs);
460 : HostConstSharedPtr chooseHostWithMetadataFallbacks(LoadBalancerContext* context,
461 : const MetadataFallbacks& metadata_fallbacks);
462 : const ProtobufWkt::Value* getMetadataFallbackList(LoadBalancerContext* context) const;
463 : LoadBalancerContextWrapper removeMetadataFallbackList(LoadBalancerContext* context);
464 :
465 : ClusterLbStats& stats_;
466 : Stats::Scope& scope_;
467 : Runtime::Loader& runtime_;
468 : Random::RandomGenerator& random_;
469 : TimeSource& time_source_;
470 :
471 : const envoy::config::cluster::v3::Cluster::LbSubsetConfig::LbSubsetFallbackPolicy
472 : fallback_policy_;
473 : const envoy::config::cluster::v3::Cluster::LbSubsetConfig::LbSubsetMetadataFallbackPolicy
474 : metadata_fallback_policy_;
475 : const SubsetMetadata default_subset_metadata_;
476 : std::vector<SubsetSelectorPtr> subset_selectors_;
477 :
478 : const PrioritySet& original_priority_set_;
479 : const PrioritySet* original_local_priority_set_;
480 : Common::CallbackHandlePtr original_priority_set_callback_handle_;
481 :
482 : ChildLoadBalancerCreatorPtr child_lb_creator_;
483 :
484 : LbSubsetEntryPtr subset_any_;
485 : LbSubsetEntryPtr subset_default_;
486 :
487 : // Reference to sub_set_any_ or subset_default_.
488 : LbSubsetEntryPtr fallback_subset_;
489 : LbSubsetEntryPtr panic_mode_subset_;
490 :
491 : // Forms a trie-like structure. Requires lexically sorted Host and Route metadata.
492 : LbSubsetMap subsets_;
493 : // Forms a trie-like structure of lexically sorted keys+fallback policy from subset
494 : // selectors configuration
495 : SubsetSelectorMapPtr selectors_;
496 :
497 : Stats::Gauge* single_duplicate_stat_{};
498 :
499 : // Keep small members (bools and enums) at the end of class, to reduce alignment overhead.
500 : const bool locality_weight_aware_ : 1;
501 : const bool scale_locality_weight_ : 1;
502 : const bool list_as_any_ : 1;
503 : const bool allow_redundant_keys_{};
504 :
505 : friend class SubsetLoadBalancerInternalStateTester;
506 : };
507 :
508 : } // namespace Upstream
509 : } // namespace Envoy
|