9
9
10
10
#include < userver/dynamic_config/source.hpp>
11
11
#include < userver/engine/task/task_processor_fwd.hpp>
12
+ #include < userver/rcu/rcu.hpp>
12
13
#include < userver/testsuite/grpc_control.hpp>
13
14
#include < userver/utils/fixed_array.hpp>
14
15
15
16
#include < userver/ugrpc/client/client_factory_settings.hpp>
16
17
#include < userver/ugrpc/client/client_settings.hpp>
17
18
#include < userver/ugrpc/client/fwd.hpp>
18
19
#include < userver/ugrpc/client/impl/channel_factory.hpp>
20
+ #include < userver/ugrpc/client/impl/stub_any.hpp>
21
+ #include < userver/ugrpc/client/impl/stub_pool.hpp>
19
22
#include < userver/ugrpc/client/middlewares/fwd.hpp>
20
23
#include < userver/ugrpc/impl/static_service_metadata.hpp>
21
24
#include < userver/ugrpc/impl/statistics.hpp>
@@ -36,7 +39,7 @@ struct ClientDependencies final {
36
39
Middlewares mws;
37
40
ugrpc::impl::CompletionQueuePoolBase& completion_queues;
38
41
ugrpc::impl::StatisticsStorage& statistics_storage;
39
- const dynamic_config::Source config_source;
42
+ dynamic_config::Source config_source;
40
43
testsuite::GrpcControl& testsuite_grpc;
41
44
const dynamic_config::Key<ClientQos>* qos{nullptr };
42
45
const ClientFactorySettings& client_factory_settings;
@@ -51,8 +54,31 @@ struct GenericClientTag final {
51
54
// / The internal state of generated gRPC clients
52
55
class ClientData final {
53
56
public:
54
- template <typename Service>
55
- using Stub = typename Service::Stub;
57
+ struct StubState {
58
+ StubPool stubs;
59
+ // method_id -> stub_pool
60
+ utils::FixedArray<StubPool> dedicated_stubs;
61
+ };
62
+
63
+ class StubHandle {
64
+ public:
65
+ StubHandle (rcu::ReadablePtr<StubState>&& state, StubAny& stub) : state_{std::move (state)}, stub_{stub} {}
66
+
67
+ StubHandle (StubHandle&&) noexcept = default ;
68
+ StubHandle& operator =(StubHandle&&) = delete ;
69
+
70
+ StubHandle (const StubHandle&) = delete ;
71
+ StubHandle& operator =(const StubHandle&) = delete ;
72
+
73
+ template <typename Stub>
74
+ Stub& Get () {
75
+ return StubCast<Stub>(stub_);
76
+ }
77
+
78
+ private:
79
+ rcu::ReadablePtr<StubState> state_;
80
+ StubAny& stub_;
81
+ };
56
82
57
83
ClientData () = delete ;
58
84
@@ -62,36 +88,42 @@ class ClientData final {
62
88
metadata_ (metadata),
63
89
service_statistics_(&GetServiceStatistics ()),
64
90
channel_factory_(CreateChannelFactory(dependencies_)),
65
- channels_(CreateChannels(channel_factory_, dependencies_.client_factory_settings.channel_count)),
66
- stubs_(MakeStubs<Service>(channels_)),
67
- dedicated_stubs_(
68
- MakeDedicatedStubs<Service>(channel_factory_, *metadata_, dependencies_.dedicated_methods_config)
69
- ) {}
91
+ stub_state_(std::make_unique<rcu::Variable<StubState>>()) {
92
+ if (dependencies_.qos ) {
93
+ SubscribeOnConfigUpdate<Service>(*dependencies_.qos );
94
+ } else {
95
+ ConstructStubState<typename Service::Stub>();
96
+ }
97
+ }
70
98
71
99
template <typename Service>
72
100
ClientData (ClientDependencies&& dependencies, GenericClientTag, std::in_place_type_t <Service>)
73
101
: dependencies_(std::move(dependencies)),
74
102
channel_factory_(CreateChannelFactory(dependencies_)),
75
- channels_(CreateChannels(channel_factory_, dependencies_.client_factory_settings.channel_count)),
76
- stubs_(MakeStubs<Service>(channels_)) {}
103
+ stub_state_(std::make_unique<rcu::Variable<StubState>>()) {
104
+ ConstructStubState<typename Service::Stub>();
105
+ }
106
+
107
+ ~ClientData ();
77
108
78
109
ClientData (ClientData&&) noexcept = default;
79
110
ClientData& operator =(ClientData&&) = delete;
80
111
81
112
ClientData (const ClientData&) = delete;
82
113
ClientData& operator =(const ClientData&) = delete ;
83
114
84
- template < typename Service>
85
- Stub<Service>& NextStubFromMethodId (std:: size_t method_id) const {
86
- if (!dedicated_stubs_ [method_id]. empty ()) {
87
- return * static_cast <Stub<Service>*>( NextStubPtr (dedicated_stubs_[method_id]). get ()) ;
88
- }
89
- return NextGenericStub<Service>() ;
115
+ StubHandle NextStubFromMethodId (std:: size_t method_id) const {
116
+ auto stub_state = stub_state_-> Read ();
117
+ auto & dedicated_stubs = stub_state-> dedicated_stubs [method_id];
118
+ auto & stubs = dedicated_stubs. Size () ? dedicated_stubs : stub_state-> stubs ;
119
+ auto & stub = stubs. NextStub ();
120
+ return StubHandle{ std::move (stub_state), stub} ;
90
121
}
91
122
92
- template <typename Service>
93
- Stub<Service>& NextGenericStub () const {
94
- return *static_cast <Stub<Service>*>(NextStubPtr (stubs_).get ());
123
+ StubHandle NextStub () const {
124
+ auto stub_state = stub_state_->Read ();
125
+ auto & stub = stub_state->stubs .NextStub ();
126
+ return StubHandle{std::move (stub_state), stub};
95
127
}
96
128
97
129
grpc::CompletionQueue& NextQueue () const ;
@@ -102,8 +134,6 @@ class ClientData final {
102
134
103
135
ugrpc::impl::MethodStatistics& GetGenericStatistics (std::string_view call_name) const ;
104
136
105
- const utils::FixedArray<std::shared_ptr<grpc::Channel>>& GetChannels () { return channels_; }
106
-
107
137
std::string_view GetClientName () const { return dependencies_.client_name ; }
108
138
109
139
const Middlewares& GetMiddlewares () const { return dependencies_.mws ; }
@@ -114,37 +144,12 @@ class ClientData final {
114
144
115
145
const dynamic_config::Key<ClientQos>* GetClientQos () const ;
116
146
117
- std:: size_t GetDedicatedChannelCount (std:: size_t method_id ) const ;
147
+ rcu::ReadablePtr<StubState> GetStubState ( ) const { return stub_state_-> Read (); }
118
148
119
149
private:
120
150
static ChannelFactory CreateChannelFactory (const ClientDependencies& dependencies);
121
151
122
- static utils::FixedArray<std::shared_ptr<grpc::Channel>>
123
- CreateChannels (const ChannelFactory& channel_factory, std::size_t channel_count);
124
-
125
- using StubDeleterType = void (*)(void *);
126
- using StubPtr = std::unique_ptr<void , StubDeleterType>;
127
-
128
- using StubPool = utils::FixedArray<StubPtr>;
129
-
130
- template <typename Service>
131
- static void StubDeleter (void * ptr) noexcept {
132
- delete static_cast <Stub<Service>*>(ptr);
133
- }
134
-
135
- template <typename Service>
136
- static StubPtr MakeStub (const std::shared_ptr<grpc::Channel>& channel) {
137
- return StubPtr (Service::NewStub (channel).release (), &StubDeleter<Service>);
138
- }
139
-
140
- template <typename Service>
141
- static StubPool MakeStubs (const utils::FixedArray<std::shared_ptr<grpc::Channel>>& channels) {
142
- return utils::GenerateFixedArray (channels.size (), [&](std::size_t index) {
143
- return MakeStub<Service>(channels[index]);
144
- });
145
- }
146
-
147
- template <typename Service>
152
+ template <typename Stub>
148
153
static utils::FixedArray<StubPool> MakeDedicatedStubs (
149
154
const ChannelFactory& channel_factory,
150
155
const ugrpc::impl::StaticServiceMetadata& metadata,
@@ -153,28 +158,45 @@ class ClientData final {
153
158
return utils::GenerateFixedArray (GetMethodsCount (metadata), [&](std::size_t method_id) {
154
159
const auto method_channel_count =
155
160
GetMethodChannelCount (dedicated_methods_config, GetMethodName (metadata, method_id));
156
- return utils::GenerateFixedArray (method_channel_count, [&](std::size_t ) {
157
- const auto channel = channel_factory.CreateChannel ();
158
- return MakeStub<Service>(channel);
159
- });
161
+ return StubPool::Create<Stub>(method_channel_count, channel_factory);
160
162
});
161
163
}
162
164
163
- const StubPtr& NextStubPtr (const StubPool& stubs) const ;
164
-
165
165
ugrpc::impl::ServiceStatistics& GetServiceStatistics ();
166
166
167
+ template <typename Service>
168
+ void SubscribeOnConfigUpdate (const dynamic_config::Key<ClientQos>& qos) {
169
+ config_subscription_ = dependencies_.config_source .UpdateAndListen (
170
+ this , dependencies_.client_name , &ClientData::OnConfigUpdate<Service>, qos
171
+ );
172
+ }
173
+
174
+ template <typename Service>
175
+ void OnConfigUpdate (const dynamic_config::Snapshot& /* config*/ ) {
176
+ ConstructStubState<typename Service::Stub>();
177
+ }
178
+
179
+ template <typename Stub>
180
+ void ConstructStubState () {
181
+ auto stubs = StubPool::Create<Stub>(dependencies_.client_factory_settings .channel_count , channel_factory_);
182
+
183
+ auto dedicated_stubs =
184
+ metadata_.has_value ()
185
+ ? MakeDedicatedStubs<Stub>(channel_factory_, *metadata_, dependencies_.dedicated_methods_config )
186
+ : utils::FixedArray<StubPool>{};
187
+
188
+ stub_state_->Assign ({std::move (stubs), std::move (dedicated_stubs)});
189
+ }
190
+
167
191
ClientDependencies dependencies_;
168
192
std::optional<ugrpc::impl::StaticServiceMetadata> metadata_{std::nullopt};
169
193
ugrpc::impl::ServiceStatistics* service_statistics_{nullptr };
170
194
171
195
ChannelFactory channel_factory_;
196
+ std::unique_ptr<rcu::Variable<StubState>> stub_state_;
172
197
173
- utils::FixedArray<std::shared_ptr<grpc::Channel>> channels_;
174
-
175
- StubPool stubs_;
176
- // method_id -> stub_pool
177
- utils::FixedArray<StubPool> dedicated_stubs_;
198
+ // These fields must be the last ones
199
+ concurrent::AsyncEventSubscriberScope config_subscription_;
178
200
};
179
201
180
202
template <typename Client>
0 commit comments