Merge github.com:grpc/grpc into tracer

pull/13026/head
Craig Tiller 8 years ago
commit d3d709a10f
  1. 1
      .clang_complete
  2. 3
      .gitmodules
  3. 3
      BUILD
  4. 465
      CMakeLists.txt
  5. 158
      Makefile
  6. 5
      WORKSPACE
  7. 3
      binding.gyp
  8. 58
      build.yaml
  9. 6
      doc/environment_variables.md
  10. 4
      gRPC-Core.podspec
  11. 2
      grpc.gemspec
  12. 3
      grpc.gyp
  13. 2
      include/grpc++/impl/codegen/call.h
  14. 18
      include/grpc/support/sync.h
  15. 2
      package.xml
  16. 255
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  17. 576
      src/core/ext/transport/chttp2/transport/flow_control.cc
  18. 328
      src/core/ext/transport/chttp2/transport/flow_control.h
  19. 4
      src/core/ext/transport/chttp2/transport/frame_settings.cc
  20. 10
      src/core/ext/transport/chttp2/transport/frame_window_update.cc
  21. 252
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  22. 177
      src/core/ext/transport/chttp2/transport/internal.h
  23. 17
      src/core/ext/transport/chttp2/transport/parsing.cc
  24. 32
      src/core/ext/transport/chttp2/transport/writing.cc
  25. 15
      src/core/lib/http/httpcli_security_connector.cc
  26. 1404
      src/core/lib/iomgr/ev_epollex_linux.cc
  27. 9
      src/core/lib/iomgr/ev_posix.cc
  28. 9
      src/core/lib/iomgr/exec_ctx.cc
  29. 2
      src/core/lib/iomgr/tcp_posix.cc
  30. 5
      src/core/lib/security/credentials/fake/fake_credentials.cc
  31. 2
      src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
  32. 6
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  33. 126
      src/core/lib/security/transport/security_connector.cc
  34. 34
      src/core/lib/security/transport/security_connector.h
  35. 6
      src/core/lib/support/cpu_linux.cc
  36. 41
      src/core/lib/support/memory.h
  37. 32
      src/core/lib/support/vector.h
  38. 5
      src/core/lib/transport/bdp_estimator.cc
  39. 29
      src/core/lib/transport/bdp_estimator.h
  40. 7
      src/core/lib/transport/metadata.cc
  41. 3
      src/core/lib/transport/metadata.h
  42. 53
      src/core/lib/transport/pid_controller.cc
  43. 110
      src/core/lib/transport/pid_controller.h
  44. 3
      src/cpp/client/create_channel.cc
  45. 4
      src/php/ext/grpc/server.c
  46. 4
      templates/CMakeLists.txt.template
  47. 1
      templates/tools/run_tests/generated/tests.json.template
  48. 2
      test/core/bad_client/gen_build_yaml.py
  49. 2
      test/core/bad_client/generate_tests.bzl
  50. 65
      test/core/debug/stats_test.cc
  51. 12
      test/core/end2end/bad_server_response_test.c
  52. 1
      test/core/end2end/tests/bad_ping.c
  53. 2
      test/core/end2end/tests/keepalive_timeout.c
  54. 3
      test/core/end2end/tests/max_connection_age.c
  55. 4
      test/core/end2end/tests/shutdown_finishes_calls.c
  56. 10
      test/core/iomgr/pollset_set_test.c
  57. 26
      test/core/support/BUILD
  58. 42
      test/core/support/vector_test.cc
  59. 7
      test/core/transport/BUILD
  60. 23
      test/core/transport/bdp_estimator_test.cc
  61. 99
      test/core/transport/chttp2/hpack_encoder_test.c
  62. 4
      test/core/transport/metadata_test.c
  63. 78
      test/core/transport/pid_controller_test.c
  64. 91
      test/core/transport/pid_controller_test.cc
  65. 160
      test/cpp/microbenchmarks/bm_chttp2_hpack.cc
  66. 36
      test/cpp/microbenchmarks/bm_chttp2_transport.cc
  67. 21
      test/cpp/microbenchmarks/bm_fullstack_trickle.cc
  68. 7
      test/cpp/microbenchmarks/helpers.cc
  69. 3
      test/cpp/microbenchmarks/helpers.h
  70. 1
      third_party/abseil-cpp
  71. 47
      tools/debug/core/error_ref_leak.py
  72. 13
      tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
  73. 1
      tools/doxygen/Doxyfile.c++.internal
  74. 2
      tools/doxygen/Doxyfile.core.internal
  75. 2
      tools/internal_ci/helper_scripts/gen_report_index.sh
  76. 1
      tools/internal_ci/helper_scripts/prepare_build_interop_rc
  77. 1
      tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc
  78. 2
      tools/internal_ci/linux/grpc_interop_matrix.sh
  79. 2
      tools/interop_matrix/create_matrix_images.py
  80. 8
      tools/run_tests/dockerize/build_interop_image.sh
  81. 77
      tools/run_tests/generated/sources_and_headers.json
  82. 581
      tools/run_tests/generated/tests.json
  83. 6
      tools/run_tests/performance/scenario_config.py
  84. 2
      tools/run_tests/python_utils/filter_pull_request_tests.py
  85. 12
      tools/run_tests/run_interop_tests.py
  86. 37
      tools/run_tests/run_tests.py
  87. 1
      tools/run_tests/sanity/check_sources_and_headers.py
  88. 1
      tools/run_tests/sanity/check_submodules.sh
  89. 3
      tools/run_tests/sanity/check_test_filtering.py

@ -9,3 +9,4 @@
-Ithird_party/benchmark/include -Ithird_party/benchmark/include
-Ithird_party/zlib -Ithird_party/zlib
-Ithird_party/protobuf/src -Ithird_party/protobuf/src
-Ithird_party/abseil-cpp

3
.gitmodules vendored

@ -27,3 +27,6 @@
[submodule "third_party/bloaty"] [submodule "third_party/bloaty"]
path = third_party/bloaty path = third_party/bloaty
url = https://github.com/google/bloaty.git url = https://github.com/google/bloaty.git
[submodule "third_party/abseil-cpp"]
path = third_party/abseil-cpp
url = https://github.com/abseil/abseil-cpp

@ -515,6 +515,7 @@ grpc_cc_library(
"src/core/lib/support/atomic_with_std.h", "src/core/lib/support/atomic_with_std.h",
"src/core/lib/support/env.h", "src/core/lib/support/env.h",
"src/core/lib/support/memory.h", "src/core/lib/support/memory.h",
"src/core/lib/support/vector.h",
"src/core/lib/support/manual_constructor.h", "src/core/lib/support/manual_constructor.h",
"src/core/lib/support/mpscq.h", "src/core/lib/support/mpscq.h",
"src/core/lib/support/murmur_hash.h", "src/core/lib/support/murmur_hash.h",
@ -529,6 +530,7 @@ grpc_cc_library(
public_hdrs = GPR_PUBLIC_HDRS, public_hdrs = GPR_PUBLIC_HDRS,
deps = [ deps = [
"gpr_codegen", "gpr_codegen",
"@com_google_absl//absl/container:inlined_vector"
], ],
) )
@ -1259,6 +1261,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame_data.h", "src/core/ext/transport/chttp2/transport/frame_data.h",
"src/core/ext/transport/chttp2/transport/frame_goaway.h", "src/core/ext/transport/chttp2/transport/frame_goaway.h",
"src/core/ext/transport/chttp2/transport/frame_ping.h", "src/core/ext/transport/chttp2/transport/frame_ping.h",

File diff suppressed because it is too large Load Diff

@ -327,7 +327,7 @@ CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin) ifeq ($(SYSTEM),Darwin)
CXXFLAGS += -stdlib=libc++ CXXFLAGS += -stdlib=libc++
endif endif
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Ithird_party/abseil-cpp
LDFLAGS += -g LDFLAGS += -g
CPPFLAGS += $(CPPFLAGS_$(CONFIG)) CPPFLAGS += $(CPPFLAGS_$(CONFIG))
@ -1091,7 +1091,6 @@ timer_heap_test: $(BINDIR)/$(CONFIG)/timer_heap_test
timer_list_test: $(BINDIR)/$(CONFIG)/timer_list_test timer_list_test: $(BINDIR)/$(CONFIG)/timer_list_test
transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_test transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_test
transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
@ -1180,6 +1179,8 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test
stress_test: $(BINDIR)/$(CONFIG)/stress_test stress_test: $(BINDIR)/$(CONFIG)/stress_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
vector_test: $(BINDIR)/$(CONFIG)/vector_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test
@ -1225,7 +1226,6 @@ connection_prefix_bad_client_test: $(BINDIR)/$(CONFIG)/connection_prefix_bad_cli
head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test
initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
large_metadata_bad_client_test: $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
server_registered_method_bad_client_test: $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test server_registered_method_bad_client_test: $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test
simple_request_bad_client_test: $(BINDIR)/$(CONFIG)/simple_request_bad_client_test simple_request_bad_client_test: $(BINDIR)/$(CONFIG)/simple_request_bad_client_test
unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
@ -1472,7 +1472,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/timer_list_test \ $(BINDIR)/$(CONFIG)/timer_list_test \
$(BINDIR)/$(CONFIG)/transport_connectivity_state_test \ $(BINDIR)/$(CONFIG)/transport_connectivity_state_test \
$(BINDIR)/$(CONFIG)/transport_metadata_test \ $(BINDIR)/$(CONFIG)/transport_metadata_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_test \ $(BINDIR)/$(CONFIG)/transport_security_test \
$(BINDIR)/$(CONFIG)/udp_server_test \ $(BINDIR)/$(CONFIG)/udp_server_test \
$(BINDIR)/$(CONFIG)/uri_parser_test \ $(BINDIR)/$(CONFIG)/uri_parser_test \
@ -1483,7 +1482,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \ $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
$(BINDIR)/$(CONFIG)/headers_bad_client_test \ $(BINDIR)/$(CONFIG)/headers_bad_client_test \
$(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \ $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test \
$(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \ $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \
$(BINDIR)/$(CONFIG)/simple_request_bad_client_test \ $(BINDIR)/$(CONFIG)/simple_request_bad_client_test \
$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \ $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
@ -1617,6 +1615,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/boringssl_aes_test \ $(BINDIR)/$(CONFIG)/boringssl_aes_test \
$(BINDIR)/$(CONFIG)/boringssl_asn1_test \ $(BINDIR)/$(CONFIG)/boringssl_asn1_test \
@ -1739,6 +1739,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \ $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
$(BINDIR)/$(CONFIG)/resolver_component_test \ $(BINDIR)/$(CONFIG)/resolver_component_test \
@ -1991,8 +1993,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/transport_connectivity_state_test || ( echo test transport_connectivity_state_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/transport_connectivity_state_test || ( echo test transport_connectivity_state_test failed ; exit 1 )
$(E) "[RUN] Testing transport_metadata_test" $(E) "[RUN] Testing transport_metadata_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 )
$(E) "[RUN] Testing transport_pid_controller_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing transport_security_test" $(E) "[RUN] Testing transport_security_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 )
$(E) "[RUN] Testing udp_server_test" $(E) "[RUN] Testing udp_server_test"
@ -2013,8 +2013,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing initial_settings_frame_bad_client_test" $(E) "[RUN] Testing initial_settings_frame_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing large_metadata_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test || ( echo test large_metadata_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing server_registered_method_bad_client_test" $(E) "[RUN] Testing server_registered_method_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing simple_request_bad_client_test" $(E) "[RUN] Testing simple_request_bad_client_test"
@ -2155,6 +2153,10 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 )
$(E) "[RUN] Testing thread_stress_test" $(E) "[RUN] Testing thread_stress_test"
$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
$(E) "[RUN] Testing transport_pid_controller_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing vector_test"
$(Q) $(BINDIR)/$(CONFIG)/vector_test || ( echo test vector_test failed ; exit 1 )
$(E) "[RUN] Testing writes_per_rpc_test" $(E) "[RUN] Testing writes_per_rpc_test"
$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
$(E) "[RUN] Testing resolver_component_tests_runner_invoker_unsecure" $(E) "[RUN] Testing resolver_component_tests_runner_invoker_unsecure"
@ -13419,38 +13421,6 @@ endif
endif endif
TRANSPORT_PID_CONTROLLER_TEST_SRC = \
test/core/transport/pid_controller_test.c \
TRANSPORT_PID_CONTROLLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_PID_CONTROLLER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/transport_pid_controller_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/transport_pid_controller_test
endif
$(OBJDIR)/$(CONFIG)/test/core/transport/pid_controller_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
endif
endif
TRANSPORT_SECURITY_TEST_SRC = \ TRANSPORT_SECURITY_TEST_SRC = \
test/core/tsi/transport_security_test.c \ test/core/tsi/transport_security_test.c \
@ -17201,6 +17171,92 @@ endif
endif endif
TRANSPORT_PID_CONTROLLER_TEST_SRC = \
test/core/transport/pid_controller_test.cc \
TRANSPORT_PID_CONTROLLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_PID_CONTROLLER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/transport_pid_controller_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/transport_pid_controller_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/transport_pid_controller_test: $(PROTOBUF_DEP) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/transport_pid_controller_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/transport/pid_controller_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep)
endif
endif
VECTOR_TEST_SRC = \
test/core/support/vector_test.cc \
VECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(VECTOR_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/vector_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/vector_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/vector_test: $(PROTOBUF_DEP) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/vector_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/support/vector_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_vector_test: $(VECTOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(VECTOR_TEST_OBJS:.o=.dep)
endif
endif
WRITES_PER_RPC_TEST_SRC = \ WRITES_PER_RPC_TEST_SRC = \
test/cpp/performance/writes_per_rpc_test.cc \ test/cpp/performance/writes_per_rpc_test.cc \
@ -18482,26 +18538,6 @@ ifneq ($(NO_DEPS),true)
endif endif
LARGE_METADATA_BAD_CLIENT_TEST_SRC = \
test/core/bad_client/tests/large_metadata.c \
LARGE_METADATA_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LARGE_METADATA_BAD_CLIENT_TEST_SRC))))
$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test: $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/large_metadata.o: $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_large_metadata_bad_client_test: $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS:.o=.dep)
ifneq ($(NO_DEPS),true)
-include $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS:.o=.dep)
endif
SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC = \ SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC = \
test/core/bad_client/tests/server_registered_method.c \ test/core/bad_client/tests/server_registered_method.c \

@ -92,3 +92,8 @@ new_local_repository(
path = "third_party/cares", path = "third_party/cares",
build_file = "third_party/cares/cares.BUILD", build_file = "third_party/cares/cares.BUILD",
) )
local_repository(
name = "com_google_absl",
path = "third_party/abseil-cpp",
)

@ -63,6 +63,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
], ],
'ldflags': [ 'ldflags': [
'-g', '-g',
@ -184,6 +185,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
], ],
'OTHER_CPLUSPLUSFLAGS': [ 'OTHER_CPLUSPLUSFLAGS': [
'-g', '-g',
@ -193,6 +195,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
'-stdlib=libc++', '-stdlib=libc++',
'-std=c++11', '-std=c++11',
'-Wno-error=deprecated-declarations' '-Wno-error=deprecated-declarations'

@ -427,6 +427,7 @@ filegroups:
- src/core/lib/slice/slice_hash_table.h - src/core/lib/slice/slice_hash_table.h
- src/core/lib/slice/slice_internal.h - src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_string_helpers.h - src/core/lib/slice/slice_string_helpers.h
- src/core/lib/support/vector.h
- src/core/lib/surface/alarm_internal.h - src/core/lib/surface/alarm_internal.h
- src/core/lib/surface/api_trace.h - src/core/lib/surface/api_trace.h
- src/core/lib/surface/call.h - src/core/lib/surface/call.h
@ -777,6 +778,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/bin_decoder.h - src/core/ext/transport/chttp2/transport/bin_decoder.h
- src/core/ext/transport/chttp2/transport/bin_encoder.h - src/core/ext/transport/chttp2/transport/bin_encoder.h
- src/core/ext/transport/chttp2/transport/chttp2_transport.h - src/core/ext/transport/chttp2/transport/chttp2_transport.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.h
- src/core/ext/transport/chttp2/transport/frame_data.h - src/core/ext/transport/chttp2/transport/frame_data.h
- src/core/ext/transport/chttp2/transport/frame_goaway.h - src/core/ext/transport/chttp2/transport/frame_goaway.h
@ -3405,18 +3407,6 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
uses_polling: false
- name: transport_pid_controller_test
build: test
language: c
src:
- test/core/transport/pid_controller_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: transport_security_test - name: transport_security_test
build: test build: test
language: c language: c
@ -3555,6 +3545,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3577,6 +3568,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3599,6 +3591,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3621,6 +3614,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3642,6 +3636,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3663,6 +3658,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3684,6 +3680,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=4 - --benchmark_min_time=4
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3705,6 +3702,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3729,6 +3727,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
excluded_poll_engines: excluded_poll_engines:
- poll - poll
@ -3756,6 +3755,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
excluded_poll_engines: excluded_poll_engines:
- poll - poll
@ -3782,6 +3782,7 @@ targets:
- grpc++_test_config - grpc++_test_config
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
excluded_poll_engines: excluded_poll_engines:
- poll - poll
@ -3809,6 +3810,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
excluded_poll_engines: excluded_poll_engines:
- poll - poll
@ -3834,6 +3836,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -3856,6 +3859,7 @@ targets:
- gpr - gpr
args: args:
- --benchmark_min_time=0 - --benchmark_min_time=0
benchmark: true
defaults: benchmark defaults: benchmark
platforms: platforms:
- mac - mac
@ -4719,6 +4723,9 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
exclude_configs:
- tsan
timeout_seconds: 1200
uses_polling: false uses_polling: false
- name: status_test - name: status_test
build: test build: test
@ -4801,6 +4808,32 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
timeout_seconds: 1200 timeout_seconds: 1200
- name: transport_pid_controller_test
build: test
language: c++
src:
- test/core/transport/pid_controller_test.cc
deps:
- grpc++_test_util
- grpc++
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: vector_test
gtest: true
build: test
language: c++
src:
- test/core/support/vector_test.cc
deps:
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
uses:
- grpc++_test
- name: writes_per_rpc_test - name: writes_per_rpc_test
gtest: true gtest: true
cpu_cost: 0.5 cpu_cost: 0.5
@ -4982,6 +5015,7 @@ defaults:
-D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
global: global:
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Ithird_party/abseil-cpp
LDFLAGS: -g LDFLAGS: -g
zlib: zlib:
CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration

@ -49,6 +49,7 @@ some configuration as environment variables that can be set.
- connectivity_state - traces connectivity state changes to channels - connectivity_state - traces connectivity state changes to channels
- channel_stack_builder - traces information about channel stacks being built - channel_stack_builder - traces information about channel stacks being built
- executor - traces grpc's internal thread pool ('the executor') - executor - traces grpc's internal thread pool ('the executor')
- glb - traces the grpclb load balancer
- http - traces state in the http2 transport engine - http - traces state in the http2 transport engine
- http2_stream_state - traces all http2 stream state mutations. - http2_stream_state - traces all http2 stream state mutations.
- http1 - traces HTTP/1.x operations performed by gRPC - http1 - traces HTTP/1.x operations performed by gRPC
@ -56,11 +57,12 @@ some configuration as environment variables that can be set.
- flowctl - traces http2 flow control - flowctl - traces http2 flow control
- op_failure - traces error information when failure is pushed onto a - op_failure - traces error information when failure is pushed onto a
completion queue completion queue
- round_robin - traces the round_robin load balancing policy
- pick_first - traces the pick first load balancing policy - pick_first - traces the pick first load balancing policy
- plugin_credentials - traces plugin credentials - plugin_credentials - traces plugin credentials
- pollable_refcount - traces reference counting of 'pollable' objects (only
in DEBUG)
- resource_quota - trace resource quota objects internals - resource_quota - trace resource quota objects internals
- glb - traces the grpclb load balancer - round_robin - traces the round_robin load balancing policy
- queue_pluck - queue_pluck
- queue_timeout - queue_timeout
- server_channel - lightweight trace of significant server channel events - server_channel - lightweight trace of significant server channel events

@ -249,6 +249,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.h', 'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.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.h',
'src/core/ext/transport/chttp2/transport/frame_data.h', 'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h', 'src/core/ext/transport/chttp2/transport/frame_goaway.h',
@ -409,6 +410,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h', 'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/support/vector.h',
'src/core/lib/surface/alarm_internal.h', 'src/core/lib/surface/alarm_internal.h',
'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h', 'src/core/lib/surface/call.h',
@ -750,6 +752,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.h', 'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.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.h',
'src/core/ext/transport/chttp2/transport/frame_data.h', 'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h', 'src/core/ext/transport/chttp2/transport/frame_goaway.h',
@ -910,6 +913,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h', 'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/support/vector.h',
'src/core/lib/surface/alarm_internal.h', 'src/core/lib/surface/alarm_internal.h',
'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h', 'src/core/lib/surface/call.h',

@ -181,6 +181,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h ) s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h )
s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.h )
@ -341,6 +342,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice_hash_table.h ) s.files += %w( src/core/lib/slice/slice_hash_table.h )
s.files += %w( src/core/lib/slice/slice_internal.h ) s.files += %w( src/core/lib/slice/slice_internal.h )
s.files += %w( src/core/lib/slice/slice_string_helpers.h ) s.files += %w( src/core/lib/slice/slice_string_helpers.h )
s.files += %w( src/core/lib/support/vector.h )
s.files += %w( src/core/lib/surface/alarm_internal.h ) s.files += %w( src/core/lib/surface/alarm_internal.h )
s.files += %w( src/core/lib/surface/api_trace.h ) s.files += %w( src/core/lib/surface/api_trace.h )
s.files += %w( src/core/lib/surface/call.h ) s.files += %w( src/core/lib/surface/call.h )

@ -57,6 +57,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
], ],
'ldflags': [ 'ldflags': [
'-g', '-g',
@ -134,6 +135,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
], ],
'OTHER_CPLUSPLUSFLAGS': [ 'OTHER_CPLUSPLUSFLAGS': [
'-g', '-g',
@ -143,6 +145,7 @@
'-Wno-long-long', '-Wno-long-long',
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1', '-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
'-stdlib=libc++', '-stdlib=libc++',
'-std=c++11', '-std=c++11',
'-Wno-error=deprecated-declarations' '-Wno-error=deprecated-declarations'

@ -163,7 +163,7 @@ class WriteOptions {
/// Clears flag indicating that this is the last message in a stream, /// Clears flag indicating that this is the last message in a stream,
/// disabling coalescing. /// disabling coalescing.
inline WriteOptions& clear_last_messsage() { inline WriteOptions& clear_last_message() {
last_message_ = false; last_message_ = false;
return *this; return *this;
} }

@ -274,7 +274,23 @@ GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c);
#endif /* 0 */ #endif /* 0 */
#ifdef __cplusplus #ifdef __cplusplus
} } // extern "C"
namespace grpc_core {
class mu_guard {
public:
mu_guard(gpr_mu *mu) : mu_(mu) { gpr_mu_lock(mu); }
~mu_guard() { gpr_mu_unlock(mu_); }
mu_guard(const mu_guard &) = delete;
mu_guard &operator=(const mu_guard &) = delete;
private:
gpr_mu *const mu_;
};
} // namespace grpc_core
#endif #endif
#endif /* GRPC_SUPPORT_SYNC_H */ #endif /* GRPC_SUPPORT_SYNC_H */

@ -193,6 +193,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/flow_control.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.h" role="src" />
@ -353,6 +354,7 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/vector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/alarm_internal.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/alarm_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />

