diff --git a/.gitignore b/.gitignore
index 53bd54a1ad1..c2b54bed8d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -175,3 +175,6 @@ iwyu_files0.txt
iwyu/
iwyu_build/
+# fuzzer logs
+fuzz-*.log
+
diff --git a/BUILD b/BUILD
index 0866d6d79ac..7a7861e5f5b 100644
--- a/BUILD
+++ b/BUILD
@@ -2469,6 +2469,23 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "bdp_estimator",
+ srcs = [
+ "src/core/lib/transport/bdp_estimator.cc",
+ ],
+ hdrs = ["src/core/lib/transport/bdp_estimator.h"],
+ tags = ["grpc-autodeps"],
+ deps = [
+ "exec_ctx",
+ "gpr_base",
+ "gpr_codegen",
+ "gpr_platform",
+ "grpc_trace",
+ "time",
+ ],
+)
+
grpc_cc_library(
name = "percent_encoding",
srcs = [
@@ -2591,8 +2608,6 @@ grpc_cc_library(
"src/core/lib/surface/server.cc",
"src/core/lib/surface/validate_metadata.cc",
"src/core/lib/surface/version.cc",
- "src/core/lib/transport/bdp_estimator.cc",
- "src/core/lib/transport/byte_stream.cc",
"src/core/lib/transport/connectivity_state.cc",
"src/core/lib/transport/error_utils.cc",
"src/core/lib/transport/metadata_batch.cc",
@@ -2689,8 +2704,6 @@ grpc_cc_library(
"src/core/lib/surface/lame_client.h",
"src/core/lib/surface/server.h",
"src/core/lib/surface/validate_metadata.h",
- "src/core/lib/transport/bdp_estimator.h",
- "src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/parsed_metadata.h",
@@ -3150,6 +3163,7 @@ grpc_cc_library(
"absl/types:variant",
"absl/status",
"absl/status:statusor",
+ "absl/utility",
"upb_lib",
],
language = "c++",
@@ -3161,6 +3175,7 @@ grpc_cc_library(
"channel_stack_type",
"chunked_vector",
"config",
+ "construct_destruct",
"debug_location",
"default_event_engine_factory_hdrs",
"dual_ref_counted",
@@ -3193,6 +3208,7 @@ grpc_cc_library(
"server_address",
"service_config_parser",
"slice",
+ "slice_buffer",
"slice_refcount",
"sockaddr_utils",
"time",
@@ -3428,8 +3444,8 @@ grpc_cc_library(
"grpc_public_hdrs",
"grpc_service_config",
"json",
- "orphanable",
"service_config_parser",
+ "slice_buffer",
],
)
@@ -3557,6 +3573,7 @@ grpc_cc_library(
"promise",
"seq",
"slice",
+ "slice_buffer",
"transport_fwd",
],
)
@@ -6028,6 +6045,36 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "chttp2_flow_control",
+ srcs = [
+ "src/core/ext/transport/chttp2/transport/flow_control.cc",
+ ],
+ hdrs = [
+ "src/core/ext/transport/chttp2/transport/flow_control.h",
+ ],
+ external_deps = [
+ "absl/functional:function_ref",
+ "absl/status",
+ "absl/strings",
+ "absl/strings:str_format",
+ "absl/types:optional",
+ "absl/utility",
+ ],
+ tags = ["grpc-autodeps"],
+ deps = [
+ "bdp_estimator",
+ "exec_ctx",
+ "gpr_base",
+ "gpr_platform",
+ "grpc_trace",
+ "memory_quota",
+ "pid_controller",
+ "time",
+ "useful",
+ ],
+)
+
grpc_cc_library(
name = "grpc_transport_chttp2",
srcs = [
@@ -6035,7 +6082,6 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_encoder.cc",
"src/core/ext/transport/chttp2/transport/chttp2_transport.cc",
"src/core/ext/transport/chttp2/transport/context_list.cc",
- "src/core/ext/transport/chttp2/transport/flow_control.cc",
"src/core/ext/transport/chttp2/transport/frame_data.cc",
"src/core/ext/transport/chttp2/transport/frame_goaway.cc",
"src/core/ext/transport/chttp2/transport/frame_ping.cc",
@@ -6058,7 +6104,6 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/context_list.h",
- "src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.h",
"src/core/ext/transport/chttp2/transport/frame_goaway.h",
@@ -6091,7 +6136,9 @@ grpc_cc_library(
visibility = ["@grpc:grpclb"],
deps = [
"arena",
+ "bdp_estimator",
"bitset",
+ "chttp2_flow_control",
"chunked_vector",
"debug_location",
"gpr_base",
@@ -6109,11 +6156,13 @@ grpc_cc_library(
"memory_quota",
"orphanable",
"pid_controller",
+ "poll",
"ref_counted",
"ref_counted_ptr",
"resource_quota",
"resource_quota_trace",
"slice",
+ "slice_buffer",
"slice_refcount",
"status_helper",
"time",
@@ -6241,8 +6290,10 @@ grpc_cc_library(
"absl/status:statusor",
"absl/strings",
"absl/types:optional",
+ "absl/utility",
],
language = "c++",
+ tags = ["grpc-autodeps"],
deps = [
"arena",
"channel_args_preconditioning",
@@ -6252,11 +6303,12 @@ grpc_cc_library(
"gpr_base",
"grpc_base",
"grpc_codegen",
+ "grpc_public_hdrs",
"grpc_trace",
"iomgr_fwd",
- "orphanable",
"ref_counted_ptr",
"slice",
+ "slice_buffer",
"time",
"transport_fwd",
"useful",
@@ -6850,6 +6902,7 @@ grpc_cc_library(
"grpc++_base",
"grpc_base",
"slice",
+ "slice_buffer",
"slice_refcount",
],
)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ede84646b09..4c47485684a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -859,7 +859,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c jwt_verifier_test)
add_dependencies(buildtests_c lame_client_test)
add_dependencies(buildtests_c load_file_test)
- add_dependencies(buildtests_c manual_constructor_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c memory_quota_stress_test)
endif()
@@ -962,7 +961,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx binder_transport_test)
add_dependencies(buildtests_cxx bitset_test)
add_dependencies(buildtests_cxx byte_buffer_test)
- add_dependencies(buildtests_cxx byte_stream_test)
add_dependencies(buildtests_cxx call_finalization_test)
add_dependencies(buildtests_cxx call_push_pull_test)
add_dependencies(buildtests_cxx cancel_ares_query_test)
@@ -2267,7 +2265,6 @@ add_library(grpc
src/core/lib/surface/validate_metadata.cc
src/core/lib/surface/version.cc
src/core/lib/transport/bdp_estimator.cc
- src/core/lib/transport/byte_stream.cc
src/core/lib/transport/connectivity_state.cc
src/core/lib/transport/error_utils.cc
src/core/lib/transport/handshaker.cc
@@ -2355,6 +2352,7 @@ target_link_libraries(grpc
absl::flat_hash_set
absl::inlined_vector
absl::bind_front
+ absl::function_ref
absl::hash
absl::type_traits
absl::statusor
@@ -2859,7 +2857,6 @@ add_library(grpc_unsecure
src/core/lib/surface/validate_metadata.cc
src/core/lib/surface/version.cc
src/core/lib/transport/bdp_estimator.cc
- src/core/lib/transport/byte_stream.cc
src/core/lib/transport/connectivity_state.cc
src/core/lib/transport/error_utils.cc
src/core/lib/transport/handshaker.cc
@@ -2923,6 +2920,7 @@ target_link_libraries(grpc_unsecure
absl::flat_hash_set
absl::inlined_vector
absl::bind_front
+ absl::function_ref
absl::hash
absl::type_traits
absl::statusor
@@ -6034,33 +6032,6 @@ target_link_libraries(load_file_test
)
-endif()
-if(gRPC_BUILD_TESTS)
-
-add_executable(manual_constructor_test
- test/core/gprpp/manual_constructor_test.cc
-)
-
-target_include_directories(manual_constructor_test
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
- ${_gRPC_RE2_INCLUDE_DIR}
- ${_gRPC_SSL_INCLUDE_DIR}
- ${_gRPC_UPB_GENERATED_DIR}
- ${_gRPC_UPB_GRPC_GENERATED_DIR}
- ${_gRPC_UPB_INCLUDE_DIR}
- ${_gRPC_XXHASH_INCLUDE_DIR}
- ${_gRPC_ZLIB_INCLUDE_DIR}
-)
-
-target_link_libraries(manual_constructor_test
- ${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
-)
-
-
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
@@ -8383,41 +8354,6 @@ target_link_libraries(byte_buffer_test
)
-endif()
-if(gRPC_BUILD_TESTS)
-
-add_executable(byte_stream_test
- test/core/transport/byte_stream_test.cc
- third_party/googletest/googletest/src/gtest-all.cc
- third_party/googletest/googlemock/src/gmock-all.cc
-)
-
-target_include_directories(byte_stream_test
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
- ${_gRPC_RE2_INCLUDE_DIR}
- ${_gRPC_SSL_INCLUDE_DIR}
- ${_gRPC_UPB_GENERATED_DIR}
- ${_gRPC_UPB_GRPC_GENERATED_DIR}
- ${_gRPC_UPB_INCLUDE_DIR}
- ${_gRPC_XXHASH_INCLUDE_DIR}
- ${_gRPC_ZLIB_INCLUDE_DIR}
- third_party/googletest/googletest/include
- third_party/googletest/googletest
- third_party/googletest/googlemock/include
- third_party/googletest/googlemock
- ${_gRPC_PROTO_GENS_DIR}
-)
-
-target_link_libraries(byte_stream_test
- ${_gRPC_PROTOBUF_LIBRARIES}
- ${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
-)
-
-
endif()
if(gRPC_BUILD_TESTS)
@@ -10766,7 +10702,29 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(flow_control_test
- test/core/end2end/cq_verifier.cc
+ src/core/ext/transport/chttp2/transport/flow_control.cc
+ src/core/ext/upb-generated/google/protobuf/any.upb.c
+ src/core/ext/upb-generated/google/rpc/status.upb.c
+ src/core/lib/debug/trace.cc
+ src/core/lib/event_engine/memory_allocator.cc
+ src/core/lib/gprpp/status_helper.cc
+ src/core/lib/gprpp/time.cc
+ src/core/lib/iomgr/combiner.cc
+ src/core/lib/iomgr/error.cc
+ src/core/lib/iomgr/exec_ctx.cc
+ src/core/lib/iomgr/executor.cc
+ src/core/lib/iomgr/iomgr_internal.cc
+ src/core/lib/promise/activity.cc
+ src/core/lib/resource_quota/memory_quota.cc
+ src/core/lib/resource_quota/resource_quota.cc
+ src/core/lib/resource_quota/thread_quota.cc
+ src/core/lib/resource_quota/trace.cc
+ src/core/lib/slice/percent_encoding.cc
+ src/core/lib/slice/slice.cc
+ src/core/lib/slice/slice_refcount.cc
+ src/core/lib/slice/slice_string_helpers.cc
+ src/core/lib/transport/bdp_estimator.cc
+ src/core/lib/transport/pid_controller.cc
test/core/transport/chttp2/flow_control_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@@ -10794,7 +10752,13 @@ target_include_directories(flow_control_test
target_link_libraries(flow_control_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
+ absl::function_ref
+ absl::type_traits
+ absl::statusor
+ absl::variant
+ absl::utility
+ gpr
+ upb
)
@@ -20462,7 +20426,7 @@ generate_pkgconfig(
"gRPC"
"high performance general RPC framework"
"${gRPC_CORE_VERSION}"
- "gpr openssl absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
+ "gpr openssl absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
"-lgrpc -laddress_sorting -lre2 -lupb -lcares -lz"
""
"grpc.pc")
@@ -20472,7 +20436,7 @@ generate_pkgconfig(
"gRPC unsecure"
"high performance general RPC framework without SSL"
"${gRPC_CORE_VERSION}"
- "gpr absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
+ "gpr absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
"-lgrpc_unsecure"
""
"grpc_unsecure.pc")
@@ -20482,7 +20446,7 @@ generate_pkgconfig(
"gRPC++"
"C++ wrapper for gRPC"
"${gRPC_CPP_VERSION}"
- "grpc absl_base absl_bind_front absl_cleanup absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
+ "grpc absl_base absl_bind_front absl_cleanup absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
"-lgrpc++"
""
"grpc++.pc")
@@ -20492,7 +20456,7 @@ generate_pkgconfig(
"gRPC++ unsecure"
"C++ wrapper for gRPC without SSL"
"${gRPC_CPP_VERSION}"
- "grpc_unsecure absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
+ "grpc_unsecure absl_base absl_bind_front absl_cord absl_core_headers absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_inlined_vector absl_memory absl_optional absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant"
"-lgrpc++_unsecure"
""
"grpc++_unsecure.pc")
diff --git a/Makefile b/Makefile
index bcd125b3b81..bb0899d6840 100644
--- a/Makefile
+++ b/Makefile
@@ -1640,7 +1640,6 @@ LIBGRPC_SRC = \
src/core/lib/surface/validate_metadata.cc \
src/core/lib/surface/version.cc \
src/core/lib/transport/bdp_estimator.cc \
- src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
src/core/lib/transport/handshaker.cc \
@@ -2073,7 +2072,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/surface/validate_metadata.cc \
src/core/lib/surface/version.cc \
src/core/lib/transport/bdp_estimator.cc \
- src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
src/core/lib/transport/handshaker.cc \
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index c1adeed03b0..5d702fb59a6 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -952,7 +952,6 @@ libs:
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/transport/bdp_estimator.h
- - src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/error_utils.h
- src/core/lib/transport/handshaker.h
@@ -1625,7 +1624,6 @@ libs:
- src/core/lib/surface/validate_metadata.cc
- src/core/lib/surface/version.cc
- src/core/lib/transport/bdp_estimator.cc
- - src/core/lib/transport/byte_stream.cc
- src/core/lib/transport/connectivity_state.cc
- src/core/lib/transport/error_utils.cc
- src/core/lib/transport/handshaker.cc
@@ -1675,6 +1673,7 @@ libs:
- absl/container:flat_hash_set
- absl/container:inlined_vector
- absl/functional:bind_front
+ - absl/functional:function_ref
- absl/hash:hash
- absl/meta:type_traits
- absl/status:statusor
@@ -2139,7 +2138,6 @@ libs:
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/transport/bdp_estimator.h
- - src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/error_utils.h
- src/core/lib/transport/handshaker.h
@@ -2455,7 +2453,6 @@ libs:
- src/core/lib/surface/validate_metadata.cc
- src/core/lib/surface/version.cc
- src/core/lib/transport/bdp_estimator.cc
- - src/core/lib/transport/byte_stream.cc
- src/core/lib/transport/connectivity_state.cc
- src/core/lib/transport/error_utils.cc
- src/core/lib/transport/handshaker.cc
@@ -2481,6 +2478,7 @@ libs:
- absl/container:flat_hash_set
- absl/container:inlined_vector
- absl/functional:bind_front
+ - absl/functional:function_ref
- absl/hash:hash
- absl/meta:type_traits
- absl/status:statusor
@@ -3832,15 +3830,6 @@ targets:
deps:
- grpc_test_util
uses_polling: false
-- name: manual_constructor_test
- build: test
- language: c
- headers: []
- src:
- - test/core/gprpp/manual_constructor_test.cc
- deps:
- - grpc_test_util
- uses_polling: false
- name: memory_quota_stress_test
build: test
language: c
@@ -4915,16 +4904,6 @@ targets:
deps:
- grpc++_test_util
uses_polling: false
-- name: byte_stream_test
- gtest: true
- build: test
- language: c++
- headers: []
- src:
- - test/core/transport/byte_stream_test.cc
- deps:
- - grpc_test_util
- uses_polling: false
- name: call_finalization_test
gtest: true
build: test
@@ -5912,12 +5891,84 @@ targets:
build: test
language: c++
headers:
- - test/core/end2end/cq_verifier.h
+ - src/core/ext/transport/chttp2/transport/flow_control.h
+ - src/core/ext/upb-generated/google/protobuf/any.upb.h
+ - src/core/ext/upb-generated/google/rpc/status.upb.h
+ - src/core/lib/debug/trace.h
+ - src/core/lib/gprpp/atomic_utils.h
+ - src/core/lib/gprpp/bitset.h
+ - src/core/lib/gprpp/cpp_impl_of.h
+ - src/core/lib/gprpp/orphanable.h
+ - src/core/lib/gprpp/ref_counted.h
+ - src/core/lib/gprpp/ref_counted_ptr.h
+ - src/core/lib/gprpp/status_helper.h
+ - src/core/lib/gprpp/time.h
+ - src/core/lib/iomgr/closure.h
+ - src/core/lib/iomgr/combiner.h
+ - src/core/lib/iomgr/error.h
+ - src/core/lib/iomgr/error_internal.h
+ - src/core/lib/iomgr/exec_ctx.h
+ - src/core/lib/iomgr/executor.h
+ - src/core/lib/iomgr/iomgr_internal.h
+ - src/core/lib/promise/activity.h
+ - src/core/lib/promise/context.h
+ - src/core/lib/promise/detail/basic_seq.h
+ - src/core/lib/promise/detail/promise_factory.h
+ - src/core/lib/promise/detail/promise_like.h
+ - src/core/lib/promise/detail/status.h
+ - src/core/lib/promise/detail/switch.h
+ - src/core/lib/promise/exec_ctx_wakeup_scheduler.h
+ - src/core/lib/promise/loop.h
+ - src/core/lib/promise/map.h
+ - src/core/lib/promise/poll.h
+ - src/core/lib/promise/race.h
+ - src/core/lib/promise/seq.h
+ - src/core/lib/resource_quota/memory_quota.h
+ - src/core/lib/resource_quota/resource_quota.h
+ - src/core/lib/resource_quota/thread_quota.h
+ - src/core/lib/resource_quota/trace.h
+ - src/core/lib/slice/percent_encoding.h
+ - src/core/lib/slice/slice.h
+ - src/core/lib/slice/slice_internal.h
+ - src/core/lib/slice/slice_refcount.h
+ - src/core/lib/slice/slice_refcount_base.h
+ - src/core/lib/slice/slice_string_helpers.h
+ - src/core/lib/transport/bdp_estimator.h
+ - src/core/lib/transport/pid_controller.h
src:
- - test/core/end2end/cq_verifier.cc
+ - src/core/ext/transport/chttp2/transport/flow_control.cc
+ - src/core/ext/upb-generated/google/protobuf/any.upb.c
+ - src/core/ext/upb-generated/google/rpc/status.upb.c
+ - src/core/lib/debug/trace.cc
+ - src/core/lib/event_engine/memory_allocator.cc
+ - src/core/lib/gprpp/status_helper.cc
+ - src/core/lib/gprpp/time.cc
+ - src/core/lib/iomgr/combiner.cc
+ - src/core/lib/iomgr/error.cc
+ - src/core/lib/iomgr/exec_ctx.cc
+ - src/core/lib/iomgr/executor.cc
+ - src/core/lib/iomgr/iomgr_internal.cc
+ - src/core/lib/promise/activity.cc
+ - src/core/lib/resource_quota/memory_quota.cc
+ - src/core/lib/resource_quota/resource_quota.cc
+ - src/core/lib/resource_quota/thread_quota.cc
+ - src/core/lib/resource_quota/trace.cc
+ - src/core/lib/slice/percent_encoding.cc
+ - src/core/lib/slice/slice.cc
+ - src/core/lib/slice/slice_refcount.cc
+ - src/core/lib/slice/slice_string_helpers.cc
+ - src/core/lib/transport/bdp_estimator.cc
+ - src/core/lib/transport/pid_controller.cc
- test/core/transport/chttp2/flow_control_test.cc
deps:
- - grpc_test_util
+ - absl/functional:function_ref
+ - absl/meta:type_traits
+ - absl/status:statusor
+ - absl/types:variant
+ - absl/utility:utility
+ - gpr
+ - upb
+ uses_polling: false
- name: for_each_test
gtest: true
build: test
diff --git a/config.m4 b/config.m4
index 9ed9418f2e0..5bd3fd9f50a 100644
--- a/config.m4
+++ b/config.m4
@@ -708,7 +708,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/surface/validate_metadata.cc \
src/core/lib/surface/version.cc \
src/core/lib/transport/bdp_estimator.cc \
- src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
src/core/lib/transport/handshaker.cc \
diff --git a/config.w32 b/config.w32
index 7a6341f07b2..4918f2edf8e 100644
--- a/config.w32
+++ b/config.w32
@@ -674,7 +674,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\surface\\validate_metadata.cc " +
"src\\core\\lib\\surface\\version.cc " +
"src\\core\\lib\\transport\\bdp_estimator.cc " +
- "src\\core\\lib\\transport\\byte_stream.cc " +
"src\\core\\lib\\transport\\connectivity_state.cc " +
"src\\core\\lib\\transport\\error_utils.cc " +
"src\\core\\lib\\transport\\handshaker.cc " +
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index 4f6201acf2b..59442f08d36 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -167,11 +167,6 @@ some configuration as environment variables that can be set.
channels (mostly due to idleness), so that the next RPC on this channel won't
fail. Set to 0 to turn off the backup polls.
-* GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL
- if set, flow control will be effectively disabled. Max out all values and
- assume the remote peer does the same. Thus we can ignore any flow control
- bookkeeping, error checking, and decision making
-
* grpc_cfstream
set to 1 to turn on CFStream experiment. With this experiment gRPC uses CFStream API to make TCP
connections. The option is only available on iOS platform and when macro GRPC_CFSTREAM is defined.
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 71a5b64da85..f732989eda8 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -203,6 +203,7 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
ss.dependency 'abseil/functional/bind_front', abseil_version
+ ss.dependency 'abseil/functional/function_ref', abseil_version
ss.dependency 'abseil/hash/hash', abseil_version
ss.dependency 'abseil/memory/memory', abseil_version
ss.dependency 'abseil/meta/type_traits', abseil_version
@@ -910,7 +911,6 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/transport/bdp_estimator.h',
- 'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/error_utils.h',
'src/core/lib/transport/handshaker.h',
@@ -1737,7 +1737,6 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/transport/bdp_estimator.h',
- 'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/error_utils.h',
'src/core/lib/transport/handshaker.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 84908871feb..78549d3c363 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -178,6 +178,7 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
ss.dependency 'abseil/functional/bind_front', abseil_version
+ ss.dependency 'abseil/functional/function_ref', abseil_version
ss.dependency 'abseil/hash/hash', abseil_version
ss.dependency 'abseil/memory/memory', abseil_version
ss.dependency 'abseil/meta/type_traits', abseil_version
@@ -1516,8 +1517,6 @@ Pod::Spec.new do |s|
'src/core/lib/surface/version.cc',
'src/core/lib/transport/bdp_estimator.cc',
'src/core/lib/transport/bdp_estimator.h',
- 'src/core/lib/transport/byte_stream.cc',
- 'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/error_utils.cc',
@@ -2342,7 +2341,6 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/transport/bdp_estimator.h',
- 'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/error_utils.h',
'src/core/lib/transport/handshaker.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 5f79dd3d68a..59754bffcdd 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1431,8 +1431,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/version.cc )
s.files += %w( src/core/lib/transport/bdp_estimator.cc )
s.files += %w( src/core/lib/transport/bdp_estimator.h )
- s.files += %w( src/core/lib/transport/byte_stream.cc )
- s.files += %w( src/core/lib/transport/byte_stream.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/error_utils.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 2179683415f..abff82779ea 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -360,6 +360,7 @@
'absl/container:flat_hash_set',
'absl/container:inlined_vector',
'absl/functional:bind_front',
+ 'absl/functional:function_ref',
'absl/hash:hash',
'absl/meta:type_traits',
'absl/status:statusor',
@@ -996,7 +997,6 @@
'src/core/lib/surface/validate_metadata.cc',
'src/core/lib/surface/version.cc',
'src/core/lib/transport/bdp_estimator.cc',
- 'src/core/lib/transport/byte_stream.cc',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/error_utils.cc',
'src/core/lib/transport/handshaker.cc',
@@ -1118,6 +1118,7 @@
'absl/container:flat_hash_set',
'absl/container:inlined_vector',
'absl/functional:bind_front',
+ 'absl/functional:function_ref',
'absl/hash:hash',
'absl/meta:type_traits',
'absl/status:statusor',
@@ -1420,7 +1421,6 @@
'src/core/lib/surface/validate_metadata.cc',
'src/core/lib/surface/version.cc',
'src/core/lib/transport/bdp_estimator.cc',
- 'src/core/lib/transport/byte_stream.cc',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/error_utils.cc',
'src/core/lib/transport/handshaker.cc',
diff --git a/include/grpc/event_engine/slice_buffer.h b/include/grpc/event_engine/slice_buffer.h
index 609b6ea0841..3861717e7b6 100644
--- a/include/grpc/event_engine/slice_buffer.h
+++ b/include/grpc/event_engine/slice_buffer.h
@@ -54,13 +54,19 @@ class SliceBuffer {
SliceBuffer(const SliceBuffer& other) = delete;
SliceBuffer(SliceBuffer&& other) noexcept
: slice_buffer_(other.slice_buffer_) {
- grpc_slice_buffer_reset_and_unref(&slice_buffer_);
+ grpc_slice_buffer_init(&slice_buffer_);
grpc_slice_buffer_swap(&slice_buffer_, &other.slice_buffer_);
}
/// Upon destruction, the underlying raw slice buffer is cleaned out and all
/// slices are unreffed.
~SliceBuffer() { grpc_slice_buffer_destroy(&slice_buffer_); }
+ SliceBuffer& operator=(const SliceBuffer&) = delete;
+ SliceBuffer& operator=(SliceBuffer&& other) noexcept {
+ grpc_slice_buffer_swap(&slice_buffer_, &other.slice_buffer_);
+ return *this;
+ }
+
/// Appends a new slice into the SliceBuffer and makes an attempt to merge
/// this slice with the last slice in the SliceBuffer.
void Append(Slice slice);
@@ -99,7 +105,7 @@ class SliceBuffer {
size_t Length() { return slice_buffer_.length; }
/// Return a pointer to the back raw grpc_slice_buffer
- grpc_slice_buffer* RawSliceBuffer() { return &slice_buffer_; }
+ grpc_slice_buffer* c_slice_buffer() { return &slice_buffer_; }
private:
/// The backing raw slice buffer.
diff --git a/package.xml b/package.xml
index c5d32110ba0..59652fde28e 100644
--- a/package.xml
+++ b/package.xml
@@ -1413,8 +1413,6 @@
-
-
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index db4db4428ab..be14d2667eb 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -2953,7 +2953,7 @@ void ClientChannel::LoadBalancedCall::RecvMessageReady(
gpr_log(GPR_INFO, "chand=%p lb_call=%p: got recv_message_ready: error=%s",
self->chand_, self, grpc_error_std_string(error).c_str());
}
- if (*self->recv_message_ != nullptr) {
+ if (self->recv_message_->has_value()) {
self->call_attempt_tracer_->RecordReceivedMessage(**self->recv_message_);
}
Closure::Run(DEBUG_LOCATION, self->original_recv_message_ready_,
diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
index 16efd351547..1b8da1eb9fc 100644
--- a/src/core/ext/filters/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -68,8 +68,8 @@
#include "src/core/lib/service_config/service_config_call_data.h"
#include "src/core/lib/service_config/service_config_parser.h"
#include "src/core/lib/slice/slice.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -534,7 +534,7 @@ class ClientChannel::LoadBalancedCall
grpc_closure* original_recv_initial_metadata_ready_ = nullptr;
// For intercepting recv_message_ready.
- OrphanablePtr* recv_message_ = nullptr;
+ absl::optional* recv_message_ = nullptr;
grpc_closure recv_message_ready_;
grpc_closure* original_recv_message_ready_ = nullptr;
diff --git a/src/core/ext/filters/client_channel/retry_filter.cc b/src/core/ext/filters/client_channel/retry_filter.cc
index b4d776e2b3b..0eafe502090 100644
--- a/src/core/ext/filters/client_channel/retry_filter.cc
+++ b/src/core/ext/filters/client_channel/retry_filter.cc
@@ -33,6 +33,7 @@
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
#include
#include
@@ -51,8 +52,8 @@
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
@@ -66,8 +67,8 @@
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/service_config/service_config.h"
#include "src/core/lib/service_config/service_config_call_data.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_refcount.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -456,9 +457,6 @@ class RetryFilter::CallData {
grpc_transport_stream_op_batch_payload batch_payload_;
// For send_initial_metadata.
grpc_metadata_batch send_initial_metadata_{calld_->arena_};
- // For send_message.
- // TODO(roth): Restructure this to eliminate use of ManualConstructor.
- ManualConstructor send_message_;
// For send_trailing_metadata.
grpc_metadata_batch send_trailing_metadata_{calld_->arena_};
// For intercepting recv_initial_metadata.
@@ -467,7 +465,8 @@ class RetryFilter::CallData {
bool trailing_metadata_available_ = false;
// For intercepting recv_message.
grpc_closure recv_message_ready_;
- OrphanablePtr recv_message_;
+ absl::optional recv_message_;
+ uint32_t recv_message_flags_;
// For intercepting recv_trailing_metadata.
grpc_metadata_batch recv_trailing_metadata_{calld_->arena_};
grpc_transport_stream_stats collect_stats_;
@@ -628,11 +627,11 @@ class RetryFilter::CallData {
// Note: We inline the cache for the first 3 send_message ops and use
// dynamic allocation after that. This number was essentially picked
// at random; it could be changed in the future to tune performance.
- // TODO(roth): As part of implementing hedging, we may need some
- // synchronization here, since ByteStreamCache does not provide any
- // synchronization, so it's not safe to have multiple
- // CachingByteStreams read from the same ByteStreamCache concurrently.
- absl::InlinedVector send_messages_;
+ struct CachedSendMessage {
+ SliceBuffer* slices;
+ uint32_t flags;
+ };
+ absl::InlinedVector send_messages_;
// send_trailing_metadata
bool seen_send_trailing_metadata_ = false;
grpc_metadata_batch send_trailing_metadata_{arena_};
@@ -1511,6 +1510,8 @@ void RetryFilter::CallData::CallAttempt::BatchData::
// Return payload.
*pending->batch->payload->recv_message.recv_message =
std::move(call_attempt_->recv_message_);
+ *pending->batch->payload->recv_message.flags =
+ call_attempt_->recv_message_flags_;
// Update bookkeeping.
// Note: Need to do this before invoking the callback, since invoking
// the callback will result in yielding the call combiner.
@@ -1555,7 +1556,7 @@ void RetryFilter::CallData::CallAttempt::BatchData::RecvMessageReady(
// the recv_trailing_metadata_ready callback, then defer propagating this
// callback back to the surface. We can evaluate whether to retry when
// recv_trailing_metadata comes back.
- if (GPR_UNLIKELY((call_attempt->recv_message_ == nullptr ||
+ if (GPR_UNLIKELY((!call_attempt->recv_message_.has_value() ||
!GRPC_ERROR_IS_NONE(error)) &&
!call_attempt->completed_recv_trailing_metadata_)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
@@ -2029,13 +2030,12 @@ void RetryFilter::CallData::CallAttempt::BatchData::
calld->chand_, calld, call_attempt_.get(),
call_attempt_->started_send_message_count_);
}
- ByteStreamCache* cache =
+ CachedSendMessage cache =
calld->send_messages_[call_attempt_->started_send_message_count_];
++call_attempt_->started_send_message_count_;
- call_attempt_->send_message_.Init(cache);
batch_.send_message = true;
- batch_.payload->send_message.send_message.reset(
- call_attempt_->send_message_.get());
+ batch_.payload->send_message.send_message = cache.slices;
+ batch_.payload->send_message.flags = cache.flags;
}
void RetryFilter::CallData::CallAttempt::BatchData::
@@ -2072,6 +2072,7 @@ void RetryFilter::CallData::CallAttempt::BatchData::
++call_attempt_->started_recv_message_count_;
batch_.recv_message = true;
batch_.payload->recv_message.recv_message = &call_attempt_->recv_message_;
+ batch_.payload->recv_message.flags = &call_attempt_->recv_message_flags_;
batch_.payload->recv_message.call_failed_before_recv_message = nullptr;
GRPC_CLOSURE_INIT(&call_attempt_->recv_message_ready_, RecvMessageReady, this,
grpc_schedule_on_exec_ctx);
@@ -2372,9 +2373,9 @@ void RetryFilter::CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) {
}
// Set up cache for send_message ops.
if (batch->send_message) {
- ByteStreamCache* cache = arena_->New(
- std::move(batch->payload->send_message.send_message));
- send_messages_.push_back(cache);
+ SliceBuffer* cache = arena_->New(std::move(
+ *absl::exchange(batch->payload->send_message.send_message, nullptr)));
+ send_messages_.push_back({cache, batch->payload->send_message.flags});
}
// Save metadata batch for send_trailing_metadata ops.
if (batch->send_trailing_metadata) {
@@ -2394,14 +2395,13 @@ void RetryFilter::CallData::FreeCachedSendInitialMetadata() {
}
void RetryFilter::CallData::FreeCachedSendMessage(size_t idx) {
- if (send_messages_[idx] != nullptr) {
+ if (send_messages_[idx].slices != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_retry_trace)) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: destroying send_messages[%" PRIuPTR "]",
chand_, this, idx);
}
- send_messages_[idx]->Destroy();
- send_messages_[idx] = nullptr;
+ Destruct(absl::exchange(send_messages_[idx].slices, nullptr));
}
}
@@ -2465,7 +2465,7 @@ RetryFilter::CallData::PendingBatch* RetryFilter::CallData::PendingBatchesAdd(
if (batch->send_message) {
pending_send_message_ = true;
bytes_buffered_for_retry_ +=
- batch->payload->send_message.send_message->length();
+ batch->payload->send_message.send_message->Length();
}
if (batch->send_trailing_metadata) {
pending_send_trailing_metadata_ = true;
diff --git a/src/core/ext/filters/client_channel/subchannel_stream_client.cc b/src/core/ext/filters/client_channel/subchannel_stream_client.cc
index 5995d63d6d8..7e3d3a9e8a4 100644
--- a/src/core/ext/filters/client_channel/subchannel_stream_client.cc
+++ b/src/core/ext/filters/client_channel/subchannel_stream_client.cc
@@ -20,15 +20,11 @@
#include
#include
-#include
-#include
#include
#include
-#include
#include
-#include
#include
#include "src/core/lib/gpr/time_precise.h"
@@ -38,7 +34,6 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/resource_quota/api.h"
#include "src/core/lib/resource_quota/resource_quota.h"
-#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/error_utils.h"
#define SUBCHANNEL_STREAM_INITIAL_CONNECT_BACKOFF_SECONDS 1
@@ -252,14 +247,9 @@ void SubchannelStreamClient::CallState::StartCallLocked() {
payload_.send_initial_metadata.peer_string = nullptr;
batch_.send_initial_metadata = true;
// Add send_message op.
- grpc_slice request_slice =
- subchannel_stream_client_->event_handler_->EncodeSendMessageLocked();
- grpc_slice_buffer slice_buffer;
- grpc_slice_buffer_init(&slice_buffer);
- grpc_slice_buffer_add(&slice_buffer, request_slice);
- send_message_.emplace(&slice_buffer, 0);
- grpc_slice_buffer_destroy_internal(&slice_buffer);
- payload_.send_message.send_message.reset(&*send_message_);
+ send_message_.Append(Slice(
+ subchannel_stream_client_->event_handler_->EncodeSendMessageLocked()));
+ payload_.send_message.send_message = &send_message_;
batch_.send_message = true;
// Add send_trailing_metadata op.
payload_.send_trailing_metadata.send_trailing_metadata =
@@ -374,42 +364,18 @@ void SubchannelStreamClient::CallState::RecvInitialMetadataReady(
self->call_->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready");
}
-void SubchannelStreamClient::CallState::DoneReadingRecvMessage(
- grpc_error_handle error) {
- recv_message_.reset();
- if (error != GRPC_ERROR_NONE) {
- GRPC_ERROR_UNREF(error);
- Cancel();
- grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
+void SubchannelStreamClient::CallState::RecvMessageReady() {
+ if (!recv_message_.has_value()) {
call_->Unref(DEBUG_LOCATION, "recv_message_ready");
return;
}
- // Concatenate the slices to form a single string.
- std::unique_ptr recv_message_deleter;
- uint8_t* recv_message;
- if (recv_message_buffer_.count == 1) {
- recv_message = GRPC_SLICE_START_PTR(recv_message_buffer_.slices[0]);
- } else {
- recv_message =
- static_cast(gpr_malloc(recv_message_buffer_.length));
- recv_message_deleter.reset(recv_message);
- size_t offset = 0;
- for (size_t i = 0; i < recv_message_buffer_.count; ++i) {
- memcpy(recv_message + offset,
- GRPC_SLICE_START_PTR(recv_message_buffer_.slices[i]),
- GRPC_SLICE_LENGTH(recv_message_buffer_.slices[i]));
- offset += GRPC_SLICE_LENGTH(recv_message_buffer_.slices[i]);
- }
- }
// Report payload.
{
MutexLock lock(&subchannel_stream_client_->mu_);
if (subchannel_stream_client_->event_handler_ != nullptr) {
- absl::string_view serialized_message(
- reinterpret_cast(recv_message), recv_message_buffer_.length);
absl::Status status =
subchannel_stream_client_->event_handler_->RecvMessageReadyLocked(
- subchannel_stream_client_.get(), serialized_message);
+ subchannel_stream_client_.get(), recv_message_->JoinIntoString());
if (!status.ok()) {
if (GPR_UNLIKELY(subchannel_stream_client_->tracer_ != nullptr)) {
gpr_log(GPR_INFO,
@@ -424,7 +390,7 @@ void SubchannelStreamClient::CallState::DoneReadingRecvMessage(
}
}
seen_response_.store(true, std::memory_order_release);
- grpc_slice_buffer_destroy_internal(&recv_message_buffer_);
+ recv_message_.reset();
// Start another recv_message batch.
// This re-uses the ref we're holding.
// Note: Can't just reuse batch_ here, since we don't know that all
@@ -438,62 +404,11 @@ void SubchannelStreamClient::CallState::DoneReadingRecvMessage(
StartBatch(&recv_message_batch_);
}
-grpc_error_handle
-SubchannelStreamClient::CallState::PullSliceFromRecvMessage() {
- grpc_slice slice;
- grpc_error_handle error = recv_message_->Pull(&slice);
- if (error == GRPC_ERROR_NONE) {
- grpc_slice_buffer_add(&recv_message_buffer_, slice);
- }
- return error;
-}
-
-void SubchannelStreamClient::CallState::ContinueReadingRecvMessage() {
- while (recv_message_->Next(SIZE_MAX, &recv_message_ready_)) {
- grpc_error_handle error = PullSliceFromRecvMessage();
- if (error != GRPC_ERROR_NONE) {
- DoneReadingRecvMessage(error);
- return;
- }
- if (recv_message_buffer_.length == recv_message_->length()) {
- DoneReadingRecvMessage(GRPC_ERROR_NONE);
- break;
- }
- }
-}
-
-void SubchannelStreamClient::CallState::OnByteStreamNext(
- void* arg, grpc_error_handle error) {
- auto* self = static_cast(arg);
- if (error != GRPC_ERROR_NONE) {
- self->DoneReadingRecvMessage(GRPC_ERROR_REF(error));
- return;
- }
- error = self->PullSliceFromRecvMessage();
- if (error != GRPC_ERROR_NONE) {
- self->DoneReadingRecvMessage(error);
- return;
- }
- if (self->recv_message_buffer_.length == self->recv_message_->length()) {
- self->DoneReadingRecvMessage(GRPC_ERROR_NONE);
- } else {
- self->ContinueReadingRecvMessage();
- }
-}
-
void SubchannelStreamClient::CallState::RecvMessageReady(
void* arg, grpc_error_handle /*error*/) {
auto* self = static_cast(arg);
GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_message_ready");
- if (self->recv_message_ == nullptr) {
- self->call_->Unref(DEBUG_LOCATION, "recv_message_ready");
- return;
- }
- grpc_slice_buffer_init(&self->recv_message_buffer_);
- GRPC_CLOSURE_INIT(&self->recv_message_ready_, OnByteStreamNext, self,
- grpc_schedule_on_exec_ctx);
- self->ContinueReadingRecvMessage();
- // Ref will continue to be held until we finish draining the byte stream.
+ self->RecvMessageReady();
}
void SubchannelStreamClient::CallState::RecvTrailingMetadataReady(
diff --git a/src/core/ext/filters/client_channel/subchannel_stream_client.h b/src/core/ext/filters/client_channel/subchannel_stream_client.h
index 08f03f7586d..32d8f00fd69 100644
--- a/src/core/ext/filters/client_channel/subchannel_stream_client.h
+++ b/src/core/ext/filters/client_channel/subchannel_stream_client.h
@@ -46,7 +46,7 @@
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/slice/slice.h"
-#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -132,6 +132,8 @@ class SubchannelStreamClient
void CallEndedLocked(bool retry)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&subchannel_stream_client_->mu_);
+ void RecvMessageReady();
+
static void OnComplete(void* arg, grpc_error_handle error);
static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
static void RecvMessageReady(void* arg, grpc_error_handle error);
@@ -139,11 +141,6 @@ class SubchannelStreamClient
static void StartCancel(void* arg, grpc_error_handle error);
static void OnCancelComplete(void* arg, grpc_error_handle error);
- static void OnByteStreamNext(void* arg, grpc_error_handle error);
- void ContinueReadingRecvMessage();
- grpc_error_handle PullSliceFromRecvMessage();
- void DoneReadingRecvMessage(grpc_error_handle error);
-
static void AfterCallStackDestruction(void* arg, grpc_error_handle error);
RefCountedPtr subchannel_stream_client_;
@@ -169,7 +166,7 @@ class SubchannelStreamClient
grpc_metadata_batch send_initial_metadata_;
// send_message
- absl::optional send_message_;
+ SliceBuffer send_message_;
// send_trailing_metadata
grpc_metadata_batch send_trailing_metadata_;
@@ -179,9 +176,8 @@ class SubchannelStreamClient
grpc_closure recv_initial_metadata_ready_;
// recv_message
- OrphanablePtr recv_message_;
+ absl::optional recv_message_;
grpc_closure recv_message_ready_;
- grpc_slice_buffer recv_message_buffer_;
std::atomic seen_response_{false};
// True if the cancel_stream batch has been started.
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
index e31f34ddb7c..aab33eb6556 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -23,33 +23,26 @@
#include
#include
-#include
#include
-#include
#include "absl/meta/type_traits.h"
-#include "absl/status/status.h"
#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
#include
#include
#include
-#include
-#include
#include
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/compression/message_compress.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/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/call.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -107,66 +100,40 @@ class CallData {
channeld->default_compression_algorithm()))) {
compression_algorithm_ = channeld->default_compression_algorithm();
}
- GRPC_CLOSURE_INIT(&start_send_message_batch_in_call_combiner_,
- StartSendMessageBatch, elem, grpc_schedule_on_exec_ctx);
+ GRPC_CLOSURE_INIT(&forward_send_message_batch_in_call_combiner_,
+ ForwardSendMessageBatch, elem, grpc_schedule_on_exec_ctx);
}
- ~CallData() {
- if (state_initialized_) {
- grpc_slice_buffer_destroy_internal(&slices_);
- }
- GRPC_ERROR_UNREF(cancel_error_);
- }
+ ~CallData() { GRPC_ERROR_UNREF(cancel_error_); }
void CompressStartTransportStreamOpBatch(
grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
private:
bool SkipMessageCompression();
- void InitializeState(grpc_call_element* elem);
+ void FinishSendMessage(grpc_call_element* elem);
void ProcessSendInitialMetadata(grpc_call_element* elem,
grpc_metadata_batch* initial_metadata);
// Methods for processing a send_message batch
- static void StartSendMessageBatch(void* elem_arg, grpc_error_handle unused);
- static void OnSendMessageNextDone(void* elem_arg, grpc_error_handle error);
- grpc_error_handle PullSliceFromSendMessage();
- void ContinueReadingSendMessage(grpc_call_element* elem);
- void FinishSendMessage(grpc_call_element* elem);
- void SendMessageBatchContinue(grpc_call_element* elem);
static void FailSendMessageBatchInCallCombiner(void* calld_arg,
grpc_error_handle error);
-
- static void SendMessageOnComplete(void* calld_arg, grpc_error_handle error);
+ static void ForwardSendMessageBatch(void* elem_arg, grpc_error_handle unused);
grpc_core::CallCombiner* call_combiner_;
grpc_compression_algorithm compression_algorithm_ = GRPC_COMPRESS_NONE;
grpc_error_handle cancel_error_ = GRPC_ERROR_NONE;
grpc_transport_stream_op_batch* send_message_batch_ = nullptr;
bool seen_initial_metadata_ = false;
- /* Set to true, if the fields below are initialized. */
- bool state_initialized_ = false;
- grpc_closure start_send_message_batch_in_call_combiner_;
- /* The fields below are only initialized when we compress the payload.
- * Keep them at the bottom of the struct, so they don't pollute the
- * cache-lines. */
- grpc_slice_buffer slices_; /**< Buffers up input slices to be compressed */
- // Allocate space for the replacement stream
- std::aligned_storage::type
- replacement_stream_;
- grpc_closure* original_send_message_on_complete_ = nullptr;
- grpc_closure send_message_on_complete_;
- grpc_closure on_send_message_next_done_;
+ grpc_closure forward_send_message_batch_in_call_combiner_;
};
// Returns true if we should skip message compression for the current message.
bool CallData::SkipMessageCompression() {
// If the flags of this message indicate that it shouldn't be compressed, we
// skip message compression.
- uint32_t flags =
- send_message_batch_->payload->send_message.send_message->flags();
+ uint32_t flags = send_message_batch_->payload->send_message.flags;
if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) {
return true;
}
@@ -175,16 +142,6 @@ bool CallData::SkipMessageCompression() {
return compression_algorithm_ == GRPC_COMPRESS_NONE;
}
-void CallData::InitializeState(grpc_call_element* elem) {
- GPR_DEBUG_ASSERT(!state_initialized_);
- state_initialized_ = true;
- grpc_slice_buffer_init(&slices_);
- GRPC_CLOSURE_INIT(&send_message_on_complete_, SendMessageOnComplete, this,
- grpc_schedule_on_exec_ctx);
- GRPC_CLOSURE_INIT(&on_send_message_next_done_, OnSendMessageNextDone, elem,
- grpc_schedule_on_exec_ctx);
-}
-
void CallData::ProcessSendInitialMetadata(
grpc_call_element* elem, grpc_metadata_batch* initial_metadata) {
ChannelData* channeld = static_cast(elem->channel_data);
@@ -197,7 +154,6 @@ void CallData::ProcessSendInitialMetadata(
break;
case GRPC_COMPRESS_DEFLATE:
case GRPC_COMPRESS_GZIP:
- InitializeState(elem);
initial_metadata->Set(grpc_core::GrpcEncodingMetadata(),
compression_algorithm_);
break;
@@ -209,68 +165,46 @@ void CallData::ProcessSendInitialMetadata(
channeld->enabled_compression_algorithms());
}
-void CallData::SendMessageOnComplete(void* calld_arg, grpc_error_handle error) {
- CallData* calld = static_cast(calld_arg);
- grpc_slice_buffer_reset_and_unref_internal(&calld->slices_);
- grpc_core::Closure::Run(DEBUG_LOCATION,
- calld->original_send_message_on_complete_,
- GRPC_ERROR_REF(error));
-}
-
-void CallData::SendMessageBatchContinue(grpc_call_element* elem) {
- // Note: The call to grpc_call_next_op() results in yielding the
- // call combiner, so we need to clear send_message_batch_ before we do that.
- grpc_transport_stream_op_batch* send_message_batch = send_message_batch_;
- send_message_batch_ = nullptr;
- grpc_call_next_op(elem, send_message_batch);
-}
-
void CallData::FinishSendMessage(grpc_call_element* elem) {
- GPR_DEBUG_ASSERT(compression_algorithm_ != GRPC_COMPRESS_NONE);
// Compress the data if appropriate.
- grpc_slice_buffer tmp;
- grpc_slice_buffer_init(&tmp);
- uint32_t send_flags =
- send_message_batch_->payload->send_message.send_message->flags();
- bool did_compress = grpc_msg_compress(compression_algorithm_, &slices_, &tmp);
- if (did_compress) {
- if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) {
- const char* algo_name;
- const size_t before_size = slices_.length;
- const size_t after_size = tmp.length;
- const float savings_ratio = 1.0f - static_cast(after_size) /
- static_cast(before_size);
- GPR_ASSERT(
- grpc_compression_algorithm_name(compression_algorithm_, &algo_name));
- gpr_log(GPR_INFO,
- "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
- " bytes (%.2f%% savings)",
- algo_name, before_size, after_size, 100 * savings_ratio);
- }
- grpc_slice_buffer_swap(&slices_, &tmp);
- send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
- } else {
- if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) {
- const char* algo_name;
- GPR_ASSERT(
- grpc_compression_algorithm_name(compression_algorithm_, &algo_name));
- gpr_log(GPR_INFO,
- "Algorithm '%s' enabled but decided not to compress. Input size: "
- "%" PRIuPTR,
- algo_name, slices_.length);
+ if (!SkipMessageCompression()) {
+ grpc_core::SliceBuffer tmp;
+ uint32_t& send_flags = send_message_batch_->payload->send_message.flags;
+ grpc_core::SliceBuffer* payload =
+ send_message_batch_->payload->send_message.send_message;
+ bool did_compress =
+ grpc_msg_compress(compression_algorithm_, payload->c_slice_buffer(),
+ tmp.c_slice_buffer());
+ if (did_compress) {
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) {
+ const char* algo_name;
+ const size_t before_size = payload->Length();
+ const size_t after_size = tmp.Length();
+ const float savings_ratio = 1.0f - static_cast(after_size) /
+ static_cast(before_size);
+ GPR_ASSERT(grpc_compression_algorithm_name(compression_algorithm_,
+ &algo_name));
+ gpr_log(GPR_INFO,
+ "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
+ " bytes (%.2f%% savings)",
+ algo_name, before_size, after_size, 100 * savings_ratio);
+ }
+ tmp.Swap(payload);
+ send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+ } else {
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) {
+ const char* algo_name;
+ GPR_ASSERT(grpc_compression_algorithm_name(compression_algorithm_,
+ &algo_name));
+ gpr_log(
+ GPR_INFO,
+ "Algorithm '%s' enabled but decided not to compress. Input size: "
+ "%" PRIuPTR,
+ algo_name, payload->Length());
+ }
}
}
- grpc_slice_buffer_destroy_internal(&tmp);
- // Swap out the original byte stream with our new one and send the
- // batch down.
- new (&replacement_stream_)
- grpc_core::SliceBufferByteStream(&slices_, send_flags);
- send_message_batch_->payload->send_message.send_message.reset(
- reinterpret_cast(
- &replacement_stream_));
- original_send_message_on_complete_ = send_message_batch_->on_complete;
- send_message_batch_->on_complete = &send_message_on_complete_;
- SendMessageBatchContinue(elem);
+ grpc_call_next_op(elem, absl::exchange(send_message_batch_, nullptr));
}
void CallData::FailSendMessageBatchInCallCombiner(void* calld_arg,
@@ -284,78 +218,11 @@ void CallData::FailSendMessageBatchInCallCombiner(void* calld_arg,
}
}
-// Pulls a slice from the send_message byte stream and adds it to slices_.
-grpc_error_handle CallData::PullSliceFromSendMessage() {
- grpc_slice incoming_slice;
- grpc_error_handle error =
- send_message_batch_->payload->send_message.send_message->Pull(
- &incoming_slice);
- if (error == GRPC_ERROR_NONE) {
- grpc_slice_buffer_add(&slices_, incoming_slice);
- }
- return error;
-}
-
-// Reads as many slices as possible from the send_message byte stream.
-// If all data has been read, invokes FinishSendMessage(). Otherwise,
-// an async call to ByteStream::Next() has been started, which will
-// eventually result in calling OnSendMessageNextDone().
-void CallData::ContinueReadingSendMessage(grpc_call_element* elem) {
- if (slices_.length ==
- send_message_batch_->payload->send_message.send_message->length()) {
- FinishSendMessage(elem);
- return;
- }
- while (send_message_batch_->payload->send_message.send_message->Next(
- ~static_cast(0), &on_send_message_next_done_)) {
- grpc_error_handle error = PullSliceFromSendMessage();
- if (error != GRPC_ERROR_NONE) {
- // Closure callback; does not take ownership of error.
- FailSendMessageBatchInCallCombiner(this, error);
- GRPC_ERROR_UNREF(error);
- return;
- }
- if (slices_.length ==
- send_message_batch_->payload->send_message.send_message->length()) {
- FinishSendMessage(elem);
- break;
- }
- }
-}
-
-// Async callback for ByteStream::Next().
-void CallData::OnSendMessageNextDone(void* elem_arg, grpc_error_handle error) {
+void CallData::ForwardSendMessageBatch(void* elem_arg,
+ grpc_error_handle /*unused*/) {
grpc_call_element* elem = static_cast(elem_arg);
CallData* calld = static_cast(elem->call_data);
- if (error != GRPC_ERROR_NONE) {
- // Closure callback; does not take ownership of error.
- FailSendMessageBatchInCallCombiner(calld, error);
- return;
- }
- error = calld->PullSliceFromSendMessage();
- if (error != GRPC_ERROR_NONE) {
- // Closure callback; does not take ownership of error.
- FailSendMessageBatchInCallCombiner(calld, error);
- GRPC_ERROR_UNREF(error);
- return;
- }
- if (calld->slices_.length == calld->send_message_batch_->payload->send_message
- .send_message->length()) {
- calld->FinishSendMessage(elem);
- } else {
- calld->ContinueReadingSendMessage(elem);
- }
-}
-
-void CallData::StartSendMessageBatch(void* elem_arg,
- grpc_error_handle /*unused*/) {
- grpc_call_element* elem = static_cast(elem_arg);
- CallData* calld = static_cast(elem->call_data);
- if (calld->SkipMessageCompression()) {
- calld->SendMessageBatchContinue(elem);
- } else {
- calld->ContinueReadingSendMessage(elem);
- }
+ calld->FinishSendMessage(elem);
}
void CallData::CompressStartTransportStreamOpBatch(
@@ -372,9 +239,6 @@ void CallData::CompressStartTransportStreamOpBatch(
GRPC_CLOSURE_CREATE(FailSendMessageBatchInCallCombiner, this,
grpc_schedule_on_exec_ctx),
GRPC_ERROR_REF(cancel_error_), "failing send_message op");
- } else {
- send_message_batch_->payload->send_message.send_message->Shutdown(
- GRPC_ERROR_REF(cancel_error_));
}
}
} else if (!GRPC_ERROR_IS_NONE(cancel_error_)) {
@@ -395,7 +259,7 @@ void CallData::CompressStartTransportStreamOpBatch(
// the call stack) will release the call combiner for each batch it sees.
if (send_message_batch_ != nullptr) {
GRPC_CALL_COMBINER_START(
- call_combiner_, &start_send_message_batch_in_call_combiner_,
+ call_combiner_, &forward_send_message_batch_in_call_combiner_,
GRPC_ERROR_NONE, "starting send_message after send_initial_metadata");
}
}
@@ -411,7 +275,7 @@ void CallData::CompressStartTransportStreamOpBatch(
call_combiner_, "send_message batch pending send_initial_metadata");
return;
}
- StartSendMessageBatch(elem, GRPC_ERROR_NONE);
+ FinishSendMessage(elem);
} else {
// Pass control down the stack.
grpc_call_next_op(elem, batch);
diff --git a/src/core/ext/filters/http/message_compress/message_decompress_filter.cc b/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
index 277989004df..14544f82894 100644
--- a/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
+++ b/src/core/ext/filters/http/message_compress/message_decompress_filter.cc
@@ -23,18 +23,13 @@
#include
#include
-#include
#include
-#include
-#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/types/optional.h"
#include
-#include
-#include
#include
#include
@@ -42,13 +37,11 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/compression/message_compress.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -83,9 +76,6 @@ class CallData {
OnRecvInitialMetadataReady, this,
grpc_schedule_on_exec_ctx);
// Initialize state for recv_message_ready callback
- grpc_slice_buffer_init(&recv_slices_);
- GRPC_CLOSURE_INIT(&on_recv_message_next_done_, OnRecvMessageNextDone, this,
- grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&on_recv_message_ready_, OnRecvMessageReady, this,
grpc_schedule_on_exec_ctx);
// Initialize state for recv_trailing_metadata_ready callback
@@ -102,8 +92,6 @@ class CallData {
}
}
- ~CallData() { grpc_slice_buffer_destroy_internal(&recv_slices_); }
-
void DecompressStartTransportStreamOpBatch(
grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
@@ -113,10 +101,6 @@ class CallData {
// Methods for processing a receive message event
void MaybeResumeOnRecvMessageReady();
static void OnRecvMessageReady(void* arg, grpc_error_handle error);
- static void OnRecvMessageNextDone(void* arg, grpc_error_handle error);
- grpc_error_handle PullSliceFromRecvMessage();
- void ContinueReadingRecvMessage();
- void FinishRecvMessage();
void ContinueRecvMessageReadyCallback(grpc_error_handle error);
// Methods for processing a recv_trailing_metadata event
@@ -134,17 +118,10 @@ class CallData {
bool seen_recv_message_ready_ = false;
int max_recv_message_length_;
grpc_compression_algorithm algorithm_ = GRPC_COMPRESS_NONE;
+ absl::optional* recv_message_ = nullptr;
+ uint32_t* recv_message_flags_ = nullptr;
grpc_closure on_recv_message_ready_;
grpc_closure* original_recv_message_ready_ = nullptr;
- grpc_closure on_recv_message_next_done_;
- OrphanablePtr* recv_message_ = nullptr;
- // recv_slices_ holds the slices read from the original recv_message stream.
- // It is initialized during construction and reset when a new stream is
- // created using it.
- grpc_slice_buffer recv_slices_;
- std::aligned_storage::type
- recv_replacement_stream_;
// Fields for handling recv_trailing_metadata_ready callback
bool seen_recv_trailing_metadata_ready_ = false;
grpc_closure on_recv_trailing_metadata_ready_;
@@ -188,101 +165,46 @@ void CallData::OnRecvMessageReady(void* arg, grpc_error_handle error) {
if (calld->algorithm_ != GRPC_COMPRESS_NONE) {
// recv_message can be NULL if trailing metadata is received instead of
// message, or it's possible that the message was not compressed.
- if (*calld->recv_message_ == nullptr ||
- (*calld->recv_message_)->length() == 0 ||
- ((*calld->recv_message_)->flags() & GRPC_WRITE_INTERNAL_COMPRESS) ==
- 0) {
+ if (!calld->recv_message_->has_value() ||
+ (*calld->recv_message_)->Length() == 0 ||
+ ((*calld->recv_message_flags_ & GRPC_WRITE_INTERNAL_COMPRESS) == 0)) {
return calld->ContinueRecvMessageReadyCallback(GRPC_ERROR_NONE);
}
if (calld->max_recv_message_length_ >= 0 &&
- (*calld->recv_message_)->length() >
+ (*calld->recv_message_)->Length() >
static_cast(calld->max_recv_message_length_)) {
GPR_DEBUG_ASSERT(GRPC_ERROR_IS_NONE(calld->error_));
calld->error_ = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrFormat("Received message larger than max (%u vs. %d)",
- (*calld->recv_message_)->length(),
+ (*calld->recv_message_)->Length(),
calld->max_recv_message_length_)),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
return calld->ContinueRecvMessageReadyCallback(
GRPC_ERROR_REF(calld->error_));
}
- grpc_slice_buffer_destroy_internal(&calld->recv_slices_);
- grpc_slice_buffer_init(&calld->recv_slices_);
- return calld->ContinueReadingRecvMessage();
+ SliceBuffer decompressed_slices;
+ if (grpc_msg_decompress(calld->algorithm_,
+ (*calld->recv_message_)->c_slice_buffer(),
+ decompressed_slices.c_slice_buffer()) == 0) {
+ GPR_DEBUG_ASSERT(GRPC_ERROR_IS_NONE(calld->error_));
+ calld->error_ = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
+ "Unexpected error decompressing data for algorithm with "
+ "enum value ",
+ calld->algorithm_));
+ } else {
+ *calld->recv_message_flags_ =
+ (*calld->recv_message_flags_ & (~GRPC_WRITE_INTERNAL_COMPRESS)) |
+ GRPC_WRITE_INTERNAL_TEST_ONLY_WAS_COMPRESSED;
+ (*calld->recv_message_)->Swap(&decompressed_slices);
+ }
+ return calld->ContinueRecvMessageReadyCallback(
+ GRPC_ERROR_REF(calld->error_));
}
}
calld->ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error));
}
-void CallData::ContinueReadingRecvMessage() {
- while ((*recv_message_)
- ->Next((*recv_message_)->length() - recv_slices_.length,
- &on_recv_message_next_done_)) {
- grpc_error_handle error = PullSliceFromRecvMessage();
- if (error != GRPC_ERROR_NONE) {
- return ContinueRecvMessageReadyCallback(error);
- }
- // We have read the entire message.
- if (recv_slices_.length == (*recv_message_)->length()) {
- return FinishRecvMessage();
- }
- }
-}
-
-grpc_error_handle CallData::PullSliceFromRecvMessage() {
- grpc_slice incoming_slice;
- grpc_error_handle error = (*recv_message_)->Pull(&incoming_slice);
- if (error == GRPC_ERROR_NONE) {
- grpc_slice_buffer_add(&recv_slices_, incoming_slice);
- }
- return error;
-}
-
-void CallData::OnRecvMessageNextDone(void* arg, grpc_error_handle error) {
- CallData* calld = static_cast(arg);
- if (error != GRPC_ERROR_NONE) {
- return calld->ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error));
- }
- error = calld->PullSliceFromRecvMessage();
- if (error != GRPC_ERROR_NONE) {
- return calld->ContinueRecvMessageReadyCallback(error);
- }
- if (calld->recv_slices_.length == (*calld->recv_message_)->length()) {
- calld->FinishRecvMessage();
- } else {
- calld->ContinueReadingRecvMessage();
- }
-}
-
-void CallData::FinishRecvMessage() {
- grpc_slice_buffer decompressed_slices;
- grpc_slice_buffer_init(&decompressed_slices);
- if (grpc_msg_decompress(algorithm_, &recv_slices_, &decompressed_slices) ==
- 0) {
- GPR_DEBUG_ASSERT(error_ == GRPC_ERROR_NONE);
- error_ = GRPC_ERROR_CREATE_FROM_CPP_STRING(
- absl::StrCat("Unexpected error decompressing data for algorithm with "
- "enum value ",
- algorithm_));
- grpc_slice_buffer_destroy_internal(&decompressed_slices);
- } else {
- uint32_t recv_flags =
- ((*recv_message_)->flags() & (~GRPC_WRITE_INTERNAL_COMPRESS)) |
- GRPC_WRITE_INTERNAL_TEST_ONLY_WAS_COMPRESSED;
- // Swap out the original receive byte stream with our new one and send the
- // batch down.
- // Initializing recv_replacement_stream_ with decompressed_slices removes
- // all the slices from decompressed_slices leaving it empty.
- new (&recv_replacement_stream_)
- SliceBufferByteStream(&decompressed_slices, recv_flags);
- recv_message_->reset(
- reinterpret_cast(&recv_replacement_stream_));
- recv_message_ = nullptr;
- }
- ContinueRecvMessageReadyCallback(GRPC_ERROR_REF(error_));
-}
-
void CallData::ContinueRecvMessageReadyCallback(grpc_error_handle error) {
MaybeResumeOnRecvTrailingMetadataReady();
// The surface will clean up the receiving stream if there is an error.
@@ -334,6 +256,7 @@ void CallData::DecompressStartTransportStreamOpBatch(
// Handle recv_message
if (batch->recv_message) {
recv_message_ = batch->payload->recv_message.recv_message;
+ recv_message_flags_ = batch->payload->recv_message.flags;
original_recv_message_ready_ =
batch->payload->recv_message.recv_message_ready;
batch->payload->recv_message.recv_message_ready = &on_recv_message_ready_;
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 2f6d2fbc1a1..a9cca8cc436 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -39,13 +39,12 @@
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/service_config/service_config_call_data.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/surface/channel_stack_type.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/transport.h"
static void recv_message_ready(void* user_data, grpc_error_handle error);
@@ -194,7 +193,7 @@ struct call_data {
// The error caused by a message that is too large, or GRPC_ERROR_NONE
grpc_error_handle error = GRPC_ERROR_NONE;
// Used by recv_message_ready.
- grpc_core::OrphanablePtr* recv_message = nullptr;
+ absl::optional* recv_message = nullptr;
// Original recv_message_ready callback, invoked after our own.
grpc_closure* next_recv_message_ready = nullptr;
// Original recv_trailing_metadata callback, invoked after our own.
@@ -210,13 +209,13 @@ struct call_data {
static void recv_message_ready(void* user_data, grpc_error_handle error) {
grpc_call_element* elem = static_cast(user_data);
call_data* calld = static_cast(elem->call_data);
- if (*calld->recv_message != nullptr && calld->limits.max_recv_size >= 0 &&
- (*calld->recv_message)->length() >
+ if (calld->recv_message->has_value() && calld->limits.max_recv_size >= 0 &&
+ (*calld->recv_message)->Length() >
static_cast(calld->limits.max_recv_size)) {
grpc_error_handle new_error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
"Received message larger than max (%u vs. %d)",
- (*calld->recv_message)->length(), calld->limits.max_recv_size)),
+ (*calld->recv_message)->Length(), calld->limits.max_recv_size)),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
error = grpc_error_add_child(GRPC_ERROR_REF(error), new_error);
GRPC_ERROR_UNREF(calld->error);
@@ -269,13 +268,13 @@ static void message_size_start_transport_stream_op_batch(
call_data* calld = static_cast(elem->call_data);
// Check max send message size.
if (op->send_message && calld->limits.max_send_size >= 0 &&
- op->payload->send_message.send_message->length() >
+ op->payload->send_message.send_message->Length() >
static_cast(calld->limits.max_send_size)) {
grpc_transport_stream_op_batch_finish_with_failure(
op,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
"Sent message larger than max (%u vs. %d)",
- op->payload->send_message.send_message->length(),
+ op->payload->send_message.send_message->Length(),
calld->limits.max_send_size)),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED),
diff --git a/src/core/ext/transport/binder/transport/binder_stream.h b/src/core/ext/transport/binder/transport/binder_stream.h
index b04076b1f85..6c753e8ca09 100644
--- a/src/core/ext/transport/binder/transport/binder_stream.h
+++ b/src/core/ext/transport/binder/transport/binder_stream.h
@@ -80,7 +80,6 @@ struct grpc_binder_stream {
grpc_binder_transport* t;
grpc_stream_refcount* refcount;
grpc_core::Arena* arena;
- grpc_core::ManualConstructor sbs;
int tx_code;
const bool is_client;
bool is_closed;
@@ -106,7 +105,7 @@ struct grpc_binder_stream {
grpc_metadata_batch* recv_initial_metadata;
grpc_closure* recv_initial_metadata_ready = nullptr;
bool* trailing_metadata_available = nullptr;
- grpc_core::OrphanablePtr* recv_message;
+ absl::optional* recv_message;
grpc_closure* recv_message_ready = nullptr;
bool* call_failed_before_recv_message = nullptr;
grpc_metadata_batch* recv_trailing_metadata;
diff --git a/src/core/ext/transport/binder/transport/binder_transport.cc b/src/core/ext/transport/binder/transport/binder_transport.cc
index d478980f668..42cd830bca2 100644
--- a/src/core/ext/transport/binder/transport/binder_transport.cc
+++ b/src/core/ext/transport/binder/transport/binder_transport.cc
@@ -37,7 +37,6 @@
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -257,12 +256,9 @@ static void recv_message_locked(void* arg, grpc_error_handle /*error*/) {
return absl_status_to_grpc_error(args->message.status());
}
}
- grpc_slice_buffer buf;
- grpc_slice_buffer_init(&buf);
- grpc_slice_buffer_add(&buf, grpc_slice_from_cpp_string(*args->message));
-
- gbs->sbs.Init(&buf, 0);
- gbs->recv_message->reset(gbs->sbs.get());
+ grpc_core::SliceBuffer buf;
+ buf.Append(grpc_core::Slice(grpc_slice_from_cpp_string(*args->message)));
+ *gbs->recv_message = std::move(buf);
return GRPC_ERROR_NONE;
}();
@@ -412,7 +408,7 @@ static void perform_stream_op_locked(void* stream_op,
if (gbs->is_closed) {
if (op->send_message) {
// Reset the send_message payload to prevent memory leaks.
- op->payload->send_message.send_message.reset();
+ op->payload->send_message.send_message->Clear();
}
if (op->recv_initial_metadata) {
grpc_core::ExecCtx::Run(
@@ -454,27 +450,7 @@ static void perform_stream_op_locked(void* stream_op,
}
if (op->send_message) {
gpr_log(GPR_INFO, "send_message");
- size_t remaining = op->payload->send_message.send_message->length();
- std::string message_data;
- while (remaining > 0) {
- grpc_slice message_slice;
- // TODO(waynetu): Temporarily assume that the message is ready.
- GPR_ASSERT(
- op->payload->send_message.send_message->Next(SIZE_MAX, nullptr));
- grpc_error_handle error =
- op->payload->send_message.send_message->Pull(&message_slice);
- // TODO(waynetu): Cancel the stream if error is not GRPC_ERROR_NONE.
- GPR_ASSERT(error == GRPC_ERROR_NONE);
- uint8_t* p = GRPC_SLICE_START_PTR(message_slice);
- size_t len = GRPC_SLICE_LENGTH(message_slice);
- remaining -= len;
- message_data += std::string(reinterpret_cast(p), len);
- grpc_slice_unref_internal(message_slice);
- }
- tx->SetData(message_data);
- // TODO(b/192369787): Are we supposed to reset here to avoid
- // use-after-free issue in call.cc?
- op->payload->send_message.send_message.reset();
+ tx->SetData(op->payload->send_message.send_message->JoinIntoString());
}
if (op->send_trailing_metadata) {
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index e17a0b36bff..03507c8c1eb 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -37,6 +37,7 @@
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "absl/types/variant.h"
#include
#include
@@ -61,9 +62,6 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/bitset.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/global_config_env.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/gprpp/time.h"
@@ -75,16 +73,17 @@
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resource_quota/api.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/resource_quota/trace.h"
#include "src/core/lib/slice/slice.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_refcount.h"
#include "src/core/lib/transport/bdp_estimator.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/http2_errors.h"
@@ -93,12 +92,6 @@
#include "src/core/lib/transport/transport.h"
#include "src/core/lib/transport/transport_impl.h"
-GPR_GLOBAL_CONFIG_DEFINE_BOOL(
- grpc_experimental_disable_flow_control, false,
- "If set, flow control will be effectively disabled. Max out all values and "
- "assume the remote peer does the same. Thus we can ignore any flow control "
- "bookkeeping, error checking, and decision making");
-
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
@@ -151,8 +144,6 @@ static void read_action(void* t, grpc_error_handle error);
static void read_action_locked(void* t, grpc_error_handle error);
static void continue_read_action_locked(grpc_chttp2_transport* t);
-static void complete_fetch(void* gs, grpc_error_handle error);
-static void complete_fetch_locked(void* gs, grpc_error_handle error);
// Set a transport level setting, and push it to our peer
static void queue_setting_update(grpc_chttp2_transport* t,
grpc_chttp2_setting_id id, uint32_t value);
@@ -202,8 +193,6 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error_handle error);
static void keepalive_watchdog_fired(void* arg, grpc_error_handle error);
static void keepalive_watchdog_fired_locked(void* arg, grpc_error_handle error);
-static void reset_byte_stream(void* arg, grpc_error_handle error);
-
namespace grpc_core {
namespace {
@@ -280,8 +269,6 @@ grpc_chttp2_transport::~grpc_chttp2_transport() {
write_cb_pool = next;
}
- flow_control.Destroy();
-
GRPC_ERROR_UNREF(closed_with_error);
gpr_free(ping_acks);
if (grpc_core::test_only_destruct_callback != nullptr) {
@@ -291,11 +278,9 @@ grpc_chttp2_transport::~grpc_chttp2_transport() {
static const grpc_transport_vtable* get_vtable(void);
-// Returns whether bdp is enabled
-static bool read_channel_args(grpc_chttp2_transport* t,
+static void read_channel_args(grpc_chttp2_transport* t,
const grpc_channel_args* channel_args,
bool is_client) {
- bool enable_bdp = true;
bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT;
size_t i;
int j;
@@ -345,9 +330,6 @@ static bool read_channel_args(grpc_chttp2_transport* t,
GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
t->write_buffer_size = static_cast(grpc_channel_arg_get_integer(
&channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}));
- } else if (0 ==
- strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
- enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
} else if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer(
@@ -439,7 +421,6 @@ static bool read_channel_args(grpc_chttp2_transport* t,
grpc_core::channelz::SocketNode::Security::GetFromChannelArgs(
channel_args));
}
- return enable_bdp;
}
static void init_transport_keepalive_settings(grpc_chttp2_transport* t) {
@@ -510,6 +491,10 @@ grpc_chttp2_transport::grpc_chttp2_transport(
GRPC_CHANNEL_READY),
is_client(is_client),
next_stream_id(is_client ? 1 : 2),
+ flow_control(peer_string.c_str(),
+ grpc_channel_args_find_bool(channel_args,
+ GRPC_ARG_HTTP2_BDP_PROBE, true),
+ &memory_owner),
deframe_state(is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0) {
GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
@@ -551,19 +536,8 @@ grpc_chttp2_transport::grpc_chttp2_transport(
configure_transport_ping_policy(this);
init_transport_keepalive_settings(this);
- bool enable_bdp = true;
- if (channel_args) {
- enable_bdp = read_channel_args(this, channel_args, is_client);
- }
-
- static const bool kEnableFlowControl =
- !GPR_GLOBAL_CONFIG_GET(grpc_experimental_disable_flow_control);
- if (kEnableFlowControl) {
- flow_control.Init(this,
- enable_bdp);
- } else {
- flow_control.Init(this);
- enable_bdp = false;
+ if (channel_args != nullptr) {
+ read_channel_args(this, channel_args, is_client);
}
// No pings allowed before receiving a header or data frame.
@@ -576,9 +550,9 @@ grpc_chttp2_transport::grpc_chttp2_transport(
init_keepalive_pings_if_enabled(this);
- if (enable_bdp) {
+ if (flow_control.bdp_probe()) {
bdp_ping_blocked = true;
- grpc_chttp2_act_on_flowctl_action(flow_control->PeriodicUpdate(), this,
+ grpc_chttp2_act_on_flowctl_action(flow_control.PeriodicUpdate(), this,
nullptr);
}
@@ -703,29 +677,23 @@ grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t,
refcount(refcount),
reffer(this),
initial_metadata_buffer(arena),
- trailing_metadata_buffer(arena) {
+ trailing_metadata_buffer(arena),
+ flow_control(&t->flow_control) {
if (server_data) {
id = static_cast(reinterpret_cast(server_data));
*t->accepting_stream = this;
grpc_chttp2_stream_map_add(&t->stream_map, id, this);
post_destructive_reclaimer(t);
}
- if (t->flow_control->flow_control_enabled()) {
- flow_control.Init(
- static_cast(
- t->flow_control.get()),
- this);
- } else {
- flow_control.Init();
- }
grpc_slice_buffer_init(&frame_storage);
- grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer);
grpc_slice_buffer_init(&flow_controlled_buffer);
- GRPC_CLOSURE_INIT(&reset_byte_stream, ::reset_byte_stream, this, nullptr);
}
grpc_chttp2_stream::~grpc_chttp2_stream() {
+ grpc_chttp2_list_remove_stalled_by_stream(t, this);
+ grpc_chttp2_list_remove_stalled_by_transport(t, this);
+
if (t->channelz_socket != nullptr) {
if ((t->is_client && eos_received) || (!t->is_client && eos_sent)) {
t->channelz_socket->RecordStreamSucceeded();
@@ -739,7 +707,6 @@ grpc_chttp2_stream::~grpc_chttp2_stream() {
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, id) == nullptr);
}
- grpc_slice_buffer_destroy_internal(&unprocessed_incoming_frames_buffer);
grpc_slice_buffer_destroy_internal(&frame_storage);
for (int i = 0; i < STREAM_LIST_COUNT; i++) {
@@ -751,7 +718,6 @@ grpc_chttp2_stream::~grpc_chttp2_stream() {
}
GPR_ASSERT(send_initial_metadata_finished == nullptr);
- GPR_ASSERT(fetching_send_message == nullptr);
GPR_ASSERT(send_trailing_metadata_finished == nullptr);
GPR_ASSERT(recv_initial_metadata_ready == nullptr);
GPR_ASSERT(recv_message_ready == nullptr);
@@ -759,8 +725,6 @@ grpc_chttp2_stream::~grpc_chttp2_stream() {
grpc_slice_buffer_destroy_internal(&flow_controlled_buffer);
GRPC_ERROR_UNREF(read_closed_error);
GRPC_ERROR_UNREF(write_closed_error);
- GRPC_ERROR_UNREF(byte_stream_error);
- flow_control.Destroy();
GRPC_CHTTP2_UNREF_TRANSPORT(t, "stream");
grpc_core::ExecCtx::Run(DEBUG_LOCATION, destroy_stream_arg, GRPC_ERROR_NONE);
}
@@ -1326,94 +1290,6 @@ static bool contains_non_ok_status(grpc_metadata_batch* batch) {
GRPC_STATUS_OK;
}
-static void maybe_become_writable_due_to_send_msg(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s) {
- if (s->id != 0 && (!s->write_buffering ||
- s->flow_controlled_buffer.length > t->write_buffer_size)) {
- grpc_chttp2_mark_stream_writable(t, s);
- grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_SEND_MESSAGE);
- }
-}
-
-static void add_fetched_slice_locked(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s) {
- s->fetched_send_message_length +=
- static_cast GRPC_SLICE_LENGTH(s->fetching_slice);
- grpc_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
- maybe_become_writable_due_to_send_msg(t, s);
-}
-
-static void continue_fetching_send_locked(grpc_chttp2_transport* t,
- grpc_chttp2_stream* s) {
- for (;;) {
- if (s->fetching_send_message == nullptr) {
- // Stream was cancelled before message fetch completed
- abort(); /* TODO(ctiller): what cleanup here? */
- }
- if (s->fetched_send_message_length == s->fetching_send_message->length()) {
- int64_t notify_offset = s->next_message_end_offset;
- if (notify_offset <= s->flow_controlled_bytes_written) {
- grpc_chttp2_complete_closure_step(
- t, s, &s->fetching_send_message_finished, GRPC_ERROR_NONE,
- "fetching_send_message_finished");
- } else {
- grpc_chttp2_write_cb* cb = t->write_cb_pool;
- if (cb == nullptr) {
- cb = static_cast(gpr_malloc(sizeof(*cb)));
- } else {
- t->write_cb_pool = cb->next;
- }
- cb->call_at_byte = notify_offset;
- cb->closure = s->fetching_send_message_finished;
- s->fetching_send_message_finished = nullptr;
- grpc_chttp2_write_cb** list =
- s->fetching_send_message->flags() & GRPC_WRITE_THROUGH
- ? &s->on_write_finished_cbs
- : &s->on_flow_controlled_cbs;
- cb->next = *list;
- *list = cb;
- }
- s->fetching_send_message.reset();
- return; /* early out */
- } else if (s->fetching_send_message->Next(
- UINT32_MAX, GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
- ::complete_fetch, s,
- grpc_schedule_on_exec_ctx))) {
- grpc_error_handle error =
- s->fetching_send_message->Pull(&s->fetching_slice);
- if (error != GRPC_ERROR_NONE) {
- s->fetching_send_message.reset();
- grpc_chttp2_cancel_stream(t, s, error);
- } else {
- add_fetched_slice_locked(t, s);
- }
- }
- }
-}
-
-static void complete_fetch(void* gs, grpc_error_handle error) {
- grpc_chttp2_stream* s = static_cast(gs);
- s->t->combiner->Run(GRPC_CLOSURE_INIT(&s->complete_fetch_locked,
- ::complete_fetch_locked, s, nullptr),
- GRPC_ERROR_REF(error));
-}
-
-static void complete_fetch_locked(void* gs, grpc_error_handle error) {
- grpc_chttp2_stream* s = static_cast(gs);
- grpc_chttp2_transport* t = s->t;
- if (error == GRPC_ERROR_NONE) {
- error = s->fetching_send_message->Pull(&s->fetching_slice);
- if (error == GRPC_ERROR_NONE) {
- add_fetched_slice_locked(t, s);
- continue_fetching_send_locked(t, s);
- }
- }
- if (error != GRPC_ERROR_NONE) {
- s->fetching_send_message.reset();
- grpc_chttp2_cancel_stream(t, s, error);
- }
-}
-
static void log_metadata(const grpc_metadata_batch* md_batch, uint32_t id,
bool is_client, bool is_initial) {
const std::string prefix = absl::StrCat(
@@ -1508,8 +1384,7 @@ static void perform_stream_op_locked(void* stream_op,
GPR_ASSERT(s->id != 0);
grpc_chttp2_mark_stream_writable(t, s);
if (!(op->send_message &&
- (op->payload->send_message.send_message->flags() &
- GRPC_WRITE_BUFFER_HINT))) {
+ (op->payload->send_message.flags & GRPC_WRITE_BUFFER_HINT))) {
grpc_chttp2_initiate_write(
t, GRPC_CHTTP2_INITIATE_WRITE_SEND_INITIAL_METADATA);
}
@@ -1533,32 +1408,28 @@ static void perform_stream_op_locked(void* stream_op,
GRPC_STATS_INC_HTTP2_OP_SEND_MESSAGE();
t->num_messages_in_next_write++;
GRPC_STATS_INC_HTTP2_SEND_MESSAGE_SIZE(
- op->payload->send_message.send_message->length());
+ op->payload->send_message.send_message->Length());
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
- s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
+ s->send_message_finished = add_closure_barrier(op->on_complete);
+ const uint32_t flags = op_payload->send_message.flags;
if (s->write_closed) {
op->payload->send_message.stream_write_closed = true;
// We should NOT return an error here, so as to avoid a cancel OP being
// started. The surface layer will notice that the stream has been closed
// for writes and fail the send message op.
- op->payload->send_message.send_message.reset();
- grpc_chttp2_complete_closure_step(
- t, s, &s->fetching_send_message_finished, GRPC_ERROR_NONE,
- "fetching_send_message_finished");
+ grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished,
+ GRPC_ERROR_NONE,
+ "fetching_send_message_finished");
} else {
- GPR_ASSERT(s->fetching_send_message == nullptr);
uint8_t* frame_hdr = grpc_slice_buffer_tiny_add(
&s->flow_controlled_buffer, GRPC_HEADER_SIZE_IN_BYTES);
- uint32_t flags = op_payload->send_message.send_message->flags();
frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
- size_t len = op_payload->send_message.send_message->length();
+ size_t len = op_payload->send_message.send_message->Length();
frame_hdr[1] = static_cast(len >> 24);
frame_hdr[2] = static_cast(len >> 16);
frame_hdr[3] = static_cast(len >> 8);
frame_hdr[4] = static_cast(len);
- s->fetching_send_message =
- std::move(op_payload->send_message.send_message);
- s->fetched_send_message_length = 0;
+
s->next_message_end_offset =
s->flow_controlled_bytes_written +
static_cast(s->flow_controlled_buffer.length) +
@@ -1569,8 +1440,44 @@ static void perform_stream_op_locked(void* stream_op,
} else {
s->write_buffering = false;
}
- continue_fetching_send_locked(t, s);
- maybe_become_writable_due_to_send_msg(t, s);
+
+ grpc_slice* const slices =
+ op_payload->send_message.send_message->c_slice_buffer()->slices;
+ grpc_slice* const end =
+ slices + op_payload->send_message.send_message->Count();
+ for (grpc_slice* slice = slices; slice != end; slice++) {
+ grpc_slice_buffer_add(&s->flow_controlled_buffer,
+ grpc_slice_ref_internal(*slice));
+ }
+
+ int64_t notify_offset = s->next_message_end_offset;
+ if (notify_offset <= s->flow_controlled_bytes_written) {
+ grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished,
+ GRPC_ERROR_NONE,
+ "fetching_send_message_finished");
+ } else {
+ grpc_chttp2_write_cb* cb = t->write_cb_pool;
+ if (cb == nullptr) {
+ cb = static_cast(gpr_malloc(sizeof(*cb)));
+ } else {
+ t->write_cb_pool = cb->next;
+ }
+ cb->call_at_byte = notify_offset;
+ cb->closure = s->send_message_finished;
+ s->send_message_finished = nullptr;
+ grpc_chttp2_write_cb** list = flags & GRPC_WRITE_THROUGH
+ ? &s->on_write_finished_cbs
+ : &s->on_flow_controlled_cbs;
+ cb->next = *list;
+ *list = cb;
+ }
+
+ if (s->id != 0 &&
+ (!s->write_buffering ||
+ s->flow_controlled_buffer.length > t->write_buffer_size)) {
+ grpc_chttp2_mark_stream_writable(t, s);
+ grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_SEND_MESSAGE);
+ }
}
}
@@ -1624,28 +1531,14 @@ static void perform_stream_op_locked(void* stream_op,
if (op->recv_message) {
GRPC_STATS_INC_HTTP2_OP_RECV_MESSAGE();
- size_t before = 0;
GPR_ASSERT(s->recv_message_ready == nullptr);
- GPR_ASSERT(!s->pending_byte_stream);
s->recv_message_ready = op_payload->recv_message.recv_message_ready;
s->recv_message = op_payload->recv_message.recv_message;
+ s->recv_message->emplace();
+ s->recv_message_flags = op_payload->recv_message.flags;
s->call_failed_before_recv_message =
op_payload->recv_message.call_failed_before_recv_message;
- if (s->id != 0) {
- if (!s->read_closed) {
- before = s->frame_storage.length +
- s->unprocessed_incoming_frames_buffer.length;
- }
- }
- grpc_chttp2_maybe_complete_recv_message(t, s);
- if (s->id != 0) {
- if (!s->read_closed && s->frame_storage.length == 0) {
- size_t after = s->unprocessed_incoming_frames_buffer_cached_length;
- s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
- before - after);
- grpc_chttp2_act_on_flowctl_action(s->flow_control->MakeAction(), t, s);
- }
- }
+ grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s);
}
if (op->recv_trailing_metadata) {
@@ -2019,10 +1912,6 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
s->published_metadata[0] != GRPC_METADATA_NOT_PUBLISHED) {
if (s->seen_error) {
grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
- if (!s->pending_byte_stream) {
- grpc_slice_buffer_reset_and_unref_internal(
- &s->unprocessed_incoming_frames_buffer);
- }
}
*s->recv_initial_metadata = std::move(s->initial_metadata_buffer);
s->recv_initial_metadata->Set(grpc_core::PeerString(), t->peer_string);
@@ -2039,47 +1928,62 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
}
}
-void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* /*t*/,
+void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
+ if (s->recv_message_ready == nullptr) return;
+
+ grpc_core::chttp2::StreamFlowControl::IncomingUpdateContext upd(
+ &s->flow_control);
grpc_error_handle error = GRPC_ERROR_NONE;
- if (s->recv_message_ready != nullptr) {
- *s->recv_message = nullptr;
+
+ // Lambda is immediately invoked as a big scoped section that can be
+ // exited out of at any point by returning.
+ [&]() {
if (s->final_metadata_requested && s->seen_error) {
grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
- if (!s->pending_byte_stream) {
- grpc_slice_buffer_reset_and_unref_internal(
- &s->unprocessed_incoming_frames_buffer);
- }
- }
- if (!s->pending_byte_stream) {
- while (s->unprocessed_incoming_frames_buffer.length > 0 ||
- s->frame_storage.length > 0) {
- if (s->unprocessed_incoming_frames_buffer.length == 0) {
- grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer,
- &s->frame_storage);
- }
- error = grpc_deframe_unprocessed_incoming_frames(
- &s->data_parser, s, &s->unprocessed_incoming_frames_buffer, nullptr,
- s->recv_message);
- if (!GRPC_ERROR_IS_NONE(error)) {
- s->seen_error = true;
- grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
- grpc_slice_buffer_reset_and_unref_internal(
- &s->unprocessed_incoming_frames_buffer);
- break;
- } else if (*s->recv_message != nullptr) {
- break;
+ s->recv_message->reset();
+ } else {
+ if (s->frame_storage.length != 0) {
+ while (true) {
+ GPR_ASSERT(s->frame_storage.length > 0);
+ uint32_t min_progress_size;
+ auto r = grpc_deframe_unprocessed_incoming_frames(
+ s, &min_progress_size, &**s->recv_message, s->recv_message_flags);
+ if (absl::holds_alternative(r)) {
+ if (s->read_closed) {
+ grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
+ s->recv_message->reset();
+ break;
+ } else {
+ upd.SetMinProgressSize(min_progress_size);
+ return; // Out of lambda to enclosing function
+ }
+ } else {
+ error = absl::get(r);
+ if (!GRPC_ERROR_IS_NONE(error)) {
+ s->seen_error = true;
+ grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
+ break;
+ } else {
+ if (t->channelz_socket != nullptr) {
+ t->channelz_socket->RecordMessageReceived();
+ }
+ break;
+ }
+ }
}
+ } else if (s->read_closed) {
+ s->recv_message->reset();
+ } else {
+ upd.SetMinProgressSize(GRPC_HEADER_SIZE_IN_BYTES);
+ return; // Out of lambda to enclosing function
}
}
// save the length of the buffer before handing control back to application
// threads. Needed to support correct flow control bookkeeping
- s->unprocessed_incoming_frames_buffer_cached_length =
- s->unprocessed_incoming_frames_buffer.length;
- if (GRPC_ERROR_IS_NONE(error) && *s->recv_message != nullptr) {
+ if (GRPC_ERROR_IS_NONE(error) && s->recv_message->has_value()) {
null_then_sched_closure(&s->recv_message_ready);
} else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) {
- *s->recv_message = nullptr;
if (s->call_failed_before_recv_message != nullptr) {
*s->call_failed_before_recv_message =
(s->published_metadata[1] != GRPC_METADATA_PUBLISHED_AT_CLOSE);
@@ -2087,7 +1991,10 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* /*t*/,
null_then_sched_closure(&s->recv_message_ready);
}
GRPC_ERROR_UNREF(error);
- }
+ }();
+
+ upd.SetPendingSize(s->frame_storage.length);
+ grpc_chttp2_act_on_flowctl_action(upd.MakeAction(), t, s);
}
void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
@@ -2097,26 +2004,8 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
s->write_closed) {
if (s->seen_error || !t->is_client) {
grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
- if (!s->pending_byte_stream) {
- grpc_slice_buffer_reset_and_unref_internal(
- &s->unprocessed_incoming_frames_buffer);
- }
}
- bool pending_data = s->pending_byte_stream ||
- s->unprocessed_incoming_frames_buffer.length > 0;
- if (s->read_closed && s->frame_storage.length > 0 && !pending_data &&
- !s->seen_error && s->recv_trailing_metadata_finished != nullptr) {
- // Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and
- // maybe decompress the next 5 bytes in the stream.
- grpc_slice_buffer_move_first(
- &s->frame_storage,
- std::min(s->frame_storage.length, size_t(GRPC_HEADER_SIZE_IN_BYTES)),
- &s->unprocessed_incoming_frames_buffer);
- if (s->unprocessed_incoming_frames_buffer.length > 0) {
- pending_data = true;
- }
- }
- if (s->read_closed && s->frame_storage.length == 0 && !pending_data &&
+ if (s->read_closed && s->frame_storage.length == 0 &&
s->recv_trailing_metadata_finished != nullptr) {
grpc_transport_move_stats(&s->stats, s->collecting_stats);
s->collecting_stats = nullptr;
@@ -2136,20 +2025,6 @@ static void remove_stream(grpc_chttp2_transport* t, uint32_t id,
t->incoming_stream = nullptr;
grpc_chttp2_parsing_become_skip_parser(t);
}
- if (s->pending_byte_stream) {
- if (s->on_next != nullptr) {
- grpc_core::Chttp2IncomingByteStream* bs = s->data_parser.parsing_frame;
- if (error == GRPC_ERROR_NONE) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
- }
- bs->PublishError(error);
- bs->Unref();
- s->data_parser.parsing_frame = nullptr;
- } else {
- GRPC_ERROR_UNREF(s->byte_stream_error);
- s->byte_stream_error = GRPC_ERROR_REF(error);
- }
- }
if (grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
post_benign_reclaimer(t);
@@ -2283,8 +2158,7 @@ void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
GRPC_ERROR_REF(error),
"send_trailing_metadata_finished");
- s->fetching_send_message.reset();
- grpc_chttp2_complete_closure_step(t, s, &s->fetching_send_message_finished,
+ grpc_chttp2_complete_closure_step(t, s, &s->send_message_finished,
GRPC_ERROR_REF(error),
"fetching_send_message_finished");
flush_write_list(t, s, &s->on_write_finished_cbs, GRPC_ERROR_REF(error));
@@ -2554,8 +2428,11 @@ void grpc_chttp2_act_on_flowctl_action(
const grpc_core::chttp2::FlowControlAction& action,
grpc_chttp2_transport* t, grpc_chttp2_stream* s) {
WithUrgency(t, action.send_stream_update(),
- GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL,
- [t, s]() { grpc_chttp2_mark_stream_writable(t, s); });
+ GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL, [t, s]() {
+ if (s->id != 0) {
+ grpc_chttp2_mark_stream_writable(t, s);
+ }
+ });
WithUrgency(t, action.send_transport_update(),
GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL, []() {});
WithUrgency(t, action.send_initial_window_update(),
@@ -2703,13 +2580,12 @@ static void continue_read_action_locked(grpc_chttp2_transport* t) {
grpc_schedule_on_exec_ctx);
grpc_endpoint_read(t->ep, &t->read_buffer, &t->read_action_locked, urgent,
/*min_progress_size=*/1);
- grpc_chttp2_act_on_flowctl_action(t->flow_control->MakeAction(), t, nullptr);
}
// t is reffed prior to calling the first time, and once the callback chain
// that kicks off finishes, it's unreffed
void schedule_bdp_ping_locked(grpc_chttp2_transport* t) {
- t->flow_control->bdp_estimator()->SchedulePing();
+ t->flow_control.bdp_estimator()->SchedulePing();
send_ping_locked(
t,
GRPC_CLOSURE_INIT(&t->start_bdp_ping_locked, start_bdp_ping, t,
@@ -2739,7 +2615,7 @@ static void start_bdp_ping_locked(void* tp, grpc_error_handle error) {
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
grpc_timer_cancel(&t->keepalive_ping_timer);
}
- t->flow_control->bdp_estimator()->StartPing();
+ t->flow_control.bdp_estimator()->StartPing();
t->bdp_ping_started = true;
}
@@ -2770,8 +2646,8 @@ static void finish_bdp_ping_locked(void* tp, grpc_error_handle error) {
}
t->bdp_ping_started = false;
grpc_core::Timestamp next_ping =
- t->flow_control->bdp_estimator()->CompletePing();
- grpc_chttp2_act_on_flowctl_action(t->flow_control->PeriodicUpdate(), t,
+ t->flow_control.bdp_estimator()->CompletePing();
+ grpc_chttp2_act_on_flowctl_action(t->flow_control.PeriodicUpdate(), t,
nullptr);
GPR_ASSERT(!t->have_next_bdp_ping_timer);
t->have_next_bdp_ping_timer = true;
@@ -2798,7 +2674,7 @@ static void next_bdp_ping_timer_expired_locked(void* tp,
GRPC_CHTTP2_UNREF_TRANSPORT(t, "bdp_ping");
return;
}
- if (t->flow_control->bdp_estimator()->accumulator() == 0) {
+ if (t->flow_control.bdp_estimator()->accumulator() == 0) {
// Block the bdp ping till we receive more data.
t->bdp_ping_blocked = true;
GRPC_CHTTP2_UNREF_TRANSPORT(t, "bdp_ping");
@@ -3034,187 +2910,6 @@ static void set_pollset_set(grpc_transport* gt, grpc_stream* /*gs*/,
grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
}
-//
-// BYTE STREAM
-//
-
-static void reset_byte_stream(void* arg, grpc_error_handle error) {
- grpc_chttp2_stream* s = static_cast(arg);
- s->pending_byte_stream = false;
- if (error == GRPC_ERROR_NONE) {
- grpc_chttp2_maybe_complete_recv_message(s->t, s);
- grpc_chttp2_maybe_complete_recv_trailing_metadata(s->t, s);
- } else {
- GPR_ASSERT(error != GRPC_ERROR_NONE);
- grpc_core::ExecCtx::Run(DEBUG_LOCATION, s->on_next, GRPC_ERROR_REF(error));
- s->on_next = nullptr;
- GRPC_ERROR_UNREF(s->byte_stream_error);
- s->byte_stream_error = GRPC_ERROR_NONE;
- grpc_chttp2_cancel_stream(s->t, s, GRPC_ERROR_REF(error));
- s->byte_stream_error = GRPC_ERROR_REF(error);
- }
-}
-
-namespace grpc_core {
-
-Chttp2IncomingByteStream::Chttp2IncomingByteStream(
- grpc_chttp2_transport* transport, grpc_chttp2_stream* stream,
- uint32_t frame_size, uint32_t flags)
- : ByteStream(frame_size, flags),
- transport_(transport),
- stream_(stream),
- refs_(2),
- remaining_bytes_(frame_size) {
- GRPC_ERROR_UNREF(stream->byte_stream_error);
- stream->byte_stream_error = GRPC_ERROR_NONE;
-}
-
-void Chttp2IncomingByteStream::OrphanLocked(
- void* arg, grpc_error_handle /*error_ignored*/) {
- Chttp2IncomingByteStream* bs = static_cast(arg);
- grpc_chttp2_stream* s = bs->stream_;
- grpc_chttp2_transport* t = s->t;
- bs->Unref();
- s->pending_byte_stream = false;
- grpc_chttp2_maybe_complete_recv_message(t, s);
- grpc_chttp2_maybe_complete_recv_trailing_metadata(t, s);
-}
-
-void Chttp2IncomingByteStream::Orphan() {
- GPR_TIMER_SCOPE("incoming_byte_stream_destroy", 0);
- transport_->combiner->Run(
- GRPC_CLOSURE_INIT(&destroy_action_,
- &Chttp2IncomingByteStream::OrphanLocked, this, nullptr),
- GRPC_ERROR_NONE);
-}
-
-void Chttp2IncomingByteStream::NextLocked(void* arg,
- grpc_error_handle /*error_ignored*/) {
- Chttp2IncomingByteStream* bs = static_cast(arg);
- grpc_chttp2_transport* t = bs->transport_;
- grpc_chttp2_stream* s = bs->stream_;
- size_t cur_length = s->frame_storage.length;
- if (!s->read_closed) {
- s->flow_control->IncomingByteStreamUpdate(bs->next_action_.max_size_hint,
- cur_length);
- grpc_chttp2_act_on_flowctl_action(s->flow_control->MakeAction(), t, s);
- }
- GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
- if (s->frame_storage.length > 0) {
- grpc_slice_buffer_swap(&s->frame_storage,
- &s->unprocessed_incoming_frames_buffer);
- ExecCtx::Run(DEBUG_LOCATION, bs->next_action_.on_complete, GRPC_ERROR_NONE);
- } else if (s->byte_stream_error != GRPC_ERROR_NONE) {
- ExecCtx::Run(DEBUG_LOCATION, bs->next_action_.on_complete,
- GRPC_ERROR_REF(s->byte_stream_error));
- if (s->data_parser.parsing_frame != nullptr) {
- s->data_parser.parsing_frame->Unref();
- s->data_parser.parsing_frame = nullptr;
- }
- } else if (s->read_closed) {
- if (bs->remaining_bytes_ != 0) {
- s->byte_stream_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
- "Truncated message", &s->read_closed_error, 1);
- ExecCtx::Run(DEBUG_LOCATION, bs->next_action_.on_complete,
- GRPC_ERROR_REF(s->byte_stream_error));
- if (s->data_parser.parsing_frame != nullptr) {
- s->data_parser.parsing_frame->Unref();
- s->data_parser.parsing_frame = nullptr;
- }
- } else {
- // Should never reach here.
- GPR_ASSERT(false);
- }
- } else {
- s->on_next = bs->next_action_.on_complete;
- }
- bs->Unref();
-}
-
-bool Chttp2IncomingByteStream::Next(size_t max_size_hint,
- grpc_closure* on_complete) {
- GPR_TIMER_SCOPE("incoming_byte_stream_next", 0);
- if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
- return true;
- } else {
- Ref();
- next_action_.max_size_hint = max_size_hint;
- next_action_.on_complete = on_complete;
- transport_->combiner->Run(
- GRPC_CLOSURE_INIT(&next_action_.closure,
- &Chttp2IncomingByteStream::NextLocked, this, nullptr),
- GRPC_ERROR_NONE);
- return false;
- }
-}
-
-grpc_error_handle Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
- GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
- grpc_error_handle error;
- if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
- error = grpc_deframe_unprocessed_incoming_frames(
- &stream_->data_parser, stream_,
- &stream_->unprocessed_incoming_frames_buffer, slice, nullptr);
- if (error != GRPC_ERROR_NONE) {
- return error;
- }
- } else {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
- stream_->t->combiner->Run(&stream_->reset_byte_stream,
- GRPC_ERROR_REF(error));
- return error;
- }
- return GRPC_ERROR_NONE;
-}
-
-void Chttp2IncomingByteStream::PublishError(grpc_error_handle error) {
- GPR_ASSERT(error != GRPC_ERROR_NONE);
- ExecCtx::Run(DEBUG_LOCATION, stream_->on_next, GRPC_ERROR_REF(error));
- stream_->on_next = nullptr;
- GRPC_ERROR_UNREF(stream_->byte_stream_error);
- stream_->byte_stream_error = GRPC_ERROR_REF(error);
- grpc_chttp2_cancel_stream(transport_, stream_, GRPC_ERROR_REF(error));
-}
-
-grpc_error_handle Chttp2IncomingByteStream::Push(const grpc_slice& slice,
- grpc_slice* slice_out) {
- if (remaining_bytes_ < GRPC_SLICE_LENGTH(slice)) {
- grpc_error_handle error =
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many bytes in stream");
- transport_->combiner->Run(&stream_->reset_byte_stream,
- GRPC_ERROR_REF(error));
- grpc_slice_unref_internal(slice);
- return error;
- } else {
- remaining_bytes_ -= static_cast GRPC_SLICE_LENGTH(slice);
- if (slice_out != nullptr) {
- *slice_out = slice;
- }
- return GRPC_ERROR_NONE;
- }
-}
-
-grpc_error_handle Chttp2IncomingByteStream::Finished(grpc_error_handle error,
- bool reset_on_error) {
- if (error == GRPC_ERROR_NONE) {
- if (remaining_bytes_ != 0) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
- }
- }
- if (error != GRPC_ERROR_NONE && reset_on_error) {
- transport_->combiner->Run(&stream_->reset_byte_stream,
- GRPC_ERROR_REF(error));
- }
- Unref();
- return error;
-}
-
-void Chttp2IncomingByteStream::Shutdown(grpc_error_handle error) {
- GRPC_ERROR_UNREF(Finished(error, true /* reset_on_error */));
-}
-
-} // namespace grpc_core
-
//
// RESOURCE QUOTAS
//
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 54aad55a994..2a0217c910b 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -23,18 +23,18 @@
#include
#include
+#include
#include
+#include
#include
+#include
+#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
-#include
-#include
#include
-#include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/ext/transport/chttp2/transport/internal.h"
-#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/resource_quota/memory_quota.h"
@@ -47,144 +47,63 @@ namespace chttp2 {
TestOnlyTransportTargetWindowEstimatesMocker*
g_test_only_transport_target_window_estimates_mocker;
-bool g_test_only_transport_flow_control_window_check;
-
namespace {
-constexpr const int kTracePadding = 30;
constexpr const int64_t kMaxWindowUpdateSize = (1u << 31) - 1;
-char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
- std::string str;
- if (old_val != new_val) {
- str = absl::StrFormat("%" PRId64 " -> %" PRId64 "", old_val, new_val);
- } else {
- str = absl::StrFormat("%" PRId64 "", old_val);
- }
- return gpr_leftpad(str.c_str(), ' ', kTracePadding);
-}
-
-char* fmt_uint32_diff_str(uint32_t old_val, uint32_t new_val) {
- std::string str;
- if (old_val != new_val) {
- str = absl::StrFormat("%" PRIu32 " -> %" PRIu32 "", old_val, new_val);
- } else {
- str = absl::StrFormat("%" PRIu32 "", old_val);
- }
- return gpr_leftpad(str.c_str(), ' ', kTracePadding);
-}
} // namespace
-void FlowControlTrace::Init(const char* reason, TransportFlowControl* tfc,
- StreamFlowControl* sfc) {
- tfc_ = tfc;
- sfc_ = sfc;
- reason_ = reason;
- remote_window_ = tfc->remote_window();
- target_window_ = tfc->target_window();
- announced_window_ = tfc->announced_window();
- if (sfc != nullptr) {
- remote_window_delta_ = sfc->remote_window_delta();
- local_window_delta_ = sfc->local_window_delta();
- announced_window_delta_ = sfc->announced_window_delta();
- }
-}
-
-void FlowControlTrace::Finish() {
- uint32_t acked_local_window =
- tfc_->transport()->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- uint32_t remote_window =
- tfc_->transport()->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- char* trw_str = fmt_int64_diff_str(remote_window_, tfc_->remote_window());
- char* tlw_str = fmt_int64_diff_str(target_window_, tfc_->target_window());
- char* taw_str =
- fmt_int64_diff_str(announced_window_, tfc_->announced_window());
- char* srw_str;
- char* slw_str;
- char* saw_str;
- if (sfc_ != nullptr) {
- srw_str = fmt_int64_diff_str(remote_window_delta_ + remote_window,
- sfc_->remote_window_delta() + remote_window);
- slw_str =
- fmt_int64_diff_str(local_window_delta_ + acked_local_window,
- sfc_->local_window_delta() + acked_local_window);
- saw_str =
- fmt_int64_diff_str(announced_window_delta_ + acked_local_window,
- sfc_->announced_window_delta() + acked_local_window);
- } else {
- srw_str = gpr_leftpad("", ' ', kTracePadding);
- slw_str = gpr_leftpad("", ' ', kTracePadding);
- saw_str = gpr_leftpad("", ' ', kTracePadding);
- }
- gpr_log(GPR_DEBUG,
- "%p[%u][%s] | %s | trw:%s, tlw:%s, taw:%s, srw:%s, slw:%s, saw:%s",
- tfc_, sfc_ != nullptr ? sfc_->stream()->id : 0,
- tfc_->transport()->is_client ? "cli" : "svr", reason_, trw_str,
- tlw_str, taw_str, srw_str, slw_str, saw_str);
- gpr_free(trw_str);
- gpr_free(tlw_str);
- gpr_free(taw_str);
- gpr_free(srw_str);
- gpr_free(slw_str);
- gpr_free(saw_str);
-}
-
const char* FlowControlAction::UrgencyString(Urgency u) {
switch (u) {
case Urgency::NO_ACTION_NEEDED:
- return "no action";
+ return "no-action";
case Urgency::UPDATE_IMMEDIATELY:
- return "update immediately";
+ return "now";
case Urgency::QUEUE_UPDATE:
- return "queue update";
+ return "queue";
default:
GPR_UNREACHABLE_CODE(return "unknown");
}
GPR_UNREACHABLE_CODE(return "unknown");
}
-void FlowControlAction::Trace(grpc_chttp2_transport* t) const {
- char* iw_str = fmt_uint32_diff_str(
- t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
- initial_window_size_);
- char* mf_str = fmt_uint32_diff_str(
- t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
- max_frame_size_);
- gpr_log(GPR_DEBUG, "t[%s], s[%s], iw:%s:%s mf:%s:%s",
- UrgencyString(send_transport_update_),
- UrgencyString(send_stream_update_),
- UrgencyString(send_initial_window_update_), iw_str,
- UrgencyString(send_max_frame_size_update_), mf_str);
- gpr_free(iw_str);
- gpr_free(mf_str);
+std::ostream& operator<<(std::ostream& out, FlowControlAction::Urgency u) {
+ return out << FlowControlAction::UrgencyString(u);
}
-TransportFlowControlDisabled::TransportFlowControlDisabled(
- grpc_chttp2_transport* t) {
- remote_window_ = kMaxWindow;
- target_initial_window_size_ = kMaxWindow;
- announced_window_ = kMaxWindow;
- t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE] =
- kFrameSize;
- t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE] =
- kFrameSize;
- t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE] =
- kFrameSize;
- t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] =
- kMaxWindow;
- t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] =
- kMaxWindow;
- t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] =
- kMaxWindow;
+std::string FlowControlAction::DebugString() const {
+ std::vector segments;
+ if (send_transport_update_ != Urgency::NO_ACTION_NEEDED) {
+ segments.push_back(
+ absl::StrCat("t:", UrgencyString(send_transport_update_)));
+ }
+ if (send_stream_update_ != Urgency::NO_ACTION_NEEDED) {
+ segments.push_back(absl::StrCat("s:", UrgencyString(send_stream_update_)));
+ }
+ if (send_initial_window_update_ != Urgency::NO_ACTION_NEEDED) {
+ segments.push_back(
+ absl::StrCat("iw=", initial_window_size_, ":",
+ UrgencyString(send_initial_window_update_)));
+ }
+ if (send_max_frame_size_update_ != Urgency::NO_ACTION_NEEDED) {
+ segments.push_back(
+ absl::StrCat("mf=", max_frame_size_, ":",
+ UrgencyString(send_max_frame_size_update_)));
+ }
+ if (segments.empty()) return "no action";
+ return absl::StrJoin(segments, ",");
}
-TransportFlowControl::TransportFlowControl(const grpc_chttp2_transport* t,
- bool enable_bdp_probe)
- : t_(t),
+std::ostream& operator<<(std::ostream& out, const FlowControlAction& action) {
+ return out << action.DebugString();
+}
+
+TransportFlowControl::TransportFlowControl(const char* name,
+ bool enable_bdp_probe,
+ MemoryOwner* memory_owner)
+ : memory_owner_(memory_owner),
enable_bdp_probe_(enable_bdp_probe),
- bdp_estimator_(t->peer_string.c_str()),
+ bdp_estimator_(name),
pid_controller_(PidController::Args()
.set_gain_p(4)
.set_gain_i(8)
@@ -196,7 +115,6 @@ TransportFlowControl::TransportFlowControl(const grpc_chttp2_transport* t,
last_pid_update_(ExecCtx::Get()->Now()) {}
uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
- FlowControlTrace trace("t updt sent", this, nullptr);
const uint32_t target_announced_window =
static_cast(target_window());
if ((writing_anyway || announced_window_ <= target_announced_window / 2) &&
@@ -210,121 +128,55 @@ uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
return 0;
}
-grpc_error_handle TransportFlowControl::ValidateRecvData(
- int64_t incoming_frame_size) {
- if (incoming_frame_size > announced_window_) {
- return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
- "frame of size %" PRId64 " overflows local window of %" PRId64,
- incoming_frame_size, announced_window_));
- }
- return GRPC_ERROR_NONE;
-}
+StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc) : tfc_(tfc) {}
-StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc,
- const grpc_chttp2_stream* s)
- : tfc_(tfc), s_(s) {}
-
-grpc_error_handle StreamFlowControl::RecvData(int64_t incoming_frame_size) {
- FlowControlTrace trace(" data recv", tfc_, this);
-
- grpc_error_handle error = GRPC_ERROR_NONE;
- error = tfc_->ValidateRecvData(incoming_frame_size);
- if (error != GRPC_ERROR_NONE) return error;
-
- uint32_t sent_init_window =
- tfc_->transport()->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- uint32_t acked_init_window =
- tfc_->transport()->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-
- int64_t acked_stream_window = announced_window_delta_ + acked_init_window;
- int64_t sent_stream_window = announced_window_delta_ + sent_init_window;
- if (incoming_frame_size > acked_stream_window) {
- if (incoming_frame_size <= sent_stream_window) {
- gpr_log(GPR_ERROR,
- "Incoming frame of size %" PRId64
- " exceeds local window size of %" PRId64
- ".\n"
- "The (un-acked, future) window size would be %" PRId64
- " which is not exceeded.\n"
- "This would usually cause a disconnection, but allowing it due to"
- "broken HTTP2 implementations in the wild.\n"
- "See (for example) https://github.com/netty/netty/issues/6520.",
- incoming_frame_size, acked_stream_window, sent_stream_window);
- } else {
- return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
+absl::Status StreamFlowControl::IncomingUpdateContext::RecvData(
+ int64_t incoming_frame_size) {
+ return tfc_upd_.RecvData(incoming_frame_size, [this, incoming_frame_size]() {
+ int64_t acked_stream_window =
+ sfc_->announced_window_delta_ + sfc_->tfc_->acked_init_window();
+ if (incoming_frame_size > acked_stream_window) {
+ return absl::InternalError(absl::StrFormat(
"frame of size %" PRId64 " overflows local window of %" PRId64,
incoming_frame_size, acked_stream_window));
}
- }
- UpdateAnnouncedWindowDelta(tfc_, -incoming_frame_size);
- local_window_delta_ -= incoming_frame_size;
- tfc_->CommitRecvData(incoming_frame_size);
- return GRPC_ERROR_NONE;
+ tfc_upd_.UpdateAnnouncedWindowDelta(&sfc_->announced_window_delta_,
+ -incoming_frame_size);
+ sfc_->min_progress_size_ -=
+ std::min(sfc_->min_progress_size_, incoming_frame_size);
+ return absl::OkStatus();
+ });
}
-uint32_t StreamFlowControl::MaybeSendUpdate() {
- FlowControlTrace trace("s updt sent", tfc_, this);
- // If a recently sent settings frame caused the stream's flow control window
- // to go in the negative (or < GRPC_HEADER_SIZE_IN_BYTES), update the delta if
- // one of the following conditions is satisfied -
- // 1) There is a pending byte_stream and higher layers have expressed interest
- // in reading additional data through the invokation of `Next()` where the
- // bytes are to be available asynchronously. 2) There is a pending
- // recv_message op.
- // In these cases, we want to make sure that bytes are still flowing.
- if (local_window_delta_ < GRPC_HEADER_SIZE_IN_BYTES) {
- if (s_->on_next != nullptr) {
- GPR_DEBUG_ASSERT(s_->pending_byte_stream);
- IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES, 0);
- } else if (s_->recv_message != nullptr) {
- IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
- s_->frame_storage.length);
- }
- }
- if (local_window_delta_ > announced_window_delta_) {
- uint32_t announce = static_cast(
- Clamp(local_window_delta_ - announced_window_delta_, int64_t(0),
- kMaxWindowUpdateSize));
- UpdateAnnouncedWindowDelta(tfc_, announce);
- return announce;
+absl::Status TransportFlowControl::IncomingUpdateContext::RecvData(
+ int64_t incoming_frame_size, absl::FunctionRef stream) {
+ if (incoming_frame_size > tfc_->announced_window_) {
+ return absl::InternalError(absl::StrFormat(
+ "frame of size %" PRId64 " overflows local window of %" PRId64,
+ incoming_frame_size, tfc_->announced_window_));
}
- return 0;
+ absl::Status error = stream();
+ if (!error.ok()) return error;
+ tfc_->announced_window_ -= incoming_frame_size;
+ return absl::OkStatus();
}
-void StreamFlowControl::IncomingByteStreamUpdate(size_t max_size_hint,
- size_t have_already) {
- FlowControlTrace trace("app st recv", tfc_, this);
- uint32_t max_recv_bytes;
-
- /* clamp max recv hint to an allowable size */
- if (max_size_hint >= kMaxWindowDelta) {
- max_recv_bytes = kMaxWindowDelta;
- } else {
- max_recv_bytes = static_cast(max_size_hint);
- }
-
- /* account for bytes already received but unknown to higher layers */
- if (max_recv_bytes >= have_already) {
- max_recv_bytes -= static_cast(have_already);
- } else {
- max_recv_bytes = 0;
- }
+int64_t TransportFlowControl::target_window() const {
+ // See comment above announced_stream_total_over_incoming_window_ for the
+ // logic behind this decision.
+ return static_cast(
+ std::min(static_cast((1u << 31) - 1),
+ announced_stream_total_over_incoming_window_ +
+ target_initial_window_size_));
+}
- /* add some small lookahead to keep pipelines flowing */
- GPR_DEBUG_ASSERT(
- max_recv_bytes <=
- kMaxWindowUpdateSize -
- tfc_->transport()
- ->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
- if (local_window_delta_ < max_recv_bytes) {
- uint32_t add_max_recv_bytes =
- static_cast(max_recv_bytes - local_window_delta_);
- local_window_delta_ += add_max_recv_bytes;
+FlowControlAction TransportFlowControl::UpdateAction(FlowControlAction action) {
+ if (announced_window_ < target_window() / 2) {
+ action.set_send_transport_update(
+ FlowControlAction::Urgency::UPDATE_IMMEDIATELY);
}
+ return action;
}
// Take in a target and modifies it based on the memory pressure of the system
@@ -345,10 +197,9 @@ static double AdjustForMemoryPressure(double memory_pressure, double target) {
}
double TransportFlowControl::TargetLogBdp() {
- return AdjustForMemoryPressure(t_->memory_owner.is_valid()
- ? t_->memory_owner.InstantaneousPressure()
- : 0.0,
- 1 + log2(bdp_estimator_.EstimateBdp()));
+ return AdjustForMemoryPressure(
+ memory_owner_->is_valid() ? memory_owner_->InstantaneousPressure() : 0.0,
+ 1 + log2(bdp_estimator_.EstimateBdp()));
}
double TransportFlowControl::SmoothLogBdp(double value) {
@@ -361,15 +212,17 @@ double TransportFlowControl::SmoothLogBdp(double value) {
return pid_controller_.Update(bdp_error, dt > kMaxDt ? kMaxDt : dt);
}
-FlowControlAction::Urgency TransportFlowControl::DeltaUrgency(
- int64_t value, grpc_chttp2_setting_id setting_id) {
- int64_t delta = value - static_cast(
- t_->settings[GRPC_LOCAL_SETTINGS][setting_id]);
+void TransportFlowControl::UpdateSetting(
+ int64_t* desired_value, int64_t new_desired_value,
+ FlowControlAction* action,
+ FlowControlAction& (FlowControlAction::*set)(FlowControlAction::Urgency,
+ uint32_t)) {
+ int64_t delta = new_desired_value - *desired_value;
// TODO(ncteisen): tune this
- if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) {
- return FlowControlAction::Urgency::QUEUE_UPDATE;
- } else {
- return FlowControlAction::Urgency::NO_ACTION_NEEDED;
+ if (delta != 0 &&
+ (delta <= -*desired_value / 5 || delta >= *desired_value / 5)) {
+ *desired_value = new_desired_value;
+ (action->*set)(FlowControlAction::Urgency::QUEUE_UPDATE, *desired_value);
}
}
@@ -389,46 +242,73 @@ FlowControlAction TransportFlowControl::PeriodicUpdate() {
}
// Though initial window 'could' drop to 0, we keep the floor at
// kMinInitialWindowSize
- target_initial_window_size_ = static_cast(Clamp(
- target, double(kMinInitialWindowSize), double(kMaxInitialWindowSize)));
- action.set_send_initial_window_update(
- DeltaUrgency(target_initial_window_size_,
- GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE),
- static_cast(target_initial_window_size_));
+ UpdateSetting(
+ &target_initial_window_size_,
+ static_cast(Clamp(target, double(kMinInitialWindowSize),
+ double(kMaxInitialWindowSize))),
+ &action, &FlowControlAction::set_send_initial_window_update);
// get bandwidth estimate and update max_frame accordingly.
double bw_dbl = bdp_estimator_.EstimateBandwidth();
// we target the max of BDP or bandwidth in microseconds.
- int32_t frame_size = static_cast(Clamp(
- std::max(
- static_cast(Clamp(bw_dbl, 0.0, double(INT_MAX))) / 1000,
- static_cast(target_initial_window_size_)),
- 16384, 16777215));
- action.set_send_max_frame_size_update(
- DeltaUrgency(static_cast(frame_size),
- GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE),
- frame_size);
+ UpdateSetting(
+ &target_frame_size_,
+ static_cast(Clamp(
+ std::max(static_cast(Clamp(bw_dbl, 0.0, double(INT_MAX))) /
+ 1000,
+ static_cast(target_initial_window_size_)),
+ 16384, 16777215)),
+ &action, &FlowControlAction::set_send_max_frame_size_update);
}
return UpdateAction(action);
}
+uint32_t StreamFlowControl::MaybeSendUpdate() {
+ TransportFlowControl::IncomingUpdateContext tfc_upd(tfc_);
+ const uint32_t announce = DesiredAnnounceSize();
+ pending_size_ = absl::nullopt;
+ tfc_upd.UpdateAnnouncedWindowDelta(&announced_window_delta_, announce);
+ GPR_ASSERT(DesiredAnnounceSize() == 0);
+ tfc_upd.MakeAction();
+ return announce;
+}
+
+uint32_t StreamFlowControl::DesiredAnnounceSize() const {
+ int64_t desired_window_delta = [this]() {
+ if (min_progress_size_ == 0) {
+ if (pending_size_.has_value() &&
+ announced_window_delta_ < -*pending_size_) {
+ return -*pending_size_;
+ } else {
+ return announced_window_delta_;
+ }
+ } else {
+ return std::min(min_progress_size_, kMaxWindowDelta);
+ }
+ }();
+ return Clamp(desired_window_delta - announced_window_delta_, int64_t(0),
+ kMaxWindowUpdateSize);
+}
+
FlowControlAction StreamFlowControl::UpdateAction(FlowControlAction action) {
- // TODO(ncteisen): tune this
- if (!s_->read_closed) {
- uint32_t sent_init_window =
- tfc_->transport()->settings[GRPC_SENT_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- if (local_window_delta_ > announced_window_delta_ &&
- announced_window_delta_ + sent_init_window <= sent_init_window / 2) {
+ const int64_t desired_announce_size = DesiredAnnounceSize();
+ if (desired_announce_size > 0) {
+ if ((min_progress_size_ > 0 && announced_window_delta_ < 0) ||
+ desired_announce_size >= 8192) {
action.set_send_stream_update(
FlowControlAction::Urgency::UPDATE_IMMEDIATELY);
- } else if (local_window_delta_ > announced_window_delta_) {
+ } else {
action.set_send_stream_update(FlowControlAction::Urgency::QUEUE_UPDATE);
}
}
-
return action;
}
+void StreamFlowControl::IncomingUpdateContext::SetPendingSize(
+ int64_t pending_size) {
+ GPR_ASSERT(pending_size >= 0);
+ sfc_->pending_size_ = pending_size;
+}
+
} // namespace chttp2
} // namespace grpc_core
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h
index c50aa5f1e23..723c9551008 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.h
+++ b/src/core/ext/transport/chttp2/transport/flow_control.h
@@ -22,22 +22,23 @@
#include
#include
-#include
-#include
+#include
+#include
+#include "absl/functional/function_ref.h"
#include "absl/status/status.h"
+#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
+
+#include
-#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/time.h"
-#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/pid_controller.h"
-struct grpc_chttp2_transport;
-struct grpc_chttp2_stream;
-
extern grpc_core::TraceFlag grpc_flowctl_trace;
namespace grpc {
@@ -50,18 +51,19 @@ namespace grpc_core {
namespace chttp2 {
static constexpr uint32_t kDefaultWindow = 65535;
+static constexpr uint32_t kDefaultFrameSize = 16384;
static constexpr int64_t kMaxWindow = static_cast((1u << 31) - 1);
// TODO(ncteisen): Tune this
static constexpr uint32_t kFrameSize = 1024 * 1024;
static constexpr const uint32_t kMinInitialWindowSize = 128;
static constexpr const uint32_t kMaxInitialWindowSize = (1u << 30);
// The maximum per-stream flow control window delta to advertise.
-static constexpr const uint32_t kMaxWindowDelta = (1u << 20);
+static constexpr const int64_t kMaxWindowDelta = (1u << 20);
class TransportFlowControl;
class StreamFlowControl;
-extern bool g_test_only_transport_flow_control_window_check;
+enum class StallEdge { kNoChange, kStalled, kUnstalled };
// Encapsulates a collections of actions the transport needs to take with
// regard to flow control. Each action comes with urgencies that tell the
@@ -111,7 +113,20 @@ class FlowControlAction {
}
static const char* UrgencyString(Urgency u);
- void Trace(grpc_chttp2_transport* t) const;
+ std::string DebugString() const;
+
+ void AssertEmpty() { GPR_ASSERT(*this == FlowControlAction()); }
+
+ bool operator==(const FlowControlAction& other) const {
+ return send_stream_update_ == other.send_stream_update_ &&
+ send_transport_update_ == other.send_transport_update_ &&
+ send_initial_window_update_ == other.send_initial_window_update_ &&
+ send_max_frame_size_update_ == other.send_max_frame_size_update_ &&
+ (send_initial_window_update_ == Urgency::NO_ACTION_NEEDED ||
+ initial_window_size_ == other.initial_window_size_) &&
+ (send_max_frame_size_update_ == Urgency::NO_ACTION_NEEDED ||
+ max_frame_size_ == other.max_frame_size_);
+ }
private:
Urgency send_stream_update_ = Urgency::NO_ACTION_NEEDED;
@@ -122,120 +137,16 @@ class FlowControlAction {
uint32_t max_frame_size_ = 0;
};
-class FlowControlTrace {
- public:
- FlowControlTrace(const char* reason, TransportFlowControl* tfc,
- StreamFlowControl* sfc) {
- if (enabled_) Init(reason, tfc, sfc);
- }
-
- ~FlowControlTrace() {
- if (enabled_) Finish();
- }
-
- private:
- void Init(const char* reason, TransportFlowControl* tfc,
- StreamFlowControl* sfc);
- void Finish();
-
- const bool enabled_ = GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace);
-
- TransportFlowControl* tfc_;
- StreamFlowControl* sfc_;
- const char* reason_;
- int64_t remote_window_;
- int64_t target_window_;
- int64_t announced_window_;
- int64_t remote_window_delta_;
- int64_t local_window_delta_;
- int64_t announced_window_delta_;
-};
-
-// Fat interface with all methods a flow control implementation needs to
-// support.
-class TransportFlowControlBase {
- public:
- TransportFlowControlBase() {}
- virtual ~TransportFlowControlBase() {}
-
- // Is flow control enabled? This is needed in other codepaths like the checks
- // in parsing and in writing.
- virtual bool flow_control_enabled() const = 0;
-
- // Called to check if the transport needs to send a WINDOW_UPDATE frame
- virtual uint32_t MaybeSendUpdate(bool /* writing_anyway */) = 0;
-
- // Using the protected members, returns and Action to be taken by the
- // tranport.
- virtual FlowControlAction MakeAction() = 0;
-
- // Using the protected members, returns and Action to be taken by the
- // tranport. Also checks for updates to our BDP estimate and acts
- // accordingly.
- virtual FlowControlAction PeriodicUpdate() = 0;
-
- // Called to do bookkeeping when a stream owned by this transport sends
- // data on the wire
- virtual void StreamSentData(int64_t /* size */) = 0;
-
- // Called to do bookkeeping when a stream owned by this transport receives
- // data from the wire. Also does error checking for frame size.
- virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
-
- // Called to do bookkeeping when we receive a WINDOW_UPDATE frame.
- virtual void RecvUpdate(uint32_t /* size */) = 0;
-
- // Returns the BdpEstimator held by this object. Caller is responsible for
- // checking for nullptr. TODO(ncteisen): consider fully encapsulating all
- // bdp estimator actions inside TransportFlowControl
- virtual BdpEstimator* bdp_estimator() { return nullptr; }
-
- // Getters
- int64_t remote_window() const { return remote_window_; }
- virtual int64_t target_window() const { return target_initial_window_size_; }
- int64_t announced_window() const { return announced_window_; }
-
- // Used in certain benchmarks in which we don't want FlowControl to be a
- // factor
- virtual void TestOnlyForceHugeWindow() {}
-
- protected:
- friend class grpc::testing::TrickledCHTTP2;
- int64_t remote_window_ = kDefaultWindow;
- int64_t target_initial_window_size_ = kDefaultWindow;
- int64_t announced_window_ = kDefaultWindow;
-};
-
-// Implementation of flow control that does NOTHING. Always returns maximum
-// values, never initiates writes, and assumes that the remote peer is doing
-// the same. To be used to narrow down on flow control as the cause of negative
-// performance.
-class TransportFlowControlDisabled final : public TransportFlowControlBase {
- public:
- // Maxes out all values
- explicit TransportFlowControlDisabled(grpc_chttp2_transport* t);
-
- bool flow_control_enabled() const override { return false; }
-
- // Never do anything.
- uint32_t MaybeSendUpdate(bool /* writing_anyway */) override { return 0; }
- FlowControlAction MakeAction() override { return FlowControlAction(); }
- FlowControlAction PeriodicUpdate() override { return FlowControlAction(); }
- void StreamSentData(int64_t /* size */) override {}
- grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
- return GRPC_ERROR_NONE;
- }
- void RecvUpdate(uint32_t /* size */) override {}
-};
+std::ostream& operator<<(std::ostream& out, FlowControlAction::Urgency urgency);
+std::ostream& operator<<(std::ostream& out, const FlowControlAction& action);
// Implementation of flow control that abides to HTTP/2 spec and attempts
// to be as performant as possible.
-class TransportFlowControl final : public TransportFlowControlBase {
+class TransportFlowControl final {
public:
- TransportFlowControl(const grpc_chttp2_transport* t, bool enable_bdp_probe);
- ~TransportFlowControl() override {}
-
- bool flow_control_enabled() const override { return true; }
+ explicit TransportFlowControl(const char* name, bool enable_bdp_probe,
+ MemoryOwner* memory_owner);
+ ~TransportFlowControl() {}
bool bdp_probe() const { return enable_bdp_probe_; }
@@ -243,85 +154,112 @@ class TransportFlowControl final : public TransportFlowControlBase {
// else returns zero; writing_anyway indicates if a write would happen
// regardless of the send - if it is false and this function returns non-zero,
// this announce will cause a write to occur
- uint32_t MaybeSendUpdate(bool writing_anyway) override;
+ uint32_t MaybeSendUpdate(bool writing_anyway);
+
+ // Track an update to the incoming flow control counters - that is how many
+ // tokens we report to our peer that we're willing to accept.
+ // Instantiators *must* call MakeAction before destruction of this value.
+ class IncomingUpdateContext {
+ public:
+ explicit IncomingUpdateContext(TransportFlowControl* tfc) : tfc_(tfc) {}
+ ~IncomingUpdateContext() { GPR_ASSERT(tfc_ == nullptr); }
+
+ IncomingUpdateContext(const IncomingUpdateContext&) = delete;
+ IncomingUpdateContext& operator=(const IncomingUpdateContext&) = delete;
+
+ // Reads the flow control data and returns an actionable struct that will
+ // tell chttp2 exactly what it needs to do
+ FlowControlAction MakeAction() {
+ return absl::exchange(tfc_, nullptr)->UpdateAction(FlowControlAction());
+ }
- // Reads the flow control data and returns and actionable struct that will
- // tell chttp2 exactly what it needs to do
- FlowControlAction MakeAction() override {
- return UpdateAction(FlowControlAction());
- }
+ // Notify of data receipt. Returns OkStatus if the data was accepted,
+ // else an error status if the connection should be closed.
+ absl::Status RecvData(
+ int64_t incoming_frame_size, absl::FunctionRef stream =
+ []() { return absl::OkStatus(); });
+
+ // Update a stream announce window delta, keeping track of how much total
+ // positive delta is present on the transport.
+ void UpdateAnnouncedWindowDelta(int64_t* delta, int64_t change) {
+ if (change == 0) return;
+ if (*delta > 0) {
+ tfc_->announced_stream_total_over_incoming_window_ -= *delta;
+ }
+ *delta += change;
+ if (*delta > 0) {
+ tfc_->announced_stream_total_over_incoming_window_ += *delta;
+ }
+ }
+
+ private:
+ TransportFlowControl* tfc_;
+ };
+
+ // Track an update to the outgoing flow control counters - that is how many
+ // tokens our peer has said we can send.
+ class OutgoingUpdateContext {
+ public:
+ explicit OutgoingUpdateContext(TransportFlowControl* tfc) : tfc_(tfc) {}
+ void StreamSentData(int64_t size) { tfc_->remote_window_ -= size; }
+
+ // we have received a WINDOW_UPDATE frame for a transport
+ void RecvUpdate(uint32_t size) { tfc_->remote_window_ += size; }
+
+ // Finish the update and check whether we became stalled or unstalled.
+ StallEdge Finish() {
+ bool is_stalled = tfc_->remote_window_ <= 0;
+ if (is_stalled != was_stalled_) {
+ return is_stalled ? StallEdge::kStalled : StallEdge::kUnstalled;
+ } else {
+ return StallEdge::kNoChange;
+ }
+ }
+
+ private:
+ TransportFlowControl* tfc_;
+ const bool was_stalled_ = tfc_->remote_window_ <= 0;
+ };
// Call periodically (at a low-ish rate, 100ms - 10s makes sense)
// to perform more complex flow control calculations and return an action
// to let chttp2 change its parameters
- FlowControlAction PeriodicUpdate() override;
+ FlowControlAction PeriodicUpdate();
- void StreamSentData(int64_t size) override { remote_window_ -= size; }
+ int64_t target_window() const;
+ int64_t target_frame_size() const { return target_frame_size_; }
- grpc_error_handle ValidateRecvData(int64_t incoming_frame_size);
- void CommitRecvData(int64_t incoming_frame_size) {
- announced_window_ -= incoming_frame_size;
- }
+ BdpEstimator* bdp_estimator() { return &bdp_estimator_; }
- grpc_error_handle RecvData(int64_t incoming_frame_size) override {
- FlowControlTrace trace(" data recv", this, nullptr);
- grpc_error_handle error = ValidateRecvData(incoming_frame_size);
- if (error != GRPC_ERROR_NONE) return error;
- CommitRecvData(incoming_frame_size);
- return GRPC_ERROR_NONE;
- }
+ uint32_t acked_init_window() const { return acked_init_window_; }
- // we have received a WINDOW_UPDATE frame for a transport
- void RecvUpdate(uint32_t size) override {
- FlowControlTrace trace("t updt recv", this, nullptr);
- remote_window_ += size;
- }
+ void SetAckedInitialWindow(uint32_t value) { acked_init_window_ = value; }
- // See comment above announced_stream_total_over_incoming_window_ for the
- // logic behind this decision.
- int64_t target_window() const override {
- return static_cast(
- std::min(static_cast((1u << 31) - 1),
- announced_stream_total_over_incoming_window_ +
- target_initial_window_size_));
- }
-
- const grpc_chttp2_transport* transport() const { return t_; }
+ // Getters
+ int64_t remote_window() const { return remote_window_; }
+ int64_t announced_window() const { return announced_window_; }
- void PreUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) {
- if (delta > 0) {
- announced_stream_total_over_incoming_window_ -= delta;
- }
+ int64_t announced_stream_total_over_incoming_window() const {
+ return announced_stream_total_over_incoming_window_;
}
- void PostUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) {
+ void RemoveAnnouncedWindowDelta(int64_t delta) {
if (delta > 0) {
- announced_stream_total_over_incoming_window_ += delta;
+ announced_stream_total_over_incoming_window_ -= delta;
}
}
- BdpEstimator* bdp_estimator() override { return &bdp_estimator_; }
-
- void TestOnlyForceHugeWindow() override {
- announced_window_ = 1024 * 1024 * 1024;
- remote_window_ = 1024 * 1024 * 1024;
- }
-
private:
double TargetLogBdp();
double SmoothLogBdp(double value);
- FlowControlAction::Urgency DeltaUrgency(int64_t value,
- grpc_chttp2_setting_id setting_id);
+ static void UpdateSetting(int64_t* desired_value, int64_t new_desired_value,
+ FlowControlAction* action,
+ FlowControlAction& (FlowControlAction::*set)(
+ FlowControlAction::Urgency, uint32_t));
- FlowControlAction UpdateAction(FlowControlAction action) {
- if (announced_window_ < target_window() / 2) {
- action.set_send_transport_update(
- FlowControlAction::Urgency::UPDATE_IMMEDIATELY);
- }
- return action;
- }
+ FlowControlAction UpdateAction(FlowControlAction action);
- const grpc_chttp2_transport* const t_;
+ MemoryOwner* const memory_owner_;
/** calculating what we should give for local window:
we track the total amount of flow control over initial window size
@@ -342,140 +280,87 @@ class TransportFlowControl final : public TransportFlowControlBase {
/* pid controller */
PidController pid_controller_;
Timestamp last_pid_update_;
+
+ int64_t remote_window_ = kDefaultWindow;
+ int64_t target_initial_window_size_ = kDefaultWindow;
+ int64_t target_frame_size_ = kDefaultFrameSize;
+ int64_t announced_window_ = kDefaultWindow;
+ uint32_t acked_init_window_ = kDefaultWindow;
};
-// Fat interface with all methods a stream flow control implementation needs
-// to support.
-class StreamFlowControlBase {
+// Implementation of flow control that abides to HTTP/2 spec and attempts
+// to be as performant as possible.
+class StreamFlowControl final {
public:
- StreamFlowControlBase() {}
- virtual ~StreamFlowControlBase() {}
-
- // Updates an action using the protected members.
- virtual FlowControlAction UpdateAction(FlowControlAction /* action */) {
- abort();
+ explicit StreamFlowControl(TransportFlowControl* tfc);
+ ~StreamFlowControl() {
+ tfc_->RemoveAnnouncedWindowDelta(announced_window_delta_);
}
- // Using the protected members, returns an Action for this stream to be
- // taken by the tranport.
- virtual FlowControlAction MakeAction() = 0;
-
- // Bookkeeping for when data is sent on this stream.
- virtual void SentData(int64_t /* outgoing_frame_size */) = 0;
-
- // Bookkeeping and error checking for when data is received by this stream.
- virtual grpc_error_handle RecvData(int64_t /* incoming_frame_size */) = 0;
+ // Track an update to the incoming flow control counters - that is how many
+ // tokens we report to our peer that we're willing to accept.
+ // Instantiators *must* call MakeAction before destruction of this value.
+ class IncomingUpdateContext {
+ public:
+ explicit IncomingUpdateContext(StreamFlowControl* sfc)
+ : tfc_upd_(sfc->tfc_), sfc_(sfc) {}
- // Called to check if this stream needs to send a WINDOW_UPDATE frame.
- virtual uint32_t MaybeSendUpdate() = 0;
-
- // Bookkeeping for receiving a WINDOW_UPDATE from for this stream.
- virtual void RecvUpdate(uint32_t /* size */) = 0;
-
- // Bookkeeping for when a call pulls bytes out of the transport. At this
- // point we consider the data 'used' and can thus let out peer know we are
- // ready for more data.
- virtual void IncomingByteStreamUpdate(size_t /* max_size_hint */,
- size_t /* have_already */) {
- abort();
- }
-
- // Used in certain benchmarks in which we don't want FlowControl to be a
- // factor
- virtual void TestOnlyForceHugeWindow() {}
-
- // Getters
- int64_t remote_window_delta() const { return remote_window_delta_; }
- int64_t local_window_delta() const { return local_window_delta_; }
- int64_t announced_window_delta() const { return announced_window_delta_; }
+ FlowControlAction MakeAction() {
+ return sfc_->UpdateAction(tfc_upd_.MakeAction());
+ }
- protected:
- friend class grpc::testing::TrickledCHTTP2;
- int64_t remote_window_delta_ = 0;
- int64_t local_window_delta_ = 0;
- int64_t announced_window_delta_ = 0;
-};
+ // we have received data from the wire
+ absl::Status RecvData(int64_t incoming_frame_size);
-// Implementation of flow control that does NOTHING. Always returns maximum
-// values, never initiates writes, and assumes that the remote peer is doing
-// the same. To be used to narrow down on flow control as the cause of negative
-// performance.
-class StreamFlowControlDisabled : public StreamFlowControlBase {
- public:
- FlowControlAction UpdateAction(FlowControlAction action) override {
- return action;
- }
- FlowControlAction MakeAction() override { return FlowControlAction(); }
- void SentData(int64_t /* outgoing_frame_size */) override {}
- grpc_error_handle RecvData(int64_t /* incoming_frame_size */) override {
- return GRPC_ERROR_NONE;
- }
- uint32_t MaybeSendUpdate() override { return 0; }
- void RecvUpdate(uint32_t /* size */) override {}
- void IncomingByteStreamUpdate(size_t /* max_size_hint */,
- size_t /* have_already */) override {}
-};
+ // the application is asking for a certain amount of bytes
+ void SetMinProgressSize(uint32_t min_progress_size) {
+ sfc_->min_progress_size_ = min_progress_size;
+ }
-// Implementation of flow control that abides to HTTP/2 spec and attempts
-// to be as performant as possible.
-class StreamFlowControl final : public StreamFlowControlBase {
- public:
- StreamFlowControl(TransportFlowControl* tfc, const grpc_chttp2_stream* s);
- ~StreamFlowControl() override {
- tfc_->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
- }
+ void SetPendingSize(int64_t pending_size);
- FlowControlAction UpdateAction(FlowControlAction action) override;
- FlowControlAction MakeAction() override {
- return UpdateAction(tfc_->MakeAction());
- }
+ private:
+ TransportFlowControl::IncomingUpdateContext tfc_upd_;
+ StreamFlowControl* const sfc_;
+ };
- // we have sent data on the wire, we must track this in our bookkeeping for
- // the remote peer's flow control.
- void SentData(int64_t outgoing_frame_size) override {
- FlowControlTrace tracer(" data sent", tfc_, this);
- tfc_->StreamSentData(outgoing_frame_size);
- remote_window_delta_ -= outgoing_frame_size;
- }
+ // Track an update to the outgoing flow control counters - that is how many
+ // tokens our peer has said we can send.
+ class OutgoingUpdateContext {
+ public:
+ explicit OutgoingUpdateContext(StreamFlowControl* sfc)
+ : tfc_upd_(sfc->tfc_), sfc_(sfc) {}
+ // we have received a WINDOW_UPDATE frame for a stream
+ void RecvUpdate(uint32_t size) { sfc_->remote_window_delta_ += size; }
+ // we have sent data on the wire, we must track this in our bookkeeping for
+ // the remote peer's flow control.
+ void SentData(int64_t outgoing_frame_size) {
+ tfc_upd_.StreamSentData(outgoing_frame_size);
+ sfc_->remote_window_delta_ -= outgoing_frame_size;
+ }
- // we have received data from the wire
- grpc_error_handle RecvData(int64_t incoming_frame_size) override;
+ private:
+ TransportFlowControl::OutgoingUpdateContext tfc_upd_;
+ StreamFlowControl* const sfc_;
+ };
// returns an announce if we should send a stream update to our peer, else
// returns zero
- uint32_t MaybeSendUpdate() override;
-
- // we have received a WINDOW_UPDATE frame for a stream
- void RecvUpdate(uint32_t size) override {
- FlowControlTrace trace("s updt recv", tfc_, this);
- remote_window_delta_ += size;
- }
-
- // the application is asking for a certain amount of bytes
- void IncomingByteStreamUpdate(size_t max_size_hint,
- size_t have_already) override;
+ uint32_t MaybeSendUpdate();
int64_t remote_window_delta() const { return remote_window_delta_; }
- int64_t local_window_delta() const { return local_window_delta_; }
int64_t announced_window_delta() const { return announced_window_delta_; }
-
- const grpc_chttp2_stream* stream() const { return s_; }
-
- void TestOnlyForceHugeWindow() override {
- announced_window_delta_ = 1024 * 1024 * 1024;
- local_window_delta_ = 1024 * 1024 * 1024;
- remote_window_delta_ = 1024 * 1024 * 1024;
- }
+ uint32_t min_progress_size() const { return min_progress_size_; }
private:
TransportFlowControl* const tfc_;
- const grpc_chttp2_stream* const s_;
+ int64_t min_progress_size_ = 0;
+ int64_t remote_window_delta_ = 0;
+ int64_t announced_window_delta_ = 0;
+ absl::optional pending_size_;
- void UpdateAnnouncedWindowDelta(TransportFlowControl* tfc, int64_t change) {
- tfc->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
- announced_window_delta_ += change;
- tfc->PostUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
- }
+ FlowControlAction UpdateAction(FlowControlAction action);
+ uint32_t DesiredAnnounceSize() const;
};
class TestOnlyTransportTargetWindowEstimatesMocker {
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc
index 8cb4354f37f..4bc9f136811 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_data.cc
@@ -20,9 +20,8 @@
#include "src/core/ext/transport/chttp2/transport/frame_data.h"
-#include
+#include
-#include "absl/base/attributes.h"
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
@@ -30,33 +29,16 @@
#include
#include "src/core/ext/transport/chttp2/transport/internal.h"
-#include "src/core/lib/channel/channelz.h"
-#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/memory.h"
-#include "src/core/lib/gprpp/ref_counted_ptr.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_refcount.h"
-#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/transport.h"
-grpc_chttp2_data_parser::~grpc_chttp2_data_parser() {
- if (parsing_frame != nullptr) {
- GRPC_ERROR_UNREF(parsing_frame->Finished(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Parser destroyed"), false));
- }
- GRPC_ERROR_UNREF(error);
-}
-
-grpc_error_handle grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser* /*parser*/, uint8_t flags, uint32_t stream_id,
- grpc_chttp2_stream* s) {
+absl::Status grpc_chttp2_data_parser_begin_frame(uint8_t flags,
+ uint32_t stream_id,
+ grpc_chttp2_stream* s) {
if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
- return grpc_error_set_int(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
- "unsupported data flags: 0x%02x", flags)),
- GRPC_ERROR_INT_STREAM_ID,
- static_cast(stream_id));
+ return absl::InternalError(absl::StrFormat(
+ "unsupported data flags: 0x%02x stream: %d", flags, stream_id));
}
if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@@ -66,7 +48,7 @@ grpc_error_handle grpc_chttp2_data_parser_begin_frame(
s->received_last_frame = false;
}
- return GRPC_ERROR_NONE;
+ return absl::OkStatus();
}
void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
@@ -97,188 +79,58 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
stats->data_bytes += write_bytes;
}
-grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
- grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
- grpc_slice_buffer* slices, grpc_slice* slice_out,
- grpc_core::OrphanablePtr* stream_out) {
+grpc_core::Poll grpc_deframe_unprocessed_incoming_frames(
+ grpc_chttp2_stream* s, uint32_t* min_progress_size,
+ grpc_core::SliceBuffer* stream_out, uint32_t* message_flags) {
+ grpc_slice_buffer* slices = &s->frame_storage;
grpc_error_handle error = GRPC_ERROR_NONE;
- grpc_chttp2_transport* t = s->t;
- while (slices->count > 0) {
- uint8_t* beg = nullptr;
- uint8_t* end = nullptr;
- uint8_t* cur = nullptr;
-
- grpc_slice* slice = grpc_slice_buffer_peek_first(slices);
- beg = GRPC_SLICE_START_PTR(*slice);
- end = GRPC_SLICE_END_PTR(*slice);
- cur = beg;
- uint32_t message_flags;
+ if (slices->length < 5) {
+ if (min_progress_size != nullptr) *min_progress_size = 5 - slices->length;
+ return grpc_core::Pending{};
+ }
- if (cur == end) {
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
+ uint8_t header[5];
+ grpc_slice_buffer_copy_first_into_buffer(slices, 5, header);
- switch (p->state) {
- case GRPC_CHTTP2_DATA_ERROR:
- p->state = GRPC_CHTTP2_DATA_ERROR;
- grpc_slice_buffer_remove_first(slices);
- return GRPC_ERROR_REF(p->error);
- case GRPC_CHTTP2_DATA_FH_0:
- s->stats.incoming.framing_bytes++;
- p->frame_type = *cur;
- switch (p->frame_type) {
- case 0:
- p->is_frame_compressed = false; /* GPR_FALSE */
- break;
- case 1:
- p->is_frame_compressed = true; /* GPR_TRUE */
- break;
- default:
- p->error = GRPC_ERROR_CREATE_FROM_CPP_STRING(
- absl::StrFormat("Bad GRPC frame type 0x%02x", p->frame_type));
- p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
- static_cast(s->id));
- grpc_core::UniquePtr dmp(
- grpc_dump_slice(*slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
- p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
- dmp.get());
- p->error =
- grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
- p->state = GRPC_CHTTP2_DATA_ERROR;
- grpc_slice_buffer_remove_first(slices);
- return GRPC_ERROR_REF(p->error);
- }
- if (++cur == end) {
- p->state = GRPC_CHTTP2_DATA_FH_1;
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
- ABSL_FALLTHROUGH_INTENDED;
- case GRPC_CHTTP2_DATA_FH_1:
- s->stats.incoming.framing_bytes++;
- p->frame_size = (static_cast(*cur)) << 24;
- if (++cur == end) {
- p->state = GRPC_CHTTP2_DATA_FH_2;
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
- ABSL_FALLTHROUGH_INTENDED;
- case GRPC_CHTTP2_DATA_FH_2:
- s->stats.incoming.framing_bytes++;
- p->frame_size |= (static_cast(*cur)) << 16;
- if (++cur == end) {
- p->state = GRPC_CHTTP2_DATA_FH_3;
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
- ABSL_FALLTHROUGH_INTENDED;
- case GRPC_CHTTP2_DATA_FH_3:
- s->stats.incoming.framing_bytes++;
- p->frame_size |= (static_cast(*cur)) << 8;
- if (++cur == end) {
- p->state = GRPC_CHTTP2_DATA_FH_4;
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
- ABSL_FALLTHROUGH_INTENDED;
- case GRPC_CHTTP2_DATA_FH_4:
- s->stats.incoming.framing_bytes++;
- GPR_ASSERT(stream_out != nullptr);
- GPR_ASSERT(p->parsing_frame == nullptr);
- p->frame_size |= (static_cast(*cur));
- if (t->channelz_socket != nullptr) {
- t->channelz_socket->RecordMessageReceived();
- }
- p->state = GRPC_CHTTP2_DATA_FRAME;
- ++cur;
- message_flags = 0;
- if (p->is_frame_compressed) {
- message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
- }
- p->parsing_frame = new grpc_core::Chttp2IncomingByteStream(
- t, s, p->frame_size, message_flags);
- stream_out->reset(p->parsing_frame);
- if (p->parsing_frame->remaining_bytes() == 0) {
- GRPC_ERROR_UNREF(p->parsing_frame->Finished(GRPC_ERROR_NONE, true));
- p->parsing_frame = nullptr;
- p->state = GRPC_CHTTP2_DATA_FH_0;
- }
- s->pending_byte_stream = true;
- if (cur != end) {
- grpc_slice_buffer_sub_first(slices, static_cast(cur - beg),
- static_cast(end - beg));
- } else {
- grpc_slice_buffer_remove_first(slices);
- }
- return GRPC_ERROR_NONE;
- case GRPC_CHTTP2_DATA_FRAME: {
- GPR_ASSERT(p->parsing_frame != nullptr);
- GPR_ASSERT(slice_out != nullptr);
- if (cur == end) {
- grpc_slice_buffer_remove_first(slices);
- continue;
- }
- uint32_t remaining = static_cast(end - cur);
- if (remaining == p->frame_size) {
- s->stats.incoming.data_bytes += remaining;
- if (GRPC_ERROR_NONE !=
- (error = p->parsing_frame->Push(
- grpc_slice_sub(*slice, static_cast(cur - beg),
- static_cast(end - beg)),
- slice_out))) {
- grpc_slice_buffer_remove_first(slices);
- return error;
- }
- if (GRPC_ERROR_NONE !=
- (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
- grpc_slice_buffer_remove_first(slices);
- return error;
- }
- p->parsing_frame = nullptr;
- p->state = GRPC_CHTTP2_DATA_FH_0;
- grpc_slice_buffer_remove_first(slices);
- return GRPC_ERROR_NONE;
- } else if (remaining < p->frame_size) {
- s->stats.incoming.data_bytes += remaining;
- if (GRPC_ERROR_NONE !=
- (error = p->parsing_frame->Push(
- grpc_slice_sub(*slice, static_cast(cur - beg),
- static_cast(end - beg)),
- slice_out))) {
- return error;
- }
- p->frame_size -= remaining;
- grpc_slice_buffer_remove_first(slices);
- return GRPC_ERROR_NONE;
- } else {
- GPR_ASSERT(remaining > p->frame_size);
- s->stats.incoming.data_bytes += p->frame_size;
- if (GRPC_ERROR_NONE !=
- p->parsing_frame->Push(
- grpc_slice_sub(
- *slice, static_cast(cur - beg),
- static_cast(cur + p->frame_size - beg)),
- slice_out)) {
- grpc_slice_buffer_remove_first(slices);
- return error;
- }
- if (GRPC_ERROR_NONE !=
- (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) {
- grpc_slice_buffer_remove_first(slices);
- return error;
- }
- p->parsing_frame = nullptr;
- p->state = GRPC_CHTTP2_DATA_FH_0;
- cur += p->frame_size;
- grpc_slice_buffer_sub_first(slices, static_cast(cur - beg),
- static_cast(end - beg));
- return GRPC_ERROR_NONE;
- }
+ switch (header[0]) {
+ case 0:
+ if (message_flags != nullptr) *message_flags = 0;
+ break;
+ case 1:
+ if (message_flags != nullptr) {
+ *message_flags = GRPC_WRITE_INTERNAL_COMPRESS;
}
+ break;
+ default:
+ error = GRPC_ERROR_CREATE_FROM_CPP_STRING(
+ absl::StrFormat("Bad GRPC frame type 0x%02x", header[0]));
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_STREAM_ID,
+ static_cast(s->id));
+ return error;
+ }
+
+ uint64_t length = (static_cast(header[1]) << 24) |
+ (static_cast(header[2]) << 16) |
+ (static_cast(header[3]) << 8) |
+ static_cast(header[4]);
+
+ if (slices->length < length + 5) {
+ if (min_progress_size != nullptr) {
+ *min_progress_size = length + 5 - slices->length;
}
+ return grpc_core::Pending{};
+ }
+
+ if (min_progress_size != nullptr) *min_progress_size = 0;
+
+ if (stream_out != nullptr) {
+ s->stats.incoming.framing_bytes += 5;
+ s->stats.incoming.data_bytes += length;
+ grpc_slice_buffer_move_first_into_buffer(slices, 5, header);
+ grpc_slice_buffer_move_first(slices, length, stream_out->c_slice_buffer());
}
+
return GRPC_ERROR_NONE;
}
@@ -287,20 +139,9 @@ grpc_error_handle grpc_chttp2_data_parser_parse(void* /*parser*/,
grpc_chttp2_stream* s,
const grpc_slice& slice,
int is_last) {
- if (!s->pending_byte_stream) {
- grpc_slice_ref_internal(slice);
- grpc_slice_buffer_add(&s->frame_storage, slice);
- grpc_chttp2_maybe_complete_recv_message(t, s);
- } else if (s->on_next) {
- GPR_ASSERT(s->frame_storage.length == 0);
- grpc_slice_ref_internal(slice);
- grpc_slice_buffer_add(&s->unprocessed_incoming_frames_buffer, slice);
- grpc_core::ExecCtx::Run(DEBUG_LOCATION, s->on_next, GRPC_ERROR_NONE);
- s->on_next = nullptr;
- } else {
- grpc_slice_ref_internal(slice);
- grpc_slice_buffer_add(&s->frame_storage, slice);
- }
+ grpc_slice_ref_internal(slice);
+ grpc_slice_buffer_add(&s->frame_storage, slice);
+ grpc_chttp2_maybe_complete_recv_message(t, s);
if (is_last && s->received_last_frame) {
grpc_chttp2_mark_stream_closed(
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index d32bba83069..e1805edcb6a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -25,45 +25,20 @@
#include
+#include "absl/status/status.h"
+
#include
#include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/promise/poll.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/transport.h"
-typedef enum {
- GRPC_CHTTP2_DATA_FH_0,
- GRPC_CHTTP2_DATA_FH_1,
- GRPC_CHTTP2_DATA_FH_2,
- GRPC_CHTTP2_DATA_FH_3,
- GRPC_CHTTP2_DATA_FH_4,
- GRPC_CHTTP2_DATA_FRAME,
- GRPC_CHTTP2_DATA_ERROR
-} grpc_chttp2_stream_state;
-
-namespace grpc_core {
-class Chttp2IncomingByteStream;
-} // namespace grpc_core
-
-struct grpc_chttp2_data_parser {
- grpc_chttp2_data_parser() = default;
- ~grpc_chttp2_data_parser();
-
- grpc_chttp2_stream_state state = GRPC_CHTTP2_DATA_FH_0;
- uint8_t frame_type = 0;
- uint32_t frame_size = 0;
- grpc_error_handle error = GRPC_ERROR_NONE;
-
- bool is_frame_compressed = false;
- grpc_core::Chttp2IncomingByteStream* parsing_frame = nullptr;
-};
-
/* start processing a new data frame */
-grpc_error_handle grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser* parser, uint8_t flags, uint32_t stream_id,
- grpc_chttp2_stream* s);
+absl::Status grpc_chttp2_data_parser_begin_frame(uint8_t flags,
+ uint32_t stream_id,
+ grpc_chttp2_stream* s);
/* handle a slice of a data frame - is_last indicates the last slice of a
frame */
@@ -78,9 +53,8 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer* inbuf,
grpc_transport_one_way_stats* stats,
grpc_slice_buffer* outbuf);
-grpc_error_handle grpc_deframe_unprocessed_incoming_frames(
- grpc_chttp2_data_parser* p, grpc_chttp2_stream* s,
- grpc_slice_buffer* slices, grpc_slice* slice_out,
- grpc_core::OrphanablePtr* stream_out);
+grpc_core::Poll grpc_deframe_unprocessed_incoming_frames(
+ grpc_chttp2_stream* s, uint32_t* min_progress_size,
+ grpc_core::SliceBuffer* stream_out, uint32_t* message_flags);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc
index dfbfde9ee7e..d0157475ba5 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc
@@ -35,11 +35,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
-#include "src/core/ext/transport/chttp2/transport/stream_map.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/iomgr/exec_ctx.h"
static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
@@ -119,22 +117,6 @@ grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
}
}
-namespace {
-
-void StreamFlowControlWindowCheck(void* user_data, uint32_t /* key */,
- void* stream) {
- bool* error = static_cast(user_data);
- grpc_chttp2_stream* s = static_cast(stream);
- if ((s->t->settings[GRPC_PEER_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] +
- s->t->initial_window_update + s->flow_control->remote_window_delta()) >
- ((1u << 31) - 1)) {
- *error = true;
- }
-}
-
-} // namespace
-
grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
grpc_chttp2_transport* t,
grpc_chttp2_stream* /*s*/,
@@ -219,12 +201,6 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
if (grpc_wire_id_to_setting_id(parser->id, &id)) {
const grpc_chttp2_setting_parameters* sp =
&grpc_chttp2_settings_parameters[id];
- // If flow control is disabled we skip these.
- if (!t->flow_control->flow_control_enabled() &&
- (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE ||
- id == GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE)) {
- continue;
- }
if (parser->value < sp->min_value || parser->value > sp->max_value) {
switch (sp->invalid_value_behavior) {
case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
@@ -250,23 +226,6 @@ grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
t->is_client ? "cli" : "svr",
static_cast(t->initial_window_update));
}
- if (grpc_core::chttp2::
- g_test_only_transport_flow_control_window_check) {
- bool error = false;
- if (parser->value > grpc_core::chttp2::kMaxInitialWindowSize ||
- parser->value < grpc_core::chttp2::kMinInitialWindowSize) {
- error = true;
- } else {
- grpc_chttp2_stream_map_for_each(
- &t->stream_map, StreamFlowControlWindowCheck, &error);
- }
- if (error) {
- grpc_chttp2_goaway_append(
- t->last_new_stream_id, sp->error_value,
- grpc_slice_from_static_string("HTTP2 settings error"),
- &t->qbuf);
- }
- }
}
parser->incoming_settings[id] = parser->value;
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.cc b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
index 790c654cb59..eb65e86d523 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.cc
@@ -29,7 +29,6 @@
#include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
grpc_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_delta, grpc_transport_one_way_stats* stats) {
@@ -98,13 +97,9 @@ grpc_error_handle grpc_chttp2_window_update_parser_parse(
if (t->incoming_stream_id != 0) {
if (s != nullptr) {
- s->flow_control->RecvUpdate(received_update);
- if (grpc_core::chttp2::
- g_test_only_transport_flow_control_window_check &&
- s->flow_control->remote_window_delta() >
- grpc_core::chttp2::kMaxWindowDelta) {
- GPR_ASSERT(false);
- }
+ grpc_core::chttp2::StreamFlowControl::OutgoingUpdateContext(
+ &s->flow_control)
+ .RecvUpdate(received_update);
if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) {
grpc_chttp2_mark_stream_writable(t, s);
grpc_chttp2_initiate_write(
@@ -112,10 +107,10 @@ grpc_error_handle grpc_chttp2_window_update_parser_parse(
}
}
} else {
- bool was_zero = t->flow_control->remote_window() <= 0;
- t->flow_control->RecvUpdate(received_update);
- bool is_zero = t->flow_control->remote_window() <= 0;
- if (was_zero && !is_zero) {
+ grpc_core::chttp2::TransportFlowControl::OutgoingUpdateContext upd(
+ &t->flow_control);
+ upd.RecvUpdate(received_update);
+ if (upd.Finish() == grpc_core::chttp2::StallEdge::kUnstalled) {
grpc_chttp2_initiate_write(
t, GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL_UNSTALLED);
}
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index d859766eadf..4af3c4ec9db 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -27,6 +27,7 @@
#include
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include
#include
@@ -34,7 +35,6 @@
#include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include "src/core/ext/transport/chttp2/transport/frame.h"
-#include "src/core/ext/transport/chttp2/transport/frame_data.h"
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
@@ -48,8 +48,6 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/bitset.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
@@ -60,7 +58,7 @@
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
-#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -230,76 +228,6 @@ typedef struct grpc_chttp2_write_cb {
struct grpc_chttp2_write_cb* next;
} grpc_chttp2_write_cb;
-namespace grpc_core {
-
-class Chttp2IncomingByteStream : public ByteStream {
- public:
- Chttp2IncomingByteStream(grpc_chttp2_transport* transport,
- grpc_chttp2_stream* stream, uint32_t frame_size,
- uint32_t flags);
-
- void Orphan() override;
-
- bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
- grpc_error_handle Pull(grpc_slice* slice) override;
- void Shutdown(grpc_error_handle error) override;
-
- // TODO(roth): When I converted this class to C++, I wanted to make it
- // inherit from RefCounted or InternallyRefCounted instead of continuing
- // to use its own custom ref-counting code. However, that would require
- // using multiple inheritance, which sucks in general. And to make matters
- // worse, it causes problems with our New<> and Delete<> wrappers.
- // Specifically, unless RefCounted is first in the list of parent classes,
- // it will see a different value of the address of the object than the one
- // we actually allocated, in which case gpr_free() will be called on a
- // different address than the one we got from gpr_malloc(), thus causing a
- // crash. Given the fragility of depending on that, as well as a desire to
- // avoid multiple inheritance in general, I've decided to leave this
- // alone for now. We can revisit this once we're able to link against
- // libc++, at which point we can eliminate New<> and Delete<> and
- // switch to std::shared_ptr<>.
- void Ref() { refs_.Ref(); }
- void Unref() {
- if (GPR_UNLIKELY(refs_.Unref())) {
- delete this;
- }
- }
-
- void PublishError(grpc_error_handle error);
-
- grpc_error_handle Push(const grpc_slice& slice, grpc_slice* slice_out);
-
- grpc_error_handle Finished(grpc_error_handle error, bool reset_on_error);
-
- uint32_t remaining_bytes() const { return remaining_bytes_; }
-
- private:
- static void NextLocked(void* arg, grpc_error_handle error_ignored);
- static void OrphanLocked(void* arg, grpc_error_handle error_ignored);
-
- grpc_chttp2_transport* transport_; // Immutable.
- grpc_chttp2_stream* stream_; // Immutable.
-
- RefCount refs_;
-
- /* Accessed only by transport thread when stream->pending_byte_stream == false
- * Accessed only by application thread when stream->pending_byte_stream ==
- * true */
- uint32_t remaining_bytes_;
-
- /* Accessed only by transport thread when stream->pending_byte_stream == false
- * Accessed only by application thread when stream->pending_byte_stream ==
- * true */
- struct {
- grpc_closure closure;
- size_t max_size_hint;
- grpc_closure* on_complete;
- } next_action_;
- grpc_closure destroy_action_;
-};
-
-} // namespace grpc_core
-
typedef enum {
GRPC_CHTTP2_KEEPALIVE_STATE_WAITING,
GRPC_CHTTP2_KEEPALIVE_STATE_PINGING,
@@ -428,11 +356,7 @@ struct grpc_chttp2_transport {
/** parser for goaway frames */
grpc_chttp2_goaway_parser goaway_parser;
- grpc_core::PolymorphicManualConstructor<
- grpc_core::chttp2::TransportFlowControlBase,
- grpc_core::chttp2::TransportFlowControl,
- grpc_core::chttp2::TransportFlowControlDisabled>
- flow_control;
+ grpc_core::chttp2::TransportFlowControl flow_control;
/** initial window change. This is tracked as we parse settings frames from
* the remote peer. If there is a positive delta, then we will make all
* streams readable since they may have become unstalled */
@@ -566,19 +490,16 @@ struct grpc_chttp2_stream {
bool* sent_trailing_metadata_op = nullptr;
grpc_closure* send_trailing_metadata_finished = nullptr;
- grpc_core::OrphanablePtr fetching_send_message;
- uint32_t fetched_send_message_length = 0;
- grpc_slice fetching_slice = grpc_empty_slice();
int64_t next_message_end_offset;
int64_t flow_controlled_bytes_written = 0;
int64_t flow_controlled_bytes_flowed = 0;
- grpc_closure complete_fetch_locked;
- grpc_closure* fetching_send_message_finished = nullptr;
+ grpc_closure* send_message_finished = nullptr;
grpc_metadata_batch* recv_initial_metadata;
grpc_closure* recv_initial_metadata_ready = nullptr;
bool* trailing_metadata_available = nullptr;
- grpc_core::OrphanablePtr* recv_message = nullptr;
+ absl::optional* recv_message = nullptr;
+ uint32_t* recv_message_flags = nullptr;
bool* call_failed_before_recv_message = nullptr;
grpc_closure* recv_message_ready = nullptr;
grpc_metadata_batch* recv_trailing_metadata;
@@ -615,22 +536,7 @@ struct grpc_chttp2_stream {
grpc_metadata_batch initial_metadata_buffer;
grpc_metadata_batch trailing_metadata_buffer;
- grpc_slice_buffer frame_storage; /* protected by t combiner */
-
- grpc_closure* on_next = nullptr; /* protected by t combiner */
- bool pending_byte_stream = false; /* protected by t combiner */
- // cached length of buffer to be used by the transport thread in cases where
- // stream->pending_byte_stream == true. The value is saved before
- // application threads are allowed to modify
- // unprocessed_incoming_frames_buffer
- size_t unprocessed_incoming_frames_buffer_cached_length = 0;
- /* Accessed only by transport thread when stream->pending_byte_stream == false
- * Accessed only by application thread when stream->pending_byte_stream ==
- * true */
- grpc_slice_buffer unprocessed_incoming_frames_buffer;
- grpc_closure reset_byte_stream;
- grpc_error_handle byte_stream_error =
- GRPC_ERROR_NONE; /* protected by t combiner */
+ grpc_slice_buffer frame_storage; /* protected by t combiner */
bool received_last_frame = false; /* protected by t combiner */
grpc_core::Timestamp deadline = grpc_core::Timestamp::InfFuture();
@@ -639,22 +545,13 @@ struct grpc_chttp2_stream {
grpc_error_handle forced_close_error = GRPC_ERROR_NONE;
/** how many header frames have we received? */
uint8_t header_frames_received = 0;
- /** parsing state for data frames */
- /* Accessed only by transport thread when stream->pending_byte_stream == false
- * Accessed only by application thread when stream->pending_byte_stream ==
- * true */
- grpc_chttp2_data_parser data_parser;
/** number of bytes received - reset at end of parse thread execution */
int64_t received_bytes = 0;
bool sent_initial_metadata = false;
bool sent_trailing_metadata = false;
- grpc_core::PolymorphicManualConstructor<
- grpc_core::chttp2::StreamFlowControlBase,
- grpc_core::chttp2::StreamFlowControl,
- grpc_core::chttp2::StreamFlowControlDisabled>
- flow_control;
+ grpc_core::chttp2::StreamFlowControl flow_control;
grpc_slice_buffer flow_controlled_buffer;
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index d91af3801be..6a45381e542 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -47,11 +47,11 @@
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/bdp_estimator.h"
+#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/http2_errors.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -218,10 +218,9 @@ grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
return GRPC_ERROR_NONE;
}
goto dts_fh_0; /* loop */
- } else if (t->flow_control->flow_control_enabled() &&
- t->incoming_frame_size >
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) {
+ } else if (t->incoming_frame_size >
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(
absl::StrFormat("Frame size %d is larger than max frame size %d",
t->incoming_frame_size,
@@ -385,7 +384,7 @@ void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t) {
static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
// Update BDP accounting since we have received a data frame.
- grpc_core::BdpEstimator* bdp_est = t->flow_control->bdp_estimator();
+ grpc_core::BdpEstimator* bdp_est = t->flow_control.bdp_estimator();
if (bdp_est) {
if (t->bdp_ping_blocked) {
t->bdp_ping_blocked = false;
@@ -396,17 +395,21 @@ static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
}
grpc_chttp2_stream* s =
grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
- grpc_error_handle err = GRPC_ERROR_NONE;
+ absl::Status status;
grpc_core::chttp2::FlowControlAction action;
if (s == nullptr) {
- err = t->flow_control->RecvData(t->incoming_frame_size);
- action = t->flow_control->MakeAction();
+ grpc_core::chttp2::TransportFlowControl::IncomingUpdateContext upd(
+ &t->flow_control);
+ status = upd.RecvData(t->incoming_frame_size);
+ action = upd.MakeAction();
} else {
- err = s->flow_control->RecvData(t->incoming_frame_size);
- action = s->flow_control->MakeAction();
+ grpc_core::chttp2::StreamFlowControl::IncomingUpdateContext upd(
+ &s->flow_control);
+ status = upd.RecvData(t->incoming_frame_size);
+ action = upd.MakeAction();
}
grpc_chttp2_act_on_flowctl_action(action, t, s);
- if (err != GRPC_ERROR_NONE) {
+ if (!status.ok()) {
goto error_handler;
}
if (s == nullptr) {
@@ -414,33 +417,29 @@ static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
}
s->received_bytes += t->incoming_frame_size;
s->stats.incoming.framing_bytes += 9;
- if (err == GRPC_ERROR_NONE && s->read_closed) {
+ if (s->read_closed) {
return init_non_header_skip_frame_parser(t);
}
- if (err == GRPC_ERROR_NONE) {
- err = grpc_chttp2_data_parser_begin_frame(
- &s->data_parser, t->incoming_frame_flags, s->id, s);
- }
+ status =
+ grpc_chttp2_data_parser_begin_frame(t->incoming_frame_flags, s->id, s);
error_handler:
- intptr_t unused;
- if (err == GRPC_ERROR_NONE) {
+ if (status.ok()) {
t->incoming_stream = s;
/* t->parser = grpc_chttp2_data_parser_parse;*/
t->parser = grpc_chttp2_data_parser_parse;
- t->parser_data = &s->data_parser;
+ t->parser_data = nullptr;
t->ping_state.last_ping_sent_time = grpc_core::Timestamp::InfPast();
return GRPC_ERROR_NONE;
- } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
+ } else if (s != nullptr) {
/* handle stream errors by closing the stream */
- if (s != nullptr) {
- grpc_chttp2_mark_stream_closed(t, s, true, false, err);
- }
+ grpc_chttp2_mark_stream_closed(t, s, true, false,
+ absl_status_to_grpc_error(status));
grpc_chttp2_add_rst_stream_to_next_write(t, t->incoming_stream_id,
GRPC_HTTP2_PROTOCOL_ERROR,
&s->stats.outgoing);
return init_non_header_skip_frame_parser(t);
} else {
- return err;
+ return absl_status_to_grpc_error(status);
}
}
@@ -569,6 +568,10 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
gpr_log(GPR_ERROR, "too many header frames received");
return init_header_skip_frame_parser(t, priority_type);
}
+ if (frame_type == HPackParser::LogInfo::kTrailers && !t->header_eof) {
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Trailing metadata frame received without an end-o-stream");
+ }
t->hpack_parser.BeginFrame(
incoming_metadata_buffer,
t->settings[GRPC_ACKED_SETTINGS]
@@ -648,6 +651,9 @@ static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
t->hpack_parser.hpack_table()->SetMaxBytes(
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+ t->flow_control.SetAckedInitialWindow(
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
t->sent_local_settings = false;
}
t->parser = grpc_chttp2_settings_parser_parse;
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.cc b/src/core/ext/transport/chttp2/transport/stream_lists.cc
index aaa73975b5c..92c36a60934 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.cc
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.cc
@@ -20,12 +20,10 @@
#include
-#include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/bitset.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
static const char* stream_list_id_string(grpc_chttp2_stream_list_id id) {
switch (id) {
@@ -189,7 +187,6 @@ void grpc_chttp2_list_remove_waiting_for_concurrency(grpc_chttp2_transport* t,
void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
- GPR_ASSERT(t->flow_control->flow_control_enabled());
stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
}
@@ -205,7 +202,6 @@ void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport* t,
void grpc_chttp2_list_add_stalled_by_stream(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
- GPR_ASSERT(t->flow_control->flow_control_enabled());
stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_STREAM);
}
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 1cc39b7135d..e676672e7d9 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -22,7 +22,6 @@
#include
#include
-#include
#include
#include "absl/types/optional.h"
@@ -50,7 +49,6 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
@@ -220,14 +218,14 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
s->flow_controlled_buffer.length, s->flow_controlled_bytes_flowed,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
- t->flow_control->remote_window(),
+ t->flow_control.remote_window(),
static_cast(std::max(
int64_t(0),
- s->flow_control->remote_window_delta() +
+ s->flow_control.remote_window_delta() +
static_cast(
t->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]))),
- s->flow_control->remote_window_delta());
+ s->flow_control.remote_window_delta());
}
}
@@ -304,7 +302,7 @@ class WriteContext {
void FlushWindowUpdates() {
uint32_t transport_announce =
- t_->flow_control->MaybeSendUpdate(t_->outbuf.count > 0);
+ t_->flow_control.MaybeSendUpdate(t_->outbuf.count > 0);
if (transport_announce) {
grpc_transport_one_way_stats throwaway_stats;
grpc_slice_buffer_add(
@@ -392,7 +390,7 @@ class DataSendContext {
uint32_t stream_remote_window() const {
return static_cast(std::max(
int64_t(0),
- s_->flow_control->remote_window_delta() +
+ s_->flow_control.remote_window_delta() +
static_cast(
t_->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE])));
@@ -402,7 +400,7 @@ class DataSendContext {
return static_cast(std::min(
t_->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
static_cast(std::min(int64_t(stream_remote_window()),
- t_->flow_control->remote_window()))));
+ t_->flow_control.remote_window()))));
}
bool AnyOutgoing() const { return max_outgoing() > 0; }
@@ -411,12 +409,11 @@ class DataSendContext {
uint32_t send_bytes = static_cast(
std::min(size_t(max_outgoing()), s_->flow_controlled_buffer.length));
is_last_frame_ = send_bytes == s_->flow_controlled_buffer.length &&
- s_->fetching_send_message == nullptr &&
s_->send_trailing_metadata != nullptr &&
s_->send_trailing_metadata->empty();
grpc_chttp2_encode_data(s_->id, &s_->flow_controlled_buffer, send_bytes,
is_last_frame_, &s_->stats.outgoing, &t_->outbuf);
- s_->flow_control->SentData(send_bytes);
+ sfc_upd_.SentData(send_bytes);
s_->sending_bytes += send_bytes;
}
@@ -436,6 +433,8 @@ class DataSendContext {
WriteContext* write_context_;
grpc_chttp2_transport* t_;
grpc_chttp2_stream* s_;
+ grpc_core::chttp2::StreamFlowControl::OutgoingUpdateContext sfc_upd_{
+ &s_->flow_control};
const size_t sending_bytes_before_;
bool is_last_frame_ = false;
};
@@ -445,11 +444,9 @@ class StreamWriteContext {
StreamWriteContext(WriteContext* write_context, grpc_chttp2_stream* s)
: write_context_(write_context), t_(write_context->transport()), s_(s) {
GRPC_CHTTP2_IF_TRACING(
- gpr_log(GPR_INFO, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t_,
+ gpr_log(GPR_INFO, "W:%p %s[%d] im-(sent,send)=(%d,%d)", t_,
t_->is_client ? "CLIENT" : "SERVER", s->id,
- s->sent_initial_metadata, s->send_initial_metadata != nullptr,
- (int)(s->flow_control->local_window_delta() -
- s->flow_control->announced_window_delta())));
+ s->sent_initial_metadata, s->send_initial_metadata != nullptr));
}
void FlushInitialMetadata() {
@@ -462,8 +459,7 @@ class StreamWriteContext {
// trailing metadata. This results in a Trailers-Only response,
// which is required for retries, as per:
// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#when-retries-are-valid
- if (!t_->is_client && s_->fetching_send_message == nullptr &&
- s_->flow_controlled_buffer.length == 0 &&
+ if (!t_->is_client && s_->flow_controlled_buffer.length == 0 &&
s_->send_trailing_metadata != nullptr &&
is_default_initial_metadata(s_->send_initial_metadata)) {
ConvertInitialMetadataToTrailingMetadata();
@@ -495,8 +491,10 @@ class StreamWriteContext {
}
void FlushWindowUpdates() {
+ if (s_->read_closed) return;
+
/* send any window updates */
- const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate();
+ const uint32_t stream_announce = s_->flow_control.MaybeSendUpdate();
if (stream_announce == 0) return;
grpc_slice_buffer_add(
@@ -516,7 +514,7 @@ class StreamWriteContext {
DataSendContext data_send_context(write_context_, t_, s_);
if (!data_send_context.AnyOutgoing()) {
- if (t_->flow_control->remote_window() <= 0) {
+ if (t_->flow_control.remote_window() <= 0) {
report_stall(t_, s_, "transport");
grpc_chttp2_list_add_stalled_by_transport(t_, s_);
} else if (data_send_context.stream_remote_window() <= 0) {
@@ -547,7 +545,6 @@ class StreamWriteContext {
if (!s_->sent_initial_metadata) return;
if (s_->send_trailing_metadata == nullptr) return;
- if (s_->fetching_send_message != nullptr) return;
if (s_->flow_controlled_buffer.length != 0) return;
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata"));
@@ -635,7 +632,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
ctx.FlushQueuedBuffers();
ctx.EnactHpackSettings();
- if (t->flow_control->remote_window() > 0) {
+ if (t->flow_control.remote_window() > 0) {
ctx.UpdateStreamsNoLongerStalled();
}
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc
index 2fe5fdf311e..19e0f721c67 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.cc
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -24,20 +24,18 @@
#include
#include
-#include
#include
#include
#include
-#include "absl/status/status.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include "third_party/objective_c/Cronet/bidirectional_stream_c.h"
#include
-#include
#include
#include
#include
@@ -48,8 +46,6 @@
#include "src/core/ext/transport/cronet/transport/cronet_status.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/error.h"
@@ -58,14 +54,15 @@
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
-#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_refcount.h"
#include "src/core/lib/surface/validate_metadata.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/lib/transport/transport_impl.h"
+// IWYU pragma: no_include
+
#define GRPC_HEADER_SIZE_IN_BYTES 5
#define GRPC_FLUSH_READ_SIZE 4096
@@ -134,9 +131,7 @@ typedef struct grpc_cronet_transport grpc_cronet_transport;
http://www.catb.org/esr/structure-packing/#_structure_reordering: */
struct read_state {
explicit read_state(grpc_core::Arena* arena)
- : trailing_metadata(arena), initial_metadata(arena) {
- grpc_slice_buffer_init(&read_slice_buffer);
- }
+ : trailing_metadata(arena), initial_metadata(arena) {}
/* vars to store data coming from server */
char* read_buffer = nullptr;
@@ -150,8 +145,7 @@ struct read_state {
bool read_stream_closed = false;
/* vars for holding data destined for the application */
- grpc_core::ManualConstructor sbs;
- grpc_slice_buffer read_slice_buffer;
+ grpc_core::SliceBuffer read_slice_buffer;
/* vars for trailing metadata */
grpc_metadata_batch trailing_metadata;
@@ -1089,38 +1083,17 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
result = NO_ACTION_POSSIBLE;
CRONET_LOG(GPR_DEBUG, "Stream is either cancelled, failed or finished");
} else {
- grpc_slice_buffer write_slice_buffer;
- grpc_slice slice;
- grpc_slice_buffer_init(&write_slice_buffer);
- while (write_slice_buffer.length <
- stream_op->payload->send_message.send_message->length()) {
- /* TODO(roth): When we add support for incremental sending,this code
- * will need to be changed to support asynchronous delivery of the
- * send_message payload. */
- if (!stream_op->payload->send_message.send_message->Next(
- stream_op->payload->send_message.send_message->length(),
- nullptr)) {
- /* Should never reach here */
- GPR_ASSERT(false);
- }
- if (GRPC_ERROR_NONE !=
- stream_op->payload->send_message.send_message->Pull(&slice)) {
- /* Should never reach here */
- GPR_ASSERT(false);
- }
- grpc_slice_buffer_add(&write_slice_buffer, slice);
- }
size_t write_buffer_size;
- create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
- &write_buffer_size,
- stream_op->payload->send_message.send_message->flags());
+ create_grpc_frame(
+ stream_op->payload->send_message.send_message->c_slice_buffer(),
+ &stream_state->ws.write_buffer, &write_buffer_size,
+ stream_op->payload->send_message.flags);
if (write_buffer_size > 0) {
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs,
stream_state->ws.write_buffer);
stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
static_cast(write_buffer_size), false);
- grpc_slice_buffer_destroy_internal(&write_slice_buffer);
if (t->use_packet_coalescing) {
if (!stream_op->send_trailing_metadata) {
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_flush (%p)", s->cbs);
@@ -1140,7 +1113,6 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
}
stream_state->state_op_done[OP_SEND_MESSAGE] = true;
oas->state.state_op_done[OP_SEND_MESSAGE] = true;
- stream_op->payload->send_message.send_message.reset();
} else if (stream_op->send_trailing_metadata &&
op_can_be_run(stream_op, s, &oas->state,
OP_SEND_TRAILING_METADATA)) {
@@ -1252,16 +1224,14 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
stream_state->rs.remaining_bytes = 0;
CRONET_LOG(GPR_DEBUG, "read operation complete. Empty response.");
/* Clean up read_slice_buffer in case there is unread data. */
- grpc_slice_buffer_destroy_internal(
- &stream_state->rs.read_slice_buffer);
- grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+ stream_state->rs.read_slice_buffer.Clear();
uint32_t flags = 0;
if (stream_state->rs.compressed) {
flags |= GRPC_WRITE_INTERNAL_COMPRESS;
}
- stream_state->rs.sbs.Init(&stream_state->rs.read_slice_buffer, flags);
- stream_op->payload->recv_message.recv_message->reset(
- stream_state->rs.sbs.get());
+ *stream_op->payload->recv_message.flags = flags;
+ *stream_op->payload->recv_message.recv_message =
+ std::move(stream_state->rs.read_slice_buffer);
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
stream_op->payload->recv_message.recv_message_ready,
@@ -1300,17 +1270,16 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
static_cast(stream_state->rs.length_field));
null_and_maybe_free_read_buffer(s);
/* Clean up read_slice_buffer in case there is unread data. */
- grpc_slice_buffer_destroy_internal(&stream_state->rs.read_slice_buffer);
- grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
- grpc_slice_buffer_add(&stream_state->rs.read_slice_buffer,
- read_data_slice);
+ stream_state->rs.read_slice_buffer.Clear();
+ stream_state->rs.read_slice_buffer.Append(
+ grpc_core::Slice(read_data_slice));
uint32_t flags = 0;
if (stream_state->rs.compressed) {
flags = GRPC_WRITE_INTERNAL_COMPRESS;
}
- stream_state->rs.sbs.Init(&stream_state->rs.read_slice_buffer, flags);
- stream_op->payload->recv_message.recv_message->reset(
- stream_state->rs.sbs.get());
+ *stream_op->payload->recv_message.flags = flags;
+ *stream_op->payload->recv_message.recv_message =
+ std::move(stream_state->rs.read_slice_buffer);
grpc_core::ExecCtx::Run(
DEBUG_LOCATION, stream_op->payload->recv_message.recv_message_ready,
GRPC_ERROR_NONE);
@@ -1426,8 +1395,6 @@ inline stream_obj::stream_obj(grpc_transport* gt, grpc_stream* gs,
inline stream_obj::~stream_obj() {
null_and_maybe_free_read_buffer(this);
- /* Clean up read_slice_buffer in case there is unread data. */
- grpc_slice_buffer_destroy_internal(&state.rs.read_slice_buffer);
GRPC_ERROR_UNREF(state.cancel_error);
}
diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc
index f6f9f6d500f..3b554775a3e 100644
--- a/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/src/core/ext/transport/inproc/inproc_transport.cc
@@ -21,7 +21,6 @@
#include "src/core/ext/transport/inproc/inproc_transport.h"
#include
-#include
#include
#include
@@ -34,11 +33,10 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
#include
#include
-#include
-#include
#include
#include
#include
@@ -50,8 +48,6 @@
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/debug_location.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/iomgr/closure.h"
@@ -62,12 +58,11 @@
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
-#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/surface/server.h"
-#include "src/core/lib/transport/byte_stream.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -92,6 +87,10 @@ void fill_in_metadata(inproc_stream* s, const grpc_metadata_batch* metadata,
uint32_t flags, grpc_metadata_batch* out_md,
uint32_t* outflags, bool* markfilled);
+void ResetSendMessage(grpc_transport_stream_op_batch* batch) {
+ absl::exchange(batch->payload->send_message.send_message, nullptr)->Clear();
+}
+
struct shared_mu {
shared_mu() {
// Share one lock between both sides since both sides get affected
@@ -226,10 +225,6 @@ struct inproc_stream {
GRPC_ERROR_UNREF(cancel_self_error);
GRPC_ERROR_UNREF(cancel_other_error);
- if (recv_inited) {
- grpc_slice_buffer_destroy_internal(&recv_message);
- }
-
t->unref();
}
@@ -283,10 +278,6 @@ struct inproc_stream {
grpc_transport_stream_op_batch* recv_message_op = nullptr;
grpc_transport_stream_op_batch* recv_trailing_md_op = nullptr;
- grpc_slice_buffer recv_message;
- grpc_core::ManualConstructor recv_stream;
- bool recv_inited = false;
-
bool initial_md_sent = false;
bool trailing_md_sent = false;
bool initial_md_recvd = false;
@@ -360,8 +351,8 @@ void fill_in_metadata(inproc_stream* s, const grpc_metadata_batch* metadata,
}
// TODO(ctiller): copy the metadata batch, don't rely on a bespoke copy
- // function. Can only do this once mdelems are out of the way though, too many
- // edge cases otherwise.
+ // function. Can only do this once mdelems are out of the way though, too
+ // many edge cases otherwise.
out_md->Clear();
CopySink sink(out_md);
metadata->Encode(&sink);
@@ -477,8 +468,8 @@ void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
if (s->recv_initial_md_op) {
grpc_error_handle err;
if (!s->t->is_client) {
- // If this is a server, provide initial metadata with a path and authority
- // since it expects that as well as no error yet
+ // If this is a server, provide initial metadata with a path and
+ // authority since it expects that as well as no error yet
grpc_metadata_batch fake_md(s->arena);
fake_md.Set(grpc_core::HttpPathMetadata(),
grpc_core::Slice::FromStaticString("/"));
@@ -537,7 +528,7 @@ void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
s->recv_message_op = nullptr;
}
if (s->send_message_op) {
- s->send_message_op->payload->send_message.send_message.reset();
+ ResetSendMessage(s->send_message_op);
complete_if_batch_end_locked(
s, error, s->send_message_op,
"fail_helper scheduling send-message-on-complete");
@@ -579,35 +570,11 @@ void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
// synchronously. That assumption is true today but may not always be
// true in the future.
void message_transfer_locked(inproc_stream* sender, inproc_stream* receiver) {
- size_t remaining =
- sender->send_message_op->payload->send_message.send_message->length();
- if (receiver->recv_inited) {
- grpc_slice_buffer_destroy_internal(&receiver->recv_message);
- }
- grpc_slice_buffer_init(&receiver->recv_message);
- receiver->recv_inited = true;
- do {
- grpc_slice message_slice;
- grpc_closure unused;
- GPR_ASSERT(
- sender->send_message_op->payload->send_message.send_message->Next(
- SIZE_MAX, &unused));
- grpc_error_handle error =
- sender->send_message_op->payload->send_message.send_message->Pull(
- &message_slice);
- if (error != GRPC_ERROR_NONE) {
- cancel_stream_locked(sender, GRPC_ERROR_REF(error));
- break;
- }
- GPR_ASSERT(error == GRPC_ERROR_NONE);
- remaining -= GRPC_SLICE_LENGTH(message_slice);
- grpc_slice_buffer_add(&receiver->recv_message, message_slice);
- } while (remaining > 0);
- sender->send_message_op->payload->send_message.send_message.reset();
-
- receiver->recv_stream.Init(&receiver->recv_message, 0);
- receiver->recv_message_op->payload->recv_message.recv_message->reset(
- receiver->recv_stream.get());
+ *receiver->recv_message_op->payload->recv_message.recv_message =
+ std::move(*sender->send_message_op->payload->send_message.send_message);
+ *receiver->recv_message_op->payload->recv_message.flags =
+ sender->send_message_op->payload->send_message.flags;
+
INPROC_LOG(GPR_INFO, "message_transfer_locked %p scheduling message-ready",
receiver);
grpc_core::ExecCtx::Run(
@@ -656,7 +623,7 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
maybe_process_ops_locked(other, GRPC_ERROR_NONE);
} else if (!s->t->is_client && s->trailing_md_sent) {
// A server send will never be matched if the server already sent status
- s->send_message_op->payload->send_message.send_message.reset();
+ ResetSendMessage(s->send_message_op);
complete_if_batch_end_locked(
s, GRPC_ERROR_NONE, s->send_message_op,
"op_state_machine scheduling send-message-on-complete case 1");
@@ -797,7 +764,7 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
if (s->recv_message_op != nullptr) {
// This message needs to be wrapped up because it will never be
// satisfied
- *s->recv_message_op->payload->recv_message.recv_message = nullptr;
+ s->recv_message_op->payload->recv_message.recv_message->reset();
INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s);
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
@@ -811,7 +778,7 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
if ((s->trailing_md_sent || s->t->is_client) && s->send_message_op) {
// Nothing further will try to receive from this stream, so finish off
// any outstanding send_message op
- s->send_message_op->payload->send_message.send_message.reset();
+ ResetSendMessage(s->send_message_op);
s->send_message_op->payload->send_message.stream_write_closed = true;
complete_if_batch_end_locked(
s, new_err, s->send_message_op,
@@ -831,7 +798,8 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
// We should schedule the recv_trailing_md_op completion if
// 1. this stream is the client-side
// 2. this stream is the server-side AND has already sent its trailing md
- // (If the server hasn't already sent its trailing md, it doesn't have
+ // (If the server hasn't already sent its trailing md, it doesn't
+ // have
// a final status, so don't mark this op complete)
if (s->t->is_client || s->trailing_md_sent) {
grpc_core::ExecCtx::Run(
@@ -876,7 +844,7 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
// No further message will come on this stream, so finish off the
// recv_message_op
INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling message-ready", s);
- *s->recv_message_op->payload->recv_message.recv_message = nullptr;
+ s->recv_message_op->payload->recv_message.recv_message->reset();
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
s->recv_message_op->payload->recv_message.recv_message_ready,
@@ -889,7 +857,7 @@ void op_state_machine_locked(inproc_stream* s, grpc_error_handle error) {
if (s->trailing_md_recvd && s->send_message_op && s->t->is_client) {
// Nothing further will try to receive from this stream, so finish off
// any outstanding send_message op
- s->send_message_op->payload->send_message.send_message.reset();
+ ResetSendMessage(s->send_message_op);
complete_if_batch_end_locked(
s, new_err, s->send_message_op,
"op_state_machine scheduling send-message-on-complete case 3");
@@ -1102,7 +1070,7 @@ void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
// Consume any send message that was sent here but that we are not
// pushing to the other side
if (op->send_message) {
- op->payload->send_message.send_message.reset();
+ ResetSendMessage(op);
}
// Schedule op's closures that we didn't push to op state machine
if (op->recv_initial_metadata) {
@@ -1138,10 +1106,10 @@ void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
GRPC_ERROR_REF(error));
}
if (op->recv_trailing_metadata) {
- INPROC_LOG(
- GPR_INFO,
- "perform_stream_op error %p scheduling trailing-metadata-ready %s",
- s, grpc_error_std_string(error).c_str());
+ INPROC_LOG(GPR_INFO,
+ "perform_stream_op error %p scheduling "
+ "trailing-metadata-ready %s",
+ s, grpc_error_std_string(error).c_str());
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready,
diff --git a/src/core/lib/channel/call_tracer.h b/src/core/lib/channel/call_tracer.h
index 58b4bd1d386..c473c354ba1 100644
--- a/src/core/lib/channel/call_tracer.h
+++ b/src/core/lib/channel/call_tracer.h
@@ -29,7 +29,7 @@
#include
#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@@ -58,13 +58,13 @@ class CallTracer {
virtual void RecordOnDoneSendInitialMetadata(gpr_atm* peer_string) = 0;
virtual void RecordSendTrailingMetadata(
grpc_metadata_batch* send_trailing_metadata) = 0;
- virtual void RecordSendMessage(const ByteStream& send_message) = 0;
+ virtual void RecordSendMessage(const SliceBuffer& send_message) = 0;
// The `RecordReceivedInitialMetadata()` and `RecordReceivedMessage()`
// methods should only be invoked when the metadata/message was
// successfully received, i.e., without any error.
virtual void RecordReceivedInitialMetadata(
grpc_metadata_batch* recv_initial_metadata, uint32_t flags) = 0;
- virtual void RecordReceivedMessage(const ByteStream& recv_message) = 0;
+ virtual void RecordReceivedMessage(const SliceBuffer& recv_message) = 0;
// If the call was cancelled before the recv_trailing_metadata op
// was started, recv_trailing_metadata and transport_stream_stats
// will be null.
diff --git a/src/core/lib/gprpp/manual_constructor.h b/src/core/lib/gprpp/manual_constructor.h
index 81c3031f02f..95e57cd0e4c 100644
--- a/src/core/lib/gprpp/manual_constructor.h
+++ b/src/core/lib/gprpp/manual_constructor.h
@@ -25,12 +25,9 @@
#include
-#include
#include
#include
-#include
-
#include "src/core/lib/gprpp/construct_destruct.h"
namespace grpc_core {
@@ -102,70 +99,6 @@ class max_align_of {
} // namespace manual_ctor_impl
-template
-class PolymorphicManualConstructor {
- public:
- // No constructor or destructor because one of the most useful uses of
- // this class is as part of a union, and members of a union could not have
- // constructors or destructors till C++11. And, anyway, the whole point of
- // this class is to bypass constructor and destructor.
-
- BaseType* get() { return reinterpret_cast(&space_); }
- const BaseType* get() const {
- return reinterpret_cast(&space_);
- }
-
- BaseType* operator->() { return get(); }
- const BaseType* operator->() const { return get(); }
-
- BaseType& operator*() { return *get(); }
- const BaseType& operator*() const { return *get(); }
-
- template
- void Init() {
- FinishInit(new (&space_) DerivedType);
- }
-
- // Init() constructs the Type instance using the given arguments
- // (which are forwarded to Type's constructor).
- //
- // Note that Init() with no arguments performs default-initialization,
- // not zero-initialization (i.e it behaves the same as "new Type;", not
- // "new Type();"), so it will leave non-class types uninitialized.
- template
- void Init(Ts&&... args) {
- FinishInit(new (&space_) DerivedType(std::forward(args)...));
- }
-
- // Init() that is equivalent to copy and move construction.
- // Enables usage like this:
- // ManualConstructor> v;
- // v.Init({1, 2, 3});
- template
- void Init(const DerivedType& x) {
- FinishInit(new (&space_) DerivedType(x));
- }
- template
- void Init(DerivedType&& x) {
- FinishInit(new (&space_) DerivedType(std::forward(x)));
- }
-
- void Destroy() { get()->~BaseType(); }
-
- private:
- template
- void FinishInit(DerivedType* p) {
- static_assert(
- manual_ctor_impl::is_one_of::value,
- "DerivedType must be one of the predeclared DerivedTypes");
- GPR_ASSERT(static_cast(p) == p);
- }
-
- typename std::aligned_storage<
- manual_ctor_impl::max_size_of::value,
- manual_ctor_impl::max_align_of::value>::type space_;
-};
-
template
class ManualConstructor {
public:
diff --git a/src/core/lib/slice/slice_buffer.cc b/src/core/lib/slice/slice_buffer.cc
index b6f33237a8f..2d2ee9fc995 100644
--- a/src/core/lib/slice/slice_buffer.cc
+++ b/src/core/lib/slice/slice_buffer.cc
@@ -51,10 +51,21 @@ void SliceBuffer::Prepend(Slice slice) {
grpc_slice_buffer_undo_take_first(&slice_buffer_, slice.TakeCSlice());
}
-Slice SliceBuffer::RefSlice(size_t index) {
+Slice SliceBuffer::RefSlice(size_t index) const {
return Slice(grpc_slice_ref_internal(slice_buffer_.slices[index]));
}
+std::string SliceBuffer::JoinIntoString() const {
+ std::string result;
+ result.reserve(slice_buffer_.length);
+ for (size_t i = 0; i < slice_buffer_.count; i++) {
+ result.append(reinterpret_cast(
+ GRPC_SLICE_START_PTR(slice_buffer_.slices[i])),
+ GRPC_SLICE_LENGTH(slice_buffer_.slices[i]));
+ }
+ return result;
+}
+
} // namespace grpc_core
/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
@@ -370,6 +381,24 @@ void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer* src, size_t n,
}
}
+void grpc_slice_buffer_copy_first_into_buffer(grpc_slice_buffer* src, size_t n,
+ void* dst) {
+ uint8_t* dstp = static_cast