|
|
|
@ -746,6 +746,113 @@ class FailLbFactory : public LoadBalancingPolicyFactory { |
|
|
|
|
std::atomic<int>* pick_counter_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// QueueOnceLoadBalancingPolicy - a load balancing policy that provides a Queue
|
|
|
|
|
// PickResult at least once, after which it delegates to PickFirst.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
constexpr char kQueueOncePolicyName[] = "queue_once"; |
|
|
|
|
|
|
|
|
|
class QueueOnceLoadBalancingPolicy : public ForwardingLoadBalancingPolicy { |
|
|
|
|
public: |
|
|
|
|
explicit QueueOnceLoadBalancingPolicy(Args args) |
|
|
|
|
: ForwardingLoadBalancingPolicy( |
|
|
|
|
std::make_unique<Helper>( |
|
|
|
|
RefCountedPtr<QueueOnceLoadBalancingPolicy>(this)), |
|
|
|
|
std::move(args), "pick_first", |
|
|
|
|
/*initial_refcount=*/2) {} |
|
|
|
|
|
|
|
|
|
// We use the standard QueuePicker which invokes ExitIdleLocked() on the first
|
|
|
|
|
// pick.
|
|
|
|
|
void ExitIdleLocked() override { |
|
|
|
|
bool needs_update = !std::exchange(seen_pick_queued_, true); |
|
|
|
|
if (needs_update) { |
|
|
|
|
channel_control_helper()->UpdateState(state_to_update_.state, |
|
|
|
|
state_to_update_.status, |
|
|
|
|
std::move(state_to_update_.picker)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
absl::string_view name() const override { return kQueueOncePolicyName; } |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
class Helper : public ChannelControlHelper { |
|
|
|
|
public: |
|
|
|
|
explicit Helper(RefCountedPtr<QueueOnceLoadBalancingPolicy> parent) |
|
|
|
|
: parent_(std::move(parent)) {} |
|
|
|
|
|
|
|
|
|
RefCountedPtr<SubchannelInterface> CreateSubchannel( |
|
|
|
|
ServerAddress address, const ChannelArgs& args) override { |
|
|
|
|
return parent_->channel_control_helper()->CreateSubchannel( |
|
|
|
|
std::move(address), args); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void UpdateState(grpc_connectivity_state state, const absl::Status& status, |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker) override { |
|
|
|
|
// If we've already seen a queued pick, just propagate the update
|
|
|
|
|
// directly.
|
|
|
|
|
if (parent_->seen_pick_queued_) { |
|
|
|
|
parent_->channel_control_helper()->UpdateState(state, status, |
|
|
|
|
std::move(picker)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Otherwise, store the update in the LB policy, to be propagated later,
|
|
|
|
|
// and return a queueing picker.
|
|
|
|
|
parent_->state_to_update_ = {state, status, std::move(picker)}; |
|
|
|
|
parent_->channel_control_helper()->UpdateState( |
|
|
|
|
state, status, MakeRefCounted<QueuePicker>(parent_->Ref())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestReresolution() override { |
|
|
|
|
parent_->channel_control_helper()->RequestReresolution(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
absl::string_view GetAuthority() override { |
|
|
|
|
return parent_->channel_control_helper()->GetAuthority(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_event_engine::experimental::EventEngine* GetEventEngine() override { |
|
|
|
|
return parent_->channel_control_helper()->GetEventEngine(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AddTraceEvent(TraceSeverity severity, |
|
|
|
|
absl::string_view message) override { |
|
|
|
|
parent_->channel_control_helper()->AddTraceEvent(severity, message); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
RefCountedPtr<QueueOnceLoadBalancingPolicy> parent_; |
|
|
|
|
}; |
|
|
|
|
struct StateToUpdate { |
|
|
|
|
grpc_connectivity_state state; |
|
|
|
|
absl::Status status; |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker; |
|
|
|
|
}; |
|
|
|
|
StateToUpdate state_to_update_; |
|
|
|
|
bool seen_pick_queued_ = false; // Has a pick been queued yet. Only accessed
|
|
|
|
|
// from within the WorkSerializer.
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class QueueOnceLbConfig : public LoadBalancingPolicy::Config { |
|
|
|
|
public: |
|
|
|
|
absl::string_view name() const override { return kQueueOncePolicyName; } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class QueueOnceLoadBalancingPolicyFactory : public LoadBalancingPolicyFactory { |
|
|
|
|
public: |
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
|
|
|
|
LoadBalancingPolicy::Args args) const override { |
|
|
|
|
return MakeOrphanable<QueueOnceLoadBalancingPolicy>(std::move(args)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
absl::string_view name() const override { return kQueueOncePolicyName; } |
|
|
|
|
|
|
|
|
|
absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>> |
|
|
|
|
ParseLoadBalancingConfig(const Json& /*json*/) const override { |
|
|
|
|
return MakeRefCounted<QueueOnceLbConfig>(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void RegisterTestPickArgsLoadBalancingPolicy( |
|
|
|
@ -788,4 +895,9 @@ void RegisterFailLoadBalancingPolicy(CoreConfiguration::Builder* builder, |
|
|
|
|
std::make_unique<FailLbFactory>(std::move(status), pick_counter)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RegisterQueueOnceLoadBalancingPolicy(CoreConfiguration::Builder* builder) { |
|
|
|
|
builder->lb_policy_registry()->RegisterLoadBalancingPolicyFactory( |
|
|
|
|
std::make_unique<QueueOnceLoadBalancingPolicyFactory>()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|