@ -54,7 +54,6 @@
#include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport.h"
#include "src/core/lib/transport/transport_impl.h" #include "src/core/lib/transport/transport_impl.h"
#define DEFAULT_WINDOW 65535
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu #define MAX_WINDOW 0x7fffffffu
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
@ -151,10 +150,14 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error); grpc_error *error);
static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t);
static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error); grpc_error *error);
static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error); grpc_error *error);
static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx,
void *tp, grpc_error *error);
static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error); grpc_error *error);
@ -217,8 +220,9 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
t->write_cb_pool = next; t->write_cb_pool = next;
} }
t->flow_control.bdp_estimator.Destroy(); t->flow_control.Destroy();
GRPC_ERROR_UNREF(t->closed_with_error);
gpr_free(t->ping_acks); gpr_free(t->ping_acks);
gpr_free(t->peer_string); gpr_free(t->peer_string);
gpr_free(t); gpr_free(t);
@ -276,10 +280,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->endpoint_reading = 1; t->endpoint_reading = 1;
t->next_stream_id = is_client ? 1 : 2; t->next_stream_id = is_client ? 1 : 2;
t->is_client = is_client; t->is_client = is_client;
t->flow_control.remote_window = DEFAULT_WINDOW;
t->flow_control.announced_window = DEFAULT_WINDOW;
t->flow_control.target_initial_window_size = DEFAULT_WINDOW;
t->flow_control.t = t;
t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
t->is_first_frame = true; t->is_first_frame = true;
grpc_connectivity_state_init( grpc_connectivity_state_init(
@ -304,6 +304,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_combiner_scheduler(t->combiner)); grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
grpc_combiner_scheduler(t->combiner)); grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
next_bdp_ping_timer_expired_locked, t,
grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked, GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked,
t, grpc_combiner_scheduler(t->combiner)); t, grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked, GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
@ -316,8 +319,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
keepalive_watchdog_fired_locked, t, keepalive_watchdog_fired_locked, t,
grpc_combiner_scheduler(t->combiner)); grpc_combiner_scheduler(t->combiner));
t->flow_control.bdp_estimator.Init(t->peer_string);
grpc_chttp2_goaway_parser_init(&t->goaway_parser); grpc_chttp2_goaway_parser_init(&t->goaway_parser);
grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser); grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
@ -341,8 +342,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
window -- this should by rights be 0 */ window -- this should by rights be 0 */
t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
t->sent_local_settings = 0; t->sent_local_settings = 0;
t->write_buffer_size = DEFAULT_WINDOW; t->write_buffer_size = grpc_core::chttp2::kDefaultWindow;
t->flow_control.enable_bdp_probe = true;
if (is_client) { if (is_client) {
grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string( grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
@ -387,6 +387,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
bool enable_bdp = true;
if (channel_args) { if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) { for (i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key, if (0 == strcmp(channel_args->args[i].key,
@ -447,8 +449,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
&channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}); &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE});
} else if (0 == } else if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
t->flow_control.enable_bdp_probe = enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
grpc_channel_arg_get_integer(&channel_args->args[i], {1, 0, 1});
} else if (0 == strcmp(channel_args->args[i].key, } else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_KEEPALIVE_TIME_MS)) { GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer( const int value = grpc_channel_arg_get_integer(
@ -543,6 +544,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
} }
} }
t->flow_control.Init(exec_ctx, t, enable_bdp);
/* No pings allowed before receiving a header or data frame. */ /* No pings allowed before receiving a header or data frame. */
t->ping_state.pings_before_data_required = 0; t->ping_state.pings_before_data_required = 0;
t->ping_state.is_delayed_ping_timer_set = false; t->ping_state.is_delayed_ping_timer_set = false;
@ -563,10 +566,13 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
} }
grpc_chttp2_act_on_flowctl_action( if (enable_bdp) {
exec_ctx, GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t, schedule_bdp_ping_locked(exec_ctx, t);
NULL);
grpc_chttp2_act_on_flowctl_action(
exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, NULL);
}
grpc_chttp2_initiate_write(exec_ctx, t, grpc_chttp2_initiate_write(exec_ctx, t,
GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE);
@ -596,7 +602,9 @@ static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
static void close_transport_locked(grpc_exec_ctx *exec_ctx, static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_error *error) { grpc_error *error) {
if (!t->closed) { end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error));
if (t->closed_with_error == GRPC_ERROR_NONE) {
if (!grpc_error_has_clear_grpc_status(error)) { if (!grpc_error_has_clear_grpc_status(error)) {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE); GRPC_STATUS_UNAVAILABLE);
@ -611,13 +619,16 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_error_add_child(t->close_transport_on_writes_finished, error); grpc_error_add_child(t->close_transport_on_writes_finished, error);
return; return;
} }
t->closed = 1; GPR_ASSERT(error != GRPC_ERROR_NONE);
t->closed_with_error = GRPC_ERROR_REF(error);
connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN, connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(error), "close_transport"); GRPC_ERROR_REF(error), "close_transport");
grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
if (t->ping_state.is_delayed_ping_timer_set) { if (t->ping_state.is_delayed_ping_timer_set) {
grpc_timer_cancel(exec_ctx, &t->ping_state.delayed_ping_timer); grpc_timer_cancel(exec_ctx, &t->ping_state.delayed_ping_timer);
} }
if (t->have_next_bdp_ping_timer) {
grpc_timer_cancel(exec_ctx, &t->next_bdp_ping_timer);
}
switch (t->keepalive_state) { switch (t->keepalive_state) {
case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING: case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING:
grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
@ -637,8 +648,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
while (grpc_chttp2_list_pop_writable_stream(t, &s)) { while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
} }
end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); GPR_ASSERT(t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE);
cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
} }
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }
@ -699,7 +710,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
post_destructive_reclaimer(exec_ctx, t); post_destructive_reclaimer(exec_ctx, t);
} }
s->flow_control.s = s; s->flow_control.Init(t->flow_control.get(), s);
GPR_TIMER_END("init_stream", 0); GPR_TIMER_END("init_stream", 0);
return 0; return 0;
@ -750,7 +761,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
GRPC_ERROR_UNREF(s->write_closed_error); GRPC_ERROR_UNREF(s->write_closed_error);
GRPC_ERROR_UNREF(s->byte_stream_error); GRPC_ERROR_UNREF(s->byte_stream_error);
grpc_chttp2_flowctl_destroy_stream(&t->flow_control, &s->flow_control); s->flow_control.Destroy();
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream"); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream");
@ -941,7 +952,8 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_mark_stream_writable(grpc_exec_ctx *exec_ctx, void grpc_chttp2_mark_stream_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s) { grpc_chttp2_stream *s) {
if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) { if (t->closed_with_error == GRPC_ERROR_NONE &&
grpc_chttp2_list_add_writable_stream(t, s)) {
GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become"); GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become");
} }
} }
@ -994,7 +1006,7 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE); GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
grpc_chttp2_begin_write_result r; grpc_chttp2_begin_write_result r;
if (t->closed) { if (t->closed_with_error != GRPC_ERROR_NONE) {
r.writing = false; r.writing = false;
} else { } else {
r = grpc_chttp2_begin_write(exec_ctx, t); r = grpc_chttp2_begin_write(exec_ctx, t);
@ -1457,7 +1469,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} }
if (!s->write_closed) { if (!s->write_closed) {
if (t->is_client) { if (t->is_client) {
if (!t->closed) { if (t->closed_with_error == GRPC_ERROR_NONE) {
GPR_ASSERT(s->id == 0); GPR_ASSERT(s->id == 0);
grpc_chttp2_list_add_waiting_for_concurrency(t, s); grpc_chttp2_list_add_waiting_for_concurrency(t, s);
maybe_start_some_streams(exec_ctx, t); maybe_start_some_streams(exec_ctx, t);
@ -1465,7 +1477,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, exec_ctx, t, s,
grpc_error_set_int( grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"), GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Transport closed", &t->closed_with_error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
} }
} else { } else {
@ -1617,13 +1630,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (s->id != 0) { if (s->id != 0) {
if (!s->read_closed) { if (!s->read_closed) {
already_received = s->frame_storage.length; already_received = s->frame_storage.length;
grpc_chttp2_flowctl_incoming_bs_update( s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
&t->flow_control, &s->flow_control, GRPC_HEADER_SIZE_IN_BYTES, already_received);
already_received); grpc_chttp2_act_on_flowctl_action(exec_ctx,
grpc_chttp2_act_on_flowctl_action( s->flow_control->MakeAction(), t, s);
exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
&s->flow_control),
t, s);
} }
} }
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
@ -1687,6 +1697,7 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* callback remaining pings: they're not allowed to call into the transpot, /* callback remaining pings: they're not allowed to call into the transpot,
and maybe they hold resources that need to be freed */ and maybe they hold resources that need to be freed */
grpc_chttp2_ping_queue *pq = &t->ping_queue; grpc_chttp2_ping_queue *pq = &t->ping_queue;
GPR_ASSERT(error != GRPC_ERROR_NONE);
for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) { for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) {
grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error)); grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]); GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]);
@ -1696,6 +1707,12 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure *on_initiate, grpc_closure *on_ack) { grpc_closure *on_initiate, grpc_closure *on_ack) {
if (t->closed_with_error != GRPC_ERROR_NONE) {
GRPC_CLOSURE_SCHED(exec_ctx, on_initiate,
GRPC_ERROR_REF(t->closed_with_error));
GRPC_CLOSURE_SCHED(exec_ctx, on_ack, GRPC_ERROR_REF(t->closed_with_error));
return;
}
grpc_chttp2_ping_queue *pq = &t->ping_queue; grpc_chttp2_ping_queue *pq = &t->ping_queue;
grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate, grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate,
GRPC_ERROR_NONE); GRPC_ERROR_NONE);
@ -1754,7 +1771,9 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
/*The transport will be closed after the write is done */ /*The transport will be closed after the write is done */
close_transport_locked( close_transport_locked(
exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings")); exec_ctx, t, grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
} }
} }
@ -2390,57 +2409,46 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
* INPUT PROCESSING - PARSING * INPUT PROCESSING - PARSING
*/ */
void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, template <class F>
grpc_chttp2_flowctl_action action, static void WithUrgency(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_transport *t, grpc_core::chttp2::FlowControlAction::Urgency urgency,
grpc_chttp2_stream *s) { grpc_chttp2_initiate_write_reason reason, F action) {
switch (action.send_stream_update) { switch (urgency) {
case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: case grpc_core::chttp2::FlowControlAction::Urgency::NO_ACTION_NEEDED:
break; break;
case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: case grpc_core::chttp2::FlowControlAction::Urgency::UPDATE_IMMEDIATELY:
grpc_chttp2_mark_stream_writable(exec_ctx, t, s); grpc_chttp2_initiate_write(exec_ctx, t, reason);
grpc_chttp2_initiate_write( // fallthrough
exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL); case grpc_core::chttp2::FlowControlAction::Urgency::QUEUE_UPDATE:
action();
break; break;
case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE:
grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
break;
}
switch (action.send_transport_update) {
case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED:
break;
case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY:
grpc_chttp2_initiate_write(
exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL);
break;
// this is the same as no action b/c every time the transport enters the
// writing path it will maybe do an update
case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE:
break;
}
if (action.send_setting_update != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) {
if (action.initial_window_size > 0) {
queue_setting_update(exec_ctx, t,
GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
(uint32_t)action.initial_window_size);
}
if (action.max_frame_size > 0) {
queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
(uint32_t)action.max_frame_size);
}
if (action.send_setting_update == GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY) {
grpc_chttp2_initiate_write(exec_ctx, t,
GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS);
}
}
if (action.need_ping) {
GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
t->flow_control.bdp_estimator->SchedulePing();
send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
&t->finish_bdp_ping_locked);
} }
} }
void grpc_chttp2_act_on_flowctl_action(
grpc_exec_ctx *exec_ctx, const grpc_core::chttp2::FlowControlAction &action,
grpc_chttp2_transport *t, grpc_chttp2_stream *s) {
WithUrgency(
exec_ctx, t, action.send_stream_update(),
GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL,
[exec_ctx, t, s]() { grpc_chttp2_mark_stream_writable(exec_ctx, t, s); });
WithUrgency(exec_ctx, t, action.send_transport_update(),
GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL, []() {});
WithUrgency(exec_ctx, t, action.send_initial_window_update(),
GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS,
[exec_ctx, t, &action]() {
queue_setting_update(exec_ctx, t,
GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
action.initial_window_size());
});
WithUrgency(
exec_ctx, t, action.send_max_frame_size_update(),
GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [exec_ctx, t, &action]() {
queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
action.max_frame_size());
});
}
static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) { grpc_chttp2_transport *t) {
grpc_http_parser parser; grpc_http_parser parser;
@ -2488,13 +2496,13 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
} }
GPR_SWAP(grpc_error *, err, error); GPR_SWAP(grpc_error *, err, error);
GRPC_ERROR_UNREF(err); GRPC_ERROR_UNREF(err);
if (!t->closed) { if (t->closed_with_error == GRPC_ERROR_NONE) {
GPR_TIMER_BEGIN("reading_action.parse", 0); GPR_TIMER_BEGIN("reading_action.parse", 0);
size_t i = 0; size_t i = 0;
grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
GRPC_ERROR_NONE}; GRPC_ERROR_NONE};
for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) { for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
t->flow_control.bdp_estimator->AddIncomingBytes( t->flow_control->bdp_estimator()->AddIncomingBytes(
(int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i])); (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]));
errors[1] = errors[1] =
grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]); grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]);
@ -2511,8 +2519,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_END("reading_action.parse", 0); GPR_TIMER_END("reading_action.parse", 0);
GPR_TIMER_BEGIN("post_parse_locked", 0); GPR_TIMER_BEGIN("post_parse_locked", 0);
if (t->flow_control.initial_window_update != 0) { if (t->initial_window_update != 0) {
if (t->flow_control.initial_window_update > 0) { if (t->initial_window_update > 0) {
grpc_chttp2_stream *s; grpc_chttp2_stream *s;
while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) { while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) {
grpc_chttp2_mark_stream_writable(exec_ctx, t, s); grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
@ -2521,20 +2529,21 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING); GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING);
} }
} }
t->flow_control.initial_window_update = 0; t->initial_window_update = 0;
} }
GPR_TIMER_END("post_parse_locked", 0); GPR_TIMER_END("post_parse_locked", 0);
} }
GPR_TIMER_BEGIN("post_reading_action_locked", 0); GPR_TIMER_BEGIN("post_reading_action_locked", 0);
bool keep_reading = false; bool keep_reading = false;
if (error == GRPC_ERROR_NONE && t->closed) { if (error == GRPC_ERROR_NONE && t->closed_with_error != GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"); error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Transport closed", &t->closed_with_error, 1);
} }
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0; t->endpoint_reading = 0;
} else if (!t->closed) { } else if (t->closed_with_error == GRPC_ERROR_NONE) {
keep_reading = true; keep_reading = true;
GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading"); GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
} }
@ -2543,10 +2552,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (keep_reading) { if (keep_reading) {
grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer,
&t->read_action_locked); &t->read_action_locked);
grpc_chttp2_act_on_flowctl_action( grpc_chttp2_act_on_flowctl_action(exec_ctx, t->flow_control->MakeAction(),
exec_ctx, t, NULL);
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
NULL);
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
} else { } else {
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action");
@ -2559,28 +2566,60 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_END("reading_action_locked", 0); GPR_TIMER_END("reading_action_locked", 0);
} }
// t is reffed prior to calling the first time, and once the callback chain
// that kicks off finishes, it's unreffed
static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
t->flow_control->bdp_estimator()->SchedulePing();
send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
&t->finish_bdp_ping_locked);
}
static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error) { grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
if (grpc_http_trace.enabled()) { if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string); gpr_log(GPR_DEBUG, "%s: Start BDP ping err=%s", t->peer_string,
grpc_error_string(error));
} }
/* Reset the keepalive ping timer */ /* Reset the keepalive ping timer */
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) { if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
} }
t->flow_control.bdp_estimator->StartPing(); t->flow_control->bdp_estimator()->StartPing();
} }
static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error) { grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
if (grpc_http_trace.enabled()) { if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string); gpr_log(GPR_DEBUG, "%s: Complete BDP ping err=%s", t->peer_string,
grpc_error_string(error));
} }
t->flow_control.bdp_estimator->CompletePing(exec_ctx); if (error != GRPC_ERROR_NONE) {
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
return;
}
grpc_millis next_ping =
t->flow_control->bdp_estimator()->CompletePing(exec_ctx);
grpc_chttp2_act_on_flowctl_action(
exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, nullptr);
GPR_ASSERT(!t->have_next_bdp_ping_timer);
t->have_next_bdp_ping_timer = true;
grpc_timer_init(exec_ctx, &t->next_bdp_ping_timer, next_ping,
&t->next_bdp_ping_timer_expired_locked);
}
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx,
void *tp, grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
GPR_ASSERT(t->have_next_bdp_ping_timer);
t->have_next_bdp_ping_timer = false;
if (error != GRPC_ERROR_NONE) {
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
return;
}
schedule_bdp_ping_locked(exec_ctx, t);
} }
void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args, void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
@ -2645,7 +2684,7 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) { grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg; grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg;
GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING); GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
if (t->destroying || t->closed) { if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
} else if (error == GRPC_ERROR_NONE) { } else if (error == GRPC_ERROR_NONE) {
if (t->keepalive_permit_without_calls || if (t->keepalive_permit_without_calls ||
@ -2703,8 +2742,11 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING( close_transport_locked(
"keepalive watchdog timeout")); exec_ctx, t,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"keepalive watchdog timeout"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL));
} }
} else { } else {
/* The watchdog timer should have been cancelled by /* The watchdog timer should have been cancelled by
@ -2787,13 +2829,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
size_t cur_length = s->frame_storage.length; size_t cur_length = s->frame_storage.length;
if (!s->read_closed) { if (!s->read_closed) {
grpc_chttp2_flowctl_incoming_bs_update(&t->flow_control, &s->flow_control, s->flow_control->IncomingByteStreamUpdate(bs->next_action.max_size_hint,
bs->next_action.max_size_hint, cur_length);
cur_length); grpc_chttp2_act_on_flowctl_action(exec_ctx, s->flow_control->MakeAction(),
grpc_chttp2_act_on_flowctl_action( t, s);
exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
&s->flow_control),
t, s);
} }
GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
if (s->frame_storage.length > 0) { if (s->frame_storage.length > 0) {

@ -16,7 +16,7 @@
* *
*/ */
#include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/ext/transport/chttp2/transport/flow_control.h"
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
@ -28,38 +28,15 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
static uint32_t grpc_chttp2_target_announced_window( namespace grpc_core {
const grpc_chttp2_transport_flowctl* tfc); namespace chttp2 {
#ifndef NDEBUG namespace {
typedef struct {
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;
uint32_t local_init_window;
uint32_t local_max_frame;
} shadow_flow_control;
static void pretrace(shadow_flow_control* shadow_fc,
grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc) {
shadow_fc->remote_window = tfc->remote_window;
shadow_fc->target_window = grpc_chttp2_target_announced_window(tfc);
shadow_fc->announced_window = tfc->announced_window;
if (sfc != NULL) {
shadow_fc->remote_window_delta = sfc->remote_window_delta;
shadow_fc->local_window_delta = sfc->local_window_delta;
shadow_fc->announced_window_delta = sfc->announced_window_delta;
}
}
#define TRACE_PADDING 30 static constexpr const int kTracePadding = 30;
static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) { static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
char* str; char* str;
@ -68,7 +45,7 @@ static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
} else { } else {
gpr_asprintf(&str, "%" PRId64 "", old_val); gpr_asprintf(&str, "%" PRId64 "", old_val);
} }
char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); char* str_lp = gpr_leftpad(str, ' ', kTracePadding);
gpr_free(str); gpr_free(str);
return str_lp; return str_lp;
} }
@ -80,47 +57,58 @@ static char* fmt_uint32_diff_str(uint32_t old_val, uint32_t new_val) {
} else { } else {
gpr_asprintf(&str, "%" PRIu32 "", old_val); gpr_asprintf(&str, "%" PRIu32 "", old_val);
} }
char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); char* str_lp = gpr_leftpad(str, ' ', kTracePadding);
gpr_free(str); gpr_free(str);
return str_lp; return str_lp;
} }
} // 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();
}
}
static void posttrace(shadow_flow_control* shadow_fc, void FlowControlTrace::Finish() {
grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc, const char* reason) {
uint32_t acked_local_window = uint32_t acked_local_window =
tfc->t->settings[GRPC_SENT_SETTINGS] tfc_->transport()->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
uint32_t remote_window = uint32_t remote_window =
tfc->t->settings[GRPC_PEER_SETTINGS] tfc_->transport()->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
char* trw_str = char* trw_str = fmt_int64_diff_str(remote_window_, tfc_->remote_window());
fmt_int64_diff_str(shadow_fc->remote_window, tfc->remote_window); char* tlw_str = fmt_int64_diff_str(target_window_, tfc_->target_window());
char* tlw_str = fmt_int64_diff_str(shadow_fc->target_window,
grpc_chttp2_target_announced_window(tfc));
char* taw_str = char* taw_str =
fmt_int64_diff_str(shadow_fc->announced_window, tfc->announced_window); fmt_int64_diff_str(announced_window_, tfc_->announced_window());
char* srw_str; char* srw_str;
char* slw_str; char* slw_str;
char* saw_str; char* saw_str;
if (sfc != NULL) { if (sfc_ != nullptr) {
srw_str = fmt_int64_diff_str(shadow_fc->remote_window_delta + remote_window, srw_str = fmt_int64_diff_str(remote_window_delta_ + remote_window,
sfc->remote_window_delta + remote_window); sfc_->remote_window_delta() + remote_window);
slw_str = slw_str = fmt_int64_diff_str(local_window_delta_ + acked_local_window,
fmt_int64_diff_str(shadow_fc->local_window_delta + acked_local_window, 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,
saw_str = fmt_int64_diff_str( announced_window_delta_ + acked_local_window);
shadow_fc->announced_window_delta + acked_local_window,
sfc->announced_window_delta + acked_local_window);
} else { } else {
srw_str = gpr_leftpad("", ' ', TRACE_PADDING); srw_str = gpr_leftpad("", ' ', kTracePadding);
slw_str = gpr_leftpad("", ' ', TRACE_PADDING); slw_str = gpr_leftpad("", ' ', kTracePadding);
saw_str = gpr_leftpad("", ' ', TRACE_PADDING); saw_str = gpr_leftpad("", ' ', kTracePadding);
} }
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s", "%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s",
tfc, sfc != NULL ? sfc->s->id : 0, tfc->t->is_client ? "cli" : "svr", tfc_, sfc_ != nullptr ? sfc_->stream()->id : 0,
reason, trw_str, tlw_str, taw_str, srw_str, slw_str, saw_str); 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(trw_str);
gpr_free(tlw_str); gpr_free(tlw_str);
gpr_free(taw_str); gpr_free(taw_str);
@ -129,13 +117,13 @@ static void posttrace(shadow_flow_control* shadow_fc,
gpr_free(saw_str); gpr_free(saw_str);
} }
static const char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) { const char* FlowControlAction::UrgencyString(Urgency u) {
switch (urgency) { switch (u) {
case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: case Urgency::NO_ACTION_NEEDED:
return "no action"; return "no action";
case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: case Urgency::UPDATE_IMMEDIATELY:
return "update immediately"; return "update immediately";
case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: case Urgency::QUEUE_UPDATE:
return "queue update"; return "queue update";
default: default:
GPR_UNREACHABLE_CODE(return "unknown"); GPR_UNREACHABLE_CODE(return "unknown");
@ -143,209 +131,132 @@ static const char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) {
GPR_UNREACHABLE_CODE(return "unknown"); GPR_UNREACHABLE_CODE(return "unknown");
} }
static void trace_action(grpc_chttp2_transport_flowctl* tfc, void FlowControlAction::Trace(grpc_chttp2_transport* t) const {
grpc_chttp2_flowctl_action action) {
char* iw_str = fmt_uint32_diff_str( char* iw_str = fmt_uint32_diff_str(
tfc->t->settings[GRPC_SENT_SETTINGS] t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], initial_window_size_);
action.initial_window_size);
char* mf_str = fmt_uint32_diff_str( char* mf_str = fmt_uint32_diff_str(
tfc->t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
action.max_frame_size); max_frame_size_);
gpr_log(GPR_DEBUG, "t[%s], s[%s], settings[%s] iw:%s mf:%s", gpr_log(GPR_DEBUG, "t[%s], s[%s], iw:%s:%s mf:%s:%s",
urgency_to_string(action.send_transport_update), UrgencyString(send_transport_update_),
urgency_to_string(action.send_stream_update), UrgencyString(send_stream_update_),
urgency_to_string(action.send_setting_update), iw_str, mf_str); UrgencyString(send_initial_window_update_), iw_str,
UrgencyString(send_max_frame_size_update_), mf_str);
gpr_free(iw_str); gpr_free(iw_str);
gpr_free(mf_str); gpr_free(mf_str);
} }
#define PRETRACE(tfc, sfc) \ TransportFlowControl::TransportFlowControl(grpc_exec_ctx* exec_ctx,
shadow_flow_control shadow_fc; \ const grpc_chttp2_transport* t,
GRPC_FLOW_CONTROL_IF_TRACING(pretrace(&shadow_fc, tfc, sfc)) bool enable_bdp_probe)
#define POSTTRACE(tfc, sfc, reason) \ : t_(t),
GRPC_FLOW_CONTROL_IF_TRACING(posttrace(&shadow_fc, tfc, sfc, reason)) enable_bdp_probe_(enable_bdp_probe),
#define TRACEACTION(tfc, action) \ bdp_estimator_(t->peer_string),
GRPC_FLOW_CONTROL_IF_TRACING(trace_action(tfc, action)) pid_controller_(grpc_core::PidController::Args()
#else .set_gain_p(4)
#define PRETRACE(tfc, sfc) .set_gain_i(8)
#define POSTTRACE(tfc, sfc, reason) .set_gain_d(0)
#define TRACEACTION(tfc, action) .set_initial_control_value(TargetLogBdp())
#endif .set_min_control_value(-1)
.set_max_control_value(25)
/* How many bytes of incoming flow control would we like to advertise */ .set_integral_range(10)),
static uint32_t grpc_chttp2_target_announced_window( last_pid_update_(grpc_exec_ctx_now(exec_ctx)) {}
const grpc_chttp2_transport_flowctl* tfc) {
return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1), uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
tfc->announced_stream_total_over_incoming_window + FlowControlTrace trace("t updt sent", this, nullptr);
tfc->target_initial_window_size); const uint32_t target_announced_window = target_window();
} if ((writing_anyway || announced_window_ <= target_announced_window / 2) &&
announced_window_ != target_announced_window) {
// we have sent data on the wire, we must track this in our bookkeeping for the const uint32_t announce = (uint32_t)GPR_CLAMP(
// remote peer's flow control. target_announced_window - announced_window_, 0, UINT32_MAX);
void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl* tfc, announced_window_ += announce;
grpc_chttp2_stream_flowctl* sfc, return announce;
int64_t size) {
PRETRACE(tfc, sfc);
tfc->remote_window -= size;
sfc->remote_window_delta -= size;
POSTTRACE(tfc, sfc, " data sent");
}
static void announced_window_delta_preupdate(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc) {
if (sfc->announced_window_delta > 0) {
tfc->announced_stream_total_over_incoming_window -=
sfc->announced_window_delta;
} else {
tfc->announced_stream_total_under_incoming_window +=
-sfc->announced_window_delta;
}
}
static void announced_window_delta_postupdate(
grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) {
if (sfc->announced_window_delta > 0) {
tfc->announced_stream_total_over_incoming_window +=
sfc->announced_window_delta;
} else {
tfc->announced_stream_total_under_incoming_window -=
-sfc->announced_window_delta;
} }
return 0;
} }
// We have received data from the wire. We must track this in our own flow grpc_error* TransportFlowControl::ValidateRecvData(
// control bookkeeping. int64_t incoming_frame_size) {
// Returns an error if the incoming frame violates our flow control. if (incoming_frame_size > announced_window_) {
grpc_error* grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc,
int64_t incoming_frame_size) {
uint32_t sent_init_window =
tfc->t->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
uint32_t acked_init_window =
tfc->t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
PRETRACE(tfc, sfc);
if (incoming_frame_size > tfc->announced_window) {
char* msg; char* msg;
gpr_asprintf(&msg, gpr_asprintf(&msg,
"frame of size %" PRId64 " overflows local window of %" PRId64, "frame of size %" PRId64 " overflows local window of %" PRId64,
incoming_frame_size, tfc->announced_window); incoming_frame_size, announced_window_);
grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg); gpr_free(msg);
return err; return err;
} }
return GRPC_ERROR_NONE;
}
if (sfc != NULL) { StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc,
int64_t acked_stream_window = const grpc_chttp2_stream* s)
sfc->announced_window_delta + acked_init_window; : tfc_(tfc), s_(s) {}
int64_t sent_stream_window = sfc->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 {
char* msg;
gpr_asprintf(&msg, "frame of size %" PRId64
" overflows local window of %" PRId64,
incoming_frame_size, acked_stream_window);
grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
}
announced_window_delta_preupdate(tfc, sfc);
sfc->announced_window_delta -= incoming_frame_size;
announced_window_delta_postupdate(tfc, sfc);
sfc->local_window_delta -= incoming_frame_size;
}
tfc->announced_window -= incoming_frame_size; grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) {
FlowControlTrace trace(" data recv", tfc_, this);
POSTTRACE(tfc, sfc, " data recv"); grpc_error* error = GRPC_ERROR_NONE;
return GRPC_ERROR_NONE; error = tfc_->ValidateRecvData(incoming_frame_size);
} if (error != GRPC_ERROR_NONE) return error;
// Returns a non zero announce integer if we should send a transport window uint32_t sent_init_window =
// update tfc_->transport()->settings[GRPC_SENT_SETTINGS]
uint32_t grpc_chttp2_flowctl_maybe_send_transport_update( [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
grpc_chttp2_transport_flowctl* tfc, bool writing_anyway) { uint32_t acked_init_window =
PRETRACE(tfc, NULL); tfc_->transport()->settings[GRPC_ACKED_SETTINGS]
uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
uint32_t threshold_to_send_transport_window_update =
tfc->t->outbuf.count > 0 ? 3 * target_announced_window / 4 int64_t acked_stream_window = announced_window_delta_ + acked_init_window;
: target_announced_window / 2; int64_t sent_stream_window = announced_window_delta_ + sent_init_window;
if ((writing_anyway || if (incoming_frame_size > acked_stream_window) {
tfc->announced_window <= threshold_to_send_transport_window_update) && if (incoming_frame_size <= sent_stream_window) {
tfc->announced_window != target_announced_window) { gpr_log(GPR_ERROR,
uint32_t announce = (uint32_t)GPR_CLAMP( "Incoming frame of size %" PRId64
target_announced_window - tfc->announced_window, 0, UINT32_MAX); " exceeds local window size of %" PRId64
tfc->announced_window += announce; ".\n"
POSTTRACE(tfc, NULL, "t updt sent"); "The (un-acked, future) window size would be %" PRId64
return announce; " 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 {
char* msg;
gpr_asprintf(&msg, "frame of size %" PRId64
" overflows local window of %" PRId64,
incoming_frame_size, acked_stream_window);
grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return err;
}
} }
GRPC_FLOW_CONTROL_IF_TRACING(
gpr_log(GPR_DEBUG, "%p[0][%s] will not send transport update", tfc, UpdateAnnouncedWindowDelta(tfc_, -incoming_frame_size);
tfc->t->is_client ? "cli" : "svr")); local_window_delta_ -= incoming_frame_size;
return 0; tfc_->CommitRecvData(incoming_frame_size);
return GRPC_ERROR_NONE;
} }
// Returns a non zero announce integer if we should send a stream window update uint32_t StreamFlowControl::MaybeSendUpdate() {
uint32_t grpc_chttp2_flowctl_maybe_send_stream_update( FlowControlTrace trace("s updt sent", tfc_, this);
grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { if (local_window_delta_ > announced_window_delta_) {
PRETRACE(tfc, sfc);
if (sfc->local_window_delta > sfc->announced_window_delta) {
uint32_t announce = (uint32_t)GPR_CLAMP( uint32_t announce = (uint32_t)GPR_CLAMP(
sfc->local_window_delta - sfc->announced_window_delta, 0, UINT32_MAX); local_window_delta_ - announced_window_delta_, 0, UINT32_MAX);
announced_window_delta_preupdate(tfc, sfc); UpdateAnnouncedWindowDelta(tfc_, announce);
sfc->announced_window_delta += announce;
announced_window_delta_postupdate(tfc, sfc);
POSTTRACE(tfc, sfc, "s updt sent");
return announce; return announce;
} }
GRPC_FLOW_CONTROL_IF_TRACING(
gpr_log(GPR_DEBUG, "%p[%u][%s] will not send stream update", tfc,
sfc->s->id, tfc->t->is_client ? "cli" : "svr"));
return 0; return 0;
} }
// we have received a WINDOW_UPDATE frame for a transport void StreamFlowControl::IncomingByteStreamUpdate(size_t max_size_hint,
void grpc_chttp2_flowctl_recv_transport_update( size_t have_already) {
grpc_chttp2_transport_flowctl* tfc, uint32_t size) { FlowControlTrace trace("app st recv", tfc_, this);
PRETRACE(tfc, NULL);
tfc->remote_window += size;
POSTTRACE(tfc, NULL, "t updt recv");
}
// we have received a WINDOW_UPDATE frame for a stream
void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc,
uint32_t size) {
PRETRACE(tfc, sfc);
sfc->remote_window_delta += size;
POSTTRACE(tfc, sfc, "s updt recv");
}
void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc,
size_t max_size_hint,
size_t have_already) {
PRETRACE(tfc, sfc);
uint32_t max_recv_bytes; uint32_t max_recv_bytes;
uint32_t sent_init_window = uint32_t sent_init_window =
tfc->t->settings[GRPC_SENT_SETTINGS] tfc_->transport()->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
/* clamp max recv hint to an allowable size */ /* clamp max recv hint to an allowable size */
if (max_size_hint >= UINT32_MAX - sent_init_window) { if (max_size_hint >= UINT32_MAX - sent_init_window) {
@ -363,68 +274,18 @@ void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl* tfc,
/* add some small lookahead to keep pipelines flowing */ /* add some small lookahead to keep pipelines flowing */
GPR_ASSERT(max_recv_bytes <= UINT32_MAX - sent_init_window); GPR_ASSERT(max_recv_bytes <= UINT32_MAX - sent_init_window);
if (sfc->local_window_delta < max_recv_bytes) { if (local_window_delta_ < max_recv_bytes) {
uint32_t add_max_recv_bytes = uint32_t add_max_recv_bytes =
(uint32_t)(max_recv_bytes - sfc->local_window_delta); (uint32_t)(max_recv_bytes - local_window_delta_);
sfc->local_window_delta += add_max_recv_bytes; local_window_delta_ += add_max_recv_bytes;
}
POSTTRACE(tfc, sfc, "app st recv");
}
void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc) {
announced_window_delta_preupdate(tfc, sfc);
}
// Returns an urgency with which to make an update
static grpc_chttp2_flowctl_urgency delta_is_significant(
const grpc_chttp2_transport_flowctl* tfc, int32_t value,
grpc_chttp2_setting_id setting_id) {
int64_t delta = (int64_t)value -
(int64_t)tfc->t->settings[GRPC_LOCAL_SETTINGS][setting_id];
// TODO(ncteisen): tune this
if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) {
return GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE;
} else {
return GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED;
} }
} }
// Takes in a target and uses the pid controller to return a stabilized
// guess at the new bdp.
static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx,
grpc_chttp2_transport_flowctl* tfc,
double target) {
grpc_millis now = grpc_exec_ctx_now(exec_ctx);
if (!tfc->pid_controller_initialized) {
tfc->last_pid_update = now;
tfc->pid_controller_initialized = true;
grpc_pid_controller_args args;
memset(&args, 0, sizeof(args));
args.gain_p = 4;
args.gain_i = 8;
args.gain_d = 0;
args.initial_control_value = target;
args.min_control_value = -1;
args.max_control_value = 25;
args.integral_range = 10;
grpc_pid_controller_init(&tfc->pid_controller, args);
return pow(2, target);
}
double bdp_error = target - grpc_pid_controller_last(&tfc->pid_controller);
double dt = (double)(now - tfc->last_pid_update) * 1e-3;
double log2_bdp_guess =
grpc_pid_controller_update(&tfc->pid_controller, bdp_error, dt);
tfc->last_pid_update = now;
return pow(2, log2_bdp_guess);
}
// Take in a target and modifies it based on the memory pressure of the system // Take in a target and modifies it based on the memory pressure of the system
static double get_target_under_memory_pressure( static double AdjustForMemoryPressure(grpc_resource_quota* quota,
grpc_chttp2_transport_flowctl* tfc, double target) { double target) {
// do not increase window under heavy memory pressure. // do not increase window under heavy memory pressure.
double memory_pressure = grpc_resource_quota_get_memory_pressure( double memory_pressure = grpc_resource_quota_get_memory_pressure(quota);
grpc_resource_user_quota(grpc_endpoint_get_resource_user(tfc->t->ep)));
static const double kLowMemPressure = 0.1; static const double kLowMemPressure = 0.1;
static const double kZeroTarget = 22; static const double kZeroTarget = 22;
static const double kHighMemPressure = 0.8; static const double kHighMemPressure = 0.8;
@ -439,77 +300,82 @@ static double get_target_under_memory_pressure(
return target; return target;
} }
grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( double TransportFlowControl::TargetLogBdp() {
grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc, return AdjustForMemoryPressure(
grpc_chttp2_stream_flowctl* sfc) { grpc_resource_user_quota(grpc_endpoint_get_resource_user(t_->ep)),
grpc_chttp2_flowctl_action action; 1 + log2(bdp_estimator_.EstimateBdp()));
memset(&action, 0, sizeof(action)); }
double TransportFlowControl::SmoothLogBdp(grpc_exec_ctx* exec_ctx,
double value) {
grpc_millis now = grpc_exec_ctx_now(exec_ctx);
double bdp_error = value - pid_controller_.last_control_value();
const double dt = (double)(now - last_pid_update_) * 1e-3;
last_pid_update_ = now;
return pid_controller_.Update(bdp_error, dt);
}
FlowControlAction::Urgency TransportFlowControl::DeltaUrgency(
int32_t value, grpc_chttp2_setting_id setting_id) {
int64_t delta =
(int64_t)value - (int64_t)t_->settings[GRPC_LOCAL_SETTINGS][setting_id];
// TODO(ncteisen): tune this // TODO(ncteisen): tune this
if (sfc != NULL && !sfc->s->read_closed) { if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) {
uint32_t sent_init_window = return FlowControlAction::Urgency::QUEUE_UPDATE;
tfc->t->settings[GRPC_SENT_SETTINGS] } else {
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; return FlowControlAction::Urgency::NO_ACTION_NEEDED;
if ((int64_t)sfc->local_window_delta >
(int64_t)sfc->announced_window_delta &&
(int64_t)sfc->announced_window_delta + sent_init_window <=
sent_init_window / 2) {
action.send_stream_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY;
} else if (sfc->local_window_delta > sfc->announced_window_delta) {
action.send_stream_update = GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE;
}
} }
if (tfc->enable_bdp_probe) { }
action.need_ping = tfc->bdp_estimator->NeedPing(exec_ctx);
FlowControlAction TransportFlowControl::PeriodicUpdate(
grpc_exec_ctx* exec_ctx) {
FlowControlAction action;
if (enable_bdp_probe_) {
// get bdp estimate and update initial_window accordingly. // get bdp estimate and update initial_window accordingly.
int64_t estimate = -1; // target might change based on how much memory pressure we are under
if (tfc->bdp_estimator->EstimateBdp(&estimate)) { // TODO(ncteisen): experiment with setting target to be huge under low
double target = 1 + log2((double)estimate); // memory pressure.
const double target = pow(2, SmoothLogBdp(exec_ctx, TargetLogBdp()));
// target might change based on how much memory pressure we are under
// TODO(ncteisen): experiment with setting target to be huge under low // Though initial window 'could' drop to 0, we keep the floor at 128
// memory pressure. target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX);
target = get_target_under_memory_pressure(tfc, target);
action.set_send_initial_window_update(
// run our target through the pid controller to stabilize change. DeltaUrgency(target_initial_window_size_,
// TODO(ncteisen): experiment with other controllers here. GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE),
double bdp_guess = get_pid_controller_guess(exec_ctx, tfc, target); target_initial_window_size_);
// Though initial window 'could' drop to 0, we keep the floor at 128
tfc->target_initial_window_size =
(int32_t)GPR_CLAMP(bdp_guess, 128, INT32_MAX);
grpc_chttp2_flowctl_urgency init_window_update_urgency =
delta_is_significant(tfc, tfc->target_initial_window_size,
GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
if (init_window_update_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) {
action.send_setting_update = init_window_update_urgency;
action.initial_window_size = (uint32_t)tfc->target_initial_window_size;
}
}
// get bandwidth estimate and update max_frame accordingly. // get bandwidth estimate and update max_frame accordingly.
double bw_dbl = -1; double bw_dbl = bdp_estimator_.EstimateBandwidth();
if (tfc->bdp_estimator->EstimateBandwidth(&bw_dbl)) { // we target the max of BDP or bandwidth in microseconds.
// we target the max of BDP or bandwidth in microseconds. int32_t frame_size = (int32_t)GPR_CLAMP(
int32_t frame_size = (int32_t)GPR_CLAMP( GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000, target_initial_window_size_),
tfc->target_initial_window_size), 16384, 16777215);
16384, 16777215); action.set_send_max_frame_size_update(
grpc_chttp2_flowctl_urgency frame_size_urgency = delta_is_significant( DeltaUrgency(frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE),
tfc, frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE); frame_size);
if (frame_size_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) {
if (frame_size_urgency > action.send_setting_update) {
action.send_setting_update = frame_size_urgency;
}
action.max_frame_size = (uint32_t)frame_size;
}
}
} }
uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); return UpdateAction(action);
if (tfc->announced_window < target_announced_window / 2) { }
action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY;
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) {
action.set_send_stream_update(
FlowControlAction::Urgency::UPDATE_IMMEDIATELY);
} else if (local_window_delta_ > announced_window_delta_) {
action.set_send_stream_update(FlowControlAction::Urgency::QUEUE_UPDATE);
}
} }
TRACEACTION(tfc, action);
return action; return action;
} }
} // namespace chttp2
} // namespace grpc_core

