Skip to content

Commit a2d79f7

Browse files
committed
refactor grpc: get rid of useless FutureImpl
commit_hash:f6d0bb7531c532aeb5030efc06fd9605d26c4aea
1 parent c4789a2 commit a2d79f7

File tree

4 files changed

+69
-94
lines changed

4 files changed

+69
-94
lines changed

grpc/include/userver/ugrpc/client/impl/async_methods.hpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -163,23 +163,6 @@ class RpcData final {
163163
grpc::Status status_;
164164
};
165165

166-
class FutureImpl final {
167-
public:
168-
explicit FutureImpl(RpcData& data) noexcept;
169-
170-
~FutureImpl() noexcept = default;
171-
172-
FutureImpl(FutureImpl&&) noexcept;
173-
FutureImpl& operator=(FutureImpl&&) noexcept;
174-
175-
RpcData* GetData() const noexcept;
176-
177-
void ClearData() noexcept;
178-
179-
private:
180-
RpcData* data_;
181-
};
182-
183166
void CheckOk(RpcData& data, AsyncMethodInvocation::WaitStatus status, std::string_view stage);
184167

185168
template <typename GrpcStream>

grpc/include/userver/ugrpc/client/rpc.hpp

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ class [[nodiscard]] UnaryFuture {
5252
) noexcept;
5353
/// @endcond
5454

55-
UnaryFuture(UnaryFuture&&) noexcept = default;
55+
UnaryFuture(UnaryFuture&&) noexcept;
5656
UnaryFuture& operator=(UnaryFuture&&) noexcept;
5757
UnaryFuture(const UnaryFuture&) = delete;
5858
UnaryFuture& operator=(const UnaryFuture&) = delete;
5959

60-
~UnaryFuture() noexcept;
60+
~UnaryFuture();
6161

6262
/// @brief Await response
6363
///
@@ -92,7 +92,7 @@ class [[nodiscard]] UnaryFuture {
9292
/// @endcond
9393

9494
private:
95-
impl::FutureImpl impl_;
95+
impl::RpcData* data_{};
9696
std::function<void(impl::RpcData& data, const grpc::Status& status)> post_finish_;
9797
};
9898

@@ -109,10 +109,12 @@ class [[nodiscard]] StreamReadFuture {
109109
) noexcept;
110110
/// @endcond
111111

112-
StreamReadFuture(StreamReadFuture&& other) noexcept = default;
112+
StreamReadFuture(StreamReadFuture&& other) noexcept;
113113
StreamReadFuture& operator=(StreamReadFuture&& other) noexcept;
114+
StreamReadFuture(const StreamReadFuture&) = delete;
115+
StreamReadFuture& operator=(const StreamReadFuture&) = delete;
114116

115-
~StreamReadFuture() noexcept;
117+
~StreamReadFuture();
116118

117119
/// @brief Await response
118120
///
@@ -131,8 +133,8 @@ class [[nodiscard]] StreamReadFuture {
131133
[[nodiscard]] bool IsReady() const noexcept;
132134

133135
private:
134-
impl::FutureImpl impl_;
135-
typename RPC::RawStream* stream_;
136+
impl::RpcData* data_{};
137+
typename RPC::RawStream* stream_{};
136138
std::function<void(impl::RpcData& data)> post_recv_message_;
137139
std::function<void(impl::RpcData& data, const grpc::Status& status)> post_finish_;
138140
};
@@ -424,53 +426,57 @@ class [[nodiscard]] BidirectionalStream final : public CallAnyBase {
424426
impl::RawReaderWriter<Request, Response> stream_;
425427
};
426428

427-
// ========================== Implementation follows ==========================
428-
429429
template <typename RPC>
430430
StreamReadFuture<RPC>::StreamReadFuture(
431431
impl::RpcData& data,
432432
typename RPC::RawStream& stream,
433433
std::function<void(impl::RpcData& data)> post_recv_message,
434434
std::function<void(impl::RpcData& data, const grpc::Status& status)> post_finish
435435
) noexcept
436-
: impl_(data),
436+
: data_(&data),
437437
stream_(&stream),
438438
post_recv_message_(std::move(post_recv_message)),
439439
post_finish_(std::move(post_finish)) {}
440440

