1
#pragma once
2

            
3
#include <vector>
4

            
5
#include "envoy/config/cluster/v3/cluster.pb.h"
6
#include "envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.pb.h"
7
#include "envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.pb.validate.h"
8
#include "envoy/runtime/runtime.h"
9
#include "envoy/stats/scope.h"
10
#include "envoy/stats/stats_macros.h"
11
#include "envoy/upstream/load_balancer.h"
12

            
13
#include "source/common/common/logger.h"
14
#include "source/extensions/load_balancing_policies/common/thread_aware_lb_impl.h"
15

            
16
namespace Envoy {
17
namespace Upstream {
18

            
19
using RingHashLbProto = envoy::extensions::load_balancing_policies::ring_hash::v3::RingHash;
20
using ClusterProto = envoy::config::cluster::v3::Cluster;
21

            
22
using CommonLbConfigProto = envoy::config::cluster::v3::Cluster::CommonLbConfig;
23
using LegacyRingHashLbProto = envoy::config::cluster::v3::Cluster::RingHashLbConfig;
24

            
25
/**
26
 * Load balancer config that used to wrap typed ring hash config.
27
 */
28
class TypedRingHashLbConfig : public Upstream::TypedHashLbConfigBase {
29
public:
30
  TypedRingHashLbConfig(const CommonLbConfigProto& common_lb_config,
31
                        const LegacyRingHashLbProto& lb_config);
32
  TypedRingHashLbConfig(const RingHashLbProto& lb_config, Regex::Engine& regex_engine,
33
                        absl::Status& creation_status);
34

            
35
  RingHashLbProto lb_config_;
36
};
37

            
38
/**
39
 * All ring hash load balancer stats. @see stats_macros.h
40
 */
41
#define ALL_RING_HASH_LOAD_BALANCER_STATS(GAUGE)                                                   \
42
91
  GAUGE(max_hashes_per_host, Accumulate)                                                           \
43
91
  GAUGE(min_hashes_per_host, Accumulate)                                                           \
44
91
  GAUGE(size, Accumulate)
45

            
46
/**
47
 * Struct definition for all ring hash load balancer stats. @see stats_macros.h
48
 */
49
struct RingHashLoadBalancerStats {
50
  ALL_RING_HASH_LOAD_BALANCER_STATS(GENERATE_GAUGE_STRUCT)
51
};
52

            
53
/**
54
 * A load balancer that implements consistent modulo hashing ("ketama"). Currently, zone aware
55
 * routing is not supported. A ring is kept for all hosts as well as a ring for healthy hosts.
56
 * Unless we are in panic mode, the healthy host ring is used.
57
 * In the future it would be nice to support:
58
 * 1) Weighting.
59
 * 2) Per-zone rings and optional zone aware routing (not all applications will want this).
60
 * 3) Max request fallback to support hot shards (not all applications will want this).
61
 */
62
class RingHashLoadBalancer : public ThreadAwareLoadBalancerBase {
63
public:
64
  RingHashLoadBalancer(const PrioritySet& priority_set, ClusterLbStats& stats, Stats::Scope& scope,
65
                       Runtime::Loader& runtime, Random::RandomGenerator& random,
66
                       uint32_t healthy_panic_threshold, const RingHashLbProto& config,
67
                       HashPolicySharedPtr hash_policy);
68

            
69
141
  const RingHashLoadBalancerStats& stats() const { return stats_; }
70

            
71
private:
72
  using HashFunction = RingHashLbProto::HashFunction;
73

            
74
  struct RingEntry {
75
    uint64_t hash_;
76
    HostConstSharedPtr host_;
77
  };
78

            
79
  struct Ring : public HashingLoadBalancer {
80
    Ring(const NormalizedHostWeightVector& normalized_host_weights, double min_normalized_weight,
81
         uint64_t min_ring_size, uint64_t max_ring_size, HashFunction hash_function,
82
         bool use_hostname_for_hashing, RingHashLoadBalancerStats& stats);
83

            
84
    // ThreadAwareLoadBalancerBase::HashingLoadBalancer
85
    HostSelectionResponse chooseHost(uint64_t hash, uint32_t attempt) const override;
86

            
87
    std::vector<RingEntry> ring_;
88

            
89
    RingHashLoadBalancerStats& stats_;
90
  };
91
  using RingConstSharedPtr = std::shared_ptr<const Ring>;
92

            
93
  // ThreadAwareLoadBalancerBase
94
  HashingLoadBalancerSharedPtr
95
  createLoadBalancer(const NormalizedHostWeightVector& normalized_host_weights,
96
171
                     double min_normalized_weight, double /* max_normalized_weight */) override {
97
171
    HashingLoadBalancerSharedPtr ring_hash_lb =
98
171
        std::make_shared<Ring>(normalized_host_weights, min_normalized_weight, min_ring_size_,
99
171
                               max_ring_size_, hash_function_, use_hostname_for_hashing_, stats_);
100
171
    if (hash_balance_factor_ == 0) {
101
163
      return ring_hash_lb;
102
163
    }
103

            
104
8
    return std::make_shared<BoundedLoadHashingLoadBalancer>(
105
8
        ring_hash_lb, std::move(normalized_host_weights), hash_balance_factor_);
106
171
  }
107

            
108
  static RingHashLoadBalancerStats generateStats(Stats::Scope& scope);
109

            
110
  Stats::ScopeSharedPtr scope_;
111
  RingHashLoadBalancerStats stats_;
112

            
113
  static const uint64_t DefaultMinRingSize = 1024;
114
  static const uint64_t DefaultMaxRingSize = 1024 * 1024 * 8;
115
  const uint64_t min_ring_size_;
116
  const uint64_t max_ring_size_;
117
  const HashFunction hash_function_;
118
  const bool use_hostname_for_hashing_;
119
  const uint32_t hash_balance_factor_;
120
};
121

            
122
} // namespace Upstream
123
} // namespace Envoy