@ -0,0 +1,328 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
#include <stdint.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/http2_settings.h"
#include "src/core/lib/support/manual_constructor.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 "C" grpc_tracer_flag grpc_flowctl_trace;
namespace grpc_core {
namespace chttp2 {
static constexpr uint32_t kDefaultWindow = 65535;
class TransportFlowControl;
class StreamFlowControl;
class FlowControlAction {
public:
enum class Urgency : uint8_t {
// Nothing to be done.
NO_ACTION_NEEDED = 0,
// Initiate a write to update the initial window immediately.
UPDATE_IMMEDIATELY,
// Push the flow control update into a send buffer, to be sent
// out the next time a write is initiated.
QUEUE_UPDATE,
};
Urgency send_stream_update() const { return send_stream_update_; }
Urgency send_transport_update() const { return send_transport_update_; }
Urgency send_initial_window_update() const {
return send_initial_window_update_;
}
Urgency send_max_frame_size_update() const {
return send_max_frame_size_update_;
}
uint32_t initial_window_size() const { return initial_window_size_; }
uint32_t max_frame_size() const { return max_frame_size_; }
FlowControlAction& set_send_stream_update(Urgency u) {
send_stream_update_ = u;
return *this;
}
FlowControlAction& set_send_transport_update(Urgency u) {
send_transport_update_ = u;
return *this;
}
FlowControlAction& set_send_initial_window_update(Urgency u,
uint32_t update) {
send_initial_window_update_ = u;
initial_window_size_ = update;
return *this;
}
FlowControlAction& set_send_max_frame_size_update(Urgency u,
uint32_t update) {
send_max_frame_size_update_ = u;
max_frame_size_ = update;
return *this;
}
static const char* UrgencyString(Urgency u);
void Trace(grpc_chttp2_transport* t) const;
private:
Urgency send_stream_update_ = Urgency::NO_ACTION_NEEDED;
Urgency send_transport_update_ = Urgency::NO_ACTION_NEEDED;
Urgency send_initial_window_update_ = Urgency::NO_ACTION_NEEDED;
Urgency send_max_frame_size_update_ = Urgency::NO_ACTION_NEEDED;
uint32_t initial_window_size_ = 0;
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_TRACER_ON(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_;
};
class TransportFlowControl {
public:
TransportFlowControl(grpc_exec_ctx* exec_ctx, const grpc_chttp2_transport* t,
bool enable_bdp_probe);
~TransportFlowControl() {}
bool bdp_probe() const { return enable_bdp_probe_; }
// returns an announce if we should send a transport update to our peer,
// 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);
// Reads the flow control data and returns and actionable struct that will
// tell chttp2 exactly what it needs to do
FlowControlAction MakeAction() { return UpdateAction(FlowControlAction()); }
// 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(grpc_exec_ctx* exec_ctx);
void StreamSentData(int64_t size) { remote_window_ -= size; }
grpc_error* ValidateRecvData(int64_t incoming_frame_size);
void CommitRecvData(int64_t incoming_frame_size) {
announced_window_ -= incoming_frame_size;
}
grpc_error* RecvData(int64_t incoming_frame_size) {
FlowControlTrace trace(" data recv", this, nullptr);
grpc_error* error = ValidateRecvData(incoming_frame_size);
if (error != GRPC_ERROR_NONE) return error;
CommitRecvData(incoming_frame_size);
return GRPC_ERROR_NONE;
}
// we have received a WINDOW_UPDATE frame for a transport
void RecvUpdate(uint32_t size) {
FlowControlTrace trace("t updt recv", this, nullptr);
remote_window_ += size;
}
int64_t remote_window() const { return remote_window_; }
int64_t target_window() const {
return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1),
announced_stream_total_over_incoming_window_ +
target_initial_window_size_);
}
int64_t announced_window() const { return announced_window_; }
const grpc_chttp2_transport* transport() const { return t_; }
void PreUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) {
if (delta > 0) {
announced_stream_total_over_incoming_window_ -= delta;
} else {
announced_stream_total_under_incoming_window_ += -delta;
}
}
void PostUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) {
if (delta > 0) {
announced_stream_total_over_incoming_window_ += delta;
} else {
announced_stream_total_under_incoming_window_ -= -delta;
}
}
BdpEstimator* bdp_estimator() { return &bdp_estimator_; }
void TestOnlyForceHugeWindow() {
announced_window_ = 1024 * 1024 * 1024;
remote_window_ = 1024 * 1024 * 1024;
}
private:
double TargetLogBdp();
double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value);
FlowControlAction::Urgency DeltaUrgency(int32_t value,
grpc_chttp2_setting_id setting_id);
FlowControlAction UpdateAction(FlowControlAction action) {
if (announced_window_ < target_window() / 2) {
action.set_send_transport_update(
FlowControlAction::Urgency::UPDATE_IMMEDIATELY);
}
return action;
}
const grpc_chttp2_transport* const t_;
/** Our bookkeeping for the remote peer's available window */
int64_t remote_window_ = kDefaultWindow;
/** calculating what we should give for local window:
we track the total amount of flow control over initial window size
across all streams: this is data that we want to receive right now (it
has an outstanding read)
and the total amount of flow control under initial window size across all
streams: this is data we've read early
we want to adjust incoming_window such that:
incoming_window = total_over - max(bdp - total_under, 0) */
int64_t announced_stream_total_over_incoming_window_ = 0;
int64_t announced_stream_total_under_incoming_window_ = 0;
/** This is out window according to what we have sent to our remote peer. The
* difference between this and target window is what we use to decide when
* to send WINDOW_UPDATE frames. */
int64_t announced_window_ = kDefaultWindow;
int32_t target_initial_window_size_ = kDefaultWindow;
/** should we probe bdp? */
const bool enable_bdp_probe_;
/* bdp estimation */
grpc_core::BdpEstimator bdp_estimator_;
/* pid controller */
grpc_core::PidController pid_controller_;
grpc_millis last_pid_update_ = 0;
};
class StreamFlowControl {
public:
StreamFlowControl(TransportFlowControl* tfc, const grpc_chttp2_stream* s);
~StreamFlowControl() {
tfc_->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
}
FlowControlAction UpdateAction(FlowControlAction action);
FlowControlAction MakeAction() { return UpdateAction(tfc_->MakeAction()); }
// 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) {
FlowControlTrace tracer(" data sent", tfc_, this);
tfc_->StreamSentData(outgoing_frame_size);
remote_window_delta_ -= outgoing_frame_size;
}
// we have received data from the wire
grpc_error* RecvData(int64_t incoming_frame_size);
// returns an announce if we should send a stream update to our peer, else
// returns zero
uint32_t MaybeSendUpdate();
// we have received a WINDOW_UPDATE frame for a stream
void RecvUpdate(uint32_t size) {
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);
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() {
announced_window_delta_ = 1024 * 1024 * 1024;
local_window_delta_ = 1024 * 1024 * 1024;
remote_window_delta_ = 1024 * 1024 * 1024;
}
private:
TransportFlowControl* const tfc_;
const grpc_chttp2_stream* const s_;
void UpdateAnnouncedWindowDelta(TransportFlowControl* tfc, int64_t change) {
tfc->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
announced_window_delta_ += change;
tfc->PostUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_);
}
/** window available for us to send to peer, over or under the initial
* window
* size of the transport... ie:
* remote_window = remote_window_delta + transport.initial_window_size */
int64_t remote_window_delta_ = 0;
/** window available for peer to send to us (as a delta on
* transport.initial_window_size)
* local_window = local_window_delta + transport.initial_window_size */
int64_t local_window_delta_ = 0;
/** window available for peer to send to us over this stream that we have
* announced to the peer */
int64_t announced_window_delta_ = 0;
};
} // namespace chttp2
} // namespace grpc_core
#endif

@ -202,12 +202,12 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
} }
if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
parser->incoming_settings[id] != parser->value) { parser->incoming_settings[id] != parser->value) {
t->flow_control.initial_window_update += t->initial_window_update +=
(int64_t)parser->value - parser->incoming_settings[id]; (int64_t)parser->value - parser->incoming_settings[id];
if (grpc_http_trace.enabled() || grpc_flowctl_trace.enabled()) { if (grpc_http_trace.enabled() || grpc_flowctl_trace.enabled()) {
gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change", gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change",
t, t->is_client ? "cli" : "svr", t, t->is_client ? "cli" : "svr",
(int)t->flow_control.initial_window_update); (int)t->initial_window_update);
} }
} }
parser->incoming_settings[id] = parser->value; parser->incoming_settings[id] = parser->value;