441441
template <typename RPC>
442-
StreamReadFuture<RPC>::~StreamReadFuture() noexcept {
443-
if (auto* const data = impl_.GetData()) {
444-
impl::RpcData::AsyncMethodInvocationGuard guard(*data);
445-
const auto wait_status = impl::Wait(data->GetAsyncMethodInvocation(), data->GetContext());
446-
if (wait_status != impl::AsyncMethodInvocation::WaitStatus::kOk) {
447-
if (wait_status == impl::AsyncMethodInvocation::WaitStatus::kCancelled) {
448-
data->GetStatsScope().OnCancelled();
449-
}
450-
impl::Finish(*stream_, *data, post_finish_, false);
451-
} else {
452-
post_recv_message_(*data);
453-
}
454-
}
455-
}
442+
StreamReadFuture<RPC>::StreamReadFuture(StreamReadFuture&& other) noexcept
443+
: data_{std::exchange(other.data_, nullptr)},
444+
stream_{other.stream_},
445+
post_recv_message_{std::move(other.post_recv_message_)},
446+
post_finish_{std::move(other.post_finish_)} {}
456447

457448
template <typename RPC>
458449
StreamReadFuture<RPC>& StreamReadFuture<RPC>::operator=(StreamReadFuture<RPC>&& other) noexcept {
459450
if (this == &other) return *this;
460451
[[maybe_unused]] auto for_destruction = std::move(*this);
461-
impl_ = std::move(other.impl_);
452+
data_ = std::exchange(other.data_, nullptr);
462453
stream_ = other.stream_;
463454
post_recv_message_ = std::move(other.post_recv_message_);
464455
post_finish_ = std::move(other.post_finish_);
465456
return *this;
466457
}
467458

