1 // 2 // Copyright 2015 gRPC authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef GRPC_SRC_CORE_LOAD_BALANCING_ENDPOINT_LIST_H 18 #define GRPC_SRC_CORE_LOAD_BALANCING_ENDPOINT_LIST_H 19 20 #include <grpc/support/port_platform.h> 21 22 #include <stdlib.h> 23 24 #include <memory> 25 #include <utility> 26 #include <vector> 27 28 #include "absl/functional/function_ref.h" 29 #include "absl/status/status.h" 30 #include "absl/types/optional.h" 31 32 #include <grpc/impl/connectivity_state.h> 33 34 #include "src/core/lib/channel/channel_args.h" 35 #include "src/core/lib/gprpp/debug_location.h" 36 #include "src/core/lib/gprpp/orphanable.h" 37 #include "src/core/lib/gprpp/ref_counted_ptr.h" 38 #include "src/core/lib/gprpp/work_serializer.h" 39 #include "src/core/lib/iomgr/resolved_address.h" 40 #include "src/core/load_balancing/lb_policy.h" 41 #include "src/core/load_balancing/subchannel_interface.h" 42 #include "src/core/resolver/endpoint_addresses.h" 43 44 namespace grpc_core { 45 46 // A list of endpoints for use in a petiole LB policy. Each endpoint may 47 // have one or more addresses, which will be passed down to a pick_first 48 // child policy. 49 // 50 // To use this, a petiole policy must define its own subclass of both 51 // EndpointList and EndpointList::Endpoint, like so: 52 /* 53 class MyEndpointList : public EndpointList { 54 public: 55 MyEndpointList(RefCountedPtr<MyLbPolicy> lb_policy, 56 EndpointAddressesIterator* endpoints, 57 const ChannelArgs& args) 58 : EndpointList(std::move(lb_policy), 59 GRPC_TRACE_FLAG_ENABLED(grpc_my_tracer) 60 ? "MyEndpointList" 61 : nullptr) { 62 Init(endpoints, args, 63 [&](RefCountedPtr<MyEndpointList> endpoint_list, 64 const EndpointAddresses& addresses, const ChannelArgs& args) { 65 return MakeOrphanable<MyEndpoint>( 66 std::move(endpoint_list), addresses, args, 67 policy<MyLbPolicy>()->work_serializer()); 68 }); 69 } 70 71 private: 72 class MyEndpoint : public Endpoint { 73 public: 74 MyEndpoint(RefCountedPtr<MyEndpointList> endpoint_list, 75 const EndpointAddresses& address, const ChannelArgs& args, 76 std::shared_ptr<WorkSerializer> work_serializer) 77 : Endpoint(std::move(endpoint_list)) { 78 Init(addresses, args, std::move(work_serializer)); 79 } 80 81 private: 82 void OnStateUpdate( 83 absl::optional<grpc_connectivity_state> old_state, 84 grpc_connectivity_state new_state, 85 const absl::Status& status) override { 86 // ...handle connectivity state change... 87 } 88 }; 89 90 LoadBalancingPolicy::ChannelControlHelper* channel_control_helper() 91 const override { 92 return policy<MyLbPolicy>()->channel_control_helper(); 93 } 94 }; 95 */ 96 // TODO(roth): Consider wrapping this in an LB policy subclass for petiole 97 // policies to inherit from. 98 class EndpointList : public InternallyRefCounted<EndpointList> { 99 public: 100 // An individual endpoint. 101 class Endpoint : public InternallyRefCounted<Endpoint> { 102 public: ~Endpoint()103 ~Endpoint() override { endpoint_list_.reset(DEBUG_LOCATION, "Endpoint"); } 104 105 void Orphan() override; 106 107 void ResetBackoffLocked(); 108 void ExitIdleLocked(); 109 connectivity_state()110 absl::optional<grpc_connectivity_state> connectivity_state() const { 111 return connectivity_state_; 112 } picker()113 RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> picker() const { 114 return picker_; 115 } 116 117 protected: 118 // We use two-phase initialization here to ensure that the vtable is 119 // initialized before we need to use it. Subclass must invoke Init() 120 // from inside its ctor. Endpoint(RefCountedPtr<EndpointList> endpoint_list)121 explicit Endpoint(RefCountedPtr<EndpointList> endpoint_list) 122 : endpoint_list_(std::move(endpoint_list)) {} 123 124 void Init(const EndpointAddresses& addresses, const ChannelArgs& args, 125 std::shared_ptr<WorkSerializer> work_serializer); 126 127 // Templated for convenience, to provide a short-hand for 128 // down-casting in the caller. 129 template <typename T> endpoint_list()130 T* endpoint_list() const { 131 return static_cast<T*>(endpoint_list_.get()); 132 } 133 134 // Templated for convenience, to provide a short-hand for down-casting 135 // in the caller. 136 template <typename T> policy()137 T* policy() const { 138 return endpoint_list_->policy<T>(); 139 } 140 141 // Returns the index of this endpoint within the EndpointList. 142 // Intended for trace logging. 143 size_t Index() const; 144 145 private: 146 class Helper; 147 148 // Called when the child policy reports a connectivity state update. 149 virtual void OnStateUpdate( 150 absl::optional<grpc_connectivity_state> old_state, 151 grpc_connectivity_state new_state, const absl::Status& status) = 0; 152 153 // Called to create a subchannel. Subclasses may override. 154 virtual RefCountedPtr<SubchannelInterface> CreateSubchannel( 155 const grpc_resolved_address& address, 156 const ChannelArgs& per_address_args, const ChannelArgs& args); 157 158 RefCountedPtr<EndpointList> endpoint_list_; 159 160 OrphanablePtr<LoadBalancingPolicy> child_policy_; 161 absl::optional<grpc_connectivity_state> connectivity_state_; 162 RefCountedPtr<LoadBalancingPolicy::SubchannelPicker> picker_; 163 }; 164 ~EndpointList()165 ~EndpointList() override { policy_.reset(DEBUG_LOCATION, "EndpointList"); } 166 Orphan()167 void Orphan() override { 168 endpoints_.clear(); 169 Unref(); 170 } 171 size()172 size_t size() const { return endpoints_.size(); } 173 endpoints()174 const std::vector<OrphanablePtr<Endpoint>>& endpoints() const { 175 return endpoints_; 176 } 177 178 void ResetBackoffLocked(); 179 180 protected: 181 // We use two-phase initialization here to ensure that the vtable is 182 // initialized before we need to use it. Subclass must invoke Init() 183 // from inside its ctor. EndpointList(RefCountedPtr<LoadBalancingPolicy> policy,const char * tracer)184 EndpointList(RefCountedPtr<LoadBalancingPolicy> policy, const char* tracer) 185 : policy_(std::move(policy)), tracer_(tracer) {} 186 187 void Init(EndpointAddressesIterator* endpoints, const ChannelArgs& args, 188 absl::FunctionRef<OrphanablePtr<Endpoint>( 189 RefCountedPtr<EndpointList>, const EndpointAddresses&, 190 const ChannelArgs&)> 191 create_endpoint); 192 193 // Templated for convenience, to provide a short-hand for down-casting 194 // in the caller. 195 template <typename T> policy()196 T* policy() const { 197 return static_cast<T*>(policy_.get()); 198 } 199 200 // Returns true if all endpoints have seen their initial connectivity 201 // state notification. AllEndpointsSeenInitialState()202 bool AllEndpointsSeenInitialState() const { 203 return num_endpoints_seen_initial_state_ == size(); 204 } 205 206 private: 207 // Returns the parent policy's helper. Needed because the accessor 208 // method is protected on LoadBalancingPolicy. 209 virtual LoadBalancingPolicy::ChannelControlHelper* channel_control_helper() 210 const = 0; 211 212 RefCountedPtr<LoadBalancingPolicy> policy_; 213 const char* tracer_; 214 std::vector<OrphanablePtr<Endpoint>> endpoints_; 215 size_t num_endpoints_seen_initial_state_ = 0; 216 }; 217 218 } // namespace grpc_core 219 220 #endif // GRPC_SRC_CORE_LOAD_BALANCING_ENDPOINT_LIST_H 221