@ -96,8 +96,7 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
if (t->incoming_stream_id != 0) { if (t->incoming_stream_id != 0) {
if (s != NULL) { if (s != NULL) {
grpc_chttp2_flowctl_recv_stream_update( s->flow_control->RecvUpdate(received_update);
&t->flow_control, &s->flow_control, received_update);
if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) { if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) {
grpc_chttp2_mark_stream_writable(exec_ctx, t, s); grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
grpc_chttp2_initiate_write( grpc_chttp2_initiate_write(
@ -106,10 +105,9 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
} }
} }
} else { } else {
bool was_zero = t->flow_control.remote_window <= 0; bool was_zero = t->flow_control->remote_window() <= 0;
grpc_chttp2_flowctl_recv_transport_update(&t->flow_control, t->flow_control->RecvUpdate(received_update);
received_update); bool is_zero = t->flow_control->remote_window() <= 0;
bool is_zero = t->flow_control.remote_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
grpc_chttp2_initiate_write( grpc_chttp2_initiate_write(
exec_ctx, t, exec_ctx, t,

@ -178,24 +178,19 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) {
c->table_elems--; c->table_elems--;
} }
/* add an element to the decoder table */ // Reserve space in table for the new element, evict entries if needed.
static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, // Return the new index of the element. Return 0 to indicate not adding to
grpc_mdelem elem) { // table.
GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem)); static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor *c,
size_t elem_size) {
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
uint32_t new_index = c->tail_remote_index + c->table_elems + 1; uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
GPR_ASSERT(elem_size < 65536); GPR_ASSERT(elem_size < 65536);
if (elem_size > c->max_table_size) { if (elem_size > c->max_table_size) {
while (c->table_size > 0) { while (c->table_size > 0) {
evict_entry(c); evict_entry(c);
} }
return; return 0;
} }
/* Reserve space for this element in the remote table: if this overflows /* Reserve space for this element in the remote table: if this overflows
@ -209,37 +204,26 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
c->table_size = (uint16_t)(c->table_size + elem_size); c->table_size = (uint16_t)(c->table_size + elem_size);
c->table_elems++; c->table_elems++;
/* Store this element into {entries,indices}_elem */ return new_index;
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { }
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; /* dummy function */
} else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], static void add_nothing(grpc_exec_ctx *exec_ctx,
elem)) { grpc_chttp2_hpack_compressor *c, grpc_mdelem elem,
/* already there (cuckoo): update with new index */ size_t elem_size) {}
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { // Add a key to the dynamic table. Both key and value will be added to table at
/* not there, but a free element: add */ // the decoder.
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); static void add_key_with_index(grpc_exec_ctx *exec_ctx,
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; grpc_chttp2_hpack_compressor *c,
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { grpc_mdelem elem, uint32_t new_index) {
/* not there (cuckoo), but a free element: add */ if (new_index == 0) {
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); return;
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} }
/* do exactly the same for the key (so we can find by that again too) */ uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
/* Store the key into {entries,indices}_keys */
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem))) { GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
@ -272,6 +256,63 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
} }
} }
/* add an element to the decoder table */
static void add_elem_with_index(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, uint32_t new_index) {
if (new_index == 0) {
return;
}
GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
/* Store this element into {entries,indices}_elem */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
/* not there, but a free element: add */
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) {
/* not there (cuckoo), but a free element: add */
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else {
/* not there: replace oldest */
GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
}
add_key_with_index(exec_ctx, c, elem, new_index);
}
static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, size_t elem_size) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_elem_with_index(exec_ctx, c, elem, new_index);
}
static void add_key(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, size_t elem_size) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_key_with_index(exec_ctx, c, elem, new_index);
}
static void emit_indexed(grpc_exec_ctx *exec_ctx, static void emit_indexed(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c, uint32_t elem_index, grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
framer_state *st) { framer_state *st) {
@ -363,7 +404,9 @@ static void emit_lithdr_noidx(grpc_exec_ctx *exec_ctx,
static void emit_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, static void emit_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, framer_state *st) { uint32_t unused_index, grpc_mdelem elem,
framer_state *st) {
GPR_ASSERT(unused_index == 0);
GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V(exec_ctx); GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V(exec_ctx);
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx); GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx);
uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
@ -385,7 +428,9 @@ static void emit_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
static void emit_lithdr_noidx_v(grpc_exec_ctx *exec_ctx, static void emit_lithdr_noidx_v(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, framer_state *st) { uint32_t unused_index, grpc_mdelem elem,
framer_state *st) {
GPR_ASSERT(unused_index == 0);
GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V(exec_ctx); GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V(exec_ctx);
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx); GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx);
uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
@ -430,9 +475,14 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
"Reserved header (colon-prefixed) happening after regular ones."); "Reserved header (colon-prefixed) happening after regular ones.");
} }
if (grpc_http_trace.enabled() && !GRPC_MDELEM_IS_INTERNED(elem)) { if (grpc_http_trace.enabled()) {
char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem)); char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
char *v = grpc_slice_to_c_string(GRPC_MDVALUE(elem)); char *v = NULL;
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
v = grpc_dump_slice(GRPC_MDVALUE(elem), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(elem));
}
gpr_log( gpr_log(
GPR_DEBUG, GPR_DEBUG,
"Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d", "Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",
@ -442,64 +492,70 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
gpr_free(k); gpr_free(k);
gpr_free(v); gpr_free(v);
} }
if (!GRPC_MDELEM_IS_INTERNED(elem)) {
emit_lithdr_noidx_v(exec_ctx, c, elem, st); bool elem_interned = GRPC_MDELEM_IS_INTERNED(elem);
bool key_interned = elem_interned || grpc_slice_is_interned(GRPC_MDKEY(elem));
// Key is not interned, emit literals.
if (!key_interned) {
emit_lithdr_noidx_v(exec_ctx, c, 0, elem, st);
return; return;
} }
uint32_t key_hash; uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t value_hash; uint32_t elem_hash = 0;
uint32_t elem_hash;
size_t decoder_space_usage;
uint32_t indices_key;
int should_add_elem;
key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); if (elem_interned) {
value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum,
c->filter_elems);
/* is this elem currently in the decoders table? */ /* is this elem currently in the decoders table? */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) && if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */ /* HIT: complete element (first cuckoo hash) */
emit_indexed(exec_ctx, c, emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st); dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st);
return; return;
} }
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) && if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */ /* HIT: complete element (second cuckoo hash) */
emit_indexed(exec_ctx, c, emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st); dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st);
return; return;
}
} }
uint32_t indices_key;
/* should this elem be in the table? */ /* should this elem be in the table? */
decoder_space_usage = grpc_mdelem_get_size_in_hpack_table(elem); size_t decoder_space_usage =
should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE && grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= bool should_add_elem = elem_interned &&
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
void (*maybe_add)(grpc_exec_ctx *, grpc_chttp2_hpack_compressor *,
grpc_mdelem, size_t) =
should_add_elem ? add_elem : add_nothing;
void (*emit)(grpc_exec_ctx *, grpc_chttp2_hpack_compressor *, uint32_t,
grpc_mdelem, framer_state *) =
should_add_elem ? emit_lithdr_incidx : emit_lithdr_noidx;
/* no hits for the elem... maybe there's a key? */ /* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem)) && GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) { indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */ /* HIT: key (first cuckoo hash) */
if (should_add_elem) { emit(exec_ctx, c, dynidx(c, indices_key), elem, st);
emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); maybe_add(exec_ctx, c, elem, decoder_space_usage);
add_elem(exec_ctx, c, elem); return;
return;
} else {
emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
return;
}
GPR_UNREACHABLE_CODE(return );
} }
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
@ -507,28 +563,20 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
GRPC_MDKEY(elem)) && GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) { indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */ /* HIT: key (first cuckoo hash) */
if (should_add_elem) { emit(exec_ctx, c, dynidx(c, indices_key), elem, st);
emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); maybe_add(exec_ctx, c, elem, decoder_space_usage);
add_elem(exec_ctx, c, elem); return;
return;
} else {
emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
return;
}
GPR_UNREACHABLE_CODE(return );
} }
/* no elem, key in the table... fall back to literal emission */ /* no elem, key in the table... fall back to literal emission */
bool should_add_key =
if (should_add_elem) { !elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE;
emit_lithdr_incidx_v(exec_ctx, c, elem, st); emit = (should_add_elem || should_add_key) ? emit_lithdr_incidx_v
add_elem(exec_ctx, c, elem); : emit_lithdr_noidx_v;
return; maybe_add =
} else { should_add_elem ? add_elem : (should_add_key ? add_key : add_nothing);
emit_lithdr_noidx_v(exec_ctx, c, elem, st); emit(exec_ctx, c, 0, elem, st);
return; maybe_add(exec_ctx, c, elem, decoder_space_usage);
}
GPR_UNREACHABLE_CODE(return );
} }
#define STRLEN_LIT(x) (sizeof(x) - 1) #define STRLEN_LIT(x) (sizeof(x) - 1)

@ -22,6 +22,7 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#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.h"
#include "src/core/ext/transport/chttp2/transport/frame_data.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_goaway.h"
@ -38,9 +39,7 @@
#include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/manual_constructor.h" #include "src/core/lib/support/manual_constructor.h"
#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/pid_controller.h"
#include "src/core/lib/transport/transport_impl.h" #include "src/core/lib/transport/transport_impl.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -238,48 +237,6 @@ typedef enum {
GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED, GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED,
} grpc_chttp2_keepalive_state; } grpc_chttp2_keepalive_state;
typedef struct {
/** 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 */
int64_t initial_window_update;
/** Our bookkeeping for the remote peer's available window */
int64_t remote_window;
/** calculating what we should give for local window:
we track the total amount of flow control over initial window size
across all streams: this is data that we want to receive right now (it
has an outstanding read)
and the total amount of flow control under initial window size across all
streams: this is data we've read early
we want to adjust incoming_window such that:
incoming_window = total_over - max(bdp - total_under, 0) */
int64_t announced_stream_total_over_incoming_window;
int64_t announced_stream_total_under_incoming_window;
/** This is out window according to what we have sent to our remote peer. The
* difference between this and target window is what we use to decide when
* to send WINDOW_UPDATE frames. */
int64_t announced_window;
int32_t target_initial_window_size;
/** should we probe bdp? */
bool enable_bdp_probe;
/* bdp estimation */
grpc_core::ManualConstructor<grpc_core::BdpEstimator> bdp_estimator;
/* pid controller */
bool pid_controller_initialized;
grpc_pid_controller pid_controller;
grpc_millis last_pid_update;
// pointer back to transport for tracing
const grpc_chttp2_transport *t;
} grpc_chttp2_transport_flowctl;
struct grpc_chttp2_transport { struct grpc_chttp2_transport {
grpc_transport base; /* must be first */ grpc_transport base; /* must be first */
gpr_refcount refs; gpr_refcount refs;
@ -298,7 +255,7 @@ struct grpc_chttp2_transport {
/** is the transport destroying itself? */ /** is the transport destroying itself? */
uint8_t destroying; uint8_t destroying;
/** has the upper layer closed the transport? */ /** has the upper layer closed the transport? */
uint8_t closed; grpc_error *closed_with_error;
/** is there a read request to the endpoint outstanding? */ /** is there a read request to the endpoint outstanding? */
uint8_t endpoint_reading; uint8_t endpoint_reading;
@ -340,7 +297,7 @@ struct grpc_chttp2_transport {
/** hpack encoding */ /** hpack encoding */
grpc_chttp2_hpack_compressor hpack_compressor; grpc_chttp2_hpack_compressor hpack_compressor;
/** is this a client? */ /** is this a client? */
uint8_t is_client; bool is_client;
/** data to write next write */ /** data to write next write */
grpc_slice_buffer qbuf; grpc_slice_buffer qbuf;
@ -350,14 +307,14 @@ struct grpc_chttp2_transport {
uint32_t write_buffer_size; uint32_t write_buffer_size;
/** have we seen a goaway */ /** have we seen a goaway */
uint8_t seen_goaway; bool seen_goaway;
/** have we sent a goaway */ /** have we sent a goaway */
grpc_chttp2_sent_goaway_state sent_goaway_state; grpc_chttp2_sent_goaway_state sent_goaway_state;
/** are the local settings dirty and need to be sent? */ /** are the local settings dirty and need to be sent? */
uint8_t dirtied_local_settings; bool dirtied_local_settings;
/** have local settings been sent? */ /** have local settings been sent? */
uint8_t sent_local_settings; bool sent_local_settings;
/** bitmask of setting indexes to send out */ /** bitmask of setting indexes to send out */
uint32_t force_send_settings; uint32_t force_send_settings;
/** settings values */ /** settings values */
@ -395,7 +352,12 @@ struct grpc_chttp2_transport {
/** parser for goaway frames */ /** parser for goaway frames */
grpc_chttp2_goaway_parser goaway_parser; grpc_chttp2_goaway_parser goaway_parser;
grpc_chttp2_transport_flowctl flow_control; grpc_core::ManualConstructor<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 */
int64_t initial_window_update = 0;
/* deframing */ /* deframing */
grpc_chttp2_deframe_transport_state deframe_state; grpc_chttp2_deframe_transport_state deframe_state;
@ -422,6 +384,7 @@ struct grpc_chttp2_transport {
grpc_chttp2_write_cb *write_cb_pool; grpc_chttp2_write_cb *write_cb_pool;
/* bdp estimator */ /* bdp estimator */
grpc_closure next_bdp_ping_timer_expired_locked;
grpc_closure start_bdp_ping_locked; grpc_closure start_bdp_ping_locked;
grpc_closure finish_bdp_ping_locked; grpc_closure finish_bdp_ping_locked;
@ -442,6 +405,10 @@ struct grpc_chttp2_transport {
/** destructive cleanup closure */ /** destructive cleanup closure */
grpc_closure destructive_reclaimer_locked; grpc_closure destructive_reclaimer_locked;
/* next bdp ping timer */
bool have_next_bdp_ping_timer;
grpc_timer next_bdp_ping_timer;
/* keep-alive ping support */ /* keep-alive ping support */
/** Closure to initialize a keepalive ping */ /** Closure to initialize a keepalive ping */
grpc_closure init_keepalive_ping_locked; grpc_closure init_keepalive_ping_locked;
@ -472,25 +439,6 @@ typedef enum {
GPRC_METADATA_PUBLISHED_AT_CLOSE GPRC_METADATA_PUBLISHED_AT_CLOSE
} grpc_published_metadata_method; } grpc_published_metadata_method;
typedef struct {
/** window available for us to send to peer, over or under the initial window
* size of the transport... ie:
* remote_window = remote_window_delta + transport.initial_window_size */
int64_t remote_window_delta;
/** window available for peer to send to us (as a delta on
* transport.initial_window_size)
* local_window = local_window_delta + transport.initial_window_size */
int64_t local_window_delta;
/** window available for peer to send to us over this stream that we have
* announced to the peer */
int64_t announced_window_delta;
// read only pointer back to stream for data
const grpc_chttp2_stream *s;
} grpc_chttp2_stream_flowctl;
struct grpc_chttp2_stream { struct grpc_chttp2_stream {
grpc_chttp2_transport *t; grpc_chttp2_transport *t;
grpc_stream_refcount *refcount; grpc_stream_refcount *refcount;
@ -584,7 +532,8 @@ struct grpc_chttp2_stream {
bool sent_initial_metadata; bool sent_initial_metadata;
bool sent_trailing_metadata; bool sent_trailing_metadata;
grpc_chttp2_stream_flowctl flow_control; grpc_core::ManualConstructor<grpc_core::chttp2::StreamFlowControl>
flow_control;
grpc_slice_buffer flow_controlled_buffer; grpc_slice_buffer flow_controlled_buffer;
@ -695,74 +644,10 @@ bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t,
/********* Flow Control ***************/ /********* Flow Control ***************/
// we have sent data on the wire
void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc,
int64_t size);
// we have received data from the wire
grpc_error *grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc,
int64_t incoming_frame_size);
// returns an announce if we should send a transport update to our peer,
// else returns zero
uint32_t grpc_chttp2_flowctl_maybe_send_transport_update(
grpc_chttp2_transport_flowctl *tfc, bool writing_anyway);
// returns an announce if we should send a stream update to our peer, else
// returns zero
uint32_t grpc_chttp2_flowctl_maybe_send_stream_update(
grpc_chttp2_transport_flowctl *tfc, grpc_chttp2_stream_flowctl *sfc);
// we have received a WINDOW_UPDATE frame for a transport
void grpc_chttp2_flowctl_recv_transport_update(
grpc_chttp2_transport_flowctl *tfc, uint32_t size);
// we have received a WINDOW_UPDATE frame for a stream
void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc,
uint32_t size);
// the application is asking for a certain amount of bytes
void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc,
size_t max_size_hint,
size_t have_already);
void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc);
typedef enum {
// Nothing to be done.
GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED = 0,
// Initiate a write to update the initial window immediately.
GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY,
// Push the flow control update into a send buffer, to be sent
// out the next time a write is initiated.
GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE,
} grpc_chttp2_flowctl_urgency;
typedef struct {
grpc_chttp2_flowctl_urgency send_stream_update;
grpc_chttp2_flowctl_urgency send_transport_update;
grpc_chttp2_flowctl_urgency send_setting_update;
uint32_t initial_window_size;
uint32_t max_frame_size;
bool need_ping;
} grpc_chttp2_flowctl_action;
// Reads the flow control data and returns and actionable struct that will tell
// chttp2 exactly what it needs to do
grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_flowctl *tfc,
grpc_chttp2_stream_flowctl *sfc);
// Takes in a flow control action and performs all the needed operations. // Takes in a flow control action and performs all the needed operations.
void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, void grpc_chttp2_act_on_flowctl_action(
grpc_chttp2_flowctl_action action, grpc_exec_ctx *exec_ctx, const grpc_core::chttp2::FlowControlAction &action,
grpc_chttp2_transport *t, grpc_chttp2_transport *t, grpc_chttp2_stream *s);
grpc_chttp2_stream *s);
/********* End of Flow Control ***************/ /********* End of Flow Control ***************/
@ -796,20 +681,10 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
extern grpc_core::Tracer grpc_http_trace; extern grpc_core::Tracer grpc_http_trace;
extern grpc_core::Tracer grpc_flowctl_trace; extern grpc_core::Tracer grpc_flowctl_trace;
#ifndef NDEBUG #define GRPC_CHTTP2_IF_TRACING(stmt) \
#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) \ if (!(GRPC_TRACER_ON(grpc_http_trace))) \
if (!(grpc_flowctl_trace.enabled())) \ ; \
; \ else \
else \
stmt
#else
#define GRPC_FLOW_CONTROL_IF_TRACING(stmt)
#endif
#define GRPC_CHTTP2_IF_TRACING(stmt) \
if (!(grpc_http_trace.enabled())) \
; \
else \
stmt stmt
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,

@ -355,14 +355,15 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s = grpc_chttp2_stream *s =
grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
grpc_error *err = GRPC_ERROR_NONE; grpc_error *err = GRPC_ERROR_NONE;
err = grpc_chttp2_flowctl_recv_data(&t->flow_control, grpc_core::chttp2::FlowControlAction action;
s == NULL ? NULL : &s->flow_control, if (s == nullptr) {
t->incoming_frame_size); err = t->flow_control->RecvData(t->incoming_frame_size);
grpc_chttp2_act_on_flowctl_action( action = t->flow_control->MakeAction();
exec_ctx, } else {
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, err = s->flow_control->RecvData(t->incoming_frame_size);
s == NULL ? NULL : &s->flow_control), action = s->flow_control->MakeAction();
t, s); }
grpc_chttp2_act_on_flowctl_action(exec_ctx, action, t, s);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
goto error_handler; goto error_handler;
} }