459+
template <typename RPC>
460+
StreamReadFuture<RPC>::~StreamReadFuture() {
461+
if (data_) {
462+
impl::RpcData::AsyncMethodInvocationGuard guard(*data_);
463+
const auto wait_status = impl::Wait(data_->GetAsyncMethodInvocation(), data_->GetContext());
464+
if (wait_status != impl::AsyncMethodInvocation::WaitStatus::kOk) {
465+
if (wait_status == impl::AsyncMethodInvocation::WaitStatus::kCancelled) {
466+
data_->GetStatsScope().OnCancelled();
467+
}
468+
impl::Finish(*stream_, *data_, post_finish_, false);
469+
} else {
470+
post_recv_message_(*data_);
471+
}
472+
}
473+
}
474+
468475
template <typename RPC>
469476
bool StreamReadFuture<RPC>::Get() {
470-
auto* const data = impl_.GetData();
471-
UINVARIANT(data, "'Get' must be called only once");
472-
impl::RpcData::AsyncMethodInvocationGuard guard(*data);
473-
impl_.ClearData();
477+
UINVARIANT(data_, "'Get' must be called only once");
478+
impl::RpcData::AsyncMethodInvocationGuard guard(*data_);
479+
auto* const data = std::exchange(data_, nullptr);
474480
const auto result = impl::Wait(data->GetAsyncMethodInvocation(), data->GetContext());
475481
if (result == impl::AsyncMethodInvocation::WaitStatus::kCancelled) {
476482
data->GetStatsScope().OnCancelled();
@@ -487,9 +493,8 @@ bool StreamReadFuture<RPC>::Get() {
487493

488494
template <typename RPC>
489495
bool StreamReadFuture<RPC>::IsReady() const noexcept {
490-
auto* const data = impl_.GetData();
491-
UINVARIANT(data, "IsReady should be called only before 'Get'");
492-
auto& method = data->GetAsyncMethodInvocation();
496+
UINVARIANT(data_, "IsReady should be called only before 'Get'");
497+
auto& method = data_->GetAsyncMethodInvocation();
493498
return method.IsReady();
494499
}
495500

grpc/src/ugrpc/client/impl/async_methods.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,6 @@ void SetErrorForSpan(RpcData& data, std::string&& message) {
7575
RpcConfigValues::RpcConfigValues(const dynamic_config::Snapshot& config)
7676
: enforce_task_deadline(config[kEnforceClientTaskDeadline]) {}
7777

78-
FutureImpl::FutureImpl(RpcData& data) noexcept : data_(&data) {}
79-
80-
FutureImpl::FutureImpl(FutureImpl&& other) noexcept : data_(std::exchange(other.data_, nullptr)) {}
81-
82-
FutureImpl& FutureImpl::operator=(FutureImpl&& other) noexcept {
83-
if (this == &other) return *this;
84-
data_ = std::exchange(other.data_, nullptr);
85-
return *this;
86-
}
87-
88-
RpcData* FutureImpl::GetData() const noexcept { return data_; }
89-
90-
void FutureImpl::ClearData() noexcept { data_ = nullptr; }
91-
9278
RpcData::RpcData(impl::CallParams&& params, CallKind call_kind)
9379
: context_(std::move(params.context)),
9480
client_name_(params.client_name),

grpc/src/ugrpc/client/rpc.cpp

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,39 @@ UnaryFuture::UnaryFuture(
4545
impl::RpcData& data,
4646
std::function<void(impl::RpcData& data, const grpc::Status& status)> post_finish
4747
) noexcept
48-
: impl_(data), post_finish_(std::move(post_finish)) {
48+
: data_(&data), post_finish_(std::move(post_finish)) {
4949
// We expect that FinishAsyncMethodInvocation was already emplaced
5050
// For unary future it is done in UnaryCall::FinishAsync
51-
UASSERT(data.HoldsFinishAsyncMethodInvocationDebug());
51+
UASSERT(data_->HoldsFinishAsyncMethodInvocationDebug());
5252
}
5353

54-
UnaryFuture::~UnaryFuture() noexcept {
55-
if (auto* const data = impl_.GetData()) {
56-
impl::RpcData::AsyncMethodInvocationGuard guard(*data);
54+
UnaryFuture::UnaryFuture(UnaryFuture&& other) noexcept
55+
: data_{std::exchange(other.data_, nullptr)}, post_finish_{std::move(other.post_finish_)} {}
5756

58-
auto& finish = data->GetFinishAsyncMethodInvocation();
57+
UnaryFuture& UnaryFuture::operator=(UnaryFuture&& other) noexcept {
58+
if (this == &other) return *this;
59+
[[maybe_unused]] auto for_destruction = std::move(*this);
60+
data_ = std::exchange(other.data_, nullptr);
61+
post_finish_ = std::move(other.post_finish_);
62+
return *this;
63+
}
64+
65+
UnaryFuture::~UnaryFuture() {
66+
if (data_) {
67+
impl::RpcData::AsyncMethodInvocationGuard guard(*data_);
5968

60-
data->GetContext().TryCancel();
69+
auto& finish = data_->GetFinishAsyncMethodInvocation();
6170

62-
const auto wait_status = impl::Wait(finish, data->GetContext());
71+
data_->GetContext().TryCancel();
72+
73+
const auto wait_status = impl::Wait(finish, data_->GetContext());
6374

6475
switch (wait_status) {
6576
case impl::AsyncMethodInvocation::WaitStatus::kOk:
6677
[[fallthrough]];
6778
case impl::AsyncMethodInvocation::WaitStatus::kError:
6879
impl::ProcessFinishResult(
69-
*data,
80+
*data_,
7081
wait_status,
7182
std::move(finish.GetStatus()),
7283
std::move(finish.GetParsedGStatus()),
@@ -75,7 +86,7 @@ UnaryFuture::~UnaryFuture() noexcept {
7586
);
7687
break;
7788
case impl::AsyncMethodInvocation::WaitStatus::kCancelled:
78-
data->GetStatsScope().OnCancelled();
89+
data_->GetStatsScope().OnCancelled();
7990
break;
8091
case impl::AsyncMethodInvocation::WaitStatus::kDeadline:
8192
UASSERT_MSG(false, "Unexpected status 'kDeadline' at UnaryFuture destruction");
@@ -84,31 +95,23 @@ UnaryFuture::~UnaryFuture() noexcept {
8495
}
8596
}
8697

87-
UnaryFuture& UnaryFuture::operator=(UnaryFuture&& other) noexcept {
88-
if (this == &other) return *this;
89-
[[maybe_unused]] auto for_destruction = std::move(*this);
90-
impl_ = std::move(other.impl_);
91-
post_finish_ = std::move(other.post_finish_);
92-
return *this;
93-
}
94-
9598
void UnaryFuture::Get() {
96-
auto* const data = impl_.GetData();
97-
UINVARIANT(data, "'Get' should not be called after readiness");
99+
UINVARIANT(data_, "'Get' should not be called after readiness");
100+
auto* const data = data_;
98101

99102
const auto result = Get(engine::Deadline{});
100103
UASSERT_MSG(result != engine::FutureStatus::kTimeout, "kTimeout has happened for infinite timeout");
101104

102105
if (result == engine::FutureStatus::kCancelled) {
103-
UASSERT_MSG(!impl_.GetData(), "Data should be cleaned up before RpcCancelledError generation");
106+
UASSERT_MSG(!data_, "Data should be cleaned up before RpcCancelledError generation");
104107
throw RpcCancelledError(data->GetCallName(), "Get()");
105108
}
106109
}
107110

108111
engine::FutureStatus UnaryFuture::Get(engine::Deadline deadline) {
109-
auto* const data = impl_.GetData();
110-
UINVARIANT(data, "'Get' should not be called after readiness");
111-
impl::RpcData::AsyncMethodInvocationGuard guard(*data);
112+
UINVARIANT(data_, "'Get' should not be called after readiness");
113+
impl::RpcData::AsyncMethodInvocationGuard guard(*data_);
114+
auto* const data = data_;
112115

113116
auto& finish = data->GetFinishAsyncMethodInvocation();
114117

@@ -132,7 +135,7 @@ engine::FutureStatus UnaryFuture::Get(engine::Deadline deadline) {
132135
// All used data could be cleared as it is not required anymore.
133136
// AsyncMethodInvocation object also should be cleared and in result
134137
// destructor will not wait any finalization from it.
135-
impl_.ClearData();
138+
data_ = nullptr;
136139
}
137140

138141
switch (wait_status) {
@@ -163,20 +166,18 @@ engine::impl::ContextAccessor* UnaryFuture::TryGetContextAccessor() noexcept {
163166
// Unfortunately, we can't require that TryGetContextAccessor is not called
164167
// after future is finished - it doesn't match pattern usage of WaitAny
165168
// Instead we should return nullptr
166-
auto* const data = impl_.GetData();
167-
if (!data) {
169+
if (!data_) {
168170
return nullptr;
169171
}
170172

171173
// if data exists, then FinishAsyncMethodInvocation also exists
172-
auto& finish = data->GetFinishAsyncMethodInvocation();
174+
auto& finish = data_->GetFinishAsyncMethodInvocation();
173175
return finish.TryGetContextAccessor();
174176
}
175177

176178
bool UnaryFuture::IsReady() const noexcept {
177-
auto* const data = impl_.GetData();
178-
UINVARIANT(data, "IsReady should be called only before 'Get'");
179-
auto& finish = data->GetFinishAsyncMethodInvocation();
179+
UINVARIANT(data_, "IsReady should be called only before 'Get'");
180+
auto& finish = data_->GetFinishAsyncMethodInvocation();
180181
return finish.IsReady();
181182
}
182183

0 commit comments

Comments
 (0)