[transport] Move call spine related types into their own file (#35689)
Part of a continued hygiene effort for transport.h
(pure code movement, no refactoring at this time)
Closes #35689
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35689 from ctiller:channel-ez 3366310cc3
PiperOrigin-RevId: 602416330
This commit is contained in:
parent
5b444972f3
commit
fb14685fd6
2
BUILD
2
BUILD
|
|
@ -1533,6 +1533,7 @@ grpc_cc_library(
|
|||
"//src/core:bitset",
|
||||
"//src/core:call_filters",
|
||||
"//src/core:call_final_info",
|
||||
"//src/core:call_spine",
|
||||
"//src/core:cancel_callback",
|
||||
"//src/core:channel_args",
|
||||
"//src/core:channel_args_endpoint_config",
|
||||
|
|
@ -1584,7 +1585,6 @@ grpc_cc_library(
|
|||
"//src/core:pollset_set",
|
||||
"//src/core:posix_event_engine_base_hdrs",
|
||||
"//src/core:posix_event_engine_endpoint",
|
||||
"//src/core:prioritized_race",
|
||||
"//src/core:promise_status",
|
||||
"//src/core:race",
|
||||
"//src/core:random_early_detection",
|
||||
|
|
|
|||
|
|
@ -2528,6 +2528,7 @@ add_library(grpc
|
|||
src/core/lib/transport/bdp_estimator.cc
|
||||
src/core/lib/transport/call_filters.cc
|
||||
src/core/lib/transport/call_final_info.cc
|
||||
src/core/lib/transport/call_spine.cc
|
||||
src/core/lib/transport/connectivity_state.cc
|
||||
src/core/lib/transport/error_utils.cc
|
||||
src/core/lib/transport/handshaker.cc
|
||||
|
|
@ -3243,6 +3244,7 @@ add_library(grpc_unsecure
|
|||
src/core/lib/transport/bdp_estimator.cc
|
||||
src/core/lib/transport/call_filters.cc
|
||||
src/core/lib/transport/call_final_info.cc
|
||||
src/core/lib/transport/call_spine.cc
|
||||
src/core/lib/transport/connectivity_state.cc
|
||||
src/core/lib/transport/error_utils.cc
|
||||
src/core/lib/transport/handshaker.cc
|
||||
|
|
@ -5330,6 +5332,7 @@ add_library(grpc_authorization_provider
|
|||
src/core/lib/transport/batch_builder.cc
|
||||
src/core/lib/transport/call_filters.cc
|
||||
src/core/lib/transport/call_final_info.cc
|
||||
src/core/lib/transport/call_spine.cc
|
||||
src/core/lib/transport/connectivity_state.cc
|
||||
src/core/lib/transport/error_utils.cc
|
||||
src/core/lib/transport/handshaker.cc
|
||||
|
|
|
|||
|
|
@ -1710,6 +1710,7 @@ LIBGRPC_SRC = \
|
|||
src/core/lib/transport/bdp_estimator.cc \
|
||||
src/core/lib/transport/call_filters.cc \
|
||||
src/core/lib/transport/call_final_info.cc \
|
||||
src/core/lib/transport/call_spine.cc \
|
||||
src/core/lib/transport/connectivity_state.cc \
|
||||
src/core/lib/transport/error_utils.cc \
|
||||
src/core/lib/transport/handshaker.cc \
|
||||
|
|
@ -2259,6 +2260,7 @@ LIBGRPC_UNSECURE_SRC = \
|
|||
src/core/lib/transport/bdp_estimator.cc \
|
||||
src/core/lib/transport/call_filters.cc \
|
||||
src/core/lib/transport/call_final_info.cc \
|
||||
src/core/lib/transport/call_spine.cc \
|
||||
src/core/lib/transport/connectivity_state.cc \
|
||||
src/core/lib/transport/error_utils.cc \
|
||||
src/core/lib/transport/handshaker.cc \
|
||||
|
|
|
|||
|
|
@ -1903,6 +1903,8 @@ let package = Package(
|
|||
"src/core/lib/transport/call_filters.h",
|
||||
"src/core/lib/transport/call_final_info.cc",
|
||||
"src/core/lib/transport/call_final_info.h",
|
||||
"src/core/lib/transport/call_spine.cc",
|
||||
"src/core/lib/transport/call_spine.h",
|
||||
"src/core/lib/transport/connectivity_state.cc",
|
||||
"src/core/lib/transport/connectivity_state.h",
|
||||
"src/core/lib/transport/custom_metadata.h",
|
||||
|
|
|
|||
|
|
@ -1179,6 +1179,7 @@ libs:
|
|||
- src/core/lib/transport/bdp_estimator.h
|
||||
- src/core/lib/transport/call_filters.h
|
||||
- src/core/lib/transport/call_final_info.h
|
||||
- src/core/lib/transport/call_spine.h
|
||||
- src/core/lib/transport/connectivity_state.h
|
||||
- src/core/lib/transport/custom_metadata.h
|
||||
- src/core/lib/transport/error_utils.h
|
||||
|
|
@ -1982,6 +1983,7 @@ libs:
|
|||
- src/core/lib/transport/bdp_estimator.cc
|
||||
- src/core/lib/transport/call_filters.cc
|
||||
- src/core/lib/transport/call_final_info.cc
|
||||
- src/core/lib/transport/call_spine.cc
|
||||
- src/core/lib/transport/connectivity_state.cc
|
||||
- src/core/lib/transport/error_utils.cc
|
||||
- src/core/lib/transport/handshaker.cc
|
||||
|
|
@ -2628,6 +2630,7 @@ libs:
|
|||
- src/core/lib/transport/bdp_estimator.h
|
||||
- src/core/lib/transport/call_filters.h
|
||||
- src/core/lib/transport/call_final_info.h
|
||||
- src/core/lib/transport/call_spine.h
|
||||
- src/core/lib/transport/connectivity_state.h
|
||||
- src/core/lib/transport/custom_metadata.h
|
||||
- src/core/lib/transport/error_utils.h
|
||||
|
|
@ -3047,6 +3050,7 @@ libs:
|
|||
- src/core/lib/transport/bdp_estimator.cc
|
||||
- src/core/lib/transport/call_filters.cc
|
||||
- src/core/lib/transport/call_final_info.cc
|
||||
- src/core/lib/transport/call_spine.cc
|
||||
- src/core/lib/transport/connectivity_state.cc
|
||||
- src/core/lib/transport/error_utils.cc
|
||||
- src/core/lib/transport/handshaker.cc
|
||||
|
|
@ -4669,6 +4673,7 @@ libs:
|
|||
- src/core/lib/transport/batch_builder.h
|
||||
- src/core/lib/transport/call_filters.h
|
||||
- src/core/lib/transport/call_final_info.h
|
||||
- src/core/lib/transport/call_spine.h
|
||||
- src/core/lib/transport/connectivity_state.h
|
||||
- src/core/lib/transport/custom_metadata.h
|
||||
- src/core/lib/transport/error_utils.h
|
||||
|
|
@ -4965,6 +4970,7 @@ libs:
|
|||
- src/core/lib/transport/batch_builder.cc
|
||||
- src/core/lib/transport/call_filters.cc
|
||||
- src/core/lib/transport/call_final_info.cc
|
||||
- src/core/lib/transport/call_spine.cc
|
||||
- src/core/lib/transport/connectivity_state.cc
|
||||
- src/core/lib/transport/error_utils.cc
|
||||
- src/core/lib/transport/handshaker.cc
|
||||
|
|
|
|||
|
|
@ -838,6 +838,7 @@ if test "$PHP_GRPC" != "no"; then
|
|||
src/core/lib/transport/bdp_estimator.cc \
|
||||
src/core/lib/transport/call_filters.cc \
|
||||
src/core/lib/transport/call_final_info.cc \
|
||||
src/core/lib/transport/call_spine.cc \
|
||||
src/core/lib/transport/connectivity_state.cc \
|
||||
src/core/lib/transport/error_utils.cc \
|
||||
src/core/lib/transport/handshaker.cc \
|
||||
|
|
|
|||
|
|
@ -803,6 +803,7 @@ if (PHP_GRPC != "no") {
|
|||
"src\\core\\lib\\transport\\bdp_estimator.cc " +
|
||||
"src\\core\\lib\\transport\\call_filters.cc " +
|
||||
"src\\core\\lib\\transport\\call_final_info.cc " +
|
||||
"src\\core\\lib\\transport\\call_spine.cc " +
|
||||
"src\\core\\lib\\transport\\connectivity_state.cc " +
|
||||
"src\\core\\lib\\transport\\error_utils.cc " +
|
||||
"src\\core\\lib\\transport\\handshaker.cc " +
|
||||
|
|
|
|||
|
|
@ -1283,6 +1283,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/transport/bdp_estimator.h',
|
||||
'src/core/lib/transport/call_filters.h',
|
||||
'src/core/lib/transport/call_final_info.h',
|
||||
'src/core/lib/transport/call_spine.h',
|
||||
'src/core/lib/transport/connectivity_state.h',
|
||||
'src/core/lib/transport/custom_metadata.h',
|
||||
'src/core/lib/transport/error_utils.h',
|
||||
|
|
@ -2537,6 +2538,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/transport/bdp_estimator.h',
|
||||
'src/core/lib/transport/call_filters.h',
|
||||
'src/core/lib/transport/call_final_info.h',
|
||||
'src/core/lib/transport/call_spine.h',
|
||||
'src/core/lib/transport/connectivity_state.h',
|
||||
'src/core/lib/transport/custom_metadata.h',
|
||||
'src/core/lib/transport/error_utils.h',
|
||||
|
|
|
|||
|
|
@ -2012,6 +2012,8 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/transport/call_filters.h',
|
||||
'src/core/lib/transport/call_final_info.cc',
|
||||
'src/core/lib/transport/call_final_info.h',
|
||||
'src/core/lib/transport/call_spine.cc',
|
||||
'src/core/lib/transport/call_spine.h',
|
||||
'src/core/lib/transport/connectivity_state.cc',
|
||||
'src/core/lib/transport/connectivity_state.h',
|
||||
'src/core/lib/transport/custom_metadata.h',
|
||||
|
|
@ -3314,6 +3316,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/transport/bdp_estimator.h',
|
||||
'src/core/lib/transport/call_filters.h',
|
||||
'src/core/lib/transport/call_final_info.h',
|
||||
'src/core/lib/transport/call_spine.h',
|
||||
'src/core/lib/transport/connectivity_state.h',
|
||||
'src/core/lib/transport/custom_metadata.h',
|
||||
'src/core/lib/transport/error_utils.h',
|
||||
|
|
|
|||
|
|
@ -1905,6 +1905,8 @@ Gem::Specification.new do |s|
|
|||
s.files += %w( src/core/lib/transport/call_filters.h )
|
||||
s.files += %w( src/core/lib/transport/call_final_info.cc )
|
||||
s.files += %w( src/core/lib/transport/call_final_info.h )
|
||||
s.files += %w( src/core/lib/transport/call_spine.cc )
|
||||
s.files += %w( src/core/lib/transport/call_spine.h )
|
||||
s.files += %w( src/core/lib/transport/connectivity_state.cc )
|
||||
s.files += %w( src/core/lib/transport/connectivity_state.h )
|
||||
s.files += %w( src/core/lib/transport/custom_metadata.h )
|
||||
|
|
|
|||
|
|
@ -1024,6 +1024,7 @@
|
|||
'src/core/lib/transport/bdp_estimator.cc',
|
||||
'src/core/lib/transport/call_filters.cc',
|
||||
'src/core/lib/transport/call_final_info.cc',
|
||||
'src/core/lib/transport/call_spine.cc',
|
||||
'src/core/lib/transport/connectivity_state.cc',
|
||||
'src/core/lib/transport/error_utils.cc',
|
||||
'src/core/lib/transport/handshaker.cc',
|
||||
|
|
@ -1513,6 +1514,7 @@
|
|||
'src/core/lib/transport/bdp_estimator.cc',
|
||||
'src/core/lib/transport/call_filters.cc',
|
||||
'src/core/lib/transport/call_final_info.cc',
|
||||
'src/core/lib/transport/call_spine.cc',
|
||||
'src/core/lib/transport/connectivity_state.cc',
|
||||
'src/core/lib/transport/error_utils.cc',
|
||||
'src/core/lib/transport/handshaker.cc',
|
||||
|
|
@ -2282,6 +2284,7 @@
|
|||
'src/core/lib/transport/batch_builder.cc',
|
||||
'src/core/lib/transport/call_filters.cc',
|
||||
'src/core/lib/transport/call_final_info.cc',
|
||||
'src/core/lib/transport/call_spine.cc',
|
||||
'src/core/lib/transport/connectivity_state.cc',
|
||||
'src/core/lib/transport/error_utils.cc',
|
||||
'src/core/lib/transport/handshaker.cc',
|
||||
|
|
|
|||
|
|
@ -1887,6 +1887,8 @@
|
|||
<file baseinstalldir="/" name="src/core/lib/transport/call_filters.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/call_final_info.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/call_final_info.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/call_spine.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/call_spine.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/transport/custom_metadata.h" role="src" />
|
||||
|
|
|
|||
|
|
@ -6788,6 +6788,30 @@ grpc_cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "call_spine",
|
||||
srcs = [
|
||||
"lib/transport/call_spine.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"lib/transport/call_spine.h",
|
||||
],
|
||||
deps = [
|
||||
"1999",
|
||||
"for_each",
|
||||
"if",
|
||||
"latch",
|
||||
"message",
|
||||
"metadata",
|
||||
"pipe",
|
||||
"prioritized_race",
|
||||
"promise_status",
|
||||
"status_flag",
|
||||
"try_seq",
|
||||
"//:gpr",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "metadata_batch",
|
||||
srcs = [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2024 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "src/core/lib/transport/call_spine.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
void ForwardCall(CallHandler call_handler, CallInitiator call_initiator,
|
||||
ClientMetadataHandle client_initial_metadata) {
|
||||
// Send initial metadata.
|
||||
call_initiator.SpawnGuarded(
|
||||
"send_initial_metadata",
|
||||
[client_initial_metadata = std::move(client_initial_metadata),
|
||||
call_initiator]() mutable {
|
||||
return call_initiator.PushClientInitialMetadata(
|
||||
std::move(client_initial_metadata));
|
||||
});
|
||||
// Read messages from handler into initiator.
|
||||
call_handler.SpawnGuarded("read_messages", [call_handler,
|
||||
call_initiator]() mutable {
|
||||
return Seq(ForEach(OutgoingMessages(call_handler),
|
||||
[call_initiator](MessageHandle msg) mutable {
|
||||
// Need to spawn a job into the initiator's activity to
|
||||
// push the message in.
|
||||
return call_initiator.SpawnWaitable(
|
||||
"send_message",
|
||||
[msg = std::move(msg), call_initiator]() mutable {
|
||||
return call_initiator.CancelIfFails(
|
||||
call_initiator.PushMessage(std::move(msg)));
|
||||
});
|
||||
}),
|
||||
[call_initiator](StatusFlag result) mutable {
|
||||
call_initiator.SpawnInfallible(
|
||||
"finish-downstream", [call_initiator, result]() mutable {
|
||||
if (result.ok()) {
|
||||
call_initiator.FinishSends();
|
||||
} else {
|
||||
call_initiator.Cancel();
|
||||
}
|
||||
return Empty{};
|
||||
});
|
||||
return result;
|
||||
});
|
||||
});
|
||||
call_initiator.SpawnInfallible("read_the_things", [call_initiator,
|
||||
call_handler]() mutable {
|
||||
return Seq(
|
||||
call_initiator.CancelIfFails(TrySeq(
|
||||
call_initiator.PullServerInitialMetadata(),
|
||||
[call_handler,
|
||||
call_initiator](absl::optional<ServerMetadataHandle> md) mutable {
|
||||
const bool has_md = md.has_value();
|
||||
call_handler.SpawnGuarded(
|
||||
"recv_initial_metadata",
|
||||
[md = std::move(md), call_handler]() mutable {
|
||||
return call_handler.PushServerInitialMetadata(
|
||||
std::move(md));
|
||||
});
|
||||
return If(
|
||||
has_md,
|
||||
ForEach(OutgoingMessages(call_initiator),
|
||||
[call_handler](MessageHandle msg) mutable {
|
||||
return call_handler.SpawnWaitable(
|
||||
"recv_message",
|
||||
[msg = std::move(msg), call_handler]() mutable {
|
||||
return call_handler.CancelIfFails(
|
||||
call_handler.PushMessage(std::move(msg)));
|
||||
});
|
||||
}),
|
||||
[]() -> StatusFlag { return Success{}; });
|
||||
})),
|
||||
call_initiator.PullServerTrailingMetadata(),
|
||||
[call_handler](ServerMetadataHandle md) mutable {
|
||||
call_handler.SpawnGuarded(
|
||||
"recv_trailing_metadata",
|
||||
[md = std::move(md), call_handler]() mutable {
|
||||
return call_handler.PushServerTrailingMetadata(std::move(md));
|
||||
});
|
||||
return Empty{};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CallInitiatorAndHandler MakeCall(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena) {
|
||||
auto spine = CallSpine::Create(event_engine, arena);
|
||||
return {CallInitiator(spine), CallHandler(spine)};
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
@ -0,0 +1,418 @@
|
|||
// Copyright 2024 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
|
||||
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include <grpc/support/log.h>
|
||||
|
||||
#include "src/core/lib/promise/detail/status.h"
|
||||
#include "src/core/lib/promise/for_each.h"
|
||||
#include "src/core/lib/promise/if.h"
|
||||
#include "src/core/lib/promise/latch.h"
|
||||
#include "src/core/lib/promise/party.h"
|
||||
#include "src/core/lib/promise/pipe.h"
|
||||
#include "src/core/lib/promise/prioritized_race.h"
|
||||
#include "src/core/lib/promise/status_flag.h"
|
||||
#include "src/core/lib/promise/try_seq.h"
|
||||
#include "src/core/lib/transport/message.h"
|
||||
#include "src/core/lib/transport/metadata.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// The common middle part of a call - a reference is held by each of
|
||||
// CallInitiator and CallHandler - which provide interfaces that are appropriate
|
||||
// for each side of a call.
|
||||
// The spine will ultimately host the pipes, filters, and context for one part
|
||||
// of a call: ie top-half client channel, sub channel call, server call.
|
||||
// TODO(ctiller): eventually drop this when we don't need to reference into
|
||||
// legacy promise calls anymore
|
||||
class CallSpineInterface {
|
||||
public:
|
||||
virtual ~CallSpineInterface() = default;
|
||||
virtual Pipe<ClientMetadataHandle>& client_initial_metadata() = 0;
|
||||
virtual Pipe<ServerMetadataHandle>& server_initial_metadata() = 0;
|
||||
virtual Pipe<MessageHandle>& client_to_server_messages() = 0;
|
||||
virtual Pipe<MessageHandle>& server_to_client_messages() = 0;
|
||||
virtual Pipe<ServerMetadataHandle>& server_trailing_metadata() = 0;
|
||||
virtual Latch<ServerMetadataHandle>& cancel_latch() = 0;
|
||||
// Add a callback to be called when server trailing metadata is received.
|
||||
void OnDone(absl::AnyInvocable<void()> fn) {
|
||||
if (on_done_ == nullptr) {
|
||||
on_done_ = std::move(fn);
|
||||
return;
|
||||
}
|
||||
on_done_ = [first = std::move(fn), next = std::move(on_done_)]() mutable {
|
||||
first();
|
||||
next();
|
||||
};
|
||||
}
|
||||
void CallOnDone() {
|
||||
if (on_done_ != nullptr) std::exchange(on_done_, nullptr)();
|
||||
}
|
||||
virtual Party& party() = 0;
|
||||
virtual void IncrementRefCount() = 0;
|
||||
virtual void Unref() = 0;
|
||||
|
||||
// Cancel the call with the given metadata.
|
||||
// Regarding the `MUST_USE_RESULT absl::nullopt_t`:
|
||||
// Most cancellation calls right now happen in pipe interceptors;
|
||||
// there `nullopt` indicates terminate processing of this pipe and close with
|
||||
// error.
|
||||
// It's convenient then to have the Cancel operation (setting the latch to
|
||||
// terminate the call) be the last thing that occurs in a pipe interceptor,
|
||||
// and this construction supports that (and has helped the author not write
|
||||
// some bugs).
|
||||
GRPC_MUST_USE_RESULT absl::nullopt_t Cancel(ServerMetadataHandle metadata) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
auto& c = cancel_latch();
|
||||
if (c.is_set()) return absl::nullopt;
|
||||
c.Set(std::move(metadata));
|
||||
CallOnDone();
|
||||
client_initial_metadata().sender.CloseWithError();
|
||||
server_initial_metadata().sender.CloseWithError();
|
||||
client_to_server_messages().sender.CloseWithError();
|
||||
server_to_client_messages().sender.CloseWithError();
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
auto WaitForCancel() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
return cancel_latch().Wait();
|
||||
}
|
||||
|
||||
// Wrap a promise so that if it returns failure it automatically cancels
|
||||
// the rest of the call.
|
||||
// The resulting (returned) promise will resolve to Empty.
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
using P = promise_detail::PromiseLike<Promise>;
|
||||
using ResultType = typename P::Result;
|
||||
return Map(std::move(promise), [this](ResultType r) {
|
||||
if (!IsStatusOk(r)) {
|
||||
std::ignore = Cancel(StatusCast<ServerMetadataHandle>(r));
|
||||
}
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
// Spawn a promise that returns Empty{} and save some boilerplate handling
|
||||
// that detail.
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
party().Spawn(name, std::move(promise_factory), [](Empty) {});
|
||||
}
|
||||
|
||||
// Spawn a promise that returns some status-like type; if the status
|
||||
// represents failure automatically cancel the rest of the call.
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
using FactoryType =
|
||||
promise_detail::OncePromiseFactory<void, PromiseFactory>;
|
||||
using PromiseType = typename FactoryType::Promise;
|
||||
using ResultType = typename PromiseType::Result;
|
||||
static_assert(
|
||||
std::is_same<bool,
|
||||
decltype(IsStatusOk(std::declval<ResultType>()))>::value,
|
||||
"SpawnGuarded promise must return a status-like object");
|
||||
party().Spawn(name, std::move(promise_factory), [this](ResultType r) {
|
||||
if (!IsStatusOk(r)) {
|
||||
if (grpc_trace_promise_primitives.enabled()) {
|
||||
gpr_log(GPR_DEBUG, "SpawnGuarded sees failure: %s",
|
||||
r.ToString().c_str());
|
||||
}
|
||||
std::ignore = Cancel(StatusCast<ServerMetadataHandle>(std::move(r)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
absl::AnyInvocable<void()> on_done_{nullptr};
|
||||
};
|
||||
|
||||
class CallSpine final : public CallSpineInterface, public Party {
|
||||
public:
|
||||
static RefCountedPtr<CallSpine> Create(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine,
|
||||
Arena* arena) {
|
||||
return RefCountedPtr<CallSpine>(arena->New<CallSpine>(event_engine, arena));
|
||||
}
|
||||
|
||||
Pipe<ClientMetadataHandle>& client_initial_metadata() override {
|
||||
return client_initial_metadata_;
|
||||
}
|
||||
Pipe<ServerMetadataHandle>& server_initial_metadata() override {
|
||||
return server_initial_metadata_;
|
||||
}
|
||||
Pipe<MessageHandle>& client_to_server_messages() override {
|
||||
return client_to_server_messages_;
|
||||
}
|
||||
Pipe<MessageHandle>& server_to_client_messages() override {
|
||||
return server_to_client_messages_;
|
||||
}
|
||||
Pipe<ServerMetadataHandle>& server_trailing_metadata() override {
|
||||
return server_trailing_metadata_;
|
||||
}
|
||||
Latch<ServerMetadataHandle>& cancel_latch() override { return cancel_latch_; }
|
||||
Party& party() override { return *this; }
|
||||
void IncrementRefCount() override { Party::IncrementRefCount(); }
|
||||
void Unref() override { Party::Unref(); }
|
||||
|
||||
private:
|
||||
friend class Arena;
|
||||
CallSpine(grpc_event_engine::experimental::EventEngine* event_engine,
|
||||
Arena* arena)
|
||||
: Party(arena, 1), event_engine_(event_engine) {}
|
||||
|
||||
class ScopedContext : public ScopedActivity,
|
||||
public promise_detail::Context<Arena> {
|
||||
public:
|
||||
explicit ScopedContext(CallSpine* spine)
|
||||
: ScopedActivity(&spine->party()), Context<Arena>(spine->arena()) {}
|
||||
};
|
||||
|
||||
bool RunParty() override {
|
||||
ScopedContext context(this);
|
||||
return Party::RunParty();
|
||||
}
|
||||
|
||||
void PartyOver() override {
|
||||
Arena* a = arena();
|
||||
{
|
||||
ScopedContext context(this);
|
||||
CancelRemainingParticipants();
|
||||
a->DestroyManagedNewObjects();
|
||||
}
|
||||
this->~CallSpine();
|
||||
a->Destroy();
|
||||
}
|
||||
|
||||
grpc_event_engine::experimental::EventEngine* event_engine() const override {
|
||||
return event_engine_;
|
||||
}
|
||||
|
||||
// Initial metadata from client to server
|
||||
Pipe<ClientMetadataHandle> client_initial_metadata_{arena()};
|
||||
// Initial metadata from server to client
|
||||
Pipe<ServerMetadataHandle> server_initial_metadata_{arena()};
|
||||
// Messages travelling from the application to the transport.
|
||||
Pipe<MessageHandle> client_to_server_messages_{arena()};
|
||||
// Messages travelling from the transport to the application.
|
||||
Pipe<MessageHandle> server_to_client_messages_{arena()};
|
||||
// Trailing metadata from server to client
|
||||
Pipe<ServerMetadataHandle> server_trailing_metadata_{arena()};
|
||||
// Latch that can be set to terminate the call
|
||||
Latch<ServerMetadataHandle> cancel_latch_;
|
||||
// Event engine associated with this call
|
||||
grpc_event_engine::experimental::EventEngine* const event_engine_;
|
||||
};
|
||||
|
||||
class CallInitiator {
|
||||
public:
|
||||
explicit CallInitiator(RefCountedPtr<CallSpineInterface> spine)
|
||||
: spine_(std::move(spine)) {}
|
||||
|
||||
auto PushClientInitialMetadata(ClientMetadataHandle md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->client_initial_metadata().sender.Push(std::move(md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
auto PullServerInitialMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->server_initial_metadata().receiver.Next(),
|
||||
[](NextResult<ServerMetadataHandle> md)
|
||||
-> ValueOrFailure<absl::optional<ServerMetadataHandle>> {
|
||||
if (!md.has_value()) {
|
||||
if (md.cancelled()) return Failure{};
|
||||
return absl::optional<ServerMetadataHandle>();
|
||||
}
|
||||
return absl::optional<ServerMetadataHandle>(std::move(*md));
|
||||
});
|
||||
}
|
||||
|
||||
auto PullServerTrailingMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return PrioritizedRace(
|
||||
Map(spine_->server_trailing_metadata().receiver.Next(),
|
||||
[spine = spine_](
|
||||
NextResult<ServerMetadataHandle> md) -> ServerMetadataHandle {
|
||||
GPR_ASSERT(md.has_value());
|
||||
return std::move(*md);
|
||||
}),
|
||||
spine_->WaitForCancel());
|
||||
}
|
||||
|
||||
auto PullMessage() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return spine_->server_to_client_messages().receiver.Next();
|
||||
}
|
||||
|
||||
auto PushMessage(MessageHandle message) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(
|
||||
spine_->client_to_server_messages().sender.Push(std::move(message)),
|
||||
[](bool r) { return StatusFlag(r); });
|
||||
}
|
||||
|
||||
void FinishSends() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
spine_->client_to_server_messages().sender.Close();
|
||||
}
|
||||
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
return spine_->CancelIfFails(std::move(promise));
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
std::ignore =
|
||||
spine_->Cancel(ServerMetadataFromStatus(absl::CancelledError()));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnGuarded(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnInfallible(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) {
|
||||
return spine_->party().SpawnWaitable(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
Arena* arena() { return spine_->party().arena(); }
|
||||
|
||||
private:
|
||||
RefCountedPtr<CallSpineInterface> spine_;
|
||||
};
|
||||
|
||||
class CallHandler {
|
||||
public:
|
||||
explicit CallHandler(RefCountedPtr<CallSpineInterface> spine)
|
||||
: spine_(std::move(spine)) {}
|
||||
|
||||
auto PullClientInitialMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->client_initial_metadata().receiver.Next(),
|
||||
[](NextResult<ClientMetadataHandle> md)
|
||||
-> ValueOrFailure<ClientMetadataHandle> {
|
||||
if (!md.has_value()) return Failure{};
|
||||
return std::move(*md);
|
||||
});
|
||||
}
|
||||
|
||||
auto PushServerInitialMetadata(absl::optional<ServerMetadataHandle> md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return If(
|
||||
md.has_value(),
|
||||
[&md, this]() {
|
||||
return Map(
|
||||
spine_->server_initial_metadata().sender.Push(std::move(*md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
},
|
||||
[this]() {
|
||||
spine_->server_initial_metadata().sender.Close();
|
||||
return []() -> StatusFlag { return Success{}; };
|
||||
});
|
||||
}
|
||||
|
||||
auto PushServerTrailingMetadata(ServerMetadataHandle md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
spine_->server_initial_metadata().sender.Close();
|
||||
spine_->server_to_client_messages().sender.Close();
|
||||
spine_->client_to_server_messages().receiver.CloseWithError();
|
||||
spine_->CallOnDone();
|
||||
return Map(spine_->server_trailing_metadata().sender.Push(std::move(md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
auto PullMessage() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return spine_->client_to_server_messages().receiver.Next();
|
||||
}
|
||||
|
||||
auto PushMessage(MessageHandle message) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(
|
||||
spine_->server_to_client_messages().sender.Push(std::move(message)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
void Cancel(ServerMetadataHandle status) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
std::ignore = spine_->Cancel(std::move(status));
|
||||
}
|
||||
|
||||
void OnDone(absl::AnyInvocable<void()> fn) { spine_->OnDone(std::move(fn)); }
|
||||
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
return spine_->CancelIfFails(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnGuarded(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnInfallible(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) {
|
||||
return spine_->party().SpawnWaitable(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
Arena* arena() { return spine_->party().arena(); }
|
||||
|
||||
private:
|
||||
RefCountedPtr<CallSpineInterface> spine_;
|
||||
};
|
||||
|
||||
struct CallInitiatorAndHandler {
|
||||
CallInitiator initiator;
|
||||
CallHandler handler;
|
||||
};
|
||||
|
||||
CallInitiatorAndHandler MakeCall(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena);
|
||||
|
||||
template <typename CallHalf>
|
||||
auto OutgoingMessages(CallHalf h) {
|
||||
struct Wrapper {
|
||||
CallHalf h;
|
||||
auto Next() { return h.PullMessage(); }
|
||||
};
|
||||
return Wrapper{std::move(h)};
|
||||
}
|
||||
|
||||
// Forward a call from `call_handler` to `call_initiator` (with initial metadata
|
||||
// `client_initial_metadata`)
|
||||
void ForwardCall(CallHandler call_handler, CallInitiator call_initiator,
|
||||
ClientMetadataHandle client_initial_metadata);
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
|
||||
|
|
@ -215,89 +215,3 @@ grpc_transport_stream_op_batch* grpc_make_transport_stream_op(
|
|||
op->op.on_complete = &op->outer_on_complete;
|
||||
return &op->op;
|
||||
}
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
void ForwardCall(CallHandler call_handler, CallInitiator call_initiator,
|
||||
ClientMetadataHandle client_initial_metadata) {
|
||||
// Send initial metadata.
|
||||
call_initiator.SpawnGuarded(
|
||||
"send_initial_metadata",
|
||||
[client_initial_metadata = std::move(client_initial_metadata),
|
||||
call_initiator]() mutable {
|
||||
return call_initiator.PushClientInitialMetadata(
|
||||
std::move(client_initial_metadata));
|
||||
});
|
||||
// Read messages from handler into initiator.
|
||||
call_handler.SpawnGuarded("read_messages", [call_handler,
|
||||
call_initiator]() mutable {
|
||||
return Seq(ForEach(OutgoingMessages(call_handler),
|
||||
[call_initiator](MessageHandle msg) mutable {
|
||||
// Need to spawn a job into the initiator's activity to
|
||||
// push the message in.
|
||||
return call_initiator.SpawnWaitable(
|
||||
"send_message",
|
||||
[msg = std::move(msg), call_initiator]() mutable {
|
||||
return call_initiator.CancelIfFails(
|
||||
call_initiator.PushMessage(std::move(msg)));
|
||||
});
|
||||
}),
|
||||
[call_initiator](StatusFlag result) mutable {
|
||||
call_initiator.SpawnInfallible(
|
||||
"finish-downstream", [call_initiator, result]() mutable {
|
||||
if (result.ok()) {
|
||||
call_initiator.FinishSends();
|
||||
} else {
|
||||
call_initiator.Cancel();
|
||||
}
|
||||
return Empty{};
|
||||
});
|
||||
return result;
|
||||
});
|
||||
});
|
||||
call_initiator.SpawnInfallible("read_the_things", [call_initiator,
|
||||
call_handler]() mutable {
|
||||
return Seq(
|
||||
call_initiator.CancelIfFails(TrySeq(
|
||||
call_initiator.PullServerInitialMetadata(),
|
||||
[call_handler,
|
||||
call_initiator](absl::optional<ServerMetadataHandle> md) mutable {
|
||||
const bool has_md = md.has_value();
|
||||
call_handler.SpawnGuarded(
|
||||
"recv_initial_metadata",
|
||||
[md = std::move(md), call_handler]() mutable {
|
||||
return call_handler.PushServerInitialMetadata(
|
||||
std::move(md));
|
||||
});
|
||||
return If(
|
||||
has_md,
|
||||
ForEach(OutgoingMessages(call_initiator),
|
||||
[call_handler](MessageHandle msg) mutable {
|
||||
return call_handler.SpawnWaitable(
|
||||
"recv_message",
|
||||
[msg = std::move(msg), call_handler]() mutable {
|
||||
return call_handler.CancelIfFails(
|
||||
call_handler.PushMessage(std::move(msg)));
|
||||
});
|
||||
}),
|
||||
[]() -> StatusFlag { return Success{}; });
|
||||
})),
|
||||
call_initiator.PullServerTrailingMetadata(),
|
||||
[call_handler](ServerMetadataHandle md) mutable {
|
||||
call_handler.SpawnGuarded(
|
||||
"recv_trailing_metadata",
|
||||
[md = std::move(md), call_handler]() mutable {
|
||||
return call_handler.PushServerTrailingMetadata(std::move(md));
|
||||
});
|
||||
return Empty{};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CallInitiatorAndHandler MakeCall(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena) {
|
||||
auto spine = CallSpine::Create(event_engine, arena);
|
||||
return {CallInitiator(spine), CallHandler(spine)};
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
#include "src/core/lib/channel/context.h"
|
||||
#include "src/core/lib/debug/trace.h"
|
||||
#include "src/core/lib/gprpp/debug_location.h"
|
||||
#include "src/core/lib/gprpp/orphanable.h"
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/iomgr/call_combiner.h"
|
||||
|
|
@ -53,16 +52,12 @@
|
|||
#include "src/core/lib/iomgr/polling_entity.h"
|
||||
#include "src/core/lib/promise/arena_promise.h"
|
||||
#include "src/core/lib/promise/context.h"
|
||||
#include "src/core/lib/promise/detail/status.h"
|
||||
#include "src/core/lib/promise/if.h"
|
||||
#include "src/core/lib/promise/latch.h"
|
||||
#include "src/core/lib/promise/party.h"
|
||||
#include "src/core/lib/promise/pipe.h"
|
||||
#include "src/core/lib/promise/prioritized_race.h"
|
||||
#include "src/core/lib/promise/status_flag.h"
|
||||
#include "src/core/lib/resource_quota/arena.h"
|
||||
#include "src/core/lib/slice/slice_buffer.h"
|
||||
#include "src/core/lib/transport/call_final_info.h"
|
||||
#include "src/core/lib/transport/call_spine.h"
|
||||
#include "src/core/lib/transport/connectivity_state.h"
|
||||
#include "src/core/lib/transport/message.h"
|
||||
#include "src/core/lib/transport/metadata.h"
|
||||
|
|
@ -160,386 +155,6 @@ struct CallArgs {
|
|||
using NextPromiseFactory =
|
||||
std::function<ArenaPromise<ServerMetadataHandle>(CallArgs)>;
|
||||
|
||||
// The common middle part of a call - a reference is held by each of
|
||||
// CallInitiator and CallHandler - which provide interfaces that are appropriate
|
||||
// for each side of a call.
|
||||
// The spine will ultimately host the pipes, filters, and context for one part
|
||||
// of a call: ie top-half client channel, sub channel call, server call.
|
||||
// TODO(ctiller): eventually drop this when we don't need to reference into
|
||||
// legacy promise calls anymore
|
||||
class CallSpineInterface {
|
||||
public:
|
||||
virtual ~CallSpineInterface() = default;
|
||||
virtual Pipe<ClientMetadataHandle>& client_initial_metadata() = 0;
|
||||
virtual Pipe<ServerMetadataHandle>& server_initial_metadata() = 0;
|
||||
virtual Pipe<MessageHandle>& client_to_server_messages() = 0;
|
||||
virtual Pipe<MessageHandle>& server_to_client_messages() = 0;
|
||||
virtual Pipe<ServerMetadataHandle>& server_trailing_metadata() = 0;
|
||||
virtual Latch<ServerMetadataHandle>& cancel_latch() = 0;
|
||||
// Add a callback to be called when server trailing metadata is received.
|
||||
void OnDone(absl::AnyInvocable<void()> fn) {
|
||||
if (on_done_ == nullptr) {
|
||||
on_done_ = std::move(fn);
|
||||
return;
|
||||
}
|
||||
on_done_ = [first = std::move(fn), next = std::move(on_done_)]() mutable {
|
||||
first();
|
||||
next();
|
||||
};
|
||||
}
|
||||
void CallOnDone() {
|
||||
if (on_done_ != nullptr) std::exchange(on_done_, nullptr)();
|
||||
}
|
||||
virtual Party& party() = 0;
|
||||
virtual void IncrementRefCount() = 0;
|
||||
virtual void Unref() = 0;
|
||||
|
||||
// Cancel the call with the given metadata.
|
||||
// Regarding the `MUST_USE_RESULT absl::nullopt_t`:
|
||||
// Most cancellation calls right now happen in pipe interceptors;
|
||||
// there `nullopt` indicates terminate processing of this pipe and close with
|
||||
// error.
|
||||
// It's convenient then to have the Cancel operation (setting the latch to
|
||||
// terminate the call) be the last thing that occurs in a pipe interceptor,
|
||||
// and this construction supports that (and has helped the author not write
|
||||
// some bugs).
|
||||
GRPC_MUST_USE_RESULT absl::nullopt_t Cancel(ServerMetadataHandle metadata) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
auto& c = cancel_latch();
|
||||
if (c.is_set()) return absl::nullopt;
|
||||
c.Set(std::move(metadata));
|
||||
CallOnDone();
|
||||
client_initial_metadata().sender.CloseWithError();
|
||||
server_initial_metadata().sender.CloseWithError();
|
||||
client_to_server_messages().sender.CloseWithError();
|
||||
server_to_client_messages().sender.CloseWithError();
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
auto WaitForCancel() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
return cancel_latch().Wait();
|
||||
}
|
||||
|
||||
// Wrap a promise so that if it returns failure it automatically cancels
|
||||
// the rest of the call.
|
||||
// The resulting (returned) promise will resolve to Empty.
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &party());
|
||||
using P = promise_detail::PromiseLike<Promise>;
|
||||
using ResultType = typename P::Result;
|
||||
return Map(std::move(promise), [this](ResultType r) {
|
||||
if (!IsStatusOk(r)) {
|
||||
std::ignore = Cancel(StatusCast<ServerMetadataHandle>(r));
|
||||
}
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
// Spawn a promise that returns Empty{} and save some boilerplate handling
|
||||
// that detail.
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
party().Spawn(name, std::move(promise_factory), [](Empty) {});
|
||||
}
|
||||
|
||||
// Spawn a promise that returns some status-like type; if the status
|
||||
// represents failure automatically cancel the rest of the call.
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
using FactoryType =
|
||||
promise_detail::OncePromiseFactory<void, PromiseFactory>;
|
||||
using PromiseType = typename FactoryType::Promise;
|
||||
using ResultType = typename PromiseType::Result;
|
||||
static_assert(
|
||||
std::is_same<bool,
|
||||
decltype(IsStatusOk(std::declval<ResultType>()))>::value,
|
||||
"SpawnGuarded promise must return a status-like object");
|
||||
party().Spawn(name, std::move(promise_factory), [this](ResultType r) {
|
||||
if (!IsStatusOk(r)) {
|
||||
if (grpc_trace_promise_primitives.enabled()) {
|
||||
gpr_log(GPR_DEBUG, "SpawnGuarded sees failure: %s",
|
||||
r.ToString().c_str());
|
||||
}
|
||||
std::ignore = Cancel(StatusCast<ServerMetadataHandle>(std::move(r)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
absl::AnyInvocable<void()> on_done_{nullptr};
|
||||
};
|
||||
|
||||
class CallSpine final : public CallSpineInterface, public Party {
|
||||
public:
|
||||
static RefCountedPtr<CallSpine> Create(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine,
|
||||
Arena* arena) {
|
||||
return RefCountedPtr<CallSpine>(arena->New<CallSpine>(event_engine, arena));
|
||||
}
|
||||
|
||||
Pipe<ClientMetadataHandle>& client_initial_metadata() override {
|
||||
return client_initial_metadata_;
|
||||
}
|
||||
Pipe<ServerMetadataHandle>& server_initial_metadata() override {
|
||||
return server_initial_metadata_;
|
||||
}
|
||||
Pipe<MessageHandle>& client_to_server_messages() override {
|
||||
return client_to_server_messages_;
|
||||
}
|
||||
Pipe<MessageHandle>& server_to_client_messages() override {
|
||||
return server_to_client_messages_;
|
||||
}
|
||||
Pipe<ServerMetadataHandle>& server_trailing_metadata() override {
|
||||
return server_trailing_metadata_;
|
||||
}
|
||||
Latch<ServerMetadataHandle>& cancel_latch() override { return cancel_latch_; }
|
||||
Party& party() override { return *this; }
|
||||
void IncrementRefCount() override { Party::IncrementRefCount(); }
|
||||
void Unref() override { Party::Unref(); }
|
||||
|
||||
private:
|
||||
friend class Arena;
|
||||
CallSpine(grpc_event_engine::experimental::EventEngine* event_engine,
|
||||
Arena* arena)
|
||||
: Party(arena, 1), event_engine_(event_engine) {}
|
||||
|
||||
class ScopedContext : public ScopedActivity,
|
||||
public promise_detail::Context<Arena> {
|
||||
public:
|
||||
explicit ScopedContext(CallSpine* spine)
|
||||
: ScopedActivity(&spine->party()), Context<Arena>(spine->arena()) {}
|
||||
};
|
||||
|
||||
bool RunParty() override {
|
||||
ScopedContext context(this);
|
||||
return Party::RunParty();
|
||||
}
|
||||
|
||||
void PartyOver() override {
|
||||
Arena* a = arena();
|
||||
{
|
||||
ScopedContext context(this);
|
||||
CancelRemainingParticipants();
|
||||
a->DestroyManagedNewObjects();
|
||||
}
|
||||
this->~CallSpine();
|
||||
a->Destroy();
|
||||
}
|
||||
|
||||
grpc_event_engine::experimental::EventEngine* event_engine() const override {
|
||||
return event_engine_;
|
||||
}
|
||||
|
||||
// Initial metadata from client to server
|
||||
Pipe<ClientMetadataHandle> client_initial_metadata_{arena()};
|
||||
// Initial metadata from server to client
|
||||
Pipe<ServerMetadataHandle> server_initial_metadata_{arena()};
|
||||
// Messages travelling from the application to the transport.
|
||||
Pipe<MessageHandle> client_to_server_messages_{arena()};
|
||||
// Messages travelling from the transport to the application.
|
||||
Pipe<MessageHandle> server_to_client_messages_{arena()};
|
||||
// Trailing metadata from server to client
|
||||
Pipe<ServerMetadataHandle> server_trailing_metadata_{arena()};
|
||||
// Latch that can be set to terminate the call
|
||||
Latch<ServerMetadataHandle> cancel_latch_;
|
||||
// Event engine associated with this call
|
||||
grpc_event_engine::experimental::EventEngine* const event_engine_;
|
||||
};
|
||||
|
||||
class CallInitiator {
|
||||
public:
|
||||
explicit CallInitiator(RefCountedPtr<CallSpineInterface> spine)
|
||||
: spine_(std::move(spine)) {}
|
||||
|
||||
auto PushClientInitialMetadata(ClientMetadataHandle md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->client_initial_metadata().sender.Push(std::move(md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
auto PullServerInitialMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->server_initial_metadata().receiver.Next(),
|
||||
[](NextResult<ServerMetadataHandle> md)
|
||||
-> ValueOrFailure<absl::optional<ServerMetadataHandle>> {
|
||||
if (!md.has_value()) {
|
||||
if (md.cancelled()) return Failure{};
|
||||
return absl::optional<ServerMetadataHandle>();
|
||||
}
|
||||
return absl::optional<ServerMetadataHandle>(std::move(*md));
|
||||
});
|
||||
}
|
||||
|
||||
auto PullServerTrailingMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return PrioritizedRace(
|
||||
Map(spine_->server_trailing_metadata().receiver.Next(),
|
||||
[spine = spine_](
|
||||
NextResult<ServerMetadataHandle> md) -> ServerMetadataHandle {
|
||||
GPR_ASSERT(md.has_value());
|
||||
return std::move(*md);
|
||||
}),
|
||||
spine_->WaitForCancel());
|
||||
}
|
||||
|
||||
auto PullMessage() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return spine_->server_to_client_messages().receiver.Next();
|
||||
}
|
||||
|
||||
auto PushMessage(MessageHandle message) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(
|
||||
spine_->client_to_server_messages().sender.Push(std::move(message)),
|
||||
[](bool r) { return StatusFlag(r); });
|
||||
}
|
||||
|
||||
void FinishSends() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
spine_->client_to_server_messages().sender.Close();
|
||||
}
|
||||
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
return spine_->CancelIfFails(std::move(promise));
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
std::ignore =
|
||||
spine_->Cancel(ServerMetadataFromStatus(absl::CancelledError()));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnGuarded(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnInfallible(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) {
|
||||
return spine_->party().SpawnWaitable(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
Arena* arena() { return spine_->party().arena(); }
|
||||
|
||||
private:
|
||||
RefCountedPtr<CallSpineInterface> spine_;
|
||||
};
|
||||
|
||||
class CallHandler {
|
||||
public:
|
||||
explicit CallHandler(RefCountedPtr<CallSpineInterface> spine)
|
||||
: spine_(std::move(spine)) {}
|
||||
|
||||
auto PullClientInitialMetadata() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(spine_->client_initial_metadata().receiver.Next(),
|
||||
[](NextResult<ClientMetadataHandle> md)
|
||||
-> ValueOrFailure<ClientMetadataHandle> {
|
||||
if (!md.has_value()) return Failure{};
|
||||
return std::move(*md);
|
||||
});
|
||||
}
|
||||
|
||||
auto PushServerInitialMetadata(absl::optional<ServerMetadataHandle> md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return If(
|
||||
md.has_value(),
|
||||
[&md, this]() {
|
||||
return Map(
|
||||
spine_->server_initial_metadata().sender.Push(std::move(*md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
},
|
||||
[this]() {
|
||||
spine_->server_initial_metadata().sender.Close();
|
||||
return []() -> StatusFlag { return Success{}; };
|
||||
});
|
||||
}
|
||||
|
||||
auto PushServerTrailingMetadata(ServerMetadataHandle md) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
spine_->server_initial_metadata().sender.Close();
|
||||
spine_->server_to_client_messages().sender.Close();
|
||||
spine_->client_to_server_messages().receiver.CloseWithError();
|
||||
spine_->CallOnDone();
|
||||
return Map(spine_->server_trailing_metadata().sender.Push(std::move(md)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
auto PullMessage() {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return spine_->client_to_server_messages().receiver.Next();
|
||||
}
|
||||
|
||||
auto PushMessage(MessageHandle message) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
return Map(
|
||||
spine_->server_to_client_messages().sender.Push(std::move(message)),
|
||||
[](bool ok) { return StatusFlag(ok); });
|
||||
}
|
||||
|
||||
void Cancel(ServerMetadataHandle status) {
|
||||
GPR_DEBUG_ASSERT(GetContext<Activity>() == &spine_->party());
|
||||
std::ignore = spine_->Cancel(std::move(status));
|
||||
}
|
||||
|
||||
void OnDone(absl::AnyInvocable<void()> fn) { spine_->OnDone(std::move(fn)); }
|
||||
|
||||
template <typename Promise>
|
||||
auto CancelIfFails(Promise promise) {
|
||||
return spine_->CancelIfFails(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnGuarded(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
|
||||
spine_->SpawnInfallible(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
template <typename PromiseFactory>
|
||||
auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) {
|
||||
return spine_->party().SpawnWaitable(name, std::move(promise_factory));
|
||||
}
|
||||
|
||||
Arena* arena() { return spine_->party().arena(); }
|
||||
|
||||
private:
|
||||
RefCountedPtr<CallSpineInterface> spine_;
|
||||
};
|
||||
|
||||
struct CallInitiatorAndHandler {
|
||||
CallInitiator initiator;
|
||||
CallHandler handler;
|
||||
};
|
||||
|
||||
CallInitiatorAndHandler MakeCall(
|
||||
grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena);
|
||||
|
||||
template <typename CallHalf>
|
||||
auto OutgoingMessages(CallHalf h) {
|
||||
struct Wrapper {
|
||||
CallHalf h;
|
||||
auto Next() { return h.PullMessage(); }
|
||||
};
|
||||
return Wrapper{std::move(h)};
|
||||
}
|
||||
|
||||
// Forward a call from `call_handler` to `call_initiator` (with initial metadata
|
||||
// `client_initial_metadata`)
|
||||
void ForwardCall(CallHandler call_handler, CallInitiator call_initiator,
|
||||
ClientMetadataHandle client_initial_metadata);
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
// forward declarations
|
||||
|
|
|
|||
|
|
@ -812,6 +812,7 @@ CORE_SOURCE_FILES = [
|
|||
'src/core/lib/transport/bdp_estimator.cc',
|
||||
'src/core/lib/transport/call_filters.cc',
|
||||
'src/core/lib/transport/call_final_info.cc',
|
||||
'src/core/lib/transport/call_spine.cc',
|
||||
'src/core/lib/transport/connectivity_state.cc',
|
||||
'src/core/lib/transport/error_utils.cc',
|
||||
'src/core/lib/transport/handshaker.cc',
|
||||
|
|
|
|||
|
|
@ -2904,6 +2904,8 @@ src/core/lib/transport/call_filters.cc \
|
|||
src/core/lib/transport/call_filters.h \
|
||||
src/core/lib/transport/call_final_info.cc \
|
||||
src/core/lib/transport/call_final_info.h \
|
||||
src/core/lib/transport/call_spine.cc \
|
||||
src/core/lib/transport/call_spine.h \
|
||||
src/core/lib/transport/connectivity_state.cc \
|
||||
src/core/lib/transport/connectivity_state.h \
|
||||
src/core/lib/transport/custom_metadata.h \
|
||||
|
|
|
|||
|
|
@ -2685,6 +2685,8 @@ src/core/lib/transport/call_filters.cc \
|
|||
src/core/lib/transport/call_filters.h \
|
||||
src/core/lib/transport/call_final_info.cc \
|
||||
src/core/lib/transport/call_final_info.h \
|
||||
src/core/lib/transport/call_spine.cc \
|
||||
src/core/lib/transport/call_spine.h \
|
||||
src/core/lib/transport/connectivity_state.cc \
|
||||
src/core/lib/transport/connectivity_state.h \
|
||||
src/core/lib/transport/custom_metadata.h \
|
||||
|
|
|
|||
Loading…
Reference in New Issue