@ -142,13 +142,13 @@ static void report_stall(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
s->flow_controlled_bytes_flowed, s->flow_controlled_bytes_flowed,
t->settings[GRPC_ACKED_SETTINGS] t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
t->flow_control.remote_window, t->flow_control->remote_window(),
(uint32_t)GPR_MAX( (uint32_t)GPR_MAX(
0, 0,
s->flow_control.remote_window_delta + s->flow_control->remote_window_delta() +
(int64_t)t->settings[GRPC_PEER_SETTINGS] (int64_t)t->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]), [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]),
s->flow_control.remote_window_delta); s->flow_control->remote_window_delta());
} }
static bool stream_ref_if_not_destroyed(gpr_refcount *r) { static bool stream_ref_if_not_destroyed(gpr_refcount *r) {
@ -212,8 +212,7 @@ class WriteContext {
void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) { void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) {
uint32_t transport_announce = uint32_t transport_announce =
grpc_chttp2_flowctl_maybe_send_transport_update(&t_->flow_control, t_->flow_control->MaybeSendUpdate(t_->outbuf.count > 0);
t_->outbuf.count > 0);
if (transport_announce) { if (transport_announce) {
grpc_transport_one_way_stats throwaway_stats; grpc_transport_one_way_stats throwaway_stats;
grpc_slice_buffer_add( grpc_slice_buffer_add(
@ -241,7 +240,8 @@ class WriteContext {
void UpdateStreamsNoLongerStalled() { void UpdateStreamsNoLongerStalled() {
grpc_chttp2_stream *s; grpc_chttp2_stream *s;
while (grpc_chttp2_list_pop_stalled_by_transport(t_, &s)) { while (grpc_chttp2_list_pop_stalled_by_transport(t_, &s)) {
if (!t_->closed && grpc_chttp2_list_add_writable_stream(t_, s)) { if (t_->closed_with_error == GRPC_ERROR_NONE &&
grpc_chttp2_list_add_writable_stream(t_, s)) {
if (!stream_ref_if_not_destroyed(&s->refcount->refs)) { if (!stream_ref_if_not_destroyed(&s->refcount->refs)) {
grpc_chttp2_list_remove_writable_stream(t_, s); grpc_chttp2_list_remove_writable_stream(t_, s);
} }
@ -307,7 +307,7 @@ class DataSendContext {
uint32_t stream_remote_window() const { uint32_t stream_remote_window() const {
return (uint32_t)GPR_MAX( return (uint32_t)GPR_MAX(
0, s_->flow_control.remote_window_delta + 0, s_->flow_control->remote_window_delta() +
(int64_t)t_->settings[GRPC_PEER_SETTINGS] (int64_t)t_->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
} }
@ -315,7 +315,7 @@ class DataSendContext {
uint32_t max_outgoing() const { uint32_t max_outgoing() const {
return (uint32_t)GPR_MIN( return (uint32_t)GPR_MIN(
t_->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], t_->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
GPR_MIN(stream_remote_window(), t_->flow_control.remote_window)); GPR_MIN(stream_remote_window(), t_->flow_control->remote_window()));
} }
bool AnyOutgoing() const { return max_outgoing() != 0; } bool AnyOutgoing() const { return max_outgoing() != 0; }
@ -347,8 +347,7 @@ class DataSendContext {
grpc_metadata_batch_is_empty(s_->send_trailing_metadata); grpc_metadata_batch_is_empty(s_->send_trailing_metadata);
grpc_chttp2_encode_data(s_->id, &s_->compressed_data_buffer, send_bytes, grpc_chttp2_encode_data(s_->id, &s_->compressed_data_buffer, send_bytes,
is_last_frame_, &s_->stats.outgoing, &t_->outbuf); is_last_frame_, &s_->stats.outgoing, &t_->outbuf);
grpc_chttp2_flowctl_sent_data(&t_->flow_control, &s_->flow_control, s_->flow_control->SentData(send_bytes);
send_bytes);
if (s_->compressed_data_buffer.length == 0) { if (s_->compressed_data_buffer.length == 0) {
s_->sending_bytes += s_->uncompressed_data_size; s_->sending_bytes += s_->uncompressed_data_size;
} }
@ -395,8 +394,8 @@ class StreamWriteContext {
gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t_, gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t_,
t_->is_client ? "CLIENT" : "SERVER", s->id, t_->is_client ? "CLIENT" : "SERVER", s->id,
s->sent_initial_metadata, s->send_initial_metadata != NULL, s->sent_initial_metadata, s->send_initial_metadata != NULL,
(int)(s->flow_control.local_window_delta - (int)(s->flow_control->local_window_delta() -
s->flow_control.announced_window_delta))); s->flow_control->announced_window_delta())));
} }
void FlushInitialMetadata(grpc_exec_ctx *exec_ctx) { void FlushInitialMetadata(grpc_exec_ctx *exec_ctx) {
@ -442,8 +441,7 @@ class StreamWriteContext {
void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) { void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) {
/* send any window updates */ /* send any window updates */
uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update( const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate();
&t_->flow_control, &s_->flow_control);
if (stream_announce == 0) return; if (stream_announce == 0) return;
grpc_slice_buffer_add( grpc_slice_buffer_add(
@ -464,10 +462,10 @@ class StreamWriteContext {
DataSendContext data_send_context(write_context_, t_, s_); DataSendContext data_send_context(write_context_, t_, s_);
if (!data_send_context.AnyOutgoing()) { if (!data_send_context.AnyOutgoing()) {
if (t_->flow_control.remote_window == 0) { if (t_->flow_control->remote_window() <= 0) {
report_stall(t_, s_, "transport"); report_stall(t_, s_, "transport");
grpc_chttp2_list_add_stalled_by_transport(t_, s_); grpc_chttp2_list_add_stalled_by_transport(t_, s_);
} else if (data_send_context.stream_remote_window() == 0) { } else if (data_send_context.stream_remote_window() <= 0) {
report_stall(t_, s_, "stream"); report_stall(t_, s_, "stream");
grpc_chttp2_list_add_stalled_by_stream(t_, s_); grpc_chttp2_list_add_stalled_by_stream(t_, s_);
} }
@ -583,7 +581,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
ctx.FlushQueuedBuffers(exec_ctx); ctx.FlushQueuedBuffers(exec_ctx);
ctx.EnactHpackSettings(exec_ctx); ctx.EnactHpackSettings(exec_ctx);
if (t->flow_control.remote_window > 0) { if (t->flow_control->remote_window() > 0) {
ctx.UpdateStreamsNoLongerStalled(); ctx.UpdateStreamsNoLongerStalled();
} }

@ -91,8 +91,17 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
} }
static int httpcli_ssl_cmp(grpc_security_connector *sc1,
grpc_security_connector *sc2) {
grpc_httpcli_ssl_channel_security_connector *c1 =
(grpc_httpcli_ssl_channel_security_connector *)sc1;
grpc_httpcli_ssl_channel_security_connector *c2 =
(grpc_httpcli_ssl_channel_security_connector *)sc2;
return strcmp(c1->secure_peer_name, c2->secure_peer_name);
}
static grpc_security_connector_vtable httpcli_ssl_vtable = { static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_check_peer}; httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp};
static grpc_security_status httpcli_ssl_channel_security_connector_create( static grpc_security_status httpcli_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, const char *pem_root_certs, grpc_exec_ctx *exec_ctx, const char *pem_root_certs,
@ -123,6 +132,10 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
*sc = NULL; *sc = NULL;
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
// We don't actually need a channel credentials object in this case,
// but we set it to a non-NULL address so that we don't trigger
// assertions in grpc_channel_security_connector_cmp().
c->base.channel_creds = (grpc_channel_credentials *)1;
c->base.add_handshakers = httpcli_ssl_add_handshakers; c->base.add_handshakers = httpcli_ssl_add_handshakers;
*sc = &c->base; *sc = &c->base;
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;

File diff suppressed because it is too large Load Diff

@ -91,12 +91,9 @@ const grpc_event_engine_vtable *init_non_polling(bool explicit_request) {
} // namespace } // namespace
static const event_engine_factory g_factories[] = { static const event_engine_factory g_factories[] = {
{"epoll1", grpc_init_epoll1_linux}, {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
{"epollsig", grpc_init_epollsig_linux}, {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
{"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
{"poll-cv", grpc_init_poll_cv_posix},
{"epollex", grpc_init_epollex_linux},
{"none", init_non_polling},
}; };
static void add(const char *beg, const char *end, char ***ss, size_t *ns) { static void add(const char *beg, const char *end, char ***ss, size_t *ns) {

@ -152,6 +152,15 @@ void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx) {
gpr_timespec grpc_millis_to_timespec(grpc_millis millis, gpr_timespec grpc_millis_to_timespec(grpc_millis millis,
gpr_clock_type clock_type) { gpr_clock_type clock_type) {
// special-case infinities as grpc_millis can be 32bit on some platforms
// while gpr_time_from_millis always takes an int64_t.
if (millis == GRPC_MILLIS_INF_FUTURE) {
return gpr_inf_future(clock_type);
}
if (millis == GRPC_MILLIS_INF_PAST) {
return gpr_inf_past(clock_type);
}
if (clock_type == GPR_TIMESPAN) { if (clock_type == GPR_TIMESPAN) {
return gpr_time_from_millis(millis, GPR_TIMESPAN); return gpr_time_from_millis(millis, GPR_TIMESPAN);
} }

@ -186,7 +186,7 @@ static void cover_self(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
} }
if (old_count == 0) { if (old_count == 0) {
GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED(exec_ctx); GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED(exec_ctx);
p = (backup_poller *)gpr_malloc(sizeof(*p) + grpc_pollset_size()); p = (backup_poller *)gpr_zalloc(sizeof(*p) + grpc_pollset_size());
if (grpc_tcp_trace.enabled()) { if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p create", p); gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p create", p);
} }

@ -38,7 +38,8 @@ static grpc_security_status fake_transport_security_create_security_connector(
grpc_call_credentials *call_creds, const char *target, grpc_call_credentials *call_creds, const char *target,
const grpc_channel_args *args, grpc_channel_security_connector **sc, const grpc_channel_args *args, grpc_channel_security_connector **sc,
grpc_channel_args **new_args) { grpc_channel_args **new_args) {
*sc = grpc_fake_channel_security_connector_create(call_creds, target, args); *sc =
grpc_fake_channel_security_connector_create(c, call_creds, target, args);
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }
@ -46,7 +47,7 @@ static grpc_security_status
fake_transport_security_server_create_security_connector( fake_transport_security_server_create_security_connector(
grpc_exec_ctx *exec_ctx, grpc_server_credentials *c, grpc_exec_ctx *exec_ctx, grpc_server_credentials *c,
grpc_server_security_connector **sc) { grpc_server_security_connector **sc) {
*sc = grpc_fake_server_security_connector_create(); *sc = grpc_fake_server_security_connector_create(c);
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }

@ -262,7 +262,7 @@ static bool oauth2_token_fetcher_get_request_metadata(
grpc_mdelem cached_access_token_md = GRPC_MDNULL; grpc_mdelem cached_access_token_md = GRPC_MDNULL;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
if (!GRPC_MDISNULL(c->access_token_md) && if (!GRPC_MDISNULL(c->access_token_md) &&
(c->token_expiration + grpc_exec_ctx_now(exec_ctx) > refresh_threshold)) { (c->token_expiration - grpc_exec_ctx_now(exec_ctx) > refresh_threshold)) {
cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md); cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md);
} }
if (!GRPC_MDISNULL(cached_access_token_md)) { if (!GRPC_MDISNULL(cached_access_token_md)) {

@ -62,7 +62,8 @@ static grpc_security_status ssl_create_security_connector(
} }
} }
status = grpc_ssl_channel_security_connector_create( status = grpc_ssl_channel_security_connector_create(
exec_ctx, call_creds, &c->config, target, overridden_target_name, sc); exec_ctx, creds, call_creds, &c->config, target, overridden_target_name,
sc);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
return status; return status;
} }
@ -128,7 +129,8 @@ static grpc_security_status ssl_server_create_security_connector(
grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds,
grpc_server_security_connector **sc) { grpc_server_security_connector **sc) {
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
return grpc_ssl_server_security_connector_create(exec_ctx, &c->config, sc); return grpc_ssl_server_security_connector_create(exec_ctx, creds, &c->config,
sc);
} }
static grpc_server_credentials_vtable ssl_server_vtable = { static grpc_server_credentials_vtable ssl_server_vtable = {

@ -136,6 +136,39 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
} }
} }
int grpc_security_connector_cmp(grpc_security_connector *sc,
grpc_security_connector *other) {
if (sc == NULL || other == NULL) return GPR_ICMP(sc, other);
int c = GPR_ICMP(sc->vtable, other->vtable);
if (c != 0) return c;
return sc->vtable->cmp(sc, other);
}
int grpc_channel_security_connector_cmp(grpc_channel_security_connector *sc1,
grpc_channel_security_connector *sc2) {
GPR_ASSERT(sc1->channel_creds != NULL);
GPR_ASSERT(sc2->channel_creds != NULL);
int c = GPR_ICMP(sc1->channel_creds, sc2->channel_creds);
if (c != 0) return c;
c = GPR_ICMP(sc1->request_metadata_creds, sc2->request_metadata_creds);
if (c != 0) return c;
c = GPR_ICMP((void *)sc1->check_call_host, (void *)sc2->check_call_host);
if (c != 0) return c;
c = GPR_ICMP((void *)sc1->cancel_check_call_host,
(void *)sc2->cancel_check_call_host);
if (c != 0) return c;
return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers);
}
int grpc_server_security_connector_cmp(grpc_server_security_connector *sc1,
grpc_server_security_connector *sc2) {
GPR_ASSERT(sc1->server_creds != NULL);
GPR_ASSERT(sc2->server_creds != NULL);
int c = GPR_ICMP(sc1->server_creds, sc2->server_creds);
if (c != 0) return c;
return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers);
}
bool grpc_channel_security_connector_check_call_host( bool grpc_channel_security_connector_check_call_host(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
const char *host, grpc_auth_context *auth_context, const char *host, grpc_auth_context *auth_context,
@ -199,25 +232,27 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc); if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc);
} }
static void connector_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { static void connector_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, (grpc_security_connector *)p, GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, (grpc_security_connector *)p,
"connector_pointer_arg_destroy"); "connector_arg_destroy");
} }
static void *connector_pointer_arg_copy(void *p) { static void *connector_arg_copy(void *p) {
return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector *)p, return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector *)p,
"connector_pointer_arg_copy"); "connector_arg_copy");
} }
static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } static int connector_cmp(void *a, void *b) {
return grpc_security_connector_cmp((grpc_security_connector *)a,
(grpc_security_connector *)b);
}
static const grpc_arg_pointer_vtable connector_pointer_vtable = { static const grpc_arg_pointer_vtable connector_arg_vtable = {
connector_pointer_arg_copy, connector_pointer_arg_destroy, connector_arg_copy, connector_arg_destroy, connector_cmp};
connector_pointer_cmp};
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
return grpc_channel_arg_pointer_create((char *)GRPC_ARG_SECURITY_CONNECTOR, return grpc_channel_arg_pointer_create((char *)GRPC_ARG_SECURITY_CONNECTOR,
sc, &connector_pointer_vtable); sc, &connector_arg_vtable);
} }
grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
@ -382,6 +417,32 @@ static void fake_server_check_peer(grpc_exec_ctx *exec_ctx,
fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
} }
static int fake_channel_cmp(grpc_security_connector *sc1,
grpc_security_connector *sc2) {
grpc_fake_channel_security_connector *c1 =
(grpc_fake_channel_security_connector *)sc1;
grpc_fake_channel_security_connector *c2 =
(grpc_fake_channel_security_connector *)sc2;
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
c = strcmp(c1->target, c2->target);
if (c != 0) return c;
if (c1->expected_targets == NULL || c2->expected_targets == NULL) {
c = GPR_ICMP(c1->expected_targets, c2->expected_targets);
} else {
c = strcmp(c1->expected_targets, c2->expected_targets);
}
if (c != 0) return c;
return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel);
}
static int fake_server_cmp(grpc_security_connector *sc1,
grpc_security_connector *sc2) {
return grpc_server_security_connector_cmp(
(grpc_server_security_connector *)sc1,
(grpc_server_security_connector *)sc2);
}
static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, grpc_channel_security_connector *sc,
const char *host, const char *host,
@ -418,12 +479,13 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx,
} }
static grpc_security_connector_vtable fake_channel_vtable = { static grpc_security_connector_vtable fake_channel_vtable = {
fake_channel_destroy, fake_channel_check_peer}; fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp};
static grpc_security_connector_vtable fake_server_vtable = { static grpc_security_connector_vtable fake_server_vtable = {
fake_server_destroy, fake_server_check_peer}; fake_server_destroy, fake_server_check_peer, fake_server_cmp};
grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_channel_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds, const char *target, grpc_call_credentials *request_metadata_creds, const char *target,
const grpc_channel_args *args) { const grpc_channel_args *args) {
grpc_fake_channel_security_connector *c = grpc_fake_channel_security_connector *c =
@ -431,6 +493,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->base.base.vtable = &fake_channel_vtable; c->base.base.vtable = &fake_channel_vtable;
c->base.channel_creds = channel_creds;
c->base.request_metadata_creds = c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds); grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = fake_channel_check_call_host; c->base.check_call_host = fake_channel_check_call_host;
@ -444,13 +507,14 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
} }
grpc_server_security_connector *grpc_fake_server_security_connector_create( grpc_server_security_connector *grpc_fake_server_security_connector_create(
void) { grpc_server_credentials *server_creds) {
grpc_server_security_connector *c = grpc_server_security_connector *c =
(grpc_server_security_connector *)gpr_zalloc( (grpc_server_security_connector *)gpr_zalloc(
sizeof(grpc_server_security_connector)); sizeof(grpc_server_security_connector));
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable; c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->server_creds = server_creds;
c->add_handshakers = fake_server_add_handshakers; c->add_handshakers = fake_server_add_handshakers;
return c; return c;
} }
@ -473,6 +537,7 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) { grpc_security_connector *sc) {
grpc_ssl_channel_security_connector *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
grpc_channel_credentials_unref(exec_ctx, c->base.channel_creds);
grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds); grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory); tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
c->client_handshaker_factory = NULL; c->client_handshaker_factory = NULL;
@ -485,6 +550,7 @@ static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) { grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c = grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc; (grpc_ssl_server_security_connector *)sc;
grpc_server_credentials_unref(exec_ctx, c->base.server_creds);
tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory); tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
c->server_handshaker_factory = NULL; c->server_handshaker_factory = NULL;
gpr_free(sc); gpr_free(sc);
@ -641,6 +707,29 @@ static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error);
} }
static int ssl_channel_cmp(grpc_security_connector *sc1,
grpc_security_connector *sc2) {
grpc_ssl_channel_security_connector *c1 =
(grpc_ssl_channel_security_connector *)sc1;
grpc_ssl_channel_security_connector *c2 =
(grpc_ssl_channel_security_connector *)sc2;
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
c = strcmp(c1->target_name, c2->target_name);
if (c != 0) return c;
return (c1->overridden_target_name == NULL ||
c2->overridden_target_name == NULL)
? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name)
: strcmp(c1->overridden_target_name, c2->overridden_target_name);
}
static int ssl_server_cmp(grpc_security_connector *sc1,
grpc_security_connector *sc2) {
return grpc_server_security_connector_cmp(
(grpc_server_security_connector *)sc1,
(grpc_server_security_connector *)sc2);
}
static void add_shallow_auth_property_to_peer(tsi_peer *peer, static void add_shallow_auth_property_to_peer(tsi_peer *peer,
const grpc_auth_property *prop, const grpc_auth_property *prop,
const char *tsi_prop_name) { const char *tsi_prop_name) {
@ -717,10 +806,10 @@ static void ssl_channel_cancel_check_call_host(
} }
static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_channel_vtable = {
ssl_channel_destroy, ssl_channel_check_peer}; ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp};
static grpc_security_connector_vtable ssl_server_vtable = { static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer}; ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
/* returns a NULL terminated slice. */ /* returns a NULL terminated slice. */
static grpc_slice compute_default_pem_root_certs_once(void) { static grpc_slice compute_default_pem_root_certs_once(void) {
@ -804,7 +893,8 @@ const char *grpc_get_default_ssl_roots(void) {
} }
grpc_security_status grpc_ssl_channel_security_connector_create( grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name, const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc) { const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
@ -840,6 +930,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable; c->base.base.vtable = &ssl_channel_vtable;
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
c->base.request_metadata_creds = c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds); grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host; c->base.check_call_host = ssl_channel_check_call_host;
@ -874,8 +965,8 @@ error:
} }
grpc_security_status grpc_ssl_server_security_connector_create( grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds,
grpc_server_security_connector **sc) { const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const char **alpn_protocol_strings = const char **alpn_protocol_strings =
(const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@ -897,6 +988,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.base.vtable = &ssl_server_vtable; c->base.base.vtable = &ssl_server_vtable;
c->base.server_creds = grpc_server_credentials_ref(server_creds);
result = tsi_create_ssl_server_handshaker_factory_ex( result = tsi_create_ssl_server_handshaker_factory_ex(
config->pem_key_cert_pairs, config->num_key_cert_pairs, config->pem_key_cert_pairs, config->num_key_cert_pairs,
config->pem_root_certs, get_tsi_client_certificate_request_type( config->pem_root_certs, get_tsi_client_certificate_request_type(

@ -60,13 +60,9 @@ typedef struct {
void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
tsi_peer peer, grpc_auth_context **auth_context, tsi_peer peer, grpc_auth_context **auth_context,
grpc_closure *on_peer_checked); grpc_closure *on_peer_checked);
int (*cmp)(grpc_security_connector *sc, grpc_security_connector *other);
} grpc_security_connector_vtable; } grpc_security_connector_vtable;
typedef struct grpc_security_connector_handshake_list {
void *handshake;
struct grpc_security_connector_handshake_list *next;
} grpc_security_connector_handshake_list;
struct grpc_security_connector { struct grpc_security_connector {
const grpc_security_connector_vtable *vtable; const grpc_security_connector_vtable *vtable;
gpr_refcount refcount; gpr_refcount refcount;
@ -104,6 +100,10 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_auth_context **auth_context, grpc_auth_context **auth_context,
grpc_closure *on_peer_checked); grpc_closure *on_peer_checked);
/* Compares two security connectors. */
int grpc_security_connector_cmp(grpc_security_connector *sc,
grpc_security_connector *other);
/* Util to encapsulate the connector in a channel arg. */ /* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
@ -116,13 +116,14 @@ grpc_security_connector *grpc_security_connector_find_in_args(
/* --- channel_security_connector object. --- /* --- channel_security_connector object. ---
A channel security connector object represents away to configure the A channel security connector object represents a way to configure the
underlying transport security mechanism on the client side. */ underlying transport security mechanism on the client side. */
typedef struct grpc_channel_security_connector grpc_channel_security_connector; typedef struct grpc_channel_security_connector grpc_channel_security_connector;
struct grpc_channel_security_connector { struct grpc_channel_security_connector {
grpc_security_connector base; grpc_security_connector base;
grpc_channel_credentials *channel_creds;
grpc_call_credentials *request_metadata_creds; grpc_call_credentials *request_metadata_creds;
bool (*check_call_host)(grpc_exec_ctx *exec_ctx, bool (*check_call_host)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, const char *host, grpc_channel_security_connector *sc, const char *host,
@ -138,6 +139,10 @@ struct grpc_channel_security_connector {
grpc_handshake_manager *handshake_mgr); grpc_handshake_manager *handshake_mgr);
}; };
/// A helper function for use in grpc_security_connector_cmp() implementations.
int grpc_channel_security_connector_cmp(grpc_channel_security_connector *sc1,
grpc_channel_security_connector *sc2);
/// Checks that the host that will be set for a call is acceptable. /// Checks that the host that will be set for a call is acceptable.
/// Returns true if completed synchronously, in which case \a error will /// Returns true if completed synchronously, in which case \a error will
/// be set to indicate the result. Otherwise, \a on_call_host_checked /// be set to indicate the result. Otherwise, \a on_call_host_checked
@ -161,18 +166,23 @@ void grpc_channel_security_connector_add_handshakers(
/* --- server_security_connector object. --- /* --- server_security_connector object. ---
A server security connector object represents away to configure the A server security connector object represents a way to configure the
underlying transport security mechanism on the server side. */ underlying transport security mechanism on the server side. */
typedef struct grpc_server_security_connector grpc_server_security_connector; typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector { struct grpc_server_security_connector {
grpc_security_connector base; grpc_security_connector base;
grpc_server_credentials *server_creds;
void (*add_handshakers)(grpc_exec_ctx *exec_ctx, void (*add_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc, grpc_server_security_connector *sc,
grpc_handshake_manager *handshake_mgr); grpc_handshake_manager *handshake_mgr);
}; };
/// A helper function for use in grpc_security_connector_cmp() implementations.
int grpc_server_security_connector_cmp(grpc_server_security_connector *sc1,
grpc_server_security_connector *sc2);
void grpc_server_security_connector_add_handshakers( void grpc_server_security_connector_add_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_handshake_manager *handshake_mgr); grpc_handshake_manager *handshake_mgr);
@ -182,13 +192,14 @@ void grpc_server_security_connector_add_handshakers(
/* For TESTING ONLY! /* For TESTING ONLY!
Creates a fake connector that emulates real channel security. */ Creates a fake connector that emulates real channel security. */
grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_channel_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds, const char *target, grpc_call_credentials *request_metadata_creds, const char *target,
const grpc_channel_args *args); const grpc_channel_args *args);
/* For TESTING ONLY! /* For TESTING ONLY!
Creates a fake connector that emulates real server security. */ Creates a fake connector that emulates real server security. */
grpc_server_security_connector *grpc_fake_server_security_connector_create( grpc_server_security_connector *grpc_fake_server_security_connector_create(
void); grpc_server_credentials *server_creds);
/* Config for ssl clients. */ /* Config for ssl clients. */
@ -211,7 +222,8 @@ typedef struct {
specific error code otherwise. specific error code otherwise.
*/ */
grpc_security_status grpc_ssl_channel_security_connector_create( grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name, const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc); const char *overridden_target_name, grpc_channel_security_connector **sc);
@ -236,8 +248,8 @@ typedef struct {
specific error code otherwise. specific error code otherwise.
*/ */
grpc_security_status grpc_ssl_server_security_connector_create( grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds,
grpc_server_security_connector **sc); const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
/* Util. */ /* Util. */
const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,

@ -38,8 +38,9 @@ static int ncpus = 0;
static void init_num_cpus() { static void init_num_cpus() {
/* This must be signed. sysconf returns -1 when the number cannot be /* This must be signed. sysconf returns -1 when the number cannot be
determined */ determined */
int cpu = sched_getcpu();
ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN);
if (ncpus < 1) { if (ncpus < 1 || cpu < 0) {
gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
ncpus = 1; ncpus = 1;
} }
@ -56,6 +57,9 @@ unsigned gpr_cpu_current_cpu(void) {
// sched_getcpu() is undefined on musl // sched_getcpu() is undefined on musl
return 0; return 0;
#else #else
if (gpr_cpu_num_cores() == 1) {
return 0;
}
int cpu = sched_getcpu(); int cpu = sched_getcpu();
if (cpu < 0) { if (cpu < 0) {
gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));

@ -21,6 +21,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <limits>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -54,6 +55,46 @@ inline UniquePtr<T> MakeUnique(Args&&... args) {
return UniquePtr<T>(New<T>(std::forward<Args>(args)...)); return UniquePtr<T>(New<T>(std::forward<Args>(args)...));
} }
// an allocator that uses gpr_malloc/gpr_free
template <class T>
class Allocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::false_type propagate_on_container_move_assignment;
template <class U>
struct rebind {
typedef Allocator<U> other;
};
typedef std::true_type is_always_equal;
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(std::size_t n,
std::allocator<void>::const_pointer hint = 0) {
return static_cast<pointer>(gpr_malloc(n * sizeof(T)));
}
void deallocate(T* p, std::size_t n) { gpr_free(p); }
size_t max_size() const {
return std::numeric_limits<size_type>::max() / sizeof(value_type);
}
void construct(pointer p, const_reference val) { new ((void*)p) T(val); }
template <class U, class... Args>
void construct(U* p, Args&&... args) {
::new ((void*)p) U(std::forward<Args>(args)...);
}
void destroy(pointer p) { p->~T(); }
template <class U>
void destroy(U* p) {
p->~U();
}
};
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */ #endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */

@ -0,0 +1,32 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_SUPPORT_VECTOR_H
#define GRPC_CORE_LIB_SUPPORT_VECTOR_H
#include "absl/container/inlined_vector.h"
#include "src/core/lib/support/memory.h"
namespace grpc_core {
template <typename T, size_t N>
using InlinedVector = absl::InlinedVector<T, N, Allocator<T>>;
} // namespace grpc_core
#endif

@ -32,13 +32,12 @@ BdpEstimator::BdpEstimator(const char *name)
accumulator_(0), accumulator_(0),
estimate_(65536), estimate_(65536),
ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)), ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)),
next_ping_scheduled_(0),
inter_ping_delay_(100.0), // start at 100ms inter_ping_delay_(100.0), // start at 100ms
stable_estimate_count_(0), stable_estimate_count_(0),
bw_est_(0), bw_est_(0),
name_(name) {} name_(name) {}
void BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) { grpc_millis BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_); gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_);
double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec; double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec;
@ -78,7 +77,7 @@ void BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) {
} }
ping_state_ = PingState::UNSCHEDULED; ping_state_ = PingState::UNSCHEDULED;
accumulator_ = 0; accumulator_ = 0;
next_ping_scheduled_ = grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_; return grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_;
} }
} // namespace grpc_core } // namespace grpc_core

@ -40,30 +40,11 @@ class BdpEstimator {
explicit BdpEstimator(const char *name); explicit BdpEstimator(const char *name);
~BdpEstimator() {} ~BdpEstimator() {}
// Returns true if a reasonable estimate could be obtained int64_t EstimateBdp() const { return estimate_; }
bool EstimateBdp(int64_t *estimate_out) const { double EstimateBandwidth() const { return bw_est_; }
*estimate_out = estimate_;
return true;
}
bool EstimateBandwidth(double *bw_out) const {
*bw_out = bw_est_;
return true;
}
void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; } void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; }
// Returns true if the user should schedule a ping
bool NeedPing(grpc_exec_ctx *exec_ctx) const {
switch (ping_state_) {
case PingState::UNSCHEDULED:
return grpc_exec_ctx_now(exec_ctx) >= next_ping_scheduled_;
case PingState::SCHEDULED:
case PingState::STARTED:
return false;
}
GPR_UNREACHABLE_CODE(return false);
}
// Schedule a ping: call in response to receiving a true from // Schedule a ping: call in response to receiving a true from
// grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
// transport (but not necessarily started) // transport (but not necessarily started)
@ -91,8 +72,8 @@ class BdpEstimator {
ping_start_time_ = gpr_now(GPR_CLOCK_MONOTONIC); ping_start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
} }
// Completes a previously started ping // Completes a previously started ping, returns when to schedule the next one
void CompletePing(grpc_exec_ctx *exec_ctx); grpc_millis CompletePing(grpc_exec_ctx *exec_ctx);
private: private:
enum class PingState { UNSCHEDULED, SCHEDULED, STARTED }; enum class PingState { UNSCHEDULED, SCHEDULED, STARTED };
@ -102,8 +83,6 @@ class BdpEstimator {
int64_t estimate_; int64_t estimate_;
// when was the current ping started? // when was the current ping started?
gpr_timespec ping_start_time_; gpr_timespec ping_start_time_;
// when should the next ping start?
grpc_millis next_ping_scheduled_;
int inter_ping_delay_; int inter_ping_delay_;
int stable_estimate_count_; int stable_estimate_count_;
double bw_est_; double bw_est_;

@ -351,11 +351,14 @@ static size_t get_base64_encoded_size(size_t raw_length) {
return raw_length / 3 * 4 + tail_xtra[raw_length % 3]; return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
} }
size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem) { size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata) {
size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem)); size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
if (grpc_is_binary_header(GRPC_MDKEY(elem))) { if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
return overhead_and_key + get_base64_encoded_size(value_len); return overhead_and_key + (use_true_binary_metadata
? value_len + 1
: get_base64_encoded_size(value_len));
} else { } else {
return overhead_and_key + value_len; return overhead_and_key + value_len;
} }

@ -132,7 +132,8 @@ grpc_mdelem grpc_mdelem_create(
bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem); size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata);
/* Mutator and accessor for grpc_mdelem user data. The destructor function /* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */ is used as a type tag and is checked during user_data fetch. */

@ -19,45 +19,30 @@
#include "src/core/lib/transport/pid_controller.h" #include "src/core/lib/transport/pid_controller.h"
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
void grpc_pid_controller_init(grpc_pid_controller *pid_controller, namespace grpc_core {
grpc_pid_controller_args args) {
pid_controller->args = args;
pid_controller->last_control_value = args.initial_control_value;
grpc_pid_controller_reset(pid_controller);
}
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) { PidController::PidController(const Args &args)
pid_controller->last_error = 0.0; : last_control_value_(args.initial_control_value()), args_(args) {}
pid_controller->last_dc_dt = 0.0;
pid_controller->error_integral = 0.0;
}
double grpc_pid_controller_update(grpc_pid_controller *pid_controller, double PidController::Update(double error, double dt) {
double error, double dt) { if (dt <= 0) return last_control_value_;
if (dt == 0) return pid_controller->last_control_value;
/* integrate error using the trapezoid rule */ /* integrate error using the trapezoid rule */
pid_controller->error_integral += error_integral_ += dt * (last_error_ + error) * 0.5;
dt * (pid_controller->last_error + error) * 0.5; error_integral_ = GPR_CLAMP(error_integral_, -args_.integral_range(),
pid_controller->error_integral = GPR_CLAMP( args_.integral_range());
pid_controller->error_integral, -pid_controller->args.integral_range, double diff_error = (error - last_error_) / dt;
pid_controller->args.integral_range);
double diff_error = (error - pid_controller->last_error) / dt;
/* calculate derivative of control value vs time */ /* calculate derivative of control value vs time */
double dc_dt = pid_controller->args.gain_p * error + double dc_dt = args_.gain_p() * error + args_.gain_i() * error_integral_ +
pid_controller->args.gain_i * pid_controller->error_integral + args_.gain_d() * diff_error;
pid_controller->args.gain_d * diff_error;
/* and perform trapezoidal integration */ /* and perform trapezoidal integration */
double new_control_value = pid_controller->last_control_value + double new_control_value =
dt * (pid_controller->last_dc_dt + dc_dt) * 0.5; last_control_value_ + dt * (last_dc_dt_ + dc_dt) * 0.5;
new_control_value = new_control_value = GPR_CLAMP(new_control_value, args_.min_control_value(),
GPR_CLAMP(new_control_value, pid_controller->args.min_control_value, args_.max_control_value());
pid_controller->args.max_control_value); last_error_ = error;
pid_controller->last_error = error; last_dc_dt_ = dc_dt;
pid_controller->last_dc_dt = dc_dt; last_control_value_ = new_control_value;
pid_controller->last_control_value = new_control_value;
return new_control_value; return new_control_value;
} }
double grpc_pid_controller_last(grpc_pid_controller *pid_controller) { } // namespace grpc_core
return pid_controller->last_control_value;
}

@ -19,9 +19,7 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H #ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
#define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H #define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
#ifdef __cplusplus #include <limits>
extern "C" {
#endif
/* \file Simple PID controller. /* \file Simple PID controller.
Implements a proportional-integral-derivative controller. Implements a proportional-integral-derivative controller.
@ -30,41 +28,87 @@ extern "C" {
Gains can be set to adjust sensitivity to current error (p), the integral Gains can be set to adjust sensitivity to current error (p), the integral
of error (i), and the derivative of error (d). */ of error (i), and the derivative of error (d). */
typedef struct { namespace grpc_core {
double gain_p;
double gain_i;
double gain_d;
double initial_control_value;
double min_control_value;
double max_control_value;
double integral_range;
} grpc_pid_controller_args;
typedef struct { class PidController {
double last_error; public:
double error_integral; class Args {
double last_control_value; public:
double last_dc_dt; double gain_p() const { return gain_p_; }
grpc_pid_controller_args args; double gain_i() const { return gain_i_; }
} grpc_pid_controller; double gain_d() const { return gain_d_; }
double initial_control_value() const { return initial_control_value_; }
double min_control_value() const { return min_control_value_; }
double max_control_value() const { return max_control_value_; }
double integral_range() const { return integral_range_; }
/** Initialize the controller */ Args& set_gain_p(double gain_p) {
void grpc_pid_controller_init(grpc_pid_controller *pid_controller, gain_p_ = gain_p;
grpc_pid_controller_args args); return *this;
}
Args& set_gain_i(double gain_i) {
gain_i_ = gain_i;
return *this;
}
Args& set_gain_d(double gain_d) {
gain_d_ = gain_d;
return *this;
}
Args& set_initial_control_value(double initial_control_value) {
initial_control_value_ = initial_control_value;
return *this;
}
Args& set_min_control_value(double min_control_value) {
min_control_value_ = min_control_value;
return *this;
}
Args& set_max_control_value(double max_control_value) {
max_control_value_ = max_control_value;
return *this;
}
Args& set_integral_range(double integral_range) {
integral_range_ = integral_range;
return *this;
}
/** Reset the controller: useful when things have changed significantly */ private:
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller); double gain_p_ = 0.0;
double gain_i_ = 0.0;
double gain_d_ = 0.0;
double initial_control_value_ = 0.0;
double min_control_value_ = std::numeric_limits<double>::min();
double max_control_value_ = std::numeric_limits<double>::max();
double integral_range_ = std::numeric_limits<double>::max();
};
/** Update the controller: given a current error estimate, and the time since explicit PidController(const Args& args);
the last update, returns a new control value */
double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
double error, double dt);
/** Returns the last control value calculated */ /// Reset the controller internal state: useful when the environment has
double grpc_pid_controller_last(grpc_pid_controller *pid_controller); /// changed significantly
void Reset() {
last_error_ = 0.0;
last_dc_dt_ = 0.0;
error_integral_ = 0.0;
}
#ifdef __cplusplus /// Update the controller: given a current error estimate, and the time since
} /// the last update, returns a new control value
#endif double Update(double error, double dt);
/// Returns the last control value calculated
double last_control_value() const { return last_control_value_; }
/// Returns the current error integral (mostly for testing)
double error_integral() const { return error_integral_; }
private:
double last_error_ = 0.0;
double error_integral_ = 0.0;
double last_control_value_;
double last_dc_dt_ = 0.0;
const Args args_;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */ #endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */

@ -38,8 +38,7 @@ std::shared_ptr<Channel> CreateCustomChannel(
const grpc::string& target, const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds, const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args) { const ChannelArguments& args) {
internal::GrpcLibrary GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds.
init_lib; // We need to call init in case of a bad creds.
return creds return creds
? creds->CreateChannel(target, args) ? creds->CreateChannel(target, args)
: CreateChannelInternal("", grpc_lame_client_channel_create( : CreateChannelInternal("", grpc_lame_client_channel_create(

@ -169,7 +169,7 @@ PHP_METHOD(Server, requestCall) {
/** /**
* Add a http2 over tcp listener. * Add a http2 over tcp listener.
* @param string $addr The address to add * @param string $addr The address to add
* @return bool True on success, false on failure * @return int Port on success, 0 on failure
*/ */
PHP_METHOD(Server, addHttp2Port) { PHP_METHOD(Server, addHttp2Port) {
const char *addr; const char *addr;
@ -190,7 +190,7 @@ PHP_METHOD(Server, addHttp2Port) {
* Add a secure http2 over tcp listener. * Add a secure http2 over tcp listener.
* @param string $addr The address to add * @param string $addr The address to add
* @param ServerCredentials The ServerCredentials object * @param ServerCredentials The ServerCredentials object
* @return bool True on success, false on failure * @return int Port on success, 0 on failure
*/ */
PHP_METHOD(Server, addSecureHttp2Port) { PHP_METHOD(Server, addSecureHttp2Port) {
const char *addr; const char *addr;

@ -73,7 +73,7 @@
set(PACKAGE_TARNAME "<%text>${PACKAGE_NAME}-${PACKAGE_VERSION}</%text>") set(PACKAGE_TARNAME "<%text>${PACKAGE_NAME}-${PACKAGE_VERSION}</%text>")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
project(<%text>${PACKAGE_NAME}</%text> C CXX) project(<%text>${PACKAGE_NAME}</%text> C CXX)
set(gRPC_INSTALL_BINDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/bin" CACHE PATH "Installation directory for executables") set(gRPC_INSTALL_BINDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/bin" CACHE PATH "Installation directory for executables")
set(gRPC_INSTALL_LIBDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/lib" CACHE PATH "Installation directory for libraries") set(gRPC_INSTALL_LIBDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/lib" CACHE PATH "Installation directory for libraries")
set(gRPC_INSTALL_INCLUDEDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/include" CACHE PATH "Installation directory for headers") set(gRPC_INSTALL_INCLUDEDIR "<%text>${CMAKE_INSTALL_PREFIX}</%text>/include" CACHE PATH "Installation directory for headers")
@ -522,6 +522,7 @@
PRIVATE <%text>${CARES_INCLUDE_DIR}</%text> PRIVATE <%text>${CARES_INCLUDE_DIR}</%text>
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
% if lib.build in ['test', 'private'] and lib.language == 'c++': % if lib.build in ['test', 'private'] and lib.language == 'c++':
PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest PRIVATE third_party/googletest/googletest
@ -593,6 +594,7 @@
PRIVATE <%text>${CARES_INCLUDE_DIR}</%text> PRIVATE <%text>${CARES_INCLUDE_DIR}</%text>
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
% if tgt.build in ['test', 'private'] and tgt.language == 'c++': % if tgt.build in ['test', 'private'] and tgt.language == 'c++':
PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest PRIVATE third_party/googletest/googletest

@ -9,6 +9,7 @@
"platforms": tgt.platforms, "platforms": tgt.platforms,
"ci_platforms": tgt.ci_platforms, "ci_platforms": tgt.ci_platforms,
"gtest": tgt.gtest, "gtest": tgt.gtest,
"benchmark": tgt.get("benchmark", False),
"exclude_configs": tgt.get("exclude_configs", []), "exclude_configs": tgt.get("exclude_configs", []),
"exclude_iomgrs": tgt.get("exclude_iomgrs", []), "exclude_iomgrs": tgt.get("exclude_iomgrs", []),
"args": tgt.get("args", []), "args": tgt.get("args", []),

@ -30,7 +30,7 @@ BAD_CLIENT_TESTS = {
'headers': default_test_options._replace(cpu_cost=0.2), 'headers': default_test_options._replace(cpu_cost=0.2),
'initial_settings_frame': default_test_options._replace(cpu_cost=0.2), 'initial_settings_frame': default_test_options._replace(cpu_cost=0.2),
'head_of_line_blocking': default_test_options, 'head_of_line_blocking': default_test_options,
'large_metadata': default_test_options, # 'large_metadata': default_test_options, #disabling as per issue #11745
'server_registered_method': default_test_options, 'server_registered_method': default_test_options,
'simple_request': default_test_options, 'simple_request': default_test_options,
'window_overflow': default_test_options, 'window_overflow': default_test_options,

@ -28,7 +28,7 @@ BAD_CLIENT_TESTS = {
'headers': test_options(), 'headers': test_options(),
'initial_settings_frame': test_options(), 'initial_settings_frame': test_options(),
'head_of_line_blocking': test_options(), 'head_of_line_blocking': test_options(),
'large_metadata': test_options(), # 'large_metadata': test_options(), # disabling as per issue #11745
'server_registered_method': test_options(), 'server_registered_method': test_options(),
'simple_request': test_options(), 'simple_request': test_options(),
'window_overflow': test_options(), 'window_overflow': test_options(),

@ -20,7 +20,11 @@ extern "C" {
#include "src/core/lib/debug/stats.h" #include "src/core/lib/debug/stats.h"
} }
#include <mutex>
#include <thread>
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -79,38 +83,59 @@ static int FindExpectedBucket(int i, int j) {
grpc_stats_histo_bucket_boundaries[i] - 1; grpc_stats_histo_bucket_boundaries[i] - 1;
} }
TEST(StatsTest, IncHistogram) { class HistogramTest : public ::testing::TestWithParam<int> {};
for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) {
std::vector<int> test_values; TEST_P(HistogramTest, IncHistogram) {
for (int j = -1000; const int kHistogram = GetParam();
j < std::vector<std::thread> threads;
grpc_stats_histo_bucket_boundaries[i] int cur_bucket = 0;
[grpc_stats_histo_buckets[i] - 1] + auto run = [kHistogram](const std::vector<int>& test_values,
1000; int expected_bucket) {
j++) { gpr_log(GPR_DEBUG, "expected_bucket:%d nvalues=%" PRIdPTR, expected_bucket,
test_values.push_back(j); test_values.size());
}
std::random_shuffle(test_values.begin(), test_values.end());
if (test_values.size() > 10000) {
test_values.resize(10000);
}
for (auto j : test_values) { for (auto j : test_values) {
Snapshot snapshot; Snapshot snapshot;
int expected_bucket = FindExpectedBucket(i, j);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_stats_inc_histogram[i](&exec_ctx, j); grpc_stats_inc_histogram[kHistogram](&exec_ctx, j);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
auto delta = snapshot.delta(); auto delta = snapshot.delta();
EXPECT_EQ(delta.histograms[grpc_stats_histo_start[i] + expected_bucket], EXPECT_EQ(
1); delta
.histograms[grpc_stats_histo_start[kHistogram] + expected_bucket],
1)
<< "\nhistogram:" << kHistogram
<< "\nexpected_bucket:" << expected_bucket << "\nj:" << j;
}
};
std::vector<int> test_values;
for (int j = -1000;
j <
grpc_stats_histo_bucket_boundaries[kHistogram]
[grpc_stats_histo_buckets[kHistogram] -
1] +
1000;
j++) {
int expected_bucket = FindExpectedBucket(kHistogram, j);
if (cur_bucket != expected_bucket) {
threads.emplace_back(
[test_values, run, cur_bucket]() { run(test_values, cur_bucket); });
cur_bucket = expected_bucket;
test_values.clear();
} }
test_values.push_back(j);
}
run(test_values, cur_bucket);
for (auto& t : threads) {
t.join();
} }
} }
INSTANTIATE_TEST_CASE_P(HistogramTestCases, HistogramTest,
::testing::Range<int>(0, GRPC_STATS_HISTOGRAM_COUNT));
} // namespace testing } // namespace testing
} // namespace grpc } // namespace grpc

@ -62,8 +62,6 @@
#define HTTP2_DETAIL_MSG(STATUS_CODE) \ #define HTTP2_DETAIL_MSG(STATUS_CODE) \
"Received http2 header with status: " #STATUS_CODE "Received http2 header with status: " #STATUS_CODE
#define UNPARSEABLE_DETAIL_MSG "Failed parsing HTTP/2"
#define HTTP1_DETAIL_MSG "Trying to connect an http1.x server" #define HTTP1_DETAIL_MSG "Trying to connect an http1.x server"
/* TODO(zyc) Check the content of incomming data instead of using this length */ /* TODO(zyc) Check the content of incomming data instead of using this length */
@ -208,8 +206,10 @@ static void start_rpc(int target_port, grpc_status_code expected_status,
cq_verify(cqv); cq_verify(cqv);
GPR_ASSERT(status == expected_status); GPR_ASSERT(status == expected_status);
GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( if (expected_detail != NULL) {
expected_detail))); GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string(
expected_detail)));
}
grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv);
@ -330,8 +330,8 @@ int main(int argc, char **argv) {
HTTP2_DETAIL_MSG(502)); HTTP2_DETAIL_MSG(502));
/* unparseable response */ /* unparseable response */
run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, GRPC_STATUS_UNKNOWN,
GRPC_STATUS_UNAVAILABLE, UNPARSEABLE_DETAIL_MSG); NULL);
/* http1 response */ /* http1 response */
run_test(HTTP1_RESP, sizeof(HTTP1_RESP) - 1, GRPC_STATUS_UNAVAILABLE, run_test(HTTP1_RESP, sizeof(HTTP1_RESP) - 1, GRPC_STATUS_UNAVAILABLE,

@ -203,7 +203,6 @@ static void test_bad_ping(grpc_end2end_test_config config) {
// The connection should be closed immediately after the misbehaved pings, // The connection should be closed immediately after the misbehaved pings,
// the in-progress RPC should fail. // the in-progress RPC should fail.
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host, validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config); config);

@ -193,7 +193,7 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) {
char *details_str = grpc_slice_to_c_string(details); char *details_str = grpc_slice_to_c_string(details);
char *method_str = grpc_slice_to_c_string(call_details.method); char *method_str = grpc_slice_to_c_string(call_details.method);
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "keepalive watchdog timeout")); GPR_ASSERT(0 == grpc_slice_str_cmp(details, "keepalive watchdog timeout"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host, validate_host_override_string("foo.test.google.fr:1234", call_details.host,

@ -203,8 +203,7 @@ static void test_max_age_forcibly_close(grpc_end2end_test_config config) {
/* The connection should be closed immediately after the max age grace period, /* The connection should be closed immediately after the max age grace period,
the in-progress RPC should fail. */ the in-progress RPC should fail. */
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host, validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config); config);

@ -159,7 +159,9 @@ static void test_early_server_shutdown_finishes_inflight_calls(
grpc_server_destroy(f.server); grpc_server_destroy(f.server);
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); // new code should give INTERNAL, some older code will give UNAVAILABLE
GPR_ASSERT(status == GRPC_STATUS_INTERNAL ||
status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host, validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config); config);

@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
@ -430,14 +431,13 @@ void pollset_set_test_empty_pollset() {
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
const char *poll_strategy = grpc_get_poll_strategy_name();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
grpc_iomgr_init(&exec_ctx); grpc_init();
grpc_iomgr_start(&exec_ctx); const char *poll_strategy = grpc_get_poll_strategy_name();
if (poll_strategy != NULL && if (poll_strategy != NULL &&
(strcmp(poll_strategy, "epoll") == 0 || (strcmp(poll_strategy, "epollsig") == 0 ||
strcmp(poll_strategy, "epoll-threadpool") == 0)) { strcmp(poll_strategy, "epoll-threadpool") == 0)) {
pollset_set_test_basic(); pollset_set_test_basic();
pollset_set_test_dup_fds(); pollset_set_test_dup_fds();
@ -449,8 +449,8 @@ int main(int argc, char **argv) {
poll_strategy); poll_strategy);
} }
grpc_iomgr_shutdown(&exec_ctx);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
grpc_shutdown();
return 0; return 0;
} }
#else /* defined(GRPC_LINUX_EPOLL) */ #else /* defined(GRPC_LINUX_EPOLL) */

@ -197,3 +197,29 @@ grpc_cc_test(
"//test/core/util:gpr_test_util", "//test/core/util:gpr_test_util",
], ],
) )
grpc_cc_test(
name = "memory_test",
srcs = ["memory_test.cc"],
language = "C++",
deps = [
"//:grpc",
"//test/core/util:gpr_test_util",
],
external_deps = [
"gtest",
],
)
grpc_cc_test(
name = "vector_test",
srcs = ["vector_test.cc"],
language = "C++",
deps = [
"//:grpc",
"//test/core/util:gpr_test_util",
],
external_deps = [
"gtest",
],
)

@ -0,0 +1,42 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/support/vector.h"
#include <gtest/gtest.h>
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
TEST(InlinedVectorTest, CreateAndIterate) {
InlinedVector<int, 1> v{1, 2, 3};
int sum = 0;
for (auto i : v) {
sum += i;
}
EXPECT_EQ(6, sum);
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -71,14 +71,17 @@ grpc_cc_test(
grpc_cc_test( grpc_cc_test(
name = "pid_controller_test", name = "pid_controller_test",
srcs = ["pid_controller_test.c"], srcs = ["pid_controller_test.cc"],
language = "C", language = "C++",
deps = [ deps = [
"//:gpr", "//:gpr",
"//:grpc", "//:grpc",
"//test/core/util:gpr_test_util", "//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
external_deps = [
"gtest",
],
) )
grpc_cc_test( grpc_cc_test(

@ -51,8 +51,7 @@ TEST(BdpEstimatorTest, NoOp) { BdpEstimator est("test"); }
TEST(BdpEstimatorTest, EstimateBdpNoSamples) { TEST(BdpEstimatorTest, EstimateBdpNoSamples) {
BdpEstimator est("test"); BdpEstimator est("test");
int64_t estimate; est.EstimateBdp();
est.EstimateBdp(&estimate);
} }
namespace { namespace {
@ -60,12 +59,10 @@ void AddSamples(BdpEstimator *estimator, int64_t *samples, size_t n) {
estimator->AddIncomingBytes(1234567); estimator->AddIncomingBytes(1234567);
inc_time(); inc_time();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
EXPECT_TRUE(estimator->NeedPing(&exec_ctx));
estimator->SchedulePing(); estimator->SchedulePing();
estimator->StartPing(); estimator->StartPing();
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
estimator->AddIncomingBytes(samples[i]); estimator->AddIncomingBytes(samples[i]);
EXPECT_FALSE(estimator->NeedPing(&exec_ctx));
} }
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(1, GPR_TIMESPAN))); gpr_time_from_millis(1, GPR_TIMESPAN)));
@ -82,16 +79,14 @@ void AddSample(BdpEstimator *estimator, int64_t sample) {
TEST(BdpEstimatorTest, GetEstimate1Sample) { TEST(BdpEstimatorTest, GetEstimate1Sample) {
BdpEstimator est("test"); BdpEstimator est("test");
AddSample(&est, 100); AddSample(&est, 100);
int64_t estimate; est.EstimateBdp();
est.EstimateBdp(&estimate);
} }
TEST(BdpEstimatorTest, GetEstimate2Samples) { TEST(BdpEstimatorTest, GetEstimate2Samples) {
BdpEstimator est("test"); BdpEstimator est("test");
AddSample(&est, 100); AddSample(&est, 100);
AddSample(&est, 100); AddSample(&est, 100);
int64_t estimate; est.EstimateBdp();
est.EstimateBdp(&estimate);
} }
TEST(BdpEstimatorTest, GetEstimate3Samples) { TEST(BdpEstimatorTest, GetEstimate3Samples) {
@ -99,17 +94,10 @@ TEST(BdpEstimatorTest, GetEstimate3Samples) {
AddSample(&est, 100); AddSample(&est, 100);
AddSample(&est, 100); AddSample(&est, 100);
AddSample(&est, 100); AddSample(&est, 100);
int64_t estimate; est.EstimateBdp();
est.EstimateBdp(&estimate);
} }
namespace { namespace {
static int64_t GetEstimate(const BdpEstimator &estimator) {
int64_t out;
EXPECT_TRUE(estimator.EstimateBdp(&out));
return out;
}
int64_t NextPow2(int64_t v) { int64_t NextPow2(int64_t v) {
v--; v--;
v |= v >> 1; v |= v >> 1;
@ -136,7 +124,7 @@ TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) {
if (sample > max) max = sample; if (sample > max) max = sample;
AddSample(&est, sample); AddSample(&est, sample);
if (i >= 3) { if (i >= 3) {
EXPECT_LE(GetEstimate(est), GPR_MAX(65536, 2 * NextPow2(max))) EXPECT_LE(est.EstimateBdp(), GPR_MAX(65536, 2 * NextPow2(max)))
<< " min:" << min << " max:" << max << " sample:" << sample; << " min:" << min << " max:" << max << " sample:" << sample;
} }
} }
@ -145,6 +133,7 @@ TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) {
INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest, INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest,
::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94, ::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94,
141, 211, 316, 474, 711)); 141, 211, 316, 474, 711));
} // namespace testing } // namespace testing
} // namespace grpc_core } // namespace grpc_core

@ -43,10 +43,15 @@ void **to_delete = NULL;
size_t num_to_delete = 0; size_t num_to_delete = 0;
size_t cap_to_delete = 0; size_t cap_to_delete = 0;
typedef struct {
bool eof;
bool use_true_binary_metadata;
bool only_intern_key;
} verify_params;
/* verify that the output generated by encoding the stream matches the /* verify that the output generated by encoding the stream matches the
hexstring passed in */ hexstring passed in */
static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof, static void verify(grpc_exec_ctx *exec_ctx, const verify_params params,
bool use_true_binary_metadata, size_t expect_window_used,
const char *expected, size_t nheaders, ...) { const char *expected, size_t nheaders, ...) {
grpc_slice_buffer output; grpc_slice_buffer output;
grpc_slice merged; grpc_slice merged;
@ -66,9 +71,13 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
e[i - 1].next = &e[i]; e[i - 1].next = &e[i];
e[i].prev = &e[i - 1]; e[i].prev = &e[i - 1];
} }
grpc_slice value_slice = grpc_slice_from_static_string(value);
if (!params.only_intern_key) {
value_slice = grpc_slice_intern(value_slice);
}
e[i].md = grpc_mdelem_from_slices( e[i].md = grpc_mdelem_from_slices(
exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)), exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)),
grpc_slice_intern(grpc_slice_from_static_string(value))); value_slice);
} }
e[0].prev = NULL; e[0].prev = NULL;
e[nheaders - 1].next = NULL; e[nheaders - 1].next = NULL;
@ -90,8 +99,8 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
memset(&stats, 0, sizeof(stats)); memset(&stats, 0, sizeof(stats));
grpc_encode_header_options hopt = { grpc_encode_header_options hopt = {
.stream_id = 0xdeadbeef, .stream_id = 0xdeadbeef,
.is_eof = eof, .is_eof = params.eof,
.use_true_binary_metadata = use_true_binary_metadata, .use_true_binary_metadata = params.use_true_binary_metadata,
.max_frame_size = 16384, .max_frame_size = 16384,
.stats = &stats, .stats = &stats,
}; };
@ -119,28 +128,27 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
static void test_basic_headers(grpc_exec_ctx *exec_ctx) { static void test_basic_headers(grpc_exec_ctx *exec_ctx) {
int i; int i;
verify(exec_ctx, 0, false, false, 0, "000005 0104 deadbeef 40 0161 0161", 1, verify_params params = {
"a", "a"); .eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a"); };
verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a"); verify(exec_ctx, params, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef be 40 0162 0163", verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
2, "a", "a", "b", "c"); verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
verify(exec_ctx, 0, false, false, 0, "000002 0104 deadbeef bf be", 2, "a", verify(exec_ctx, params, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a",
"a", "b", "c"); "b", "c");
verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 7f 00 0164", 1, verify(exec_ctx, params, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c");
"a", "d"); verify(exec_ctx, params, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
/* flush out what's there to make a few values look very popular */ /* flush out what's there to make a few values look very popular */
for (i = 0; i < 350; i++) { for (i = 0; i < 350; i++) {
verify(exec_ctx, 0, false, false, 0, "000003 0104 deadbeef c0 bf be", 3, verify(exec_ctx, params, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b",
"a", "a", "b", "c", "a", "d"); "c", "a", "d");
} }
verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef c0 00 016b 0176", verify(exec_ctx, params, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a",
2, "a", "a", "k", "v"); "k", "v");
/* this could be 000004 0104 deadbeef 0f 30 0176 also */ /* this could be 000004 0104 deadbeef 0f 30 0176 also */
verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 0f 2f 0176", 1, verify(exec_ctx, params, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
"a", "v");
} }
static void encode_int_to_str(int i, char *p) { static void encode_int_to_str(int i, char *p) {
@ -156,6 +164,10 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
char key[3], value[3]; char key[3], value[3];
char *expect; char *expect;
verify_params params = {
.eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
};
for (i = 0; i < 114; i++) { for (i = 0; i < 114; i++) {
encode_int_to_str(i, key); encode_int_to_str(i, key);
encode_int_to_str(i + 1, value); encode_int_to_str(i + 1, value);
@ -174,27 +186,28 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
} }
if (i > 0) { if (i > 0) {
verify(exec_ctx, 0, false, false, 0, expect, 2, "aa", "ba", key, value); verify(exec_ctx, params, expect, 2, "aa", "ba", key, value);
} else { } else {
verify(exec_ctx, 0, false, false, 0, expect, 1, key, value); verify(exec_ctx, params, expect, 1, key, value);
} }
gpr_free(expect); gpr_free(expect);
} }
/* if the above passes, then we must have just knocked this pair out of the /* if the above passes, then we must have just knocked this pair out of the
decoder stack, and so we'll be forced to re-encode it */ decoder stack, and so we'll be forced to re-encode it */
verify(exec_ctx, 0, false, false, 0, "000007 0104 deadbeef 40 026161 026261", verify(exec_ctx, params, "000007 0104 deadbeef 40 026161 026261", 1, "aa",
1, "aa", "ba"); "ba");
} }
static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx, static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
const char *key, const char *key,
const char *value) { const char *value,
bool use_true_binary) {
grpc_slice_buffer output; grpc_slice_buffer output;
grpc_mdelem elem = grpc_mdelem_from_slices( grpc_mdelem elem = grpc_mdelem_from_slices(
exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)), exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)),
grpc_slice_intern(grpc_slice_from_static_string(value))); grpc_slice_intern(grpc_slice_from_static_string(value)));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary);
size_t initial_table_size = g_compressor.table_size; size_t initial_table_size = g_compressor.table_size;
grpc_linked_mdelem *e = gpr_malloc(sizeof(*e)); grpc_linked_mdelem *e = gpr_malloc(sizeof(*e));
grpc_metadata_batch b; grpc_metadata_batch b;
@ -209,11 +222,12 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
grpc_transport_one_way_stats stats; grpc_transport_one_way_stats stats;
memset(&stats, 0, sizeof(stats)); memset(&stats, 0, sizeof(stats));
grpc_encode_header_options hopt = {.stream_id = 0xdeadbeef, grpc_encode_header_options hopt = {
.is_eof = false, .stream_id = 0xdeadbeef,
.use_true_binary_metadata = false, .is_eof = false,
.max_frame_size = 16384, .use_true_binary_metadata = use_true_binary,
.stats = &stats}; .max_frame_size = 16384,
.stats = &stats};
grpc_chttp2_encode_header(exec_ctx, &g_compressor, NULL, 0, &b, &hopt, grpc_chttp2_encode_header(exec_ctx, &g_compressor, NULL, 0, &b, &hopt,
&output); &output);
grpc_slice_buffer_destroy_internal(exec_ctx, &output); grpc_slice_buffer_destroy_internal(exec_ctx, &output);
@ -224,8 +238,24 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
} }
static void test_encode_header_size(grpc_exec_ctx *exec_ctx) { static void test_encode_header_size(grpc_exec_ctx *exec_ctx) {
verify_table_size_change_match_elem_size(exec_ctx, "hello", "world"); verify_table_size_change_match_elem_size(exec_ctx, "hello", "world", false);
verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world"); verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world",
false);
verify_table_size_change_match_elem_size(exec_ctx, "true-binary-bin",
"I_am_true_binary_value", true);
}
static void test_interned_key_indexed(grpc_exec_ctx *exec_ctx) {
int i;
verify_params params = {
.eof = false, .use_true_binary_metadata = false, .only_intern_key = true,
};
verify(exec_ctx, params, "000009 0104 deadbeef 40 0161 0162 0f2f 0163", 2,
"a", "b", "a", "c");
for (i = 0; i < 10; i++) {
verify(exec_ctx, params, "000008 0104 deadbeef 0f2f 0162 0f2f 0163", 2, "a",
"b", "a", "c");
}
} }
static void run_test(void (*test)(grpc_exec_ctx *exec_ctx), const char *name) { static void run_test(void (*test)(grpc_exec_ctx *exec_ctx), const char *name) {
@ -245,6 +275,7 @@ int main(int argc, char **argv) {
TEST(test_basic_headers); TEST(test_basic_headers);
TEST(test_decode_table_overflow); TEST(test_decode_table_overflow);
TEST(test_encode_header_size); TEST(test_encode_header_size);
TEST(test_interned_key_indexed);
grpc_shutdown(); grpc_shutdown();
for (i = 0; i < num_to_delete; i++) { for (i = 0; i < num_to_delete; i++) {
gpr_free(to_delete[i]); gpr_free(to_delete[i]);

@ -302,7 +302,7 @@ static void verify_ascii_header_size(grpc_exec_ctx *exec_ctx, const char *key,
grpc_mdelem elem = grpc_mdelem_from_slices( grpc_mdelem elem = grpc_mdelem_from_slices(
exec_ctx, maybe_intern(grpc_slice_from_static_string(key), intern_key), exec_ctx, maybe_intern(grpc_slice_from_static_string(key), intern_key),
maybe_intern(grpc_slice_from_static_string(value), intern_value)); maybe_intern(grpc_slice_from_static_string(value), intern_value));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
size_t expected_size = 32 + strlen(key) + strlen(value); size_t expected_size = 32 + strlen(key) + strlen(value);
GPR_ASSERT(expected_size == elem_size); GPR_ASSERT(expected_size == elem_size);
GRPC_MDELEM_UNREF(exec_ctx, elem); GRPC_MDELEM_UNREF(exec_ctx, elem);
@ -316,7 +316,7 @@ static void verify_binary_header_size(grpc_exec_ctx *exec_ctx, const char *key,
maybe_intern(grpc_slice_from_static_buffer(value, value_len), maybe_intern(grpc_slice_from_static_buffer(value, value_len),
intern_value)); intern_value));
GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem))); GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
grpc_slice value_slice = grpc_slice value_slice =
grpc_slice_from_copied_buffer((const char *)value, value_len); grpc_slice_from_copied_buffer((const char *)value, value_len);
grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice); grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);

@ -1,78 +0,0 @@
/*
*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/transport/pid_controller.h"
#include <float.h>
#include <math.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/lib/support/string.h"
#include "test/core/util/test_config.h"
static void test_noop(void) {
gpr_log(GPR_INFO, "test_noop");
grpc_pid_controller pid;
grpc_pid_controller_init(
&pid, (grpc_pid_controller_args){.gain_p = 1,
.gain_i = 1,
.gain_d = 1,
.initial_control_value = 1,
.min_control_value = DBL_MIN,
.max_control_value = DBL_MAX,
.integral_range = DBL_MAX});
}
static void test_simple_convergence(double gain_p, double gain_i, double gain_d,
double dt, double set_point, double start) {
gpr_log(GPR_INFO,
"test_simple_convergence(p=%lf, i=%lf, d=%lf); dt=%lf set_point=%lf "
"start=%lf",
gain_p, gain_i, gain_d, dt, set_point, start);
grpc_pid_controller pid;
grpc_pid_controller_init(
&pid, (grpc_pid_controller_args){.gain_p = gain_p,
.gain_i = gain_i,
.gain_d = gain_d,
.initial_control_value = start,
.min_control_value = DBL_MIN,
.max_control_value = DBL_MAX,
.integral_range = DBL_MAX});
for (int i = 0; i < 100000; i++) {
grpc_pid_controller_update(&pid, set_point - grpc_pid_controller_last(&pid),
1);
}
GPR_ASSERT(fabs(set_point - grpc_pid_controller_last(&pid)) < 0.1);
if (gain_i > 0) {
GPR_ASSERT(fabs(pid.error_integral) < 0.1);
}
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_noop();
test_simple_convergence(0.2, 0, 0, 1, 100, 0);
test_simple_convergence(0.2, 0.1, 0, 1, 100, 0);
test_simple_convergence(0.2, 0.1, 0.1, 1, 100, 0);
return 0;
}

@ -0,0 +1,91 @@
/*
*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/transport/pid_controller.h"
#include <float.h>
#include <math.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include <gtest/gtest.h>
#include "src/core/lib/support/string.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
TEST(PidController, NoOp) {
PidController pid(PidController::Args()
.set_gain_p(1)
.set_gain_i(1)
.set_gain_d(1)
.set_initial_control_value(1));
}
struct SimpleConvergenceTestArgs {
double gain_p;
double gain_i;
double gain_d;
double dt;
double set_point;
double start;
};
std::ostream& operator<<(std::ostream& out, SimpleConvergenceTestArgs args) {
return out << "gain_p:" << args.gain_p << " gain_i:" << args.gain_i
<< " gain_d:" << args.gain_d << " dt:" << args.dt
<< " set_point:" << args.set_point << " start:" << args.start;
}
class SimpleConvergenceTest
: public ::testing::TestWithParam<SimpleConvergenceTestArgs> {};
TEST_P(SimpleConvergenceTest, Converges) {
PidController pid(PidController::Args()
.set_gain_p(GetParam().gain_p)
.set_gain_i(GetParam().gain_i)
.set_gain_d(GetParam().gain_d)
.set_initial_control_value(GetParam().start));
for (int i = 0; i < 100000; i++) {
pid.Update(GetParam().set_point - pid.last_control_value(), GetParam().dt);
}
EXPECT_LT(fabs(GetParam().set_point - pid.last_control_value()), 0.1);
if (GetParam().gain_i > 0) {
EXPECT_LT(fabs(pid.error_integral()), 0.1);
}
}
INSTANTIATE_TEST_CASE_P(
X, SimpleConvergenceTest,
::testing::Values(SimpleConvergenceTestArgs{0.2, 0, 0, 1, 100, 0},
SimpleConvergenceTestArgs{0.2, 0.1, 0, 1, 100, 0},
SimpleConvergenceTestArgs{0.2, 0.1, 0.1, 1, 100, 0}));
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -34,6 +34,15 @@ extern "C" {
auto &force_library_initialization = Library::get(); auto &force_library_initialization = Library::get();
static grpc_slice MakeSlice(std::vector<uint8_t> bytes) {
grpc_slice s = grpc_slice_malloc(bytes.size());
uint8_t *p = GRPC_SLICE_START_PTR(s);
for (auto b : bytes) {
*p++ = b;
}
return s;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// HPACK encoder // HPACK encoder
// //
@ -52,6 +61,48 @@ static void BM_HpackEncoderInitDestroy(benchmark::State &state) {
} }
BENCHMARK(BM_HpackEncoderInitDestroy); BENCHMARK(BM_HpackEncoderInitDestroy);
static void BM_HpackEncoderEncodeDeadline(benchmark::State &state) {
TrackCounters track_counters;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_millis saved_now = grpc_exec_ctx_now(&exec_ctx);
grpc_metadata_batch b;
grpc_metadata_batch_init(&b);
b.deadline = saved_now + 30 * 1000;
grpc_chttp2_hpack_compressor c;
grpc_chttp2_hpack_compressor_init(&c);
grpc_transport_one_way_stats stats;
memset(&stats, 0, sizeof(stats));
grpc_slice_buffer outbuf;
grpc_slice_buffer_init(&outbuf);
while (state.KeepRunning()) {
grpc_encode_header_options hopt = {
static_cast<uint32_t>(state.iterations()),
true,
false,
(size_t)1024,
&stats,
};
grpc_chttp2_encode_header(&exec_ctx, &c, NULL, 0, &b, &hopt, &outbuf);
grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, &outbuf);
grpc_exec_ctx_flush(&exec_ctx);
}
grpc_metadata_batch_destroy(&exec_ctx, &b);
grpc_chttp2_hpack_compressor_destroy(&exec_ctx, &c);
grpc_slice_buffer_destroy_internal(&exec_ctx, &outbuf);
grpc_exec_ctx_finish(&exec_ctx);
std::ostringstream label;
label << "framing_bytes/iter:" << (static_cast<double>(stats.framing_bytes) /
static_cast<double>(state.iterations()))
<< " header_bytes/iter:" << (static_cast<double>(stats.header_bytes) /
static_cast<double>(state.iterations()));
track_counters.AddLabel(label.str());
track_counters.Finish(state);
}
BENCHMARK(BM_HpackEncoderEncodeDeadline);
template <class Fixture> template <class Fixture>
static void BM_HpackEncoderEncodeHeader(benchmark::State &state) { static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
TrackCounters track_counters; TrackCounters track_counters;
@ -104,7 +155,7 @@ static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
static_cast<double>(state.iterations())) static_cast<double>(state.iterations()))
<< " header_bytes/iter:" << (static_cast<double>(stats.header_bytes) / << " header_bytes/iter:" << (static_cast<double>(stats.header_bytes) /
static_cast<double>(state.iterations())); static_cast<double>(state.iterations()));
state.SetLabel(label.str()); track_counters.AddLabel(label.str());
track_counters.Finish(state); track_counters.Finish(state);
} }
@ -220,6 +271,45 @@ class RepresentativeClientInitialMetadata {
} }
}; };
// This fixture reflects how initial metadata are sent by a production client,
// with non-indexed :path and binary headers. The metadata here are the same as
// the corresponding parser benchmark below.
class MoreRepresentativeClientInitialMetadata {
public:
static constexpr bool kEnableTrueBinary = true;
static std::vector<grpc_mdelem> GetElems(grpc_exec_ctx *exec_ctx) {
return {
GRPC_MDELEM_SCHEME_HTTP, GRPC_MDELEM_METHOD_POST,
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH,
grpc_slice_intern(grpc_slice_from_static_string(
"/grpc.test.FooService/BarMethod"))),
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_AUTHORITY,
grpc_slice_intern(grpc_slice_from_static_string(
"foo.test.google.fr:1234"))),
grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_GRPC_TRACE_BIN,
grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18"
"\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28"
"\x29\x2a\x2b\x2c\x2d\x2e\x2f"
"\x30")),
grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_GRPC_TAGS_BIN,
grpc_slice_from_static_string("\x00\x01\x02\x03\x04\x05\x06\x07\x08"
"\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13")),
GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP,
GRPC_MDELEM_TE_TRAILERS,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC,
grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_USER_AGENT,
grpc_slice_intern(grpc_slice_from_static_string(
"grpc-c/3.0.0-dev (linux; chttp2; green)")))};
}
};
class RepresentativeServerInitialMetadata { class RepresentativeServerInitialMetadata {
public: public:
static constexpr bool kEnableTrueBinary = true; static constexpr bool kEnableTrueBinary = true;
@ -316,6 +406,9 @@ BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
RepresentativeClientInitialMetadata) RepresentativeClientInitialMetadata)
->Args({0, 16384}); ->Args({0, 16384});
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
MoreRepresentativeClientInitialMetadata)
->Args({0, 16384});
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
RepresentativeServerInitialMetadata) RepresentativeServerInitialMetadata)
->Args({0, 16384}); ->Args({0, 16384});
@ -359,11 +452,13 @@ static void BM_HpackParserParseHeader(benchmark::State &state) {
p.on_header = UnrefHeader; p.on_header = UnrefHeader;
p.on_header_user_data = nullptr; p.on_header_user_data = nullptr;
for (auto slice : init_slices) { for (auto slice : init_slices) {
grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice); GPR_ASSERT(GRPC_ERROR_NONE ==
grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice));
} }
while (state.KeepRunning()) { while (state.KeepRunning()) {
for (auto slice : benchmark_slices) { for (auto slice : benchmark_slices) {
grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice); GPR_ASSERT(GRPC_ERROR_NONE ==
grpc_chttp2_hpack_parser_parse(&exec_ctx, &p, slice));
} }
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
} }
@ -376,15 +471,6 @@ static void BM_HpackParserParseHeader(benchmark::State &state) {
namespace hpack_parser_fixtures { namespace hpack_parser_fixtures {
static grpc_slice MakeSlice(std::vector<uint8_t> bytes) {
grpc_slice s = grpc_slice_malloc(bytes.size());
uint8_t *p = GRPC_SLICE_START_PTR(s);
for (auto b : bytes) {
*p++ = b;
}
return s;
}
class EmptyBatch { class EmptyBatch {
public: public:
static std::vector<grpc_slice> GetInitSlices() { return {}; } static std::vector<grpc_slice> GetInitSlices() { return {}; }
@ -572,6 +658,54 @@ class RepresentativeClientInitialMetadata {
} }
}; };
// This fixture reflects how initial metadata are sent by a production client,
// with non-indexed :path and binary headers. The metadata here are the same as
// the corresponding encoder benchmark above.
class MoreRepresentativeClientInitialMetadata {
public:
static std::vector<grpc_slice> GetInitSlices() {
return {MakeSlice(
{0x40, 0x07, ':', 's', 'c', 'h', 'e', 'm', 'e', 0x04, 'h', 't',
't', 'p', 0x40, 0x07, ':', 'm', 'e', 't', 'h', 'o', 'd', 0x04,
'P', 'O', 'S', 'T', 0x40, 0x05, ':', 'p', 'a', 't', 'h', 0x1f,
'/', 'g', 'r', 'p', 'c', '.', 't', 'e', 's', 't', '.', 'F',
'o', 'o', 'S', 'e', 'r', 'v', 'i', 'c', 'e', '/', 'B', 'a',
'r', 'M', 'e', 't', 'h', 'o', 'd', 0x40, 0x0a, ':', 'a', 'u',
't', 'h', 'o', 'r', 'i', 't', 'y', 0x09, 'l', 'o', 'c', 'a',
'l', 'h', 'o', 's', 't', 0x40, 0x0e, 'g', 'r', 'p', 'c', '-',
't', 'r', 'a', 'c', 'e', '-', 'b', 'i', 'n', 0x31, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x40,
0x0d, 'g', 'r', 'p', 'c', '-', 't', 'a', 'g', 's', '-', 'b',
'i', 'n', 0x14, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x40,
0x0c, 'c', 'o', 'n', 't', 'e', 'n', 't', '-', 't', 'y', 'p',
'e', 0x10, 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o',
'n', '/', 'g', 'r', 'p', 'c', 0x40, 0x14, 'g', 'r', 'p', 'c',
'-', 'a', 'c', 'c', 'e', 'p', 't', '-', 'e', 'n', 'c', 'o',
'd', 'i', 'n', 'g', 0x15, 'i', 'd', 'e', 'n', 't', 'i', 't',
'y', ',', 'd', 'e', 'f', 'l', 'a', 't', 'e', ',', 'g', 'z',
'i', 'p', 0x40, 0x02, 't', 'e', 0x08, 't', 'r', 'a', 'i', 'l',
'e', 'r', 's', 0x40, 0x0a, 'u', 's', 'e', 'r', '-', 'a', 'g',
'e', 'n', 't', 0x22, 'b', 'a', 'd', '-', 'c', 'l', 'i', 'e',
'n', 't', ' ', 'g', 'r', 'p', 'c', '-', 'c', '/', '0', '.',
'1', '2', '.', '0', '.', '0', ' ', '(', 'l', 'i', 'n', 'u',
'x', ')'})};
}
static std::vector<grpc_slice> GetBenchmarkSlices() {
return {MakeSlice(
{0xc7, 0xc6, 0xc5, 0xc4, 0x7f, 0x04, 0x31, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x7f, 0x03, 0x14, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0xc1, 0xc0, 0xbf, 0xbe})};
}
};
class RepresentativeServerInitialMetadata { class RepresentativeServerInitialMetadata {
public: public:
static std::vector<grpc_slice> GetInitSlices() { static std::vector<grpc_slice> GetInitSlices() {
@ -645,6 +779,8 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>); BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeClientInitialMetadata); RepresentativeClientInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
MoreRepresentativeClientInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata); RepresentativeServerInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,

@ -428,9 +428,8 @@ static void BM_TransportStreamSend(benchmark::State &state) {
return; return;
} }
// force outgoing window to be yuge // force outgoing window to be yuge
s->chttp2_stream()->flow_control.remote_window_delta = s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
1024 * 1024 * 1024; f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
f.chttp2_transport()->flow_control.remote_window = 1024 * 1024 * 1024;
grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0); grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0);
reset_op(); reset_op();
op.on_complete = c.get(); op.on_complete = c.get();
@ -560,22 +559,21 @@ static void BM_TransportStreamRecv(benchmark::State &state) {
std::unique_ptr<Closure> drain_continue; std::unique_ptr<Closure> drain_continue;
grpc_slice recv_slice; grpc_slice recv_slice;
std::unique_ptr<Closure> c = MakeClosure([&](grpc_exec_ctx *exec_ctx, std::unique_ptr<Closure> c =
grpc_error *error) { MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
if (!state.KeepRunning()) return; if (!state.KeepRunning()) return;
// force outgoing window to be yuge // force outgoing window to be yuge
s.chttp2_stream()->flow_control.local_window_delta = 1024 * 1024 * 1024; s.chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
s.chttp2_stream()->flow_control.announced_window_delta = 1024 * 1024 * 1024; f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
f.chttp2_transport()->flow_control.announced_window = 1024 * 1024 * 1024; received = 0;
received = 0; reset_op();
reset_op(); op.on_complete = do_nothing.get();
op.on_complete = do_nothing.get(); op.recv_message = true;
op.recv_message = true; op.payload->recv_message.recv_message = &recv_stream;
op.payload->recv_message.recv_message = &recv_stream; op.payload->recv_message.recv_message_ready = drain_start.get();
op.payload->recv_message.recv_message_ready = drain_start.get(); s.Op(exec_ctx, &op);
s.Op(exec_ctx, &op); f.PushInput(grpc_slice_ref(incoming_data));
f.PushInput(grpc_slice_ref(incoming_data)); });
});
drain_start = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { drain_start = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
if (recv_stream == NULL) { if (recv_stream == NULL) {

@ -142,15 +142,18 @@ class TrickledCHTTP2 : public EndpointPairFixture {
client->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr, client->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
server->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr, server->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr,
server->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr, server->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
client->flow_control.remote_window, server->flow_control.remote_window, client->flow_control->remote_window(),
client->flow_control.announced_window, server->flow_control->remote_window(),
server->flow_control.announced_window, client->flow_control->announced_window(),
client_stream ? client_stream->flow_control.remote_window_delta : -1, server->flow_control->announced_window(),
server_stream ? server_stream->flow_control.remote_window_delta : -1, client_stream ? client_stream->flow_control->remote_window_delta() : -1,
client_stream ? client_stream->flow_control.local_window_delta : -1, server_stream ? server_stream->flow_control->remote_window_delta() : -1,
server_stream ? server_stream->flow_control.local_window_delta : -1, client_stream ? client_stream->flow_control->local_window_delta() : -1,
client_stream ? client_stream->flow_control.announced_window_delta : -1, server_stream ? server_stream->flow_control->local_window_delta() : -1,
server_stream ? server_stream->flow_control.announced_window_delta : -1, client_stream ? client_stream->flow_control->announced_window_delta()
: -1,
server_stream ? server_stream->flow_control->announced_window_delta()
: -1,
client->settings[GRPC_PEER_SETTINGS] client->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
client->settings[GRPC_LOCAL_SETTINGS] client->settings[GRPC_LOCAL_SETTINGS]

@ -20,6 +20,9 @@
void TrackCounters::Finish(benchmark::State &state) { void TrackCounters::Finish(benchmark::State &state) {
std::ostringstream out; std::ostringstream out;
for (const auto &l : labels_) {
out << l << ' ';
}
AddToLabel(out, state); AddToLabel(out, state);
std::string label = out.str(); std::string label = out.str();
if (label.length() && label[0] == ' ') { if (label.length() && label[0] == ' ') {
@ -28,6 +31,10 @@ void TrackCounters::Finish(benchmark::State &state) {
state.SetLabel(label.c_str()); state.SetLabel(label.c_str());
} }
void TrackCounters::AddLabel(const grpc::string &label) {
labels_.push_back(label);
}
void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) { void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) {
grpc_stats_data stats_end; grpc_stats_data stats_end;
grpc_stats_collect(&stats_end); grpc_stats_collect(&stats_end);

@ -20,6 +20,7 @@
#define TEST_CPP_MICROBENCHMARKS_COUNTERS_H #define TEST_CPP_MICROBENCHMARKS_COUNTERS_H
#include <sstream> #include <sstream>
#include <vector>
extern "C" { extern "C" {
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
@ -65,10 +66,12 @@ class TrackCounters {
public: public:
TrackCounters() { grpc_stats_collect(&stats_begin_); } TrackCounters() { grpc_stats_collect(&stats_begin_); }
virtual void Finish(benchmark::State& state); virtual void Finish(benchmark::State& state);
virtual void AddLabel(const grpc::string& label);
virtual void AddToLabel(std::ostream& out, benchmark::State& state); virtual void AddToLabel(std::ostream& out, benchmark::State& state);
private: private:
grpc_stats_data stats_begin_; grpc_stats_data stats_begin_;
std::vector<grpc::string> labels_;
#ifdef GPR_LOW_LEVEL_COUNTERS #ifdef GPR_LOW_LEVEL_COUNTERS
const size_t mu_locks_at_start_ = gpr_atm_no_barrier_load(&gpr_mu_locks); const size_t mu_locks_at_start_ = gpr_atm_no_barrier_load(&gpr_mu_locks);
const size_t atm_cas_at_start_ = const size_t atm_cas_at_start_ =

@ -0,0 +1 @@
Subproject commit cc4bed2d74f7c8717e31f9579214ab52a9c9c610

@ -0,0 +1,47 @@
#!/usr/bin/env python2.7
#
# Copyright 2017 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Reads stdin to find error_refcount log lines, and prints reference leaks
# to stdout
# usege: python error_ref_leak < logfile.txt
import sys
import re
data = sys.stdin.readlines()
errs = []
for line in data:
# if we care about the line
if re.search(r'error.cc', line):
# str manip to cut off left part of log line
line = line.partition('error.cc:')[-1]
line = re.sub(r'\d+] ', r'', line)
line = line.strip().split()
err = line[0].strip(":")
if line[1] == "create":
assert(err not in errs)
errs.append(err)
elif line[0] == "realloc":
errs.remove(line[1])
errs.append(line[3])
# explicitly look for the last dereference
elif line[1] == "1" and line[3] == "0":
assert(err in errs)
errs.remove(err)
print "leaked:", errs

@ -17,17 +17,18 @@
set -e set -e
mkdir -p /var/local/git mkdir -p /var/local/git
git clone /var/local/jenkins/grpc /var/local/git/grpc git clone /var/local/jenkins/grpc-node /var/local/git/grpc-node
# clone gRPC submodules, use data from locally cloned submodules where possible # clone gRPC submodules, use data from locally cloned submodules where possible
(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \ (cd /var/local/jenkins/grpc-node/ && git submodule foreach 'cd /var/local/git/grpc-node \
&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \ && git submodule update --init --recursive --reference /var/local/jenkins/grpc-node/${name} \
${name}') ${name}')
# copy service account keys if available # copy service account keys if available
cp -r /var/local/jenkins/service_account $HOME || true cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc cd /var/local/git/grpc-node
# build Node interop client & server # build Node interop client & server
npm install -g node-gyp npm install -g node-gyp gulp
npm install --unsafe-perm --build-from-source npm install
gulp setup

@ -1041,6 +1041,7 @@ src/core/lib/support/string.h \
src/core/lib/support/string_windows.h \ src/core/lib/support/string_windows.h \
src/core/lib/support/time_precise.h \ src/core/lib/support/time_precise.h \
src/core/lib/support/tmpfile.h \ src/core/lib/support/tmpfile.h \
src/core/lib/support/vector.h \
src/core/lib/surface/alarm_internal.h \ src/core/lib/surface/alarm_internal.h \
src/core/lib/surface/api_trace.h \ src/core/lib/surface/api_trace.h \
src/core/lib/surface/call.h \ src/core/lib/surface/call.h \

@ -1020,6 +1020,7 @@ src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.cc \ src/core/ext/transport/chttp2/transport/chttp2_transport.cc \
src/core/ext/transport/chttp2/transport/chttp2_transport.h \ src/core/ext/transport/chttp2/transport/chttp2_transport.h \
src/core/ext/transport/chttp2/transport/flow_control.cc \ src/core/ext/transport/chttp2/transport/flow_control.cc \
src/core/ext/transport/chttp2/transport/flow_control.h \
src/core/ext/transport/chttp2/transport/frame.h \ src/core/ext/transport/chttp2/transport/frame.h \
src/core/ext/transport/chttp2/transport/frame_data.cc \ src/core/ext/transport/chttp2/transport/frame_data.cc \
src/core/ext/transport/chttp2/transport/frame_data.h \ src/core/ext/transport/chttp2/transport/frame_data.h \
@ -1354,6 +1355,7 @@ src/core/lib/support/tmpfile.h \
src/core/lib/support/tmpfile_msys.cc \ src/core/lib/support/tmpfile_msys.cc \
src/core/lib/support/tmpfile_posix.cc \ src/core/lib/support/tmpfile_posix.cc \
src/core/lib/support/tmpfile_windows.cc \ src/core/lib/support/tmpfile_windows.cc \
src/core/lib/support/vector.h \
src/core/lib/support/wrap_memcpy.cc \ src/core/lib/support/wrap_memcpy.cc \
src/core/lib/surface/README.md \ src/core/lib/surface/README.md \
src/core/lib/surface/alarm.cc \ src/core/lib/surface/alarm.cc \

@ -26,7 +26,7 @@ mkdir -p reports
echo '<html><head></head><body>' > reports/kokoro_index.html echo '<html><head></head><body>' > reports/kokoro_index.html
echo '<h1>'${KOKORO_JOB_NAME}', build '#${KOKORO_BUILD_NUMBER}'</h1>' >> reports/kokoro_index.html echo '<h1>'${KOKORO_JOB_NAME}', build '#${KOKORO_BUILD_NUMBER}'</h1>' >> reports/kokoro_index.html
echo '<h2><a href="https://kokoro.corp.google.com/job/'${KOKORO_JOB_PATH}'/'${KOKORO_BUILD_NUMBER}'/">Kokoro build dashboard (internal only)</a></h2>' >> reports/kokoro_index.html echo '<h2><a href="https://kokoro2.corp.google.com/job/'${KOKORO_JOB_PATH}'/'${KOKORO_BUILD_NUMBER}'/">Kokoro build dashboard (internal only)</a></h2>' >> reports/kokoro_index.html
echo '<h2><a href="https://sponge.corp.google.com/invocation?id='${KOKORO_BUILD_ID}'&searchFor=">Test result dashboard (internal only)</a></h2>' >> reports/kokoro_index.html echo '<h2><a href="https://sponge.corp.google.com/invocation?id='${KOKORO_BUILD_ID}'&searchFor=">Test result dashboard (internal only)</a></h2>' >> reports/kokoro_index.html
echo '<h2><a href="test_report.html">HTML test report (Not available yet)</a></h2>' >> reports/kokoro_index.html echo '<h2><a href="test_report.html">HTML test report (Not available yet)</a></h2>' >> reports/kokoro_index.html
echo '<h2><a href="test_log.txt">Test log (Not available yet)</a></h2>' >> reports/kokoro_index.html echo '<h2><a href="test_log.txt">Test log (Not available yet)</a></h2>' >> reports/kokoro_index.html

@ -26,6 +26,7 @@ git submodule update --init
# Set up gRPC-Go and gRPC-Java to test # Set up gRPC-Go and gRPC-Java to test
git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
# Download json file. # Download json file.
mkdir ~/service_account mkdir ~/service_account

@ -30,6 +30,7 @@ brew install md5sha1sum
# Set up gRPC-Go and gRPC-Java to test # Set up gRPC-Go and gRPC-Java to test
git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
# Set up Docker for Mac # Set up Docker for Mac
docker-machine create -d virtualbox --virtualbox-share-folder "/Users/kbuilder/workspace:" default docker-machine create -d virtualbox --virtualbox-share-folder "/Users/kbuilder/workspace:" default

@ -22,4 +22,4 @@ cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc source tools/internal_ci/helper_scripts/prepare_build_linux_rc
tools/interop_matrix/run_interop_matrix_tests.py --language=all --release=all --report_file=sponge_log.xml --bq_result_table interop_results $@ tools/interop_matrix/run_interop_matrix_tests.py --language=all --release=all --allow_flakes --report_file=sponge_log.xml --bq_result_table interop_results $@

@ -174,7 +174,7 @@ def build_all_images_for_release(lang, release):
# If we not using current tree or the sibling for grpc stack, do checkout. # If we not using current tree or the sibling for grpc stack, do checkout.
if args.git_checkout: if args.git_checkout:
stack_base = checkout_grpc_stack(lang, release) stack_base = checkout_grpc_stack(lang, release)
var ={'go': 'GRPC_GO_ROOT', 'java': 'GRPC_JAVA_ROOT'}.get(lang, 'GRPC_ROOT') var ={'go': 'GRPC_GO_ROOT', 'java': 'GRPC_JAVA_ROOT', 'node': 'GRPC_NODE_ROOT'}.get(lang, 'GRPC_ROOT')
env[var] = stack_base env[var] = stack_base
for runtime in client_matrix.LANG_RUNTIME_MATRIX[lang]: for runtime in client_matrix.LANG_RUNTIME_MATRIX[lang]:

@ -48,6 +48,14 @@ else
echo "WARNING: grpc-go not found, it won't be mounted to the docker container." echo "WARNING: grpc-go not found, it won't be mounted to the docker container."
fi fi
echo "GRPC_NODE_ROOT: ${GRPC_NODE_ROOT:=$(cd ../grpc-node && pwd)}"
if [ -n "$GRPC_NODE_ROOT" ]
then
MOUNT_ARGS+=" -v $GRPC_NODE_ROOT:/var/local/jenkins/grpc-node:ro"
else
echo "WARNING: grpc-node not found, it won't be mounted to the docker container."
fi
mkdir -p /tmp/ccache mkdir -p /tmp/ccache
# Mount service account dir if available. # Mount service account dir if available.

@ -2437,23 +2437,6 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "transport_pid_controller_test",
"src": [
"test/core/transport/pid_controller_test.c"
],
"third_party": false,
"type": "target"
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -4242,6 +4225,44 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc++",
"grpc++_test_util",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "transport_pid_controller_test",
"src": [
"test/core/transport/pid_controller_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc++",
"grpc++_test",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "vector_test",
"src": [
"test/core/support/vector_test.cc"
],
"third_party": false,
"type": "target"
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -4898,24 +4919,6 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [
"bad_client_test",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "large_metadata_bad_client_test",
"src": [
"test/core/bad_client/tests/large_metadata.c"
],
"third_party": false,
"type": "target"
},
{ {
"deps": [ "deps": [
"bad_client_test", "bad_client_test",
@ -8249,6 +8252,7 @@
"src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_hash_table.h",
"src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_internal.h",
"src/core/lib/slice/slice_string_helpers.h", "src/core/lib/slice/slice_string_helpers.h",
"src/core/lib/support/vector.h",
"src/core/lib/surface/alarm_internal.h", "src/core/lib/surface/alarm_internal.h",
"src/core/lib/surface/api_trace.h", "src/core/lib/surface/api_trace.h",
"src/core/lib/surface/call.h", "src/core/lib/surface/call.h",
@ -8384,6 +8388,7 @@
"src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_hash_table.h",
"src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_internal.h",
"src/core/lib/slice/slice_string_helpers.h", "src/core/lib/slice/slice_string_helpers.h",
"src/core/lib/support/vector.h",
"src/core/lib/surface/alarm_internal.h", "src/core/lib/surface/alarm_internal.h",
"src/core/lib/surface/api_trace.h", "src/core/lib/surface/api_trace.h",
"src/core/lib/surface/call.h", "src/core/lib/surface/call.h",
@ -9005,6 +9010,7 @@
"src/core/ext/transport/chttp2/transport/bin_decoder.h", "src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.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.h",
"src/core/ext/transport/chttp2/transport/frame_data.h", "src/core/ext/transport/chttp2/transport/frame_data.h",
"src/core/ext/transport/chttp2/transport/frame_goaway.h", "src/core/ext/transport/chttp2/transport/frame_goaway.h",
@ -9034,6 +9040,7 @@
"src/core/ext/transport/chttp2/transport/chttp2_transport.cc", "src/core/ext/transport/chttp2/transport/chttp2_transport.cc",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/flow_control.cc", "src/core/ext/transport/chttp2/transport/flow_control.cc",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.cc", "src/core/ext/transport/chttp2/transport/frame_data.cc",
"src/core/ext/transport/chttp2/transport/frame_data.h", "src/core/ext/transport/chttp2/transport/frame_data.h",

File diff suppressed because it is too large Load Diff

@ -132,7 +132,6 @@ def _ping_pong_scenario(name, rpc_type,
'name': name, 'name': name,
'num_servers': 1, 'num_servers': 1,
'num_clients': 1, 'num_clients': 1,
'spawn_local_worker_count': -2,
'client_config': { 'client_config': {
'client_type': client_type, 'client_type': client_type,
'security_params': _get_secargs(secure), 'security_params': _get_secargs(secure),
@ -177,7 +176,6 @@ def _ping_pong_scenario(name, rpc_type,
deep = int(math.ceil(1.0 * outstanding_calls / wide)) deep = int(math.ceil(1.0 * outstanding_calls / wide))
scenario['num_clients'] = num_clients if num_clients is not None else 0 # use as many clients as available. scenario['num_clients'] = num_clients if num_clients is not None else 0 # use as many clients as available.
scenario['spawn_local_worker_count'] = -1 - scenario['num_clients']
scenario['client_config']['outstanding_rpcs_per_channel'] = deep scenario['client_config']['outstanding_rpcs_per_channel'] = deep
scenario['client_config']['client_channels'] = wide scenario['client_config']['client_channels'] = wide
scenario['client_config']['async_client_threads'] = 0 scenario['client_config']['async_client_threads'] = 0
@ -254,8 +252,8 @@ class CXXLanguage:
rpc_type='UNARY', client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', rpc_type='UNARY', client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
req_size=300, resp_size=50, req_size=300, resp_size=50,
unconstrained_client='async', outstanding=30000, channels=300, unconstrained_client='async', outstanding=30000, channels=300,
offered_load=37500, num_clients=2, secure=False, offered_load=37500, secure=False,
async_server_threads=16, server_threads_per_cq=16, async_server_threads=16, server_threads_per_cq=1,
categories=[SMOKETEST] + [SCALABLE]) categories=[SMOKETEST] + [SCALABLE])
for secure in [True, False]: for secure in [True, False]:

@ -78,7 +78,7 @@ _WHITELIST_DICT = {
'^src/python/': [_PYTHON_TEST_SUITE], '^src/python/': [_PYTHON_TEST_SUITE],
'^src/ruby/': [_RUBY_TEST_SUITE], '^src/ruby/': [_RUBY_TEST_SUITE],
'^templates/': [], '^templates/': [],
'^test/core/': [_CORE_TEST_SUITE], '^test/core/': [_CORE_TEST_SUITE, _CPP_TEST_SUITE],
'^test/cpp/': [_CPP_TEST_SUITE], '^test/cpp/': [_CPP_TEST_SUITE],
'^test/distrib/cpp/': [_CPP_TEST_SUITE], '^test/distrib/cpp/': [_CPP_TEST_SUITE],
'^test/distrib/csharp/': [_CSHARP_TEST_SUITE], '^test/distrib/csharp/': [_CSHARP_TEST_SUITE],

@ -313,20 +313,20 @@ class Http2Client:
class NodeLanguage: class NodeLanguage:
def __init__(self): def __init__(self):
self.client_cwd = None self.client_cwd = '../grpc-node'
self.server_cwd = None self.server_cwd = '../grpc-node'
self.safename = str(self) self.safename = str(self)
def client_cmd(self, args): def client_cmd(self, args):
return ['tools/run_tests/interop/with_nvm.sh', return ['packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
'node', 'src/node/interop/interop_client.js'] + args 'node', 'test/interop/interop_client.js'] + args
def cloud_to_prod_env(self): def cloud_to_prod_env(self):
return {} return {}
def server_cmd(self, args): def server_cmd(self, args):
return ['tools/run_tests/interop/with_nvm.sh', return ['packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh',
'node', 'src/node/interop/interop_server.js'] + args 'node', 'test/interop/interop_server.js'] + args
def global_env(self): def global_env(self):
return {} return {}

@ -63,8 +63,7 @@ _FORCE_ENVIRON_FOR_WRAPPERS = {
} }
_POLLING_STRATEGIES = { _POLLING_STRATEGIES = {
'linux': ['epollsig', 'epoll1', 'poll', 'poll-cv'], 'linux': ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv'],
# TODO(ctiller, sreecha): enable epollex, epoll-thread-pool
'mac': ['poll'], 'mac': ['poll'],
} }
@ -122,7 +121,7 @@ def max_parallel_tests_for_current_platform():
# so far on windows. # so far on windows.
if jobset.platform_string() == 'windows': if jobset.platform_string() == 'windows':
return 64 return 64
return 128 return 1024
# SimpleConfig: just compile with CONFIG=config, and run the binary to test # SimpleConfig: just compile with CONFIG=config, and run the binary to test
class Config(object): class Config(object):
@ -149,10 +148,8 @@ class Config(object):
for k, v in environ.items(): for k, v in environ.items():
actual_environ[k] = v actual_environ[k] = v
if not flaky and shortname and shortname in flaky_tests: if not flaky and shortname and shortname in flaky_tests:
print('Setting %s to flaky' % shortname)
flaky = True flaky = True
if shortname in shortname_to_cpu: if shortname in shortname_to_cpu:
print('Update CPU cost for %s: %f -> %f' % (shortname, cpu_cost, shortname_to_cpu[shortname]))
cpu_cost = shortname_to_cpu[shortname] cpu_cost = shortname_to_cpu[shortname]
return jobset.JobSpec(cmdline=self.tool_prefix + cmdline, return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
shortname=shortname, shortname=shortname,
@ -332,11 +329,29 @@ class CLanguage(object):
if cpu_cost == 'capacity': if cpu_cost == 'capacity':
cpu_cost = multiprocessing.cpu_count() cpu_cost = multiprocessing.cpu_count()
if os.path.isfile(binary): if os.path.isfile(binary):
if 'gtest' in target and target['gtest']: list_test_command = None
# here we parse the output of --gtest_list_tests to build up a filter_test_command = None
# complete list of the tests contained in a binary
# for each test, we then add a job to run, filtering for just that # these are the flag defined by gtest and benchmark framework to list
# test # and filter test runs. We use them to split each individual test
# into its own JobSpec, and thus into its own process.
if 'benchmark' in target and target['benchmark']:
with open(os.devnull, 'w') as fnull:
tests = subprocess.check_output([binary, '--benchmark_list_tests'],
stderr=fnull)
for line in tests.split('\n'):
test = line.strip()
if not test: continue
cmdline = [binary, '--benchmark_filter=%s$' % test] + target['args']
out.append(self.config.job_spec(cmdline,
shortname='%s %s' % (' '.join(cmdline), shortname_ext),
cpu_cost=cpu_cost,
timeout_seconds=_DEFAULT_TIMEOUT_SECONDS * timeout_scaling,
environ=env))
elif 'gtest' in target and target['gtest']:
# here we parse the output of --gtest_list_tests to build up a complete
# list of the tests contained in a binary for each test, we then
# add a job to run, filtering for just that test.
with open(os.devnull, 'w') as fnull: with open(os.devnull, 'w') as fnull:
tests = subprocess.check_output([binary, '--gtest_list_tests'], tests = subprocess.check_output([binary, '--gtest_list_tests'],
stderr=fnull) stderr=fnull)
@ -355,7 +370,7 @@ class CLanguage(object):
out.append(self.config.job_spec(cmdline, out.append(self.config.job_spec(cmdline,
shortname='%s %s' % (' '.join(cmdline), shortname_ext), shortname='%s %s' % (' '.join(cmdline), shortname_ext),
cpu_cost=cpu_cost, cpu_cost=cpu_cost,
timeout_seconds=_DEFAULT_TIMEOUT_SECONDS * timeout_scaling, timeout_seconds=target.get('timeout_seconds', _DEFAULT_TIMEOUT_SECONDS) * timeout_scaling,
environ=env)) environ=env))
else: else:
cmdline = [binary] + target['args'] cmdline = [binary] + target['args']

@ -36,6 +36,7 @@ def get_target(name):
assert False, 'no target %s' % name assert False, 'no target %s' % name
def target_has_header(target, name): def target_has_header(target, name):
if name.startswith('absl/'): return True
# print target['name'], name # print target['name'], name
if name in target['headers']: if name in target['headers']:
return True return True

@ -35,6 +35,7 @@ cat << EOF | awk '{ print $1 }' | sort > $want_submodules
cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11) cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0) 3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0)
73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty 73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty
cc4bed2d74f7c8717e31f9579214ab52a9c9c610 third_party/abseil-cpp
EOF EOF
diff -u $submodules $want_submodules diff -u $submodules $want_submodules

@ -81,7 +81,8 @@ class TestFilteringTest(unittest.TestCase):
self.test_filtering(['src/core/foo.bar'], [_LIST_OF_LANGUAGE_LABELS]) self.test_filtering(['src/core/foo.bar'], [_LIST_OF_LANGUAGE_LABELS])
# Testing individual languages # Testing individual languages
self.test_filtering(['test/core/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in self.test_filtering(['test/core/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in
filter_pull_request_tests._CORE_TEST_SUITE.labels]) filter_pull_request_tests._CORE_TEST_SUITE.labels +
filter_pull_request_tests._CPP_TEST_SUITE.labels])
self.test_filtering(['src/cpp/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in self.test_filtering(['src/cpp/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in
filter_pull_request_tests._CPP_TEST_SUITE.labels]) filter_pull_request_tests._CPP_TEST_SUITE.labels])
self.test_filtering(['src/csharp/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in self.test_filtering(['src/csharp/foo.bar'], [label for label in _LIST_OF_LANGUAGE_LABELS if label not in

Loading…
Cancel
Save