Merge remote-tracking branch 'upstream/master' into pick_first_subchannel_list

pull/12878/head
Mark D. Roth 7 years ago
commit d38a2e89ab
  1. 1
      .clang_complete
  2. 3
      .gitmodules
  3. 4
      BUILD
  4. 589
      CMakeLists.txt
  5. 296
      Makefile
  6. 5
      WORKSPACE
  7. 3
      binding.gyp
  8. 202
      build.yaml
  9. 6
      doc/environment_variables.md
  10. 6
      gRPC-Core.podspec
  11. 7
      grpc.gemspec
  12. 7
      grpc.gyp
  13. 8
      include/grpc++/impl/codegen/call.h
  14. 23
      include/grpc/impl/codegen/port_platform.h
  15. 18
      include/grpc/support/sync.h
  16. 3
      package.xml
  17. 8
      setup.py
  18. 12
      src/c-ares/gen_build_yaml.py
  19. 8
      src/core/ext/filters/client_channel/client_channel.cc
  20. 256
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  21. 577
      src/core/ext/transport/chttp2/transport/flow_control.cc
  22. 328
      src/core/ext/transport/chttp2/transport/flow_control.h
  23. 4
      src/core/ext/transport/chttp2/transport/frame_settings.cc
  24. 10
      src/core/ext/transport/chttp2/transport/frame_window_update.cc
  25. 252
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  26. 10
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  27. 170
      src/core/ext/transport/chttp2/transport/internal.h
  28. 37
      src/core/ext/transport/chttp2/transport/parsing.cc
  29. 32
      src/core/ext/transport/chttp2/transport/writing.cc
  30. 2
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  31. 6
      src/core/ext/transport/inproc/inproc_transport.cc
  32. 18
      src/core/lib/debug/stats_data.cc
  33. 27
      src/core/lib/debug/stats_data.h
  34. 21
      src/core/lib/debug/stats_data.yaml
  35. 9
      src/core/lib/debug/stats_data_bq_schema.sql
  36. 15
      src/core/lib/http/httpcli_security_connector.cc
  37. 11
      src/core/lib/iomgr/call_combiner.cc
  38. 1
      src/core/lib/iomgr/combiner.cc
  39. 1409
      src/core/lib/iomgr/ev_epollex_linux.cc
  40. 9
      src/core/lib/iomgr/ev_posix.cc
  41. 9
      src/core/lib/iomgr/exec_ctx.cc
  42. 10
      src/core/lib/iomgr/port.h
  43. 2
      src/core/lib/iomgr/tcp_posix.cc
  44. 5
      src/core/lib/security/credentials/fake/fake_credentials.cc
  45. 2
      src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
  46. 6
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  47. 126
      src/core/lib/security/transport/security_connector.cc
  48. 34
      src/core/lib/security/transport/security_connector.h
  49. 76
      src/core/lib/support/manual_constructor.h
  50. 41
      src/core/lib/support/memory.h
  51. 2
      src/core/lib/support/time_posix.cc
  52. 32
      src/core/lib/support/vector.h
  53. 15
      src/core/lib/surface/completion_queue.cc
  54. 127
      src/core/lib/transport/bdp_estimator.cc
  55. 113
      src/core/lib/transport/bdp_estimator.h
  56. 7
      src/core/lib/transport/metadata.cc
  57. 3
      src/core/lib/transport/metadata.h
  58. 53
      src/core/lib/transport/pid_controller.cc
  59. 110
      src/core/lib/transport/pid_controller.h
  60. 3
      src/cpp/client/create_channel.cc
  61. 5
      src/cpp/server/server_cc.cc
  62. 16
      src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
  63. 16
      src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
  64. 14
      src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
  65. 15
      src/csharp/Grpc.Core/AsyncUnaryCall.cs
  66. 41
      src/objective-c/tests/GRPCClientTests.m
  67. 83
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  68. 27
      src/objective-c/tests/version.h
  69. 4
      src/php/ext/grpc/server.c
  70. 4
      src/ruby/ext/grpc/extconf.rb
  71. 1
      src/ruby/ext/grpc/rb_call.c
  72. 4
      templates/CMakeLists.txt.template
  73. 29
      templates/src/objective-c/tests/version.h.template
  74. 1
      templates/tools/run_tests/generated/tests.json.template
  75. 2
      test/core/bad_client/gen_build_yaml.py
  76. 2
      test/core/bad_client/generate_tests.bzl
  77. 65
      test/core/debug/stats_test.cc
  78. 12
      test/core/end2end/bad_server_response_test.c
  79. 1
      test/core/end2end/tests/bad_ping.c
  80. 2
      test/core/end2end/tests/keepalive_timeout.c
  81. 3
      test/core/end2end/tests/max_connection_age.c
  82. 4
      test/core/end2end/tests/shutdown_finishes_calls.c
  83. 10
      test/core/iomgr/pollset_set_test.c
  84. 26
      test/core/support/BUILD
  85. 42
      test/core/support/vector_test.cc
  86. 14
      test/core/transport/BUILD
  87. 162
      test/core/transport/bdp_estimator_test.c
  88. 149
      test/core/transport/bdp_estimator_test.cc
  89. 99
      test/core/transport/chttp2/hpack_encoder_test.c
  90. 4
      test/core/transport/metadata_test.c
  91. 78
      test/core/transport/pid_controller_test.c
  92. 91
      test/core/transport/pid_controller_test.cc
  93. 17
      test/core/util/BUILD
  94. 2
      test/core/util/debugger_macros.cc
  95. 8
      test/core/util/debugger_macros.h
  96. 8
      test/core/util/trickle_endpoint.h
  97. 8
      test/cpp/end2end/end2end_test.cc
  98. 244
      test/cpp/microbenchmarks/bm_chttp2_hpack.cc
  99. 38
      test/cpp/microbenchmarks/bm_chttp2_transport.cc
  100. 31
      test/cpp/microbenchmarks/bm_fullstack_trickle.cc
  101. Some files were not shown because too many files have changed in this diff Show More

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

3
.gitmodules vendored

@ -27,3 +27,6 @@
[submodule "third_party/bloaty"]
path = third_party/bloaty
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,8 @@ grpc_cc_library(
"src/core/lib/support/atomic_with_std.h",
"src/core/lib/support/env.h",
"src/core/lib/support/memory.h",
"src/core/lib/support/vector.h",
"src/core/lib/support/manual_constructor.h",
"src/core/lib/support/mpscq.h",
"src/core/lib/support/murmur_hash.h",
"src/core/lib/support/spinlock.h",
@ -528,6 +530,7 @@ grpc_cc_library(
public_hdrs = GPR_PUBLIC_HDRS,
deps = [
"gpr_codegen",
"@com_google_absl//absl/container:inlined_vector"
],
)
@ -1275,6 +1278,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/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_goaway.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)
CXXFLAGS += -stdlib=libc++
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
CPPFLAGS += $(CPPFLAGS_$(CONFIG))
@ -952,7 +952,6 @@ api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer
arena_test: $(BINDIR)/$(CONFIG)/arena_test
backoff_test: $(BINDIR)/$(CONFIG)/backoff_test
bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test
bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
byte_stream_test: $(BINDIR)/$(CONFIG)/byte_stream_test
@ -1092,7 +1091,6 @@ timer_heap_test: $(BINDIR)/$(CONFIG)/timer_heap_test
timer_list_test: $(BINDIR)/$(CONFIG)/timer_list_test
transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_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
udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
@ -1101,6 +1099,7 @@ wakeup_fd_cv_test: $(BINDIR)/$(CONFIG)/wakeup_fd_cv_test
alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
bm_arena: $(BINDIR)/$(CONFIG)/bm_arena
bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create
bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
@ -1149,6 +1148,7 @@ h2_ssl_cert_test: $(BINDIR)/$(CONFIG)/h2_ssl_cert_test
health_service_end2end_test: $(BINDIR)/$(CONFIG)/health_service_end2end_test
http2_client: $(BINDIR)/$(CONFIG)/http2_client
hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
inproc_sync_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test
interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server
interop_test: $(BINDIR)/$(CONFIG)/interop_test
@ -1180,6 +1180,8 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test
stress_test: $(BINDIR)/$(CONFIG)/stress_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_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
public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test
@ -1225,7 +1227,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
headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_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
simple_request_bad_client_test: $(BINDIR)/$(CONFIG)/simple_request_bad_client_test
unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
@ -1352,7 +1353,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/arena_test \
$(BINDIR)/$(CONFIG)/backoff_test \
$(BINDIR)/$(CONFIG)/bad_server_response_test \
$(BINDIR)/$(CONFIG)/bdp_estimator_test \
$(BINDIR)/$(CONFIG)/bin_decoder_test \
$(BINDIR)/$(CONFIG)/bin_encoder_test \
$(BINDIR)/$(CONFIG)/byte_stream_test \
@ -1473,7 +1473,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/timer_list_test \
$(BINDIR)/$(CONFIG)/transport_connectivity_state_test \
$(BINDIR)/$(CONFIG)/transport_metadata_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_test \
$(BINDIR)/$(CONFIG)/udp_server_test \
$(BINDIR)/$(CONFIG)/uri_parser_test \
@ -1484,7 +1483,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
$(BINDIR)/$(CONFIG)/headers_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)/simple_request_bad_client_test \
$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
@ -1545,6 +1543,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/alarm_cpp_test \
$(BINDIR)/$(CONFIG)/async_end2end_test \
$(BINDIR)/$(CONFIG)/auth_property_iterator_test \
$(BINDIR)/$(CONFIG)/bdp_estimator_test \
$(BINDIR)/$(CONFIG)/bm_arena \
$(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
@ -1586,6 +1585,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/health_service_end2end_test \
$(BINDIR)/$(CONFIG)/http2_client \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \
@ -1617,6 +1617,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/boringssl_aes_test \
$(BINDIR)/$(CONFIG)/boringssl_asn1_test \
@ -1666,6 +1668,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/alarm_cpp_test \
$(BINDIR)/$(CONFIG)/async_end2end_test \
$(BINDIR)/$(CONFIG)/auth_property_iterator_test \
$(BINDIR)/$(CONFIG)/bdp_estimator_test \
$(BINDIR)/$(CONFIG)/bm_arena \
$(BINDIR)/$(CONFIG)/bm_call_create \
$(BINDIR)/$(CONFIG)/bm_chttp2_hpack \
@ -1707,6 +1710,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/health_service_end2end_test \
$(BINDIR)/$(CONFIG)/http2_client \
$(BINDIR)/$(CONFIG)/hybrid_end2end_test \
$(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test \
$(BINDIR)/$(CONFIG)/interop_client \
$(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \
@ -1738,6 +1742,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
$(BINDIR)/$(CONFIG)/resolver_component_test \
@ -1766,8 +1772,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/backoff_test || ( echo test backoff_test failed ; exit 1 )
$(E) "[RUN] Testing bad_server_response_test"
$(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 )
$(E) "[RUN] Testing bdp_estimator_test"
$(Q) $(BINDIR)/$(CONFIG)/bdp_estimator_test || ( echo test bdp_estimator_test failed ; exit 1 )
$(E) "[RUN] Testing bin_decoder_test"
$(Q) $(BINDIR)/$(CONFIG)/bin_decoder_test || ( echo test bin_decoder_test failed ; exit 1 )
$(E) "[RUN] Testing bin_encoder_test"
@ -1992,8 +1996,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/transport_connectivity_state_test || ( echo test transport_connectivity_state_test failed ; exit 1 )
$(E) "[RUN] Testing transport_metadata_test"
$(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"
$(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 )
$(E) "[RUN] Testing udp_server_test"
@ -2014,8 +2016,6 @@ test_c: buildtests_c
$(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"
$(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"
$(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"
@ -2040,6 +2040,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing auth_property_iterator_test"
$(Q) $(BINDIR)/$(CONFIG)/auth_property_iterator_test || ( echo test auth_property_iterator_test failed ; exit 1 )
$(E) "[RUN] Testing bdp_estimator_test"
$(Q) $(BINDIR)/$(CONFIG)/bdp_estimator_test || ( echo test bdp_estimator_test failed ; exit 1 )
$(E) "[RUN] Testing bm_arena"
$(Q) $(BINDIR)/$(CONFIG)/bm_arena || ( echo test bm_arena failed ; exit 1 )
$(E) "[RUN] Testing bm_call_create"
@ -2114,6 +2116,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/h2_ssl_cert_test || ( echo test h2_ssl_cert_test failed ; exit 1 )
$(E) "[RUN] Testing health_service_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/health_service_end2end_test || ( echo test health_service_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing inproc_sync_unary_ping_pong_test"
$(Q) $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test || ( echo test inproc_sync_unary_ping_pong_test failed ; exit 1 )
$(E) "[RUN] Testing interop_test"
$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
$(E) "[RUN] Testing memory_test"
@ -2154,6 +2158,10 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 )
$(E) "[RUN] Testing thread_stress_test"
$(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"
$(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"
@ -3610,7 +3618,7 @@ LIBGRPC_TEST_UTIL_SRC = \
test/core/end2end/fixtures/http_proxy_fixture.c \
test/core/end2end/fixtures/proxy.c \
test/core/iomgr/endpoint_tests.c \
test/core/util/debugger_macros.c \
test/core/util/debugger_macros.cc \
test/core/util/grpc_profiler.c \
test/core/util/memory_counters.c \
test/core/util/mock_endpoint.c \
@ -3865,7 +3873,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
test/core/end2end/fixtures/http_proxy_fixture.c \
test/core/end2end/fixtures/proxy.c \
test/core/iomgr/endpoint_tests.c \
test/core/util/debugger_macros.c \
test/core/util/debugger_macros.cc \
test/core/util/grpc_profiler.c \
test/core/util/memory_counters.c \
test/core/util/mock_endpoint.c \
@ -8425,7 +8433,7 @@ PUBLIC_HEADERS_C += \
LIBARES_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBARES_SRC))))
$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares -fvisibility=hidden -D_GNU_SOURCE $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) $(if $(subst FreeBSD,,$(SYSTEM)),,-Ithird_party/cares/config_freebsd) $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst OpenBSD,,$(SYSTEM)),,-Ithird_party/cares/config_openbsd) -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
$(LIBARES_OBJS): CFLAGS += -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32) $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
$(LIBDIR)/$(CONFIG)/libares.a: $(ZLIB_DEP) $(LIBARES_OBJS)
@ -8966,38 +8974,6 @@ endif
endif
BDP_ESTIMATOR_TEST_SRC = \
test/core/transport/bdp_estimator_test.c \
BDP_ESTIMATOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BDP_ESTIMATOR_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/bdp_estimator_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/bdp_estimator_test: $(BDP_ESTIMATOR_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) $(BDP_ESTIMATOR_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)/bdp_estimator_test
endif
$(OBJDIR)/$(CONFIG)/test/core/transport/bdp_estimator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_bdp_estimator_test: $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
endif
endif
BIN_DECODER_TEST_SRC = \
test/core/transport/chttp2/bin_decoder_test.c \
@ -13452,38 +13428,6 @@ 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 = \
test/core/tsi/transport_security_test.c \
@ -13773,6 +13717,49 @@ endif
endif
BDP_ESTIMATOR_TEST_SRC = \
test/core/transport/bdp_estimator_test.cc \
BDP_ESTIMATOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BDP_ESTIMATOR_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/bdp_estimator_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)/bdp_estimator_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/bdp_estimator_test: $(PROTOBUF_DEP) $(BDP_ESTIMATOR_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) $(BDP_ESTIMATOR_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)/bdp_estimator_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/transport/bdp_estimator_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_bdp_estimator_test: $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(BDP_ESTIMATOR_TEST_OBJS:.o=.dep)
endif
endif
BM_ARENA_SRC = \
test/cpp/microbenchmarks/bm_arena.cc \
@ -15818,6 +15805,49 @@ endif
endif
INPROC_SYNC_UNARY_PING_PONG_TEST_SRC = \
test/cpp/qps/inproc_sync_unary_ping_pong_test.cc \
INPROC_SYNC_UNARY_PING_PONG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INPROC_SYNC_UNARY_PING_PONG_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_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)/inproc_sync_unary_ping_pong_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test: $(PROTOBUF_DEP) $(INPROC_SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(INPROC_SYNC_UNARY_PING_PONG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/qps/inproc_sync_unary_ping_pong_test.o: $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
deps_inproc_sync_unary_ping_pong_test: $(INPROC_SYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(INPROC_SYNC_UNARY_PING_PONG_TEST_OBJS:.o=.dep)
endif
endif
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
@ -17191,6 +17221,92 @@ 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 = \
test/cpp/performance/writes_per_rpc_test.cc \
@ -18472,26 +18588,6 @@ ifneq ($(NO_DEPS),true)
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 = \
test/core/bad_client/tests/server_registered_method.c \

@ -92,3 +92,8 @@ new_local_repository(
path = "third_party/cares",
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-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'ldflags': [
'-g',
@ -184,6 +185,7 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'OTHER_CPLUSPLUSFLAGS': [
'-g',
@ -193,6 +195,7 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
'-stdlib=libc++',
'-std=c++11',
'-Wno-error=deprecated-declarations'

@ -143,6 +143,7 @@ filegroups:
- src/core/lib/support/atomic_with_atm.h
- src/core/lib/support/atomic_with_std.h
- src/core/lib/support/env.h
- src/core/lib/support/manual_constructor.h
- src/core/lib/support/memory.h
- src/core/lib/support/mpscq.h
- src/core/lib/support/murmur_hash.h
@ -426,6 +427,7 @@ filegroups:
- src/core/lib/slice/slice_hash_table.h
- src/core/lib/slice/slice_internal.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/api_trace.h
- src/core/lib/surface/call.h
@ -751,7 +753,7 @@ filegroups:
- test/core/end2end/fixtures/http_proxy_fixture.c
- test/core/end2end/fixtures/proxy.c
- test/core/iomgr/endpoint_tests.c
- test/core/util/debugger_macros.c
- test/core/util/debugger_macros.cc
- test/core/util/grpc_profiler.c
- test/core/util/memory_counters.c
- test/core/util/mock_endpoint.c
@ -786,6 +788,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/bin_decoder.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/flow_control.h
- src/core/ext/transport/chttp2/transport/frame.h
- src/core/ext/transport/chttp2/transport/frame_data.h
- src/core/ext/transport/chttp2/transport/frame_goaway.h
@ -1745,6 +1748,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: alloc_test
build: test
language: c
@ -1753,6 +1757,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: alpn_test
build: test
language: c
@ -1785,6 +1790,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: backoff_test
build: test
language: c
@ -1795,6 +1801,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: bad_server_response_test
build: test
language: c
@ -1808,16 +1815,6 @@ targets:
- gpr
exclude_iomgrs:
- uv
- name: bdp_estimator_test
build: test
language: c
src:
- test/core/transport/bdp_estimator_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: bin_decoder_test
build: test
language: c
@ -1826,6 +1823,7 @@ targets:
deps:
- grpc_test_util
- grpc
uses_polling: false
- name: bin_encoder_test
build: test
language: c
@ -1834,6 +1832,7 @@ targets:
deps:
- grpc_test_util
- grpc
uses_polling: false
- name: byte_stream_test
build: test
language: c
@ -1844,6 +1843,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: census_context_test
build: test
language: c
@ -1854,6 +1854,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: census_intrusive_hash_map_test
build: test
language: c
@ -1864,6 +1865,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: census_resource_test
build: test
language: c
@ -1874,6 +1876,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: census_trace_context_test
build: test
language: c
@ -1884,6 +1887,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: channel_create_test
build: test
language: c
@ -1912,6 +1916,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: chttp2_stream_map_test
build: test
language: c
@ -1922,6 +1927,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: chttp2_varint_test
build: test
language: c
@ -1932,6 +1938,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: client_fuzzer
build: fuzzer
language: c
@ -1967,6 +1974,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: concurrent_connectivity_test
cpu_cost: 2.0
build: test
@ -2054,6 +2062,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: ev_epollsig_linux_test
cpu_cost: 3
build: test
@ -2186,6 +2195,7 @@ targets:
deps:
- gpr
- grpc
uses_polling: false
- name: gen_legal_metadata_characters
build: tool
language: c
@ -2198,6 +2208,7 @@ targets:
src:
- tools/codegen/core/gen_percent_encoding_tables.c
deps: []
uses_polling: false
- name: goaway_server_test
cpu_cost: 0.1
build: test
@ -2223,6 +2234,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_cmdline_test
build: test
language: c
@ -2231,6 +2243,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_cpu_test
cpu_cost: 30
build: test
@ -2240,6 +2253,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_env_test
build: test
language: c
@ -2248,6 +2262,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_histogram_test
build: test
language: c
@ -2256,6 +2271,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_host_port_test
build: test
language: c
@ -2264,6 +2280,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_log_test
build: test
language: c
@ -2272,6 +2289,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_mpscq_test
cpu_cost: 30
build: test
@ -2291,6 +2309,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_stack_lockfree_test
cpu_cost: 7
build: test
@ -2300,6 +2319,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_string_test
build: test
language: c
@ -2308,6 +2328,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_sync_test
cpu_cost: 10
build: test
@ -2317,6 +2338,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_thd_test
cpu_cost: 10
build: test
@ -2326,6 +2348,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_time_test
build: test
language: c
@ -2334,6 +2357,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_tls_test
build: test
language: c
@ -2342,6 +2366,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_useful_test
build: test
language: c
@ -2350,6 +2375,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_auth_context_test
build: test
language: c
@ -2360,6 +2386,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_b64_test
build: test
language: c
@ -2370,6 +2397,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_byte_buffer_reader_test
build: test
language: c
@ -2380,6 +2408,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_channel_args_test
build: test
language: c
@ -2390,6 +2419,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_channel_stack_builder_test
build: test
language: c
@ -2410,6 +2440,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_completion_queue_test
build: test
language: c
@ -2441,6 +2472,7 @@ targets:
- grpc
- gpr
secure: true
uses_polling: false
- name: grpc_credentials_test
build: test
language: c
@ -2472,6 +2504,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_json_token_test
build: test
language: c
@ -2486,6 +2519,7 @@ targets:
- linux
- posix
- mac
uses_polling: false
- name: grpc_jwt_verifier_test
build: test
language: c
@ -2496,6 +2530,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: grpc_print_google_default_creds_token
build: tool
language: c
@ -2504,6 +2539,7 @@ targets:
deps:
- grpc
- gpr
uses_polling: false
- name: grpc_security_connector_test
build: test
language: c
@ -2522,6 +2558,7 @@ targets:
deps:
- grpc
- gpr
uses_polling: false
- name: handshake_client
build: test
language: c
@ -2576,6 +2613,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: hpack_table_test
build: test
language: c
@ -2586,6 +2624,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: http_parser_test
build: test
language: c
@ -2596,6 +2635,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: http_request_fuzzer_test
build: fuzzer
language: c
@ -2670,6 +2710,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: invalid_call_argument_test
cpu_cost: 0.1
build: test
@ -2703,6 +2744,7 @@ targets:
deps:
- grpc
- gpr
uses_polling: false
- name: json_rewrite_test
build: test
language: c
@ -2713,6 +2755,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: json_stream_error_test
build: test
language: c
@ -2723,6 +2766,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: json_test
build: test
language: c
@ -2733,6 +2777,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: lame_client_test
build: test
language: c
@ -2755,6 +2800,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: load_file_test
build: test
language: c
@ -2765,6 +2811,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: low_level_ping_pong_benchmark
build: benchmark
language: c
@ -2790,6 +2837,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: memory_profile_server
build: test
run: false
@ -2826,6 +2874,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: minimal_stack_is_minimal_test
build: test
language: c
@ -2836,6 +2885,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: mlog_test
flaky: true
build: test
@ -2847,6 +2897,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: multiple_server_queues_test
build: test
language: c
@ -2865,6 +2916,7 @@ targets:
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: nanopb_fuzzer_response_test
build: fuzzer
language: c
@ -2924,6 +2976,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: percent_decode_fuzzer
build: fuzzer
language: c
@ -2960,6 +3013,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: pollset_set_test
build: test
language: c
@ -3089,6 +3143,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: slice_hash_table_test
build: test
language: c
@ -3099,6 +3154,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: slice_string_helpers_test
build: test
language: c
@ -3109,6 +3165,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: slice_test
build: test
language: c
@ -3119,6 +3176,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: sockaddr_resolver_test
build: test
language: c
@ -3193,6 +3251,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: stream_compression_test
build: test
language: c
@ -3203,6 +3262,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: stream_owned_slice_test
build: test
language: c
@ -3213,6 +3273,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: tcp_client_posix_test
cpu_cost: 0.5
build: test
@ -3298,6 +3359,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: timeout_encoding_test
build: test
language: c
@ -3308,6 +3370,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: timer_heap_test
build: test
language: c
@ -3320,6 +3383,7 @@ targets:
- gpr
exclude_iomgrs:
- uv
uses_polling: false
- name: timer_list_test
build: test
language: c
@ -3332,6 +3396,7 @@ targets:
- gpr
exclude_iomgrs:
- uv
uses_polling: false
- name: transport_connectivity_state_test
build: test
language: c
@ -3352,16 +3417,6 @@ targets:
- grpc
- gpr_test_util
- gpr
- 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
- name: transport_security_test
build: test
language: c
@ -3470,6 +3525,20 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: bdp_estimator_test
build: test
language: c++
src:
- test/core/transport/bdp_estimator_test.cc
deps:
- grpc++_test_util
- grpc++
- grpc_test_util
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: bm_arena
build: test
language: c++
@ -3486,11 +3555,13 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
- linux
- posix
uses_polling: false
- name: bm_call_create
build: test
language: c++
@ -3507,11 +3578,13 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
- linux
- posix
uses_polling: false
- name: bm_chttp2_hpack
build: test
language: c++
@ -3528,11 +3601,13 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
- linux
- posix
uses_polling: false
- name: bm_chttp2_transport
build: test
language: c++
@ -3549,6 +3624,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
@ -3570,6 +3646,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
@ -3591,6 +3668,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
@ -3612,6 +3690,7 @@ targets:
- gpr
args:
- --benchmark_min_time=4
benchmark: true
defaults: benchmark
platforms:
- mac
@ -3633,11 +3712,13 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
- linux
- posix
uses_polling: false
- name: bm_fullstack_streaming_ping_pong
build: test
language: c++
@ -3656,6 +3737,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
excluded_poll_engines:
- poll
@ -3683,6 +3765,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
excluded_poll_engines:
- poll
@ -3709,6 +3792,7 @@ targets:
- grpc++_test_config
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
excluded_poll_engines:
- poll
@ -3736,6 +3820,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
excluded_poll_engines:
- poll
@ -3761,11 +3846,13 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
- linux
- posix
uses_polling: false
- name: bm_pollset
build: test
language: c++
@ -3782,6 +3869,7 @@ targets:
- gpr
args:
- --benchmark_min_time=0
benchmark: true
defaults: benchmark
platforms:
- mac
@ -3797,6 +3885,7 @@ targets:
- grpc++
- grpc
- gpr
uses_polling: false
- name: channel_filter_test
gtest: true
build: test
@ -3807,6 +3896,7 @@ targets:
- grpc++
- grpc
- gpr
uses_polling: false
- name: cli_call_test
gtest: true
build: test
@ -3886,6 +3976,7 @@ targets:
- gpr
filegroups:
- grpc++_codegen_base
uses_polling: false
- name: codegen_test_minimal
gtest: true
build: test
@ -3904,6 +3995,7 @@ targets:
filegroups:
- grpc++_codegen_base
- grpc++_codegen_base_src
uses_polling: false
- name: credentials_test
gtest: true
build: test
@ -3926,6 +4018,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: cxx_slice_test
gtest: true
build: test
@ -3938,6 +4031,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: cxx_string_ref_test
gtest: true
build: test
@ -3947,6 +4041,7 @@ targets:
deps:
- grpc++
- grpc
uses_polling: false
- name: cxx_time_test
gtest: true
build: test
@ -3959,6 +4054,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: end2end_test
gtest: true
cpu_cost: 0.5
@ -4022,6 +4118,7 @@ targets:
- gpr
args:
- --generated_file_path=gens/src/proto/grpc/testing/
uses_polling: false
- name: grpc_cli
build: test
run: false
@ -4227,6 +4324,25 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: inproc_sync_unary_ping_pong_test
build: test
language: c++
src:
- test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
deps:
- qps
- grpc++_core_stats
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
- grpc++_test_config
platforms:
- mac
- linux
- posix
- name: interop_client
build: test
run: false
@ -4314,6 +4430,7 @@ targets:
- gpr
uses:
- grpc++_test
uses_polling: false
- name: metrics_client
build: test
run: false
@ -4378,6 +4495,7 @@ targets:
filegroups:
- grpc++_codegen_base
- grpc++_codegen_proto
uses_polling: false
- name: qps_interarrival_test
build: test
run: false
@ -4397,6 +4515,7 @@ targets:
- mac
- linux
- posix
uses_polling: false
- name: qps_json_driver
build: test
run: false
@ -4633,6 +4752,10 @@ targets:
- grpc
- gpr_test_util
- gpr
exclude_configs:
- tsan
timeout_seconds: 1200
uses_polling: false
- name: status_test
build: test
language: c++
@ -4644,6 +4767,7 @@ targets:
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: streaming_throughput_test
gtest: true
build: test
@ -4713,6 +4837,32 @@ targets:
- gpr_test_util
- gpr
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
gtest: true
cpu_cost: 0.5
@ -4880,10 +5030,11 @@ defaults:
ares:
CFLAGS: -Wno-sign-conversion $(if $(subst Darwin,,$(SYSTEM)),,-Wno-shorten-64-to-32)
$(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
$(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden
-D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst
MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares -fvisibility=hidden -D_GNU_SOURCE
$(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) $(if $(subst
FreeBSD,,$(SYSTEM)),,-Ithird_party/cares/config_freebsd) $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
$(if $(subst OpenBSD,,$(SYSTEM)),,-Ithird_party/cares/config_openbsd) -DWIN32_LEAN_AND_MEAN
-D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
benchmark:
CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
boringssl:
@ -4893,6 +5044,7 @@ defaults:
-D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
global:
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Ithird_party/abseil-cpp
LDFLAGS: -g
zlib:
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
- channel_stack_builder - traces information about channel stacks being built
- executor - traces grpc's internal thread pool ('the executor')
- glb - traces the grpclb load balancer
- http - traces state in the http2 transport engine
- http2_stream_state - traces all http2 stream state mutations.
- 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
- op_failure - traces error information when failure is pushed onto a
completion queue
- round_robin - traces the round_robin load balancing policy
- pick_first - traces the pick first load balancing policy
- plugin_credentials - traces plugin credentials
- pollable_refcount - traces reference counting of 'pollable' objects (only
in DEBUG)
- 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_timeout
- server_channel - lightweight trace of significant server channel events

@ -191,6 +191,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/atomic_with_atm.h',
'src/core/lib/support/atomic_with_std.h',
'src/core/lib/support/env.h',
'src/core/lib/support/manual_constructor.h',
'src/core/lib/support/memory.h',
'src/core/lib/support/mpscq.h',
'src/core/lib/support/murmur_hash.h',
@ -248,6 +249,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.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/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
@ -408,6 +410,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.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/api_trace.h',
'src/core/lib/surface/call.h',
@ -738,6 +741,7 @@ Pod::Spec.new do |s|
'src/core/lib/support/atomic_with_atm.h',
'src/core/lib/support/atomic_with_std.h',
'src/core/lib/support/env.h',
'src/core/lib/support/manual_constructor.h',
'src/core/lib/support/memory.h',
'src/core/lib/support/mpscq.h',
'src/core/lib/support/murmur_hash.h',
@ -750,6 +754,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_decoder.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/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
'src/core/ext/transport/chttp2/transport/frame_data.h',
'src/core/ext/transport/chttp2/transport/frame_goaway.h',
@ -910,6 +915,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.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/api_trace.h',
'src/core/lib/surface/call.h',

@ -89,6 +89,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/atomic_with_atm.h )
s.files += %w( src/core/lib/support/atomic_with_std.h )
s.files += %w( src/core/lib/support/env.h )
s.files += %w( src/core/lib/support/manual_constructor.h )
s.files += %w( src/core/lib/support/memory.h )
s.files += %w( src/core/lib/support/mpscq.h )
s.files += %w( src/core/lib/support/murmur_hash.h )
@ -180,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_encoder.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_data.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.h )
@ -340,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_internal.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/api_trace.h )
s.files += %w( src/core/lib/surface/call.h )
@ -1125,8 +1128,10 @@ Gem::Specification.new do |s|
s.files += %w( third_party/cares/cares/config-win32.h )
s.files += %w( third_party/cares/cares/setup_once.h )
s.files += %w( third_party/cares/ares_build.h )
s.files += %w( third_party/cares/config_linux/ares_config.h )
s.files += %w( third_party/cares/config_darwin/ares_config.h )
s.files += %w( third_party/cares/config_freebsd/ares_config.h )
s.files += %w( third_party/cares/config_linux/ares_config.h )
s.files += %w( third_party/cares/config_openbsd/ares_config.h )
s.files += %w( third_party/cares/cares/ares__close_sockets.c )
s.files += %w( third_party/cares/cares/ares__get_hostent.c )
s.files += %w( third_party/cares/cares/ares__read_line.c )

@ -57,6 +57,7 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'ldflags': [
'-g',
@ -134,6 +135,7 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'OTHER_CPLUSPLUSFLAGS': [
'-g',
@ -143,6 +145,7 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
'-stdlib=libc++',
'-std=c++11',
'-Wno-error=deprecated-declarations'
@ -516,7 +519,7 @@
'test/core/end2end/fixtures/http_proxy_fixture.c',
'test/core/end2end/fixtures/proxy.c',
'test/core/iomgr/endpoint_tests.c',
'test/core/util/debugger_macros.c',
'test/core/util/debugger_macros.cc',
'test/core/util/grpc_profiler.c',
'test/core/util/memory_counters.c',
'test/core/util/mock_endpoint.c',
@ -723,7 +726,7 @@
'test/core/end2end/fixtures/http_proxy_fixture.c',
'test/core/end2end/fixtures/proxy.c',
'test/core/iomgr/endpoint_tests.c',
'test/core/util/debugger_macros.c',
'test/core/util/debugger_macros.cc',
'test/core/util/grpc_profiler.c',
'test/core/util/memory_counters.c',
'test/core/util/mock_endpoint.c',

@ -163,7 +163,7 @@ class WriteOptions {
/// Clears flag indicating that this is the last message in a stream,
/// disabling coalescing.
inline WriteOptions& clear_last_messsage() {
inline WriteOptions& clear_last_message() {
last_message_ = false;
return *this;
}
@ -318,7 +318,11 @@ template <class M>
Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
write_options_ = options;
bool own_buf;
Status result = SerializationTraits<M>::Serialize(
// TODO(vjpai): Remove the void below when possible
// The void in the template parameter below should not be needed
// (since it should be implicit) but is needed due to an observed
// difference in behavior between clang and gcc for certain internal users
Status result = SerializationTraits<M, void>::Serialize(
message, send_buf_.bbuf_ptr(), &own_buf);
if (!own_buf) {
send_buf_.Duplicate();

@ -241,6 +241,29 @@
#else /* _LP64 */
#define GPR_ARCH_32 1
#endif /* _LP64 */
#elif defined(__OpenBSD__)
#define GPR_PLATFORM_STRING "openbsd"
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#define GPR_OPENBSD 1
#define GPR_CPU_POSIX 1
#define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#define GPR_POSIX_LOG 1
#define GPR_POSIX_ENV 1
#define GPR_POSIX_TMPFILE 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#ifdef _LP64
#define GPR_ARCH_64 1
#else /* _LP64 */
#define GPR_ARCH_32 1
#endif /* _LP64 */
#elif defined(__native_client__)
#define GPR_PLATFORM_STRING "nacl"
#ifndef _BSD_SOURCE

@ -274,7 +274,23 @@ GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c);
#endif /* 0 */
#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 /* GRPC_SUPPORT_SYNC_H */

@ -101,6 +101,7 @@
<file baseinstalldir="/" name="src/core/lib/support/atomic_with_atm.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/atomic_with_std.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/manual_constructor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/memory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/mpscq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
@ -192,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_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/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_data.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.h" role="src" />
@ -352,6 +354,7 @@
<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_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/api_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />

@ -40,10 +40,14 @@ ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
CARES_INCLUDE = (
os.path.join('third_party', 'cares'),
os.path.join('third_party', 'cares', 'cares'),)
if 'linux' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
if 'darwin' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_darwin'),)
if 'freebsd' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_freebsd'),)
if 'linux' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_linux'),)
if 'openbsd' in sys.platform:
CARES_INCLUDE += (os.path.join('third_party', 'cares', 'config_openbsd'),)
README = os.path.join(PYTHON_STEM, 'README.rst')
# Ensure we're in the proper directory whether or not we're being used by pip.

@ -29,10 +29,14 @@ try:
subprocess.call("third_party/cares/cares/configure", shell=True)
def config_platform(x):
if 'linux' in sys.platform:
return 'src/cares/cares/config_linux/ares_config.h'
if 'darwin' in sys.platform:
return 'src/cares/cares/config_darwin/ares_config.h'
if 'freebsd' in sys.platform:
return 'src/cares/cares/config_freebsd/ares_config.h'
if 'linux' in sys.platform:
return 'src/cares/cares/config_linux/ares_config.h'
if 'openbsd' in sys.platform:
return 'src/cares/cares/config_openbsd/ares_config.h'
if not os.path.isfile('third_party/cares/cares/ares_config.h'):
gen_ares_build(x)
return 'third_party/cares/cares/ares_config.h'
@ -124,8 +128,10 @@ try:
"third_party/cares/cares/config-win32.h",
"third_party/cares/cares/setup_once.h",
"third_party/cares/ares_build.h",
"third_party/cares/config_darwin/ares_config.h",
"third_party/cares/config_freebsd/ares_config.h",
"third_party/cares/config_linux/ares_config.h",
"third_party/cares/config_darwin/ares_config.h"
"third_party/cares/config_openbsd/ares_config.h"
],
}]
except:

@ -1599,8 +1599,8 @@ int grpc_client_channel_num_external_connectivity_watchers(
return count;
}
static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
static void on_external_watch_complete_locked(grpc_exec_ctx *exec_ctx,
void *arg, grpc_error *error) {
external_connectivity_watcher *w = (external_connectivity_watcher *)arg;
grpc_closure *follow_up = w->on_complete;
grpc_polling_entity_del_from_pollset_set(exec_ctx, &w->pollent,
@ -1619,8 +1619,8 @@ static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (w->state != NULL) {
external_connectivity_watcher_list_append(w->chand, w);
GRPC_CLOSURE_RUN(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE);
GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete, w,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&w->my_closure, on_external_watch_complete_locked, w,
grpc_combiner_scheduler(w->chand->combiner));
grpc_connectivity_state_notify_on_state_change(
exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
} else {

@ -54,7 +54,6 @@
#include "src/core/lib/transport/transport.h"
#include "src/core/lib/transport/transport_impl.h"
#define DEFAULT_WINDOW 65535
#define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024)
#define MAX_WINDOW 0x7fffffffu
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
@ -152,10 +151,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,
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,
grpc_error *error);
static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
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,
grpc_error *error);
@ -218,6 +221,9 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
t->write_cb_pool = next;
}
t->flow_control.Destroy();
GRPC_ERROR_UNREF(t->closed_with_error);
gpr_free(t->ping_acks);
gpr_free(t->peer_string);
gpr_free(t);
@ -275,10 +281,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->endpoint_reading = 1;
t->next_stream_id = is_client ? 1 : 2;
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->is_first_frame = true;
grpc_connectivity_state_init(
@ -303,6 +305,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
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,
t, grpc_combiner_scheduler(t->combiner));
GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
@ -315,8 +320,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
keepalive_watchdog_fired_locked, t,
grpc_combiner_scheduler(t->combiner));
grpc_bdp_estimator_init(&t->flow_control.bdp_estimator, t->peer_string);
grpc_chttp2_goaway_parser_init(&t->goaway_parser);
grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
@ -340,8 +343,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
window -- this should by rights be 0 */
t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
t->sent_local_settings = 0;
t->write_buffer_size = DEFAULT_WINDOW;
t->flow_control.enable_bdp_probe = true;
t->write_buffer_size = grpc_core::chttp2::kDefaultWindow;
if (is_client) {
grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
@ -386,6 +388,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY;
bool enable_bdp = true;
if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) {
if (0 == strcmp(channel_args->args[i].key,
@ -446,8 +450,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
&channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE});
} else if (0 ==
strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) {
t->flow_control.enable_bdp_probe =
grpc_channel_arg_get_integer(&channel_args->args[i], {1, 0, 1});
enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true);
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_KEEPALIVE_TIME_MS)) {
const int value = grpc_channel_arg_get_integer(
@ -542,6 +545,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. */
t->ping_state.pings_before_data_required = 0;
t->ping_state.is_delayed_ping_timer_set = false;
@ -562,10 +567,13 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
}
grpc_chttp2_act_on_flowctl_action(
exec_ctx,
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
NULL);
if (enable_bdp) {
GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
schedule_bdp_ping_locked(exec_ctx, t);
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_INITIAL_WRITE);
@ -595,7 +603,9 @@ static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
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)) {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE);
@ -610,13 +620,16 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_error_add_child(t->close_transport_on_writes_finished, error);
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,
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) {
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) {
case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING:
grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
@ -636,8 +649,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
}
end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error));
GPR_ASSERT(t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE);
grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
@ -698,7 +711,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
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);
return 0;
@ -749,7 +762,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
GRPC_ERROR_UNREF(s->write_closed_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");
@ -940,7 +953,8 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_mark_stream_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
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");
}
}
@ -993,7 +1007,7 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
grpc_chttp2_begin_write_result r;
if (t->closed) {
if (t->closed_with_error != GRPC_ERROR_NONE) {
r.writing = false;
} else {
r = grpc_chttp2_begin_write(exec_ctx, t);
@ -1456,7 +1470,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (!s->write_closed) {
if (t->is_client) {
if (!t->closed) {
if (t->closed_with_error == GRPC_ERROR_NONE) {
GPR_ASSERT(s->id == 0);
grpc_chttp2_list_add_waiting_for_concurrency(t, s);
maybe_start_some_streams(exec_ctx, t);
@ -1464,7 +1478,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
grpc_chttp2_cancel_stream(
exec_ctx, t, s,
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));
}
} else {
@ -1616,13 +1631,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (s->id != 0) {
if (!s->read_closed) {
already_received = s->frame_storage.length;
grpc_chttp2_flowctl_incoming_bs_update(
&t->flow_control, &s->flow_control, GRPC_HEADER_SIZE_IN_BYTES,
already_received);
grpc_chttp2_act_on_flowctl_action(
exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
&s->flow_control),
t, s);
s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES,
already_received);
grpc_chttp2_act_on_flowctl_action(exec_ctx,
s->flow_control->MakeAction(), t, s);
}
}
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
@ -1686,6 +1698,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,
and maybe they hold resources that need to be freed */
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++) {
grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]);
@ -1695,6 +1708,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,
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_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate,
GRPC_ERROR_NONE);
@ -1753,7 +1772,9 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
/*The transport will be closed after the write is done */
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));
}
}
@ -2389,55 +2410,44 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
* INPUT PROCESSING - PARSING
*/
void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx,
grpc_chttp2_flowctl_action action,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
switch (action.send_stream_update) {
case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED:
template <class F>
static void WithUrgency(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_core::chttp2::FlowControlAction::Urgency urgency,
grpc_chttp2_initiate_write_reason reason, F action) {
switch (urgency) {
case grpc_core::chttp2::FlowControlAction::Urgency::NO_ACTION_NEEDED:
break;
case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY:
grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
grpc_chttp2_initiate_write(
exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL);
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:
case grpc_core::chttp2::FlowControlAction::Urgency::UPDATE_IMMEDIATELY:
grpc_chttp2_initiate_write(exec_ctx, t, reason);
// fallthrough
case grpc_core::chttp2::FlowControlAction::Urgency::QUEUE_UPDATE:
action();
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");
grpc_bdp_estimator_schedule_ping(&t->flow_control.bdp_estimator);
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,
@ -2487,14 +2497,13 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
}
GPR_SWAP(grpc_error *, err, error);
GRPC_ERROR_UNREF(err);
if (!t->closed) {
if (t->closed_with_error == GRPC_ERROR_NONE) {
GPR_TIMER_BEGIN("reading_action.parse", 0);
size_t i = 0;
grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
GRPC_ERROR_NONE};
for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
grpc_bdp_estimator_add_incoming_bytes(
&t->flow_control.bdp_estimator,
t->flow_control->bdp_estimator()->AddIncomingBytes(
(int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i]));
errors[1] =
grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]);
@ -2511,8 +2520,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
GPR_TIMER_END("reading_action.parse", 0);
GPR_TIMER_BEGIN("post_parse_locked", 0);
if (t->flow_control.initial_window_update != 0) {
if (t->flow_control.initial_window_update > 0) {
if (t->initial_window_update != 0) {
if (t->initial_window_update > 0) {
grpc_chttp2_stream *s;
while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) {
grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
@ -2521,20 +2530,21 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
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_BEGIN("post_reading_action_locked", 0);
bool keep_reading = false;
if (error == GRPC_ERROR_NONE && t->closed) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed");
if (error == GRPC_ERROR_NONE && t->closed_with_error != GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Transport closed", &t->closed_with_error, 1);
}
if (error != GRPC_ERROR_NONE) {
close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0;
} else if (!t->closed) {
} else if (t->closed_with_error == GRPC_ERROR_NONE) {
keep_reading = true;
GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
}
@ -2543,10 +2553,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
if (keep_reading) {
grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer,
&t->read_action_locked);
grpc_chttp2_act_on_flowctl_action(
exec_ctx,
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
NULL);
grpc_chttp2_act_on_flowctl_action(exec_ctx, t->flow_control->MakeAction(),
t, NULL);
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
} else {
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action");
@ -2559,28 +2567,60 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
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,
grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
if (GRPC_TRACER_ON(grpc_http_trace)) {
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 */
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
}
grpc_bdp_estimator_start_ping(&t->flow_control.bdp_estimator);
t->flow_control->bdp_estimator()->StartPing();
}
static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
if (GRPC_TRACER_ON(grpc_http_trace)) {
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));
}
grpc_bdp_estimator_complete_ping(exec_ctx, &t->flow_control.bdp_estimator);
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,
@ -2645,7 +2685,7 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg;
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;
} else if (error == GRPC_ERROR_NONE) {
if (t->keepalive_permit_without_calls ||
@ -2703,8 +2743,11 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
if (error == GRPC_ERROR_NONE) {
t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"keepalive watchdog timeout"));
close_transport_locked(
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 {
/* The watchdog timer should have been cancelled by
@ -2787,13 +2830,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
size_t cur_length = s->frame_storage.length;
if (!s->read_closed) {
grpc_chttp2_flowctl_incoming_bs_update(&t->flow_control, &s->flow_control,
bs->next_action.max_size_hint,
cur_length);
grpc_chttp2_act_on_flowctl_action(
exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
&s->flow_control),
t, s);
s->flow_control->IncomingByteStreamUpdate(bs->next_action.max_size_hint,
cur_length);
grpc_chttp2_act_on_flowctl_action(exec_ctx, s->flow_control->MakeAction(),
t, s);
}
GPR_ASSERT(s->unprocessed_incoming_frames_buffer.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 <limits.h>
@ -28,38 +28,15 @@
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/support/string.h"
static uint32_t grpc_chttp2_target_announced_window(
const grpc_chttp2_transport_flowctl* tfc);
#ifndef NDEBUG
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;
}
}
namespace grpc_core {
namespace chttp2 {
namespace {
#define TRACE_PADDING 30
static constexpr const int kTracePadding = 30;
static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
char* str;
@ -68,7 +45,7 @@ static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) {
} else {
gpr_asprintf(&str, "%" PRId64 "", old_val);
}
char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING);
char* str_lp = gpr_leftpad(str, ' ', kTracePadding);
gpr_free(str);
return str_lp;
}
@ -80,47 +57,58 @@ static char* fmt_uint32_diff_str(uint32_t old_val, uint32_t new_val) {
} else {
gpr_asprintf(&str, "%" PRIu32 "", old_val);
}
char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING);
char* str_lp = gpr_leftpad(str, ' ', kTracePadding);
gpr_free(str);
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,
grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc, const char* reason) {
void FlowControlTrace::Finish() {
uint32_t acked_local_window =
tfc->t->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
tfc_->transport()->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
uint32_t remote_window =
tfc->t->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
char* trw_str =
fmt_int64_diff_str(shadow_fc->remote_window, tfc->remote_window);
char* tlw_str = fmt_int64_diff_str(shadow_fc->target_window,
grpc_chttp2_target_announced_window(tfc));
tfc_->transport()->settings[GRPC_PEER_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
char* trw_str = fmt_int64_diff_str(remote_window_, tfc_->remote_window());
char* tlw_str = fmt_int64_diff_str(target_window_, tfc_->target_window());
char* taw_str =
fmt_int64_diff_str(shadow_fc->announced_window, tfc->announced_window);
fmt_int64_diff_str(announced_window_, tfc_->announced_window());
char* srw_str;
char* slw_str;
char* saw_str;
if (sfc != NULL) {
srw_str = fmt_int64_diff_str(shadow_fc->remote_window_delta + remote_window,
sfc->remote_window_delta + remote_window);
slw_str =
fmt_int64_diff_str(shadow_fc->local_window_delta + acked_local_window,
sfc->local_window_delta + acked_local_window);
saw_str = fmt_int64_diff_str(
shadow_fc->announced_window_delta + acked_local_window,
sfc->announced_window_delta + acked_local_window);
if (sfc_ != nullptr) {
srw_str = fmt_int64_diff_str(remote_window_delta_ + remote_window,
sfc_->remote_window_delta() + remote_window);
slw_str = fmt_int64_diff_str(local_window_delta_ + acked_local_window,
local_window_delta_ + acked_local_window);
saw_str = fmt_int64_diff_str(announced_window_delta_ + acked_local_window,
announced_window_delta_ + acked_local_window);
} else {
srw_str = gpr_leftpad("", ' ', TRACE_PADDING);
slw_str = gpr_leftpad("", ' ', TRACE_PADDING);
saw_str = gpr_leftpad("", ' ', TRACE_PADDING);
srw_str = gpr_leftpad("", ' ', kTracePadding);
slw_str = gpr_leftpad("", ' ', kTracePadding);
saw_str = gpr_leftpad("", ' ', kTracePadding);
}
gpr_log(GPR_DEBUG,
"%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s",
tfc, sfc != NULL ? sfc->s->id : 0, tfc->t->is_client ? "cli" : "svr",
reason, trw_str, tlw_str, taw_str, srw_str, slw_str, saw_str);
tfc_, sfc_ != nullptr ? sfc_->stream()->id : 0,
tfc_->transport()->is_client ? "cli" : "svr", reason_, trw_str,
tlw_str, taw_str, srw_str, slw_str, saw_str);
gpr_free(trw_str);
gpr_free(tlw_str);
gpr_free(taw_str);
@ -129,13 +117,13 @@ static void posttrace(shadow_flow_control* shadow_fc,
gpr_free(saw_str);
}
static const char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) {
switch (urgency) {
case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED:
const char* FlowControlAction::UrgencyString(Urgency u) {
switch (u) {
case Urgency::NO_ACTION_NEEDED:
return "no action";
case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY:
case Urgency::UPDATE_IMMEDIATELY:
return "update immediately";
case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE:
case Urgency::QUEUE_UPDATE:
return "queue update";
default:
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");
}
static void trace_action(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_flowctl_action action) {
void FlowControlAction::Trace(grpc_chttp2_transport* t) const {
char* iw_str = fmt_uint32_diff_str(
tfc->t->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
action.initial_window_size);
t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
initial_window_size_);
char* mf_str = fmt_uint32_diff_str(
tfc->t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
action.max_frame_size);
gpr_log(GPR_DEBUG, "t[%s], s[%s], settings[%s] iw:%s mf:%s",
urgency_to_string(action.send_transport_update),
urgency_to_string(action.send_stream_update),
urgency_to_string(action.send_setting_update), iw_str, mf_str);
t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
max_frame_size_);
gpr_log(GPR_DEBUG, "t[%s], s[%s], iw:%s:%s mf:%s:%s",
UrgencyString(send_transport_update_),
UrgencyString(send_stream_update_),
UrgencyString(send_initial_window_update_), iw_str,
UrgencyString(send_max_frame_size_update_), mf_str);
gpr_free(iw_str);
gpr_free(mf_str);
}
#define PRETRACE(tfc, sfc) \
shadow_flow_control shadow_fc; \
GRPC_FLOW_CONTROL_IF_TRACING(pretrace(&shadow_fc, tfc, sfc))
#define POSTTRACE(tfc, sfc, reason) \
GRPC_FLOW_CONTROL_IF_TRACING(posttrace(&shadow_fc, tfc, sfc, reason))
#define TRACEACTION(tfc, action) \
GRPC_FLOW_CONTROL_IF_TRACING(trace_action(tfc, action))
#else
#define PRETRACE(tfc, sfc)
#define POSTTRACE(tfc, sfc, reason)
#define TRACEACTION(tfc, action)
#endif
/* How many bytes of incoming flow control would we like to advertise */
static uint32_t grpc_chttp2_target_announced_window(
const grpc_chttp2_transport_flowctl* tfc) {
return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1),
tfc->announced_stream_total_over_incoming_window +
tfc->target_initial_window_size);
}
// we have sent data on the wire, we must track this in our bookkeeping for the
// remote peer's flow control.
void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc,
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;
TransportFlowControl::TransportFlowControl(grpc_exec_ctx* exec_ctx,
const grpc_chttp2_transport* t,
bool enable_bdp_probe)
: t_(t),
enable_bdp_probe_(enable_bdp_probe),
bdp_estimator_(t->peer_string),
pid_controller_(grpc_core::PidController::Args()
.set_gain_p(4)
.set_gain_i(8)
.set_gain_d(0)
.set_initial_control_value(TargetLogBdp())
.set_min_control_value(-1)
.set_max_control_value(25)
.set_integral_range(10)),
last_pid_update_(grpc_exec_ctx_now(exec_ctx)) {}
uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) {
FlowControlTrace trace("t updt sent", this, nullptr);
const uint32_t target_announced_window = target_window();
if ((writing_anyway || announced_window_ <= target_announced_window / 2) &&
announced_window_ != target_announced_window) {
const uint32_t announce = (uint32_t)GPR_CLAMP(
target_announced_window - announced_window_, 0, UINT32_MAX);
announced_window_ += announce;
return announce;
}
return 0;
}
// We have received data from the wire. We must track this in our own flow
// control bookkeeping.
// Returns an error if the incoming frame violates our flow control.
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) {
grpc_error* TransportFlowControl::ValidateRecvData(
int64_t incoming_frame_size) {
if (incoming_frame_size > announced_window_) {
char* msg;
gpr_asprintf(&msg,
"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);
gpr_free(msg);
return err;
}
return GRPC_ERROR_NONE;
}
if (sfc != NULL) {
int64_t acked_stream_window =
sfc->announced_window_delta + acked_init_window;
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;
}
StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc,
const grpc_chttp2_stream* s)
: tfc_(tfc), s_(s) {}
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");
return GRPC_ERROR_NONE;
}
grpc_error* error = 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
// update
uint32_t grpc_chttp2_flowctl_maybe_send_transport_update(
grpc_chttp2_transport_flowctl* tfc, bool writing_anyway) {
PRETRACE(tfc, NULL);
uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc);
uint32_t threshold_to_send_transport_window_update =
tfc->t->outbuf.count > 0 ? 3 * target_announced_window / 4
: target_announced_window / 2;
if ((writing_anyway ||
tfc->announced_window <= threshold_to_send_transport_window_update) &&
tfc->announced_window != target_announced_window) {
uint32_t announce = (uint32_t)GPR_CLAMP(
target_announced_window - tfc->announced_window, 0, UINT32_MAX);
tfc->announced_window += announce;
POSTTRACE(tfc, NULL, "t updt sent");
return announce;
uint32_t sent_init_window =
tfc_->transport()->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
uint32_t acked_init_window =
tfc_->transport()->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
int64_t acked_stream_window = announced_window_delta_ + acked_init_window;
int64_t sent_stream_window = announced_window_delta_ + sent_init_window;
if (incoming_frame_size > acked_stream_window) {
if (incoming_frame_size <= sent_stream_window) {
gpr_log(GPR_ERROR,
"Incoming frame of size %" PRId64
" exceeds local window size of %" PRId64
".\n"
"The (un-acked, future) window size would be %" PRId64
" which is not exceeded.\n"
"This would usually cause a disconnection, but allowing it due to"
"broken HTTP2 implementations in the wild.\n"
"See (for example) https://github.com/netty/netty/issues/6520.",
incoming_frame_size, acked_stream_window, sent_stream_window);
} else {
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,
tfc->t->is_client ? "cli" : "svr"));
return 0;
UpdateAnnouncedWindowDelta(tfc_, -incoming_frame_size);
local_window_delta_ -= incoming_frame_size;
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 grpc_chttp2_flowctl_maybe_send_stream_update(
grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) {
PRETRACE(tfc, sfc);
if (sfc->local_window_delta > sfc->announced_window_delta) {
uint32_t StreamFlowControl::MaybeSendUpdate() {
FlowControlTrace trace("s updt sent", tfc_, this);
if (local_window_delta_ > announced_window_delta_) {
uint32_t announce = (uint32_t)GPR_CLAMP(
sfc->local_window_delta - sfc->announced_window_delta, 0, UINT32_MAX);
announced_window_delta_preupdate(tfc, sfc);
sfc->announced_window_delta += announce;
announced_window_delta_postupdate(tfc, sfc);
POSTTRACE(tfc, sfc, "s updt sent");
local_window_delta_ - announced_window_delta_, 0, UINT32_MAX);
UpdateAnnouncedWindowDelta(tfc_, 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;
}
// 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) {
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);
void StreamFlowControl::IncomingByteStreamUpdate(size_t max_size_hint,
size_t have_already) {
FlowControlTrace trace("app st recv", tfc_, this);
uint32_t max_recv_bytes;
uint32_t sent_init_window =
tfc->t->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
tfc_->transport()->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
/* clamp max recv hint to an allowable size */
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 */
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)(max_recv_bytes - sfc->local_window_delta);
sfc->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;
(uint32_t)(max_recv_bytes - local_window_delta_);
local_window_delta_ += add_max_recv_bytes;
}
}
// 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
static double get_target_under_memory_pressure(
grpc_chttp2_transport_flowctl* tfc, double target) {
static double AdjustForMemoryPressure(grpc_resource_quota* quota,
double target) {
// do not increase window under heavy memory pressure.
double memory_pressure = grpc_resource_quota_get_memory_pressure(
grpc_resource_user_quota(grpc_endpoint_get_resource_user(tfc->t->ep)));
double memory_pressure = grpc_resource_quota_get_memory_pressure(quota);
static const double kLowMemPressure = 0.1;
static const double kZeroTarget = 22;
static const double kHighMemPressure = 0.8;
@ -439,78 +300,82 @@ static double get_target_under_memory_pressure(
return target;
}
grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action(
grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc,
grpc_chttp2_stream_flowctl* sfc) {
grpc_chttp2_flowctl_action action;
memset(&action, 0, sizeof(action));
double TransportFlowControl::TargetLogBdp() {
return AdjustForMemoryPressure(
grpc_resource_user_quota(grpc_endpoint_get_resource_user(t_->ep)),
1 + log2(bdp_estimator_.EstimateBdp()));
}
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
if (sfc != NULL && !sfc->s->read_closed) {
uint32_t sent_init_window =
tfc->t->settings[GRPC_SENT_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
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 (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) {
return FlowControlAction::Urgency::QUEUE_UPDATE;
} else {
return FlowControlAction::Urgency::NO_ACTION_NEEDED;
}
if (tfc->enable_bdp_probe) {
action.need_ping =
grpc_bdp_estimator_need_ping(exec_ctx, &tfc->bdp_estimator);
}
FlowControlAction TransportFlowControl::PeriodicUpdate(
grpc_exec_ctx* exec_ctx) {
FlowControlAction action;
if (enable_bdp_probe_) {
// get bdp estimate and update initial_window accordingly.
int64_t estimate = -1;
if (grpc_bdp_estimator_get_estimate(&tfc->bdp_estimator, &estimate)) {
double target = 1 + log2((double)estimate);
// target might change based on how much memory pressure we are under
// TODO(ncteisen): experiment with setting target to be huge under low
// memory pressure.
target = get_target_under_memory_pressure(tfc, target);
// run our target through the pid controller to stabilize change.
// TODO(ncteisen): experiment with other controllers here.
double bdp_guess = get_pid_controller_guess(exec_ctx, tfc, target);
// 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;
}
}
// target might change based on how much memory pressure we are under
// TODO(ncteisen): experiment with setting target to be huge under low
// memory pressure.
const double target = pow(2, SmoothLogBdp(exec_ctx, TargetLogBdp()));
// Though initial window 'could' drop to 0, we keep the floor at 128
target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX);
action.set_send_initial_window_update(
DeltaUrgency(target_initial_window_size_,
GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE),
target_initial_window_size_);
// get bandwidth estimate and update max_frame accordingly.
double bw_dbl = -1;
if (grpc_bdp_estimator_get_bw(&tfc->bdp_estimator, &bw_dbl)) {
// we target the max of BDP or bandwidth in microseconds.
int32_t frame_size = (int32_t)GPR_CLAMP(
GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
tfc->target_initial_window_size),
16384, 16777215);
grpc_chttp2_flowctl_urgency frame_size_urgency = delta_is_significant(
tfc, frame_size, GRPC_CHTTP2_SETTINGS_MAX_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;
}
}
double bw_dbl = bdp_estimator_.EstimateBandwidth();
// we target the max of BDP or bandwidth in microseconds.
int32_t frame_size = (int32_t)GPR_CLAMP(
GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000,
target_initial_window_size_),
16384, 16777215);
action.set_send_max_frame_size_update(
DeltaUrgency(frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE),
frame_size);
}
uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc);
if (tfc->announced_window < target_announced_window / 2) {
action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY;
return UpdateAction(action);
}
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;
}
} // 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,13 +202,13 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
}
if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
parser->incoming_settings[id] != parser->value) {
t->flow_control.initial_window_update +=
t->initial_window_update +=
(int64_t)parser->value - parser->incoming_settings[id];
if (GRPC_TRACER_ON(grpc_http_trace) ||
GRPC_TRACER_ON(grpc_flowctl_trace)) {
gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change",
t, t->is_client ? "cli" : "svr",
(int)t->flow_control.initial_window_update);
(int)t->initial_window_update);
}
}
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 (s != NULL) {
grpc_chttp2_flowctl_recv_stream_update(
&t->flow_control, &s->flow_control, received_update);
s->flow_control->RecvUpdate(received_update);
if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) {
grpc_chttp2_mark_stream_writable(exec_ctx, t, s);
grpc_chttp2_initiate_write(
@ -106,10 +105,9 @@ grpc_error *grpc_chttp2_window_update_parser_parse(
}
}
} else {
bool was_zero = t->flow_control.remote_window <= 0;
grpc_chttp2_flowctl_recv_transport_update(&t->flow_control,
received_update);
bool is_zero = t->flow_control.remote_window <= 0;
bool was_zero = t->flow_control->remote_window() <= 0;
t->flow_control->RecvUpdate(received_update);
bool is_zero = t->flow_control->remote_window() <= 0;
if (was_zero && !is_zero) {
grpc_chttp2_initiate_write(
exec_ctx, t,

@ -178,24 +178,19 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) {
c->table_elems--;
}
/* add an element to the decoder table */
static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem) {
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);
// Reserve space in table for the new element, evict entries if needed.
// Return the new index of the element. Return 0 to indicate not adding to
// table.
static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor *c,
size_t elem_size) {
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);
if (elem_size > c->max_table_size) {
while (c->table_size > 0) {
evict_entry(c);
}
return;
return 0;
}
/* 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_elems++;
/* 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;
return new_index;
}
/* dummy function */
static void add_nothing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c, grpc_mdelem elem,
size_t elem_size) {}
// Add a key to the dynamic table. Both key and value will be added to table at
// the decoder.
static void add_key_with_index(grpc_exec_ctx *exec_ctx,
grpc_chttp2_hpack_compressor *c,
grpc_mdelem elem, uint32_t new_index) {
if (new_index == 0) {
return;
}
/* 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)],
GRPC_MDKEY(elem))) {
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,
grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
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,
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_UNCOMPRESSED(exec_ctx);
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,
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_UNCOMPRESSED(exec_ctx);
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.");
}
if (GRPC_TRACER_ON(grpc_http_trace) && !GRPC_MDELEM_IS_INTERNED(elem)) {
if (GRPC_TRACER_ON(grpc_http_trace)) {
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_DEBUG,
"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(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;
}
uint32_t key_hash;
uint32_t value_hash;
uint32_t elem_hash;
size_t decoder_space_usage;
uint32_t indices_key;
int should_add_elem;
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t elem_hash = 0;
key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
if (elem_interned) {
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
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) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st);
return;
}
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) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st);
return;
}
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) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st);
return;
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) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(exec_ctx, c,
dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st);
return;
}
}
uint32_t indices_key;
/* should this elem be in the table? */
decoder_space_usage = grpc_mdelem_get_size_in_hpack_table(elem);
should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
size_t decoder_space_usage =
grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
bool should_add_elem = elem_interned &&
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? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
add_elem(exec_ctx, c, elem);
return;
} else {
emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
return;
}
GPR_UNREACHABLE_CODE(return );
emit(exec_ctx, c, dynidx(c, indices_key), elem, st);
maybe_add(exec_ctx, c, elem, decoder_space_usage);
return;
}
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)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
add_elem(exec_ctx, c, elem);
return;
} else {
emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st);
return;
}
GPR_UNREACHABLE_CODE(return );
emit(exec_ctx, c, dynidx(c, indices_key), elem, st);
maybe_add(exec_ctx, c, elem, decoder_space_usage);
return;
}
/* no elem, key in the table... fall back to literal emission */
if (should_add_elem) {
emit_lithdr_incidx_v(exec_ctx, c, elem, st);
add_elem(exec_ctx, c, elem);
return;
} else {
emit_lithdr_noidx_v(exec_ctx, c, elem, st);
return;
}
GPR_UNREACHABLE_CODE(return );
bool should_add_key =
!elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE;
emit = (should_add_elem || should_add_key) ? emit_lithdr_incidx_v
: emit_lithdr_noidx_v;
maybe_add =
should_add_elem ? add_elem : (should_add_key ? add_key : add_nothing);
emit(exec_ctx, c, 0, elem, st);
maybe_add(exec_ctx, c, elem, decoder_space_usage);
}
#define STRLEN_LIT(x) (sizeof(x) - 1)

@ -33,6 +33,7 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/http2_errors.h"
@ -650,9 +651,14 @@ static const uint8_t inverse_base64[256] = {
/* emission helpers */
static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
grpc_mdelem md, int add_to_table) {
if (GRPC_TRACER_ON(grpc_http_trace) && !GRPC_MDELEM_IS_INTERNED(md)) {
if (GRPC_TRACER_ON(grpc_http_trace)) {
char *k = grpc_slice_to_c_string(GRPC_MDKEY(md));
char *v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
char *v = NULL;
if (grpc_is_binary_header(GRPC_MDKEY(md))) {
v = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
}
gpr_log(
GPR_DEBUG,
"Decode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",

@ -22,6 +22,7 @@
#include <assert.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_data.h"
#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
@ -37,9 +38,8 @@
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/support/manual_constructor.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"
#ifdef __cplusplus
@ -237,48 +237,6 @@ typedef enum {
GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED,
} 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_bdp_estimator 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 {
grpc_transport base; /* must be first */
gpr_refcount refs;
@ -297,7 +255,7 @@ struct grpc_chttp2_transport {
/** is the transport destroying itself? */
uint8_t destroying;
/** has the upper layer closed the transport? */
uint8_t closed;
grpc_error *closed_with_error;
/** is there a read request to the endpoint outstanding? */
uint8_t endpoint_reading;
@ -339,7 +297,7 @@ struct grpc_chttp2_transport {
/** hpack encoding */
grpc_chttp2_hpack_compressor hpack_compressor;
/** is this a client? */
uint8_t is_client;
bool is_client;
/** data to write next write */
grpc_slice_buffer qbuf;
@ -349,14 +307,14 @@ struct grpc_chttp2_transport {
uint32_t write_buffer_size;
/** have we seen a goaway */
uint8_t seen_goaway;
bool seen_goaway;
/** have we sent a goaway */
grpc_chttp2_sent_goaway_state sent_goaway_state;
/** are the local settings dirty and need to be sent? */
uint8_t dirtied_local_settings;
bool dirtied_local_settings;
/** have local settings been sent? */
uint8_t sent_local_settings;
bool sent_local_settings;
/** bitmask of setting indexes to send out */
uint32_t force_send_settings;
/** settings values */
@ -394,7 +352,12 @@ struct grpc_chttp2_transport {
/** parser for goaway frames */
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 */
grpc_chttp2_deframe_transport_state deframe_state;
@ -421,6 +384,7 @@ struct grpc_chttp2_transport {
grpc_chttp2_write_cb *write_cb_pool;
/* bdp estimator */
grpc_closure next_bdp_ping_timer_expired_locked;
grpc_closure start_bdp_ping_locked;
grpc_closure finish_bdp_ping_locked;
@ -441,6 +405,10 @@ struct grpc_chttp2_transport {
/** destructive cleanup closure */
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 */
/** Closure to initialize a keepalive ping */
grpc_closure init_keepalive_ping_locked;
@ -471,25 +439,6 @@ typedef enum {
GPRC_METADATA_PUBLISHED_AT_CLOSE
} 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 {
grpc_chttp2_transport *t;
grpc_stream_refcount *refcount;
@ -583,7 +532,8 @@ struct grpc_chttp2_stream {
bool sent_initial_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;
@ -694,74 +644,10 @@ bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t,
/********* 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.
void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx,
grpc_chttp2_flowctl_action action,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
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);
/********* End of Flow Control ***************/
@ -795,16 +681,6 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
extern grpc_tracer_flag grpc_http_trace;
extern grpc_tracer_flag grpc_flowctl_trace;
#ifndef NDEBUG
#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) \
if (!(GRPC_TRACER_ON(grpc_flowctl_trace))) \
; \
else \
stmt
#else
#define GRPC_FLOW_CONTROL_IF_TRACING(stmt)
#endif
#define GRPC_CHTTP2_IF_TRACING(stmt) \
if (!(GRPC_TRACER_ON(grpc_http_trace))) \
; \

@ -355,14 +355,15 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s =
grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
grpc_error *err = GRPC_ERROR_NONE;
err = grpc_chttp2_flowctl_recv_data(&t->flow_control,
s == NULL ? NULL : &s->flow_control,
t->incoming_frame_size);
grpc_chttp2_act_on_flowctl_action(
exec_ctx,
grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control,
s == NULL ? NULL : &s->flow_control),
t, s);
grpc_core::chttp2::FlowControlAction action;
if (s == nullptr) {
err = t->flow_control->RecvData(t->incoming_frame_size);
action = t->flow_control->MakeAction();
} else {
err = s->flow_control->RecvData(t->incoming_frame_size);
action = s->flow_control->MakeAction();
}
grpc_chttp2_act_on_flowctl_action(exec_ctx, action, t, s);
if (err != GRPC_ERROR_NONE) {
goto error_handler;
}
@ -434,19 +435,21 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_millis *cached_timeout =
static_cast<grpc_millis *>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout == NULL) {
/* not already parsed: parse it now, and store the result away */
cached_timeout = (grpc_millis *)gpr_malloc(sizeof(grpc_millis));
if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) {
if (cached_timeout != NULL) {
timeout = *cached_timeout;
} else {
if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout)) {
char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
*cached_timeout = GRPC_MILLIS_INF_FUTURE;
timeout = GRPC_MILLIS_INF_FUTURE;
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* store the result */
cached_timeout = (grpc_millis *)gpr_malloc(sizeof(grpc_millis));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
timeout = *cached_timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
} else {
timeout = *cached_timeout;
}
if (timeout != GRPC_MILLIS_INF_FUTURE) {
grpc_chttp2_incoming_metadata_buffer_set_deadline(

@ -146,13 +146,13 @@ static void report_stall(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
s->flow_controlled_bytes_flowed,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
t->flow_control.remote_window,
t->flow_control->remote_window(),
(uint32_t)GPR_MAX(
0,
s->flow_control.remote_window_delta +
s->flow_control->remote_window_delta() +
(int64_t)t->settings[GRPC_PEER_SETTINGS]
[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) {
@ -216,8 +216,7 @@ class WriteContext {
void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) {
uint32_t transport_announce =
grpc_chttp2_flowctl_maybe_send_transport_update(&t_->flow_control,
t_->outbuf.count > 0);
t_->flow_control->MaybeSendUpdate(t_->outbuf.count > 0);
if (transport_announce) {
grpc_transport_one_way_stats throwaway_stats;
grpc_slice_buffer_add(
@ -245,7 +244,8 @@ class WriteContext {
void UpdateStreamsNoLongerStalled() {
grpc_chttp2_stream *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)) {
grpc_chttp2_list_remove_writable_stream(t_, s);
}
@ -311,7 +311,7 @@ class DataSendContext {
uint32_t stream_remote_window() const {
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]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
}
@ -319,7 +319,7 @@ class DataSendContext {
uint32_t max_outgoing() const {
return (uint32_t)GPR_MIN(
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; }
@ -351,8 +351,7 @@ class DataSendContext {
grpc_metadata_batch_is_empty(s_->send_trailing_metadata);
grpc_chttp2_encode_data(s_->id, &s_->compressed_data_buffer, send_bytes,
is_last_frame_, &s_->stats.outgoing, &t_->outbuf);
grpc_chttp2_flowctl_sent_data(&t_->flow_control, &s_->flow_control,
send_bytes);
s_->flow_control->SentData(send_bytes);
if (s_->compressed_data_buffer.length == 0) {
s_->sending_bytes += s_->uncompressed_data_size;
}
@ -399,8 +398,8 @@ class StreamWriteContext {
gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t_,
t_->is_client ? "CLIENT" : "SERVER", s->id,
s->sent_initial_metadata, s->send_initial_metadata != NULL,
(int)(s->flow_control.local_window_delta -
s->flow_control.announced_window_delta)));
(int)(s->flow_control->local_window_delta() -
s->flow_control->announced_window_delta())));
}
void FlushInitialMetadata(grpc_exec_ctx *exec_ctx) {
@ -446,8 +445,7 @@ class StreamWriteContext {
void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) {
/* send any window updates */
uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update(
&t_->flow_control, &s_->flow_control);
const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate();
if (stream_announce == 0) return;
grpc_slice_buffer_add(
@ -468,10 +466,10 @@ class StreamWriteContext {
DataSendContext data_send_context(write_context_, t_, s_);
if (!data_send_context.AnyOutgoing()) {
if (t_->flow_control.remote_window == 0) {
if (t_->flow_control->remote_window() <= 0) {
report_stall(t_, s_, "transport");
grpc_chttp2_list_add_stalled_by_transport(t_, s_);
} else if (data_send_context.stream_remote_window() == 0) {
} else if (data_send_context.stream_remote_window() <= 0) {
report_stall(t_, s_, "stream");
grpc_chttp2_list_add_stalled_by_stream(t_, s_);
}
@ -587,7 +585,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
ctx.FlushQueuedBuffers(exec_ctx);
ctx.EnactHpackSettings(exec_ctx);
if (t->flow_control.remote_window > 0) {
if (t->flow_control->remote_window() > 0) {
ctx.UpdateStreamsNoLongerStalled();
}

@ -692,7 +692,7 @@ static void create_grpc_frame(grpc_exec_ctx *exec_ctx,
uint8_t *p = (uint8_t *)write_buffer;
/* Append 5 byte header */
/* Compressed flag */
*p++ = (flags & GRPC_WRITE_INTERNAL_COMPRESS) ? 1 : 0;
*p++ = (uint8_t)((flags & GRPC_WRITE_INTERNAL_COMPRESS) ? 1 : 0);
/* Message length */
*p++ = (uint8_t)(length >> 24);
*p++ = (uint8_t)(length >> 16);

@ -623,7 +623,7 @@ static void op_state_machine(grpc_exec_ctx *exec_ctx, void *arg,
fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
goto done;
} else {
if (other && !other->closed) {
if (!other || !other->closed) {
fill_in_metadata(exec_ctx, s,
s->send_trailing_md_op->payload->send_trailing_metadata
.send_trailing_metadata,
@ -925,7 +925,7 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
INPROC_LOG(GPR_DEBUG, "Extra initial metadata %p", s);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra initial metadata");
} else {
if (!other->closed) {
if (!other || !other->closed) {
fill_in_metadata(
exec_ctx, s,
op->payload->send_initial_metadata.send_initial_metadata,
@ -976,7 +976,7 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
(other->recv_trailing_md_op != NULL))) ||
(op->send_trailing_metadata && !op->send_message) ||
(op->recv_initial_metadata && s->to_read_initial_md_filled) ||
(op->recv_message && (other && other->send_message_op != NULL)) ||
(op->recv_message && other && (other->send_message_op != NULL)) ||
(s->to_read_trailing_md_filled || s->trailing_md_recvd)) {
if (!s->op_closure_scheduled) {
GRPC_CLOSURE_SCHED(exec_ctx, &s->op_closure, GRPC_ERROR_NONE);

@ -104,6 +104,10 @@ const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {
"combiner_locks_scheduled_items",
"combiner_locks_scheduled_final_items",
"combiner_locks_offloaded",
"call_combiner_locks_initiated",
"call_combiner_locks_scheduled_items",
"call_combiner_set_notify_on_cancel",
"call_combiner_cancelled",
"executor_scheduled_short_items",
"executor_scheduled_long_items",
"executor_scheduled_to_self",
@ -112,6 +116,9 @@ const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT] = {
"executor_push_retries",
"server_requested_calls",
"server_slowpath_requests_queued",
"cq_ev_queue_trylock_failures",
"cq_ev_queue_trylock_successes",
"cq_ev_queue_transient_pop_failures",
};
const char *grpc_stats_counter_doc[GRPC_STATS_COUNTER_COUNT] = {
"Number of client side calls created by this process",
@ -210,6 +217,11 @@ const char *grpc_stats_counter_doc[GRPC_STATS_COUNTER_COUNT] = {
"Number of items scheduled against combiner locks",
"Number of final items scheduled against combiner locks",
"Number of combiner locks offloaded to different threads",
"Number of call combiner lock entries by process (first items queued to a "
"call combiner)",
"Number of items scheduled against call combiner locks",
"Number of times a cancellation callback was set on a call combiner",
"Number of times a call combiner was cancelled",
"Number of finite runtime closures scheduled against the executor (gRPC "
"thread pool)",
"Number of potentially infinite runtime closures scheduled against the "
@ -222,6 +234,12 @@ const char *grpc_stats_counter_doc[GRPC_STATS_COUNTER_COUNT] = {
"How many calls were requested (not necessarily received) by the server",
"How many times was the server slow path taken (indicates too few "
"outstanding requests)",
"Number of lock (trylock) acquisition failures on completion queue event "
"queue. High value here indicates high contention on completion queues",
"Number of lock (trylock) acquisition successes on completion queue event "
"queue.",
"Number of times NULL was popped out of completion queue's event queue "
"even though the event queue was not empty",
};
const char *grpc_stats_histogram_name[GRPC_STATS_HISTOGRAM_COUNT] = {
"call_initial_size",

@ -110,6 +110,10 @@ typedef enum {
GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_ITEMS,
GRPC_STATS_COUNTER_COMBINER_LOCKS_SCHEDULED_FINAL_ITEMS,
GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED,
GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_INITIATED,
GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS,
GRPC_STATS_COUNTER_CALL_COMBINER_SET_NOTIFY_ON_CANCEL,
GRPC_STATS_COUNTER_CALL_COMBINER_CANCELLED,
GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_SHORT_ITEMS,
GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_LONG_ITEMS,
GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_TO_SELF,
@ -118,6 +122,9 @@ typedef enum {
GRPC_STATS_COUNTER_EXECUTOR_PUSH_RETRIES,
GRPC_STATS_COUNTER_SERVER_REQUESTED_CALLS,
GRPC_STATS_COUNTER_SERVER_SLOWPATH_REQUESTS_QUEUED,
GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRYLOCK_FAILURES,
GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRYLOCK_SUCCESSES,
GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRANSIENT_POP_FAILURES,
GRPC_STATS_COUNTER_COUNT
} grpc_stats_counters;
extern const char *grpc_stats_counter_name[GRPC_STATS_COUNTER_COUNT];
@ -404,6 +411,17 @@ typedef enum {
#define GRPC_STATS_INC_COMBINER_LOCKS_OFFLOADED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_COMBINER_LOCKS_OFFLOADED)
#define GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_INITIATED)
#define GRPC_STATS_INC_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx) \
GRPC_STATS_INC_COUNTER( \
(exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS)
#define GRPC_STATS_INC_CALL_COMBINER_SET_NOTIFY_ON_CANCEL(exec_ctx) \
GRPC_STATS_INC_COUNTER( \
(exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_SET_NOTIFY_ON_CANCEL)
#define GRPC_STATS_INC_CALL_COMBINER_CANCELLED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), GRPC_STATS_COUNTER_CALL_COMBINER_CANCELLED)
#define GRPC_STATS_INC_EXECUTOR_SCHEDULED_SHORT_ITEMS(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_EXECUTOR_SCHEDULED_SHORT_ITEMS)
@ -425,6 +443,15 @@ typedef enum {
#define GRPC_STATS_INC_SERVER_SLOWPATH_REQUESTS_QUEUED(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_SERVER_SLOWPATH_REQUESTS_QUEUED)
#define GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_FAILURES(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRYLOCK_FAILURES)
#define GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_SUCCESSES(exec_ctx) \
GRPC_STATS_INC_COUNTER((exec_ctx), \
GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRYLOCK_SUCCESSES)
#define GRPC_STATS_INC_CQ_EV_QUEUE_TRANSIENT_POP_FAILURES(exec_ctx) \
GRPC_STATS_INC_COUNTER( \
(exec_ctx), GRPC_STATS_COUNTER_CQ_EV_QUEUE_TRANSIENT_POP_FAILURES)
#define GRPC_STATS_INC_CALL_INITIAL_SIZE(exec_ctx, value) \
grpc_stats_inc_call_initial_size((exec_ctx), (int)(value))
void grpc_stats_inc_call_initial_size(grpc_exec_ctx *exec_ctx, int x);

@ -245,6 +245,16 @@
doc: Number of final items scheduled against combiner locks
- counter: combiner_locks_offloaded
doc: Number of combiner locks offloaded to different threads
# call combiner locks
- counter: call_combiner_locks_initiated
doc: Number of call combiner lock entries by process
(first items queued to a call combiner)
- counter: call_combiner_locks_scheduled_items
doc: Number of items scheduled against call combiner locks
- counter: call_combiner_set_notify_on_cancel
doc: Number of times a cancellation callback was set on a call combiner
- counter: call_combiner_cancelled
doc: Number of times a call combiner was cancelled
# executor
- counter: executor_scheduled_short_items
doc: Number of finite runtime closures scheduled against the executor
@ -272,4 +282,13 @@
- counter: server_slowpath_requests_queued
doc: How many times was the server slow path taken (indicates too few
outstanding requests)
# cq
- counter: cq_ev_queue_trylock_failures
doc: Number of lock (trylock) acquisition failures on completion queue event
queue. High value here indicates high contention on completion queues
- counter: cq_ev_queue_trylock_successes
doc: Number of lock (trylock) acquisition successes on completion queue event
queue.
- counter: cq_ev_queue_transient_pop_failures
doc: Number of times NULL was popped out of completion queue's event queue
even though the event queue was not empty

@ -79,6 +79,10 @@ combiner_locks_initiated_per_iteration:FLOAT,
combiner_locks_scheduled_items_per_iteration:FLOAT,
combiner_locks_scheduled_final_items_per_iteration:FLOAT,
combiner_locks_offloaded_per_iteration:FLOAT,
call_combiner_locks_initiated_per_iteration:FLOAT,
call_combiner_locks_scheduled_items_per_iteration:FLOAT,
call_combiner_set_notify_on_cancel_per_iteration:FLOAT,
call_combiner_cancelled_per_iteration:FLOAT,
executor_scheduled_short_items_per_iteration:FLOAT,
executor_scheduled_long_items_per_iteration:FLOAT,
executor_scheduled_to_self_per_iteration:FLOAT,
@ -86,4 +90,7 @@ executor_wakeup_initiated_per_iteration:FLOAT,
executor_queue_drained_per_iteration:FLOAT,
executor_push_retries_per_iteration:FLOAT,
server_requested_calls_per_iteration:FLOAT,
server_slowpath_requests_queued_per_iteration:FLOAT
server_slowpath_requests_queued_per_iteration:FLOAT,
cq_ev_queue_trylock_failures_per_iteration:FLOAT,
cq_ev_queue_trylock_successes_per_iteration:FLOAT,
cq_ev_queue_transient_pop_failures_per_iteration:FLOAT

@ -91,8 +91,17 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
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 = {
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(
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;
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;
*sc = &c->base;
return GRPC_SECURITY_OK;

@ -21,6 +21,8 @@
#include <inttypes.h>
#include <grpc/support/log.h>
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/profiling/timers.h"
grpc_tracer_flag grpc_call_combiner_trace =
GRPC_TRACER_INITIALIZER(false, "call_combiner");
@ -60,6 +62,7 @@ void grpc_call_combiner_start(grpc_exec_ctx* exec_ctx,
grpc_closure* closure,
grpc_error* error DEBUG_ARGS,
const char* reason) {
GPR_TIMER_BEGIN("call_combiner_start", 0);
if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
gpr_log(GPR_DEBUG,
"==> grpc_call_combiner_start() [%p] closure=%p [" DEBUG_FMT_STR
@ -73,7 +76,10 @@ void grpc_call_combiner_start(grpc_exec_ctx* exec_ctx,
gpr_log(GPR_DEBUG, " size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
prev_size + 1);
}
GRPC_STATS_INC_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS(exec_ctx);
if (prev_size == 0) {
GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(exec_ctx);
GPR_TIMER_MARK("call_combiner_initiate", 0);
if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
gpr_log(GPR_DEBUG, " EXECUTING IMMEDIATELY");
}
@ -87,11 +93,13 @@ void grpc_call_combiner_start(grpc_exec_ctx* exec_ctx,
closure->error_data.error = error;
gpr_mpscq_push(&call_combiner->queue, (gpr_mpscq_node*)closure);
}
GPR_TIMER_END("call_combiner_start", 0);
}
void grpc_call_combiner_stop(grpc_exec_ctx* exec_ctx,
grpc_call_combiner* call_combiner DEBUG_ARGS,
const char* reason) {
GPR_TIMER_BEGIN("call_combiner_stop", 0);
if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
gpr_log(GPR_DEBUG,
"==> grpc_call_combiner_stop() [%p] [" DEBUG_FMT_STR "%s]",
@ -130,11 +138,13 @@ void grpc_call_combiner_stop(grpc_exec_ctx* exec_ctx,
} else if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
gpr_log(GPR_DEBUG, " queue empty");
}
GPR_TIMER_END("call_combiner_stop", 0);
}
void grpc_call_combiner_set_notify_on_cancel(grpc_exec_ctx* exec_ctx,
grpc_call_combiner* call_combiner,
grpc_closure* closure) {
GRPC_STATS_INC_CALL_COMBINER_SET_NOTIFY_ON_CANCEL(exec_ctx);
while (true) {
// Decode original state.
gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state);
@ -179,6 +189,7 @@ void grpc_call_combiner_set_notify_on_cancel(grpc_exec_ctx* exec_ctx,
void grpc_call_combiner_cancel(grpc_exec_ctx* exec_ctx,
grpc_call_combiner* call_combiner,
grpc_error* error) {
GRPC_STATS_INC_CALL_COMBINER_CANCELLED(exec_ctx);
while (true) {
gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state);
grpc_error* original_error = decode_cancel_state_error(original_state);

@ -165,6 +165,7 @@ static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
lock, cl, last));
if (last == 1) {
GRPC_STATS_INC_COMBINER_LOCKS_INITIATED(exec_ctx);
GPR_TIMER_MARK("combiner.initiated", 0);
gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null,
(gpr_atm)exec_ctx);
// first element on this list: add it to the list of combiner locks

File diff suppressed because it is too large Load Diff

@ -92,12 +92,9 @@ const grpc_event_engine_vtable *init_non_polling(bool explicit_request) {
} // namespace
static const event_engine_factory g_factories[] = {
{"epoll1", grpc_init_epoll1_linux},
{"epollsig", grpc_init_epollsig_linux},
{"poll", grpc_init_poll_posix},
{"poll-cv", grpc_init_poll_cv_posix},
{"epollex", grpc_init_epollex_linux},
{"none", init_non_polling},
{"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
{"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
{"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
};
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_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) {
return gpr_time_from_millis(millis, GPR_TIMESPAN);
}

@ -109,6 +109,16 @@
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_OPENBSD)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_NACL)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1

@ -186,7 +186,7 @@ static void cover_self(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
}
if (old_count == 0) {
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_TRACER_ON(grpc_tcp_trace)) {
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,
const grpc_channel_args *args, grpc_channel_security_connector **sc,
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;
}
@ -46,7 +47,7 @@ static grpc_security_status
fake_transport_security_server_create_security_connector(
grpc_exec_ctx *exec_ctx, grpc_server_credentials *c,
grpc_server_security_connector **sc) {
*sc = grpc_fake_server_security_connector_create();
*sc = grpc_fake_server_security_connector_create(c);
return GRPC_SECURITY_OK;
}

@ -262,7 +262,7 @@ static bool oauth2_token_fetcher_get_request_metadata(
grpc_mdelem cached_access_token_md = GRPC_MDNULL;
gpr_mu_lock(&c->mu);
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);
}
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(
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) {
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_server_security_connector **sc) {
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 = {

@ -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(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
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);
}
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,
"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,
"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 = {
connector_pointer_arg_copy, connector_pointer_arg_destroy,
connector_pointer_cmp};
static const grpc_arg_pointer_vtable connector_arg_vtable = {
connector_arg_copy, connector_arg_destroy, connector_cmp};
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
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) {
@ -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);
}
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,
grpc_channel_security_connector *sc,
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 = {
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 = {
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_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds, const char *target,
const grpc_channel_args *args) {
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);
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->base.base.vtable = &fake_channel_vtable;
c->base.channel_creds = channel_creds;
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
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(
void) {
grpc_server_credentials *server_creds) {
grpc_server_security_connector *c =
(grpc_server_security_connector *)gpr_zalloc(
sizeof(grpc_server_security_connector));
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->server_creds = server_creds;
c->add_handshakers = fake_server_add_handshakers;
return c;
}
@ -473,6 +537,7 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
grpc_ssl_channel_security_connector *c =
(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);
tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
c->client_handshaker_factory = NULL;
@ -485,6 +550,7 @@ static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c =
(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);
c->server_handshaker_factory = NULL;
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);
}
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,
const grpc_auth_property *prop,
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 = {
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 = {
ssl_server_destroy, ssl_server_check_peer};
ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
/* returns a NULL terminated slice. */
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_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 char *overridden_target_name, grpc_channel_security_connector **sc) {
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);
c->base.base.vtable = &ssl_channel_vtable;
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
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_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
grpc_server_security_connector **sc) {
grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds,
const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const char **alpn_protocol_strings =
(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);
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
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(
config->pem_key_cert_pairs, config->num_key_cert_pairs,
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,
tsi_peer peer, grpc_auth_context **auth_context,
grpc_closure *on_peer_checked);
int (*cmp)(grpc_security_connector *sc, grpc_security_connector *other);
} 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 {
const grpc_security_connector_vtable *vtable;
gpr_refcount refcount;
@ -104,6 +100,10 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_auth_context **auth_context,
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. */
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. ---
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. */
typedef struct grpc_channel_security_connector grpc_channel_security_connector;
struct grpc_channel_security_connector {
grpc_security_connector base;
grpc_channel_credentials *channel_creds;
grpc_call_credentials *request_metadata_creds;
bool (*check_call_host)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, const char *host,
@ -138,6 +139,10 @@ struct grpc_channel_security_connector {
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.
/// Returns true if completed synchronously, in which case \a error will
/// 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. ---
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. */
typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector {
grpc_security_connector base;
grpc_server_credentials *server_creds;
void (*add_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
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(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_handshake_manager *handshake_mgr);
@ -182,13 +192,14 @@ void grpc_server_security_connector_add_handshakers(
/* For TESTING ONLY!
Creates a fake connector that emulates real channel security. */
grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_channel_credentials *channel_creds,
grpc_call_credentials *request_metadata_creds, const char *target,
const grpc_channel_args *args);
/* For TESTING ONLY!
Creates a fake connector that emulates real server security. */
grpc_server_security_connector *grpc_fake_server_security_connector_create(
void);
grpc_server_credentials *server_creds);
/* Config for ssl clients. */
@ -211,7 +222,8 @@ typedef struct {
specific error code otherwise.
*/
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 char *overridden_target_name, grpc_channel_security_connector **sc);
@ -236,8 +248,8 @@ typedef struct {
specific error code otherwise.
*/
grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
grpc_server_security_connector **sc);
grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds,
const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
/* Util. */
const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,

@ -0,0 +1,76 @@
/*
*
* 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.
*
*/
#ifndef GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H
#define GRPC_CORE_LIB_SUPPORT_MANUAL_CONSTRUCTOR_H
// manually construct a region of memory with some type
#include <stddef.h>
#include <new>
#include <type_traits>
#include <utility>
namespace grpc_core {
template <typename Type>
class ManualConstructor {
public:
// No constructor or destructor because one of the most useful uses of
// this class is as part of a union, and members of a union could not have
// constructors or destructors till C++11. And, anyway, the whole point of
// this class is to bypass constructor and destructor.
Type* get() { return reinterpret_cast<Type*>(&space_); }
const Type* get() const { return reinterpret_cast<const Type*>(&space_); }
Type* operator->() { return get(); }
const Type* operator->() const { return get(); }
Type& operator*() { return *get(); }
const Type& operator*() const { return *get(); }
void Init() { new (&space_) Type; }
// Init() constructs the Type instance using the given arguments
// (which are forwarded to Type's constructor).
//
// Note that Init() with no arguments performs default-initialization,
// not zero-initialization (i.e it behaves the same as "new Type;", not
// "new Type();"), so it will leave non-class types uninitialized.
template <typename... Ts>
void Init(Ts&&... args) {
new (&space_) Type(std::forward<Ts>(args)...);
}
// Init() that is equivalent to copy and move construction.
// Enables usage like this:
// ManualConstructor<std::vector<int>> v;
// v.Init({1, 2, 3});
void Init(const Type& x) { new (&space_) Type(x); }
void Init(Type&& x) { new (&space_) Type(std::move(x)); }
void Destroy() { get()->~Type(); }
private:
typename std::aligned_storage<sizeof(Type), alignof(Type)>::type space_;
};
} // namespace grpc_core
#endif

@ -21,6 +21,7 @@
#include <grpc/support/alloc.h>
#include <limits>
#include <memory>
#include <utility>
@ -54,6 +55,46 @@ inline UniquePtr<T> MakeUnique(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
#endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */

@ -42,7 +42,7 @@ static struct timespec timespec_from_gpr(gpr_timespec gts) {
return rv;
}
#if _POSIX_TIMERS > 0
#if _POSIX_TIMERS > 0 || defined(__OpenBSD__)
static gpr_timespec gpr_from_timespec(struct timespec ts,
gpr_clock_type clock_type) {
/*

@ -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

@ -362,11 +362,24 @@ static bool cq_event_queue_push(grpc_cq_event_queue *q, grpc_cq_completion *c) {
static grpc_cq_completion *cq_event_queue_pop(grpc_cq_event_queue *q) {
grpc_cq_completion *c = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
if (gpr_spinlock_trylock(&q->queue_lock)) {
c = (grpc_cq_completion *)gpr_mpscq_pop(&q->queue);
GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_SUCCESSES(&exec_ctx);
bool is_empty = false;
c = (grpc_cq_completion *)gpr_mpscq_pop_and_check_end(&q->queue, &is_empty);
gpr_spinlock_unlock(&q->queue_lock);
if (c == NULL && !is_empty) {
GRPC_STATS_INC_CQ_EV_QUEUE_TRANSIENT_POP_FAILURES(&exec_ctx);
}
} else {
GRPC_STATS_INC_CQ_EV_QUEUE_TRYLOCK_FAILURES(&exec_ctx);
}
grpc_exec_ctx_finish(&exec_ctx);
if (c) {
gpr_atm_no_barrier_fetch_add(&q->num_queue_items, -1);
}

@ -21,117 +21,64 @@
#include <inttypes.h>
#include <stdlib.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
grpc_tracer_flag grpc_bdp_estimator_trace =
GRPC_TRACER_INITIALIZER(false, "bdp_estimator");
void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name) {
estimator->estimate = 65536;
estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
estimator->ping_start_time = gpr_time_0(GPR_CLOCK_MONOTONIC);
estimator->next_ping_scheduled = 0;
estimator->name = name;
estimator->bw_est = 0;
estimator->inter_ping_delay = 100.0; // start at 100ms
estimator->stable_estimate_count = 0;
}
bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator,
int64_t *estimate) {
*estimate = estimator->estimate;
return true;
}
bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator,
double *bw) {
*bw = estimator->bw_est;
return true;
}
void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
int64_t num_bytes) {
estimator->accumulator += num_bytes;
}
bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
const grpc_bdp_estimator *estimator) {
switch (estimator->ping_state) {
case GRPC_BDP_PING_UNSCHEDULED:
return grpc_exec_ctx_now(exec_ctx) >= estimator->next_ping_scheduled;
case GRPC_BDP_PING_SCHEDULED:
return false;
case GRPC_BDP_PING_STARTED:
return false;
}
GPR_UNREACHABLE_CODE(return false);
}
namespace grpc_core {
void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator) {
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64,
estimator->name, estimator->accumulator, estimator->estimate);
}
GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_UNSCHEDULED);
estimator->ping_state = GRPC_BDP_PING_SCHEDULED;
estimator->accumulator = 0;
}
BdpEstimator::BdpEstimator(const char *name)
: ping_state_(PingState::UNSCHEDULED),
accumulator_(0),
estimate_(65536),
ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)),
inter_ping_delay_(100.0), // start at 100ms
stable_estimate_count_(0),
bw_est_(0),
name_(name) {}
void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator) {
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64,
estimator->name, estimator->accumulator, estimator->estimate);
}
GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_SCHEDULED);
estimator->ping_state = GRPC_BDP_PING_STARTED;
estimator->accumulator = 0;
estimator->ping_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
}
void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
grpc_bdp_estimator *estimator) {
grpc_millis BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec dt_ts = gpr_time_sub(now, estimator->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 bw = dt > 0 ? ((double)estimator->accumulator / dt) : 0;
int start_inter_ping_delay = estimator->inter_ping_delay;
double bw = dt > 0 ? ((double)accumulator_ / dt) : 0;
int start_inter_ping_delay = inter_ping_delay_;
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64
" dt=%lf bw=%lfMbs bw_est=%lfMbs",
estimator->name, estimator->accumulator, estimator->estimate, dt,
bw / 125000.0, estimator->bw_est / 125000.0);
name_, accumulator_, estimate_, dt, bw / 125000.0,
bw_est_ / 125000.0);
}
GPR_ASSERT(estimator->ping_state == GRPC_BDP_PING_STARTED);
if (estimator->accumulator > 2 * estimator->estimate / 3 &&
bw > estimator->bw_est) {
estimator->estimate =
GPR_MAX(estimator->accumulator, estimator->estimate * 2);
estimator->bw_est = bw;
GPR_ASSERT(ping_state_ == PingState::STARTED);
if (accumulator_ > 2 * estimate_ / 3 && bw > bw_est_) {
estimate_ = GPR_MAX(accumulator_, estimate_ * 2);
bw_est_ = bw;
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64,
estimator->name, estimator->estimate);
gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64, name_,
estimate_);
}
estimator->inter_ping_delay /= 2; // if the ping estimate changes,
// exponentially get faster at probing
} else if (estimator->inter_ping_delay < 10000) {
estimator->stable_estimate_count++;
if (estimator->stable_estimate_count >= 2) {
estimator->inter_ping_delay +=
inter_ping_delay_ /= 2; // if the ping estimate changes,
// exponentially get faster at probing
} else if (inter_ping_delay_ < 10000) {
stable_estimate_count_++;
if (stable_estimate_count_ >= 2) {
inter_ping_delay_ +=
100 +
(int)(rand() * 100.0 / RAND_MAX); // if the ping estimate is steady,
// slowly ramp down the probe time
}
}
if (start_inter_ping_delay != estimator->inter_ping_delay) {
estimator->stable_estimate_count = 0;
if (start_inter_ping_delay != inter_ping_delay_) {
stable_estimate_count_ = 0;
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", estimator->name,
estimator->inter_ping_delay);
gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", name_,
inter_ping_delay_);
}
}
estimator->ping_state = GRPC_BDP_PING_UNSCHEDULED;
estimator->accumulator = 0;
estimator->next_ping_scheduled =
grpc_exec_ctx_now(exec_ctx) + estimator->inter_ping_delay;
ping_state_ = PingState::UNSCHEDULED;
accumulator_ = 0;
return grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_;
}
} // namespace grpc_core

@ -19,67 +19,76 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
#define GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H
#include <grpc/support/time.h>
#include <grpc/support/port_platform.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#define GRPC_BDP_SAMPLES 16
#define GRPC_BDP_MIN_SAMPLES_FOR_ESTIMATE 3
extern grpc_tracer_flag grpc_bdp_estimator_trace;
#ifdef __cplusplus
extern "C" {
#endif
namespace grpc_core {
extern grpc_tracer_flag grpc_bdp_estimator_trace;
class BdpEstimator {
public:
explicit BdpEstimator(const char *name);
~BdpEstimator() {}
typedef enum {
GRPC_BDP_PING_UNSCHEDULED,
GRPC_BDP_PING_SCHEDULED,
GRPC_BDP_PING_STARTED
} grpc_bdp_estimator_ping_state;
int64_t EstimateBdp() const { return estimate_; }
double EstimateBandwidth() const { return bw_est_; }
typedef struct grpc_bdp_estimator {
grpc_bdp_estimator_ping_state ping_state;
int64_t accumulator;
int64_t estimate;
void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; }
// 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
// transport (but not necessarily started)
void SchedulePing() {
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64, name_,
accumulator_, estimate_);
}
GPR_ASSERT(ping_state_ == PingState::UNSCHEDULED);
ping_state_ = PingState::SCHEDULED;
accumulator_ = 0;
}
// Start a ping: call after calling grpc_bdp_estimator_schedule_ping and
// once
// the ping is on the wire
void StartPing() {
if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64, name_,
accumulator_, estimate_);
}
GPR_ASSERT(ping_state_ == PingState::SCHEDULED);
ping_state_ = PingState::STARTED;
accumulator_ = 0;
ping_start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
}
// Completes a previously started ping, returns when to schedule the next one
grpc_millis CompletePing(grpc_exec_ctx *exec_ctx);
private:
enum class PingState { UNSCHEDULED, SCHEDULED, STARTED };
PingState ping_state_;
int64_t accumulator_;
int64_t estimate_;
// when was the current ping started?
gpr_timespec ping_start_time;
// when should the next ping start?
grpc_millis next_ping_scheduled;
int inter_ping_delay;
int stable_estimate_count;
double bw_est;
const char *name;
} grpc_bdp_estimator;
void grpc_bdp_estimator_init(grpc_bdp_estimator *estimator, const char *name);
// Returns true if a reasonable estimate could be obtained
bool grpc_bdp_estimator_get_estimate(const grpc_bdp_estimator *estimator,
int64_t *estimate);
// Tracks new bytes read.
bool grpc_bdp_estimator_get_bw(const grpc_bdp_estimator *estimator, double *bw);
// Returns true if the user should schedule a ping
void grpc_bdp_estimator_add_incoming_bytes(grpc_bdp_estimator *estimator,
int64_t num_bytes);
// Returns true if the user should schedule a ping
bool grpc_bdp_estimator_need_ping(grpc_exec_ctx *exec_ctx,
const grpc_bdp_estimator *estimator);
// 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
// transport (but not necessarily started)
void grpc_bdp_estimator_schedule_ping(grpc_bdp_estimator *estimator);
// Start a ping: call after calling grpc_bdp_estimator_schedule_ping and once
// the ping is on the wire
void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator);
// Completes a previously started ping
void grpc_bdp_estimator_complete_ping(grpc_exec_ctx *exec_ctx,
grpc_bdp_estimator *estimator);
#ifdef __cplusplus
}
#endif
gpr_timespec ping_start_time_;
int inter_ping_delay_;
int stable_estimate_count_;
double bw_est_;
const char *name_;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H */

@ -352,11 +352,14 @@ static size_t get_base64_encoded_size(size_t raw_length) {
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 value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(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 {
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);
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
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 <grpc/support/useful.h>
void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
grpc_pid_controller_args args) {
pid_controller->args = args;
pid_controller->last_control_value = args.initial_control_value;
grpc_pid_controller_reset(pid_controller);
}
namespace grpc_core {
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) {
pid_controller->last_error = 0.0;
pid_controller->last_dc_dt = 0.0;
pid_controller->error_integral = 0.0;
}
PidController::PidController(const Args &args)
: last_control_value_(args.initial_control_value()), args_(args) {}
double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
double error, double dt) {
if (dt == 0) return pid_controller->last_control_value;
double PidController::Update(double error, double dt) {
if (dt <= 0) return last_control_value_;
/* integrate error using the trapezoid rule */
pid_controller->error_integral +=
dt * (pid_controller->last_error + error) * 0.5;
pid_controller->error_integral = GPR_CLAMP(
pid_controller->error_integral, -pid_controller->args.integral_range,
pid_controller->args.integral_range);
double diff_error = (error - pid_controller->last_error) / dt;
error_integral_ += dt * (last_error_ + error) * 0.5;
error_integral_ = GPR_CLAMP(error_integral_, -args_.integral_range(),
args_.integral_range());
double diff_error = (error - last_error_) / dt;
/* calculate derivative of control value vs time */
double dc_dt = pid_controller->args.gain_p * error +
pid_controller->args.gain_i * pid_controller->error_integral +
pid_controller->args.gain_d * diff_error;
double dc_dt = args_.gain_p() * error + args_.gain_i() * error_integral_ +
args_.gain_d() * diff_error;
/* and perform trapezoidal integration */
double new_control_value = pid_controller->last_control_value +
dt * (pid_controller->last_dc_dt + dc_dt) * 0.5;
new_control_value =
GPR_CLAMP(new_control_value, pid_controller->args.min_control_value,
pid_controller->args.max_control_value);
pid_controller->last_error = error;
pid_controller->last_dc_dt = dc_dt;
pid_controller->last_control_value = new_control_value;
double new_control_value =
last_control_value_ + dt * (last_dc_dt_ + dc_dt) * 0.5;
new_control_value = GPR_CLAMP(new_control_value, args_.min_control_value(),
args_.max_control_value());
last_error_ = error;
last_dc_dt_ = dc_dt;
last_control_value_ = new_control_value;
return new_control_value;
}
double grpc_pid_controller_last(grpc_pid_controller *pid_controller) {
return pid_controller->last_control_value;
}
} // namespace grpc_core

@ -19,9 +19,7 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
#define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <limits>
/* \file Simple PID 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
of error (i), and the derivative of error (d). */
typedef struct {
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;
namespace grpc_core {
typedef struct {
double last_error;
double error_integral;
double last_control_value;
double last_dc_dt;
grpc_pid_controller_args args;
} grpc_pid_controller;
class PidController {
public:
class Args {
public:
double gain_p() const { return gain_p_; }
double gain_i() const { return gain_i_; }
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 */
void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
grpc_pid_controller_args args);
Args& set_gain_p(double gain_p) {
gain_p_ = gain_p;
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 */
void grpc_pid_controller_reset(grpc_pid_controller *pid_controller);
private:
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
the last update, returns a new control value */
double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
double error, double dt);
explicit PidController(const Args& args);
/** Returns the last control value calculated */
double grpc_pid_controller_last(grpc_pid_controller *pid_controller);
/// Reset the controller internal state: useful when the environment has
/// changed significantly
void Reset() {
last_error_ = 0.0;
last_dc_dt_ = 0.0;
error_integral_ = 0.0;
}
#ifdef __cplusplus
}
#endif
/// Update the controller: given a current error estimate, and the time since
/// the last update, returns a new control value
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 */

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

@ -266,8 +266,11 @@ class Server::SyncRequestThreadManager : public ThreadManager {
WorkStatus PollForWork(void** tag, bool* ok) override {
*tag = nullptr;
// TODO(ctiller): workaround for GPR_TIMESPAN based deadlines not working
// right now
gpr_timespec deadline =
gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN);
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN));
switch (server_cq_->AsyncNext(tag, ok, deadline)) {
case CompletionQueue::TIMEOUT:

@ -36,7 +36,21 @@ namespace Grpc.Core
readonly Func<Metadata> getTrailersFunc;
readonly Action disposeAction;
internal AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)
/// <summary>
/// Creates a new AsyncClientStreamingCall object with the specified properties.
/// </summary>
/// <param name="requestStream">Stream of request values.</param>
/// <param name="responseAsync">The response of the asynchronous call.</param>
/// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
/// <param name="getStatusFunc">Delegate returning the status of the call.</param>
/// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
/// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
public AsyncClientStreamingCall(IClientStreamWriter<TRequest> requestStream,
Task<TResponse> responseAsync,
Task<Metadata> responseHeadersAsync,
Func<Status> getStatusFunc,
Func<Metadata> getTrailersFunc,
Action disposeAction)
{
this.requestStream = requestStream;
this.responseAsync = responseAsync;

@ -35,7 +35,21 @@ namespace Grpc.Core
readonly Func<Metadata> getTrailersFunc;
readonly Action disposeAction;
internal AsyncDuplexStreamingCall(IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)
/// <summary>
/// Creates a new AsyncDuplexStreamingCall object with the specified properties.
/// </summary>
/// <param name="requestStream">Stream of request values.</param>
/// <param name="responseStream">Stream of response values.</param>
/// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
/// <param name="getStatusFunc">Delegate returning the status of the call.</param>
/// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
/// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
public AsyncDuplexStreamingCall(IClientStreamWriter<TRequest> requestStream,
IAsyncStreamReader<TResponse> responseStream,
Task<Metadata> responseHeadersAsync,
Func<Status> getStatusFunc,
Func<Metadata> getTrailersFunc,
Action disposeAction)
{
this.requestStream = requestStream;
this.responseStream = responseStream;

@ -33,7 +33,19 @@ namespace Grpc.Core
readonly Func<Metadata> getTrailersFunc;
readonly Action disposeAction;
internal AsyncServerStreamingCall(IAsyncStreamReader<TResponse> responseStream, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)
/// <summary>
/// Creates a new AsyncDuplexStreamingCall object with the specified properties.
/// </summary>
/// <param name="responseStream">Stream of response values.</param>
/// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
/// <param name="getStatusFunc">Delegate returning the status of the call.</param>
/// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
/// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
public AsyncServerStreamingCall(IAsyncStreamReader<TResponse> responseStream,
Task<Metadata> responseHeadersAsync,
Func<Status> getStatusFunc,
Func<Metadata> getTrailersFunc,
Action disposeAction)
{
this.responseStream = responseStream;
this.responseHeadersAsync = responseHeadersAsync;

@ -34,7 +34,20 @@ namespace Grpc.Core
readonly Func<Metadata> getTrailersFunc;
readonly Action disposeAction;
internal AsyncUnaryCall(Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)
/// <summary>
/// Creates a new AsyncUnaryCall object with the specified properties.
/// </summary>
/// <param name="responseAsync">The response of the asynchronous call.</param>
/// <param name="responseHeadersAsync">Response headers of the asynchronous call.</param>
/// <param name="getStatusFunc">Delegate returning the status of the call.</param>
/// <param name="getTrailersFunc">Delegate returning the trailing metadata of the call.</param>
/// <param name="disposeAction">Delegate to invoke when Dispose is called on the call object.</param>
public AsyncUnaryCall(Task<TResponse> responseAsync,
Task<Metadata> responseHeadersAsync,
Func<Status> getStatusFunc,
Func<Metadata> getTrailersFunc,
Action disposeAction)
{
this.responseAsync = responseAsync;
this.responseHeadersAsync = responseHeadersAsync;

@ -18,6 +18,7 @@
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <grpc/grpc.h>
#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+ChannelArg.h>
@ -30,6 +31,8 @@
#import <RxLibrary/GRXWriter+Immediate.h>
#import <RxLibrary/GRXBufferedPipe.h>
#import "version.h"
#define TEST_TIMEOUT 16
static NSString * const kHostAddress = @"localhost:5050";
@ -266,12 +269,38 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTAssertNotNil(value, @"nil value received as response.");
XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
/* This test needs to be more clever in regards to changing the version of the core.
XCTAssertEqualObjects(call.responseHeaders[@"x-grpc-test-echo-useragent"],
@"Foo grpc-objc/0.13.0 grpc-c/0.14.0-dev (ios)",
@"Did not receive expected user agent %@",
call.responseHeaders[@"x-grpc-test-echo-useragent"]);
*/
NSString *userAgent = call.responseHeaders[@"x-grpc-test-echo-useragent"];
NSError *error = nil;
// Test the regex is correct
NSString *expectedUserAgent = @"Foo grpc-objc/";
expectedUserAgent =
[expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:@" grpc-c/"];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:@" (ios; chttp2; "];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]];
expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"];
XCTAssertEqualObjects(userAgent, expectedUserAgent);
// Change in format of user-agent field in a direction that does not match the regex will likely
// cause problem for certain gRPC users. For details, refer to internal doc https://goo.gl/c2diBc
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:@" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?"
options:0
error:&error];
NSString *customUserAgent =
[regex stringByReplacingMatchesInString:userAgent
options:0
range:NSMakeRange(0, [userAgent length])
withTemplate:@""];
XCTAssertEqualObjects(customUserAgent, @"Foo");
[response fulfill];
} completionHandler:^(NSError *errorOrNil) {
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);

@ -144,6 +144,7 @@
5EAD6D241E27047400002378 /* CronetUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = "<group>"; };
5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5EAFE8271F8EFB87007F2189 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteWithCronet.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemoteWithCronet.m; sourceTree = "<group>"; };
5EE84BF51D4717E40050C6CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -398,6 +399,7 @@
635697C91B14FC11007A7283 /* Tests */ = {
isa = PBXGroup;
children = (
5EAFE8271F8EFB87007F2189 /* version.h */,
6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */,
63E240CC1B6C4D3A005F3B0E /* InteropTests.h */,
635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */,
@ -740,9 +742,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -755,9 +760,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-frameworks.sh",
"${PODS_ROOT}/CronetFramework/Cronet.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -770,13 +778,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-InteropTestsRemote-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
4F5690DC0E6AD6663FE78B8B /* [CP] Embed Pods Frameworks */ = {
@ -800,13 +811,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalSSL-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5F14F59509E10C2852014F9E /* [CP] Embed Pods Frameworks */ = {
@ -830,9 +844,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -845,9 +862,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -860,13 +880,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-InteropTestsLocalCleartext-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
796680C7599CB4ED736DD62A /* [CP] Check Pods Manifest.lock */ = {
@ -875,13 +898,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
80E2DDD2EC04A4009F45E933 /* [CP] Check Pods Manifest.lock */ = {
@ -890,13 +916,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-CronetUnitTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
8AD3130D3C58A0FB32FF2A36 /* [CP] Copy Pods Resources */ = {
@ -905,9 +934,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -935,13 +967,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-AllTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A441F71824DCB9D0CA297748 /* [CP] Copy Pods Resources */ = {
@ -950,9 +985,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -965,9 +1003,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-frameworks.sh",
"${PODS_ROOT}/CronetFramework/Cronet.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -995,9 +1036,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1010,13 +1054,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RxLibraryUnitTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */ = {
@ -1025,13 +1072,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-InteropTestsRemoteWithCronet-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = {
@ -1040,9 +1090,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1070,9 +1123,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1085,9 +1141,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh",
$PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle,
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1100,9 +1159,12 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh",
"${PODS_ROOT}/CronetFramework/Cronet.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1115,13 +1177,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-CoreCronetEnd2EndTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

@ -0,0 +1,27 @@
/*
*
* Copyright 2015 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.
*
*/
// This file is autogenerated from a template file. Please make
// modifications to
// `templates/src/objective-c/GRPCClient/private/version.h.template`
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"1.8.0-dev"
#define GRPC_C_VERSION_STRING @"5.0.0-dev"

@ -169,7 +169,7 @@ PHP_METHOD(Server, requestCall) {
/**
* Add a http2 over tcp listener.
* @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) {
const char *addr;
@ -190,7 +190,7 @@ PHP_METHOD(Server, addHttp2Port) {
* Add a secure http2 over tcp listener.
* @param string $addr The address to add
* @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) {
const char *addr;

@ -41,6 +41,7 @@ LIB_DIRS = [
]
windows = RUBY_PLATFORM =~ /mingw|mswin/
bsd = RUBY_PLATFORM =~ /bsd/
grpc_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
@ -70,7 +71,8 @@ unless windows
puts 'Building internal gRPC into ' + grpc_lib_dir
nproc = 4
nproc = Etc.nprocessors * 2 if Etc.respond_to? :nprocessors
system("make -j#{nproc} -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config} Q=")
make = bsd ? 'gmake' : 'make'
system("#{make} -j#{nproc} -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config} Q=")
exit 1 unless $? == 0
end

@ -221,6 +221,7 @@ static VALUE grpc_rb_call_close(VALUE self) {
TypedData_Get_Struct(self, grpc_rb_call, &grpc_call_data_type, call);
if (call != NULL) {
destroy_call(call);
xfree(RTYPEDDATA_DATA(self));
RTYPEDDATA_DATA(self) = NULL;
}
return Qnil;

@ -73,7 +73,7 @@
set(PACKAGE_TARNAME "<%text>${PACKAGE_NAME}-${PACKAGE_VERSION}</%text>")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
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_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")
@ -522,6 +522,7 @@
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/gflags/include
PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
% if lib.build in ['test', 'private'] and lib.language == 'c++':
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
@ -593,6 +594,7 @@
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/gflags/include
PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
% if tgt.build in ['test', 'private'] and tgt.language == 'c++':
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest

@ -0,0 +1,29 @@
%YAML 1.2
--- |
/*
*
* Copyright 2015 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.
*
*/
// This file is autogenerated from a template file. Please make
// modifications to
// `templates/src/objective-c/GRPCClient/private/version.h.template`
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"${settings.version}"
#define GRPC_C_VERSION_STRING @"${settings.core_version}"

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

@ -30,7 +30,7 @@ BAD_CLIENT_TESTS = {
'headers': 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,
'large_metadata': default_test_options,
# 'large_metadata': default_test_options, #disabling as per issue #11745
'server_registered_method': default_test_options,
'simple_request': default_test_options,
'window_overflow': default_test_options,

@ -28,7 +28,7 @@ BAD_CLIENT_TESTS = {
'headers': test_options(),
'initial_settings_frame': 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(),
'simple_request': test_options(),
'window_overflow': test_options(),

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

@ -62,8 +62,6 @@
#define HTTP2_DETAIL_MSG(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"
/* 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);
GPR_ASSERT(status == expected_status);
GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string(
expected_detail)));
if (expected_detail != NULL) {
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(&trailing_metadata_recv);
@ -330,8 +330,8 @@ int main(int argc, char **argv) {
HTTP2_DETAIL_MSG(502));
/* unparseable response */
run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1,
GRPC_STATUS_UNAVAILABLE, UNPARSEABLE_DETAIL_MSG);
run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, GRPC_STATUS_UNKNOWN,
NULL);
/* http1 response */
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 in-progress RPC should fail.
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"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
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 *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(call_details.method, "/foo"));
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 in-progress RPC should fail. */
GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);

@ -159,7 +159,9 @@ static void test_early_server_shutdown_finishes_inflight_calls(
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"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);

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

@ -197,3 +197,29 @@ grpc_cc_test(
"//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();
}

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

@ -1,162 +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/bdp_estimator.h"
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include <limits.h>
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/support/string.h"
#include "test/core/util/test_config.h"
extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
static int g_clock = 0;
static gpr_timespec fake_gpr_now(gpr_clock_type clock_type) {
return (gpr_timespec){
.tv_sec = g_clock, .tv_nsec = 0, .clock_type = clock_type,
};
}
static void inc_time(void) { g_clock += 30; }
static void test_noop(void) {
gpr_log(GPR_INFO, "test_noop");
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
}
static void test_get_estimate_no_samples(void) {
gpr_log(GPR_INFO, "test_get_estimate_no_samples");
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
int64_t estimate;
grpc_bdp_estimator_get_estimate(&est, &estimate);
}
static void add_samples(grpc_bdp_estimator *estimator, int64_t *samples,
size_t n) {
grpc_bdp_estimator_add_incoming_bytes(estimator, 1234567);
inc_time();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == true);
grpc_bdp_estimator_schedule_ping(estimator);
grpc_bdp_estimator_start_ping(estimator);
for (size_t i = 0; i < n; i++) {
grpc_bdp_estimator_add_incoming_bytes(estimator, samples[i]);
GPR_ASSERT(grpc_bdp_estimator_need_ping(&exec_ctx, estimator) == false);
}
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(1, GPR_TIMESPAN)));
grpc_bdp_estimator_complete_ping(&exec_ctx, estimator);
grpc_exec_ctx_finish(&exec_ctx);
}
static void add_sample(grpc_bdp_estimator *estimator, int64_t sample) {
add_samples(estimator, &sample, 1);
}
static void test_get_estimate_1_sample(void) {
gpr_log(GPR_INFO, "test_get_estimate_1_sample");
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
add_sample(&est, 100);
int64_t estimate;
grpc_bdp_estimator_get_estimate(&est, &estimate);
}
static void test_get_estimate_2_samples(void) {
gpr_log(GPR_INFO, "test_get_estimate_2_samples");
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
add_sample(&est, 100);
add_sample(&est, 100);
int64_t estimate;
grpc_bdp_estimator_get_estimate(&est, &estimate);
}
static int64_t get_estimate(grpc_bdp_estimator *estimator) {
int64_t out;
GPR_ASSERT(grpc_bdp_estimator_get_estimate(estimator, &out));
return out;
}
static void test_get_estimate_3_samples(void) {
gpr_log(GPR_INFO, "test_get_estimate_3_samples");
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
add_sample(&est, 100);
add_sample(&est, 100);
add_sample(&est, 100);
int64_t estimate;
grpc_bdp_estimator_get_estimate(&est, &estimate);
}
static int64_t next_pow_2(int64_t v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
return v;
}
static void test_get_estimate_random_values(size_t n) {
gpr_log(GPR_INFO, "test_get_estimate_random_values(%" PRIdPTR ")", n);
grpc_bdp_estimator est;
grpc_bdp_estimator_init(&est, "test");
const int kMaxSample = 65535;
int min = kMaxSample;
int max = 0;
for (size_t i = 0; i < n; i++) {
int sample = rand() % (kMaxSample + 1);
if (sample < min) min = sample;
if (sample > max) max = sample;
add_sample(&est, sample);
if (i >= 3) {
gpr_log(GPR_DEBUG, "est:%" PRId64 " min:%d max:%d", get_estimate(&est),
min, max);
GPR_ASSERT(get_estimate(&est) <= GPR_MAX(65536, 2 * next_pow_2(max)));
}
}
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
gpr_now_impl = fake_gpr_now;
grpc_init();
grpc_timer_manager_set_threading(false);
test_noop();
test_get_estimate_no_samples();
test_get_estimate_1_sample();
test_get_estimate_2_samples();
test_get_estimate_3_samples();
for (size_t i = 3; i < 1000; i = i * 3 / 2) {
test_get_estimate_random_values(i);
}
grpc_shutdown();
return 0;
}

@ -0,0 +1,149 @@
/*
*
* 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/bdp_estimator.h"
#include <grpc/grpc.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 <limits.h>
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/support/string.h"
#include "test/core/util/test_config.h"
extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
namespace grpc_core {
namespace testing {
namespace {
int g_clock = 0;
gpr_timespec fake_gpr_now(gpr_clock_type clock_type) {
gpr_timespec ts;
ts.tv_sec = g_clock;
ts.tv_nsec = 0;
ts.clock_type = clock_type;
return ts;
}
void inc_time(void) { g_clock += 30; }
} // namespace
TEST(BdpEstimatorTest, NoOp) { BdpEstimator est("test"); }
TEST(BdpEstimatorTest, EstimateBdpNoSamples) {
BdpEstimator est("test");
est.EstimateBdp();
}
namespace {
void AddSamples(BdpEstimator *estimator, int64_t *samples, size_t n) {
estimator->AddIncomingBytes(1234567);
inc_time();
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
estimator->SchedulePing();
estimator->StartPing();
for (size_t i = 0; i < n; i++) {
estimator->AddIncomingBytes(samples[i]);
}
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(1, GPR_TIMESPAN)));
grpc_exec_ctx_invalidate_now(&exec_ctx);
estimator->CompletePing(&exec_ctx);
grpc_exec_ctx_finish(&exec_ctx);
}
void AddSample(BdpEstimator *estimator, int64_t sample) {
AddSamples(estimator, &sample, 1);
}
} // namespace
TEST(BdpEstimatorTest, GetEstimate1Sample) {
BdpEstimator est("test");
AddSample(&est, 100);
est.EstimateBdp();
}
TEST(BdpEstimatorTest, GetEstimate2Samples) {
BdpEstimator est("test");
AddSample(&est, 100);
AddSample(&est, 100);
est.EstimateBdp();
}
TEST(BdpEstimatorTest, GetEstimate3Samples) {
BdpEstimator est("test");
AddSample(&est, 100);
AddSample(&est, 100);
AddSample(&est, 100);
est.EstimateBdp();
}
namespace {
int64_t NextPow2(int64_t v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
return v;
}
} // namespace
class BdpEstimatorRandomTest : public ::testing::TestWithParam<size_t> {};
TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) {
BdpEstimator est("test");
const int kMaxSample = 65535;
int min = kMaxSample;
int max = 0;
for (size_t i = 0; i < GetParam(); i++) {
int sample = rand() % (kMaxSample + 1);
if (sample < min) min = sample;
if (sample > max) max = sample;
AddSample(&est, sample);
if (i >= 3) {
EXPECT_LE(est.EstimateBdp(), GPR_MAX(65536, 2 * NextPow2(max)))
<< " min:" << min << " max:" << max << " sample:" << sample;
}
}
}
INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest,
::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94,
141, 211, 316, 474, 711));
} // namespace testing
} // namespace grpc_core
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
gpr_now_impl = grpc_core::testing::fake_gpr_now;
grpc_init();
grpc_timer_manager_set_threading(false);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -43,10 +43,15 @@ void **to_delete = NULL;
size_t num_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
hexstring passed in */
static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof,
bool use_true_binary_metadata, size_t expect_window_used,
static void verify(grpc_exec_ctx *exec_ctx, const verify_params params,
const char *expected, size_t nheaders, ...) {
grpc_slice_buffer output;
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].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(
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[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));
grpc_encode_header_options hopt = {
.stream_id = 0xdeadbeef,
.is_eof = eof,
.use_true_binary_metadata = use_true_binary_metadata,
.is_eof = params.eof,
.use_true_binary_metadata = params.use_true_binary_metadata,
.max_frame_size = 16384,
.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) {
int i;
verify(exec_ctx, 0, false, false, 0, "000005 0104 deadbeef 40 0161 0161", 1,
"a", "a");
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, 0, false, false, 0, "000006 0104 deadbeef be 40 0162 0163",
2, "a", "a", "b", "c");
verify(exec_ctx, 0, false, false, 0, "000002 0104 deadbeef bf be", 2, "a",
"a", "b", "c");
verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 7f 00 0164", 1,
"a", "d");
verify_params params = {
.eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
};
verify(exec_ctx, params, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a");
verify(exec_ctx, params, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a",
"b", "c");
verify(exec_ctx, params, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c");
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 */
for (i = 0; i < 350; i++) {
verify(exec_ctx, 0, false, false, 0, "000003 0104 deadbeef c0 bf be", 3,
"a", "a", "b", "c", "a", "d");
verify(exec_ctx, params, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b",
"c", "a", "d");
}
verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef c0 00 016b 0176",
2, "a", "a", "k", "v");
verify(exec_ctx, params, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a",
"k", "v");
/* this could be 000004 0104 deadbeef 0f 30 0176 also */
verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 0f 2f 0176", 1,
"a", "v");
verify(exec_ctx, params, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
}
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 *expect;
verify_params params = {
.eof = false, .use_true_binary_metadata = false, .only_intern_key = false,
};
for (i = 0; i < 114; i++) {
encode_int_to_str(i, key);
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) {
verify(exec_ctx, 0, false, false, 0, expect, 2, "aa", "ba", key, value);
verify(exec_ctx, params, expect, 2, "aa", "ba", key, value);
} else {
verify(exec_ctx, 0, false, false, 0, expect, 1, key, value);
verify(exec_ctx, params, expect, 1, key, value);
}
gpr_free(expect);
}
/* 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 */
verify(exec_ctx, 0, false, false, 0, "000007 0104 deadbeef 40 026161 026261",
1, "aa", "ba");
verify(exec_ctx, params, "000007 0104 deadbeef 40 026161 026261", 1, "aa",
"ba");
}
static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
const char *key,
const char *value) {
const char *value,
bool use_true_binary) {
grpc_slice_buffer output;
grpc_mdelem elem = grpc_mdelem_from_slices(
exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)),
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;
grpc_linked_mdelem *e = gpr_malloc(sizeof(*e));
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;
memset(&stats, 0, sizeof(stats));
grpc_encode_header_options hopt = {.stream_id = 0xdeadbeef,
.is_eof = false,
.use_true_binary_metadata = false,
.max_frame_size = 16384,
.stats = &stats};
grpc_encode_header_options hopt = {
.stream_id = 0xdeadbeef,
.is_eof = false,
.use_true_binary_metadata = use_true_binary,
.max_frame_size = 16384,
.stats = &stats};
grpc_chttp2_encode_header(exec_ctx, &g_compressor, NULL, 0, &b, &hopt,
&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) {
verify_table_size_change_match_elem_size(exec_ctx, "hello", "world");
verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "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",
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) {
@ -245,6 +275,7 @@ int main(int argc, char **argv) {
TEST(test_basic_headers);
TEST(test_decode_table_overflow);
TEST(test_encode_header_size);
TEST(test_interned_key_indexed);
grpc_shutdown();
for (i = 0; i < num_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(
exec_ctx, maybe_intern(grpc_slice_from_static_string(key), intern_key),
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);
GPR_ASSERT(expected_size == elem_size);
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),
intern_value));
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_from_copied_buffer((const char *)value, value_len);
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();
}

@ -31,10 +31,23 @@ grpc_cc_library(
deps = ["//:gpr"],
)
grpc_cc_library(
name = "grpc_debugger_macros",
srcs = [
"debugger_macros.cc",
],
hdrs = [
"debugger_macros.h",
],
deps = [
":gpr_test_util",
"//:grpc_common",
],
)
grpc_cc_library(
name = "grpc_test_util_base",
srcs = [
"debugger_macros.c",
"grpc_profiler.c",
"mock_endpoint.c",
"parse_hexstring.c",
@ -47,7 +60,6 @@ grpc_cc_library(
"trickle_endpoint.c",
],
hdrs = [
"debugger_macros.h",
"grpc_profiler.h",
"mock_endpoint.h",
"parse_hexstring.h",
@ -63,6 +75,7 @@ grpc_cc_library(
deps = [
":gpr_test_util",
"//:grpc_common",
":grpc_debugger_macros"
],
)

@ -29,7 +29,7 @@
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/surface/call.h"
void grpc_summon_debugger_macros() {}
extern "C" void grpc_summon_debugger_macros() {}
grpc_stream *grpc_transport_stream_from_call(grpc_call *call) {
grpc_call_stack *cs = grpc_call_get_call_stack(call);

@ -19,6 +19,14 @@
#ifndef GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
#define GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void grpc_summon_debugger_macros();
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H */

@ -21,6 +21,10 @@
#include "src/core/lib/iomgr/endpoint.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
grpc_endpoint *grpc_trickle_endpoint_create(grpc_endpoint *wrap,
double bytes_per_second);
@ -30,4 +34,8 @@ size_t grpc_trickle_endpoint_trickle(grpc_exec_ctx *exec_ctx,
size_t grpc_trickle_get_backlog(grpc_endpoint *endpoint);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif

@ -220,7 +220,8 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
End2endTest()
: is_server_started_(false),
kMaxMessageSize_(8192),
special_service_("special") {
special_service_("special"),
first_picked_port_(0) {
GetParam().Log();
}
@ -229,10 +230,14 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
server_->Shutdown();
if (proxy_server_) proxy_server_->Shutdown();
}
if (first_picked_port_ > 0) {
grpc_recycle_unused_port(first_picked_port_);
}
}
void StartServer(const std::shared_ptr<AuthMetadataProcessor>& processor) {
int port = grpc_pick_unused_port_or_die();
first_picked_port_ = port;
server_address_ << "127.0.0.1:" << port;
// Setup server
BuildAndStartServer(processor);
@ -328,6 +333,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
TestServiceImpl special_service_;
TestServiceImplDupPkg dup_pkg_service_;
grpc::string user_agent_prefix_;
int first_picked_port_;
};
static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs,

@ -28,12 +28,22 @@ extern "C" {
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
}
#include "test/cpp/microbenchmarks/helpers.h"
#include "third_party/benchmark/include/benchmark/benchmark.h"
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
//
@ -52,6 +62,48 @@ static void BM_HpackEncoderInitDestroy(benchmark::State &state) {
}
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>
static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
TrackCounters track_counters;
@ -104,7 +156,7 @@ static void BM_HpackEncoderEncodeHeader(benchmark::State &state) {
static_cast<double>(state.iterations()))
<< " header_bytes/iter:" << (static_cast<double>(stats.header_bytes) /
static_cast<double>(state.iterations()));
state.SetLabel(label.str());
track_counters.AddLabel(label.str());
track_counters.Finish(state);
}
@ -220,6 +272,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 {
public:
static constexpr bool kEnableTrueBinary = true;
@ -316,6 +407,9 @@ BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader, SingleNonInternedElem)
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
RepresentativeClientInitialMetadata)
->Args({0, 16384});
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
MoreRepresentativeClientInitialMetadata)
->Args({0, 16384});
BENCHMARK_TEMPLATE(BM_HpackEncoderEncodeHeader,
RepresentativeServerInitialMetadata)
->Args({0, 16384});
@ -348,7 +442,8 @@ static void UnrefHeader(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_MDELEM_UNREF(exec_ctx, md);
}
template <class Fixture>
template <class Fixture,
void (*OnHeader)(grpc_exec_ctx *, void *, grpc_mdelem) = UnrefHeader>
static void BM_HpackParserParseHeader(benchmark::State &state) {
TrackCounters track_counters;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@ -356,14 +451,16 @@ static void BM_HpackParserParseHeader(benchmark::State &state) {
std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
grpc_chttp2_hpack_parser p;
grpc_chttp2_hpack_parser_init(&exec_ctx, &p);
p.on_header = UnrefHeader;
p.on_header = OnHeader;
p.on_header_user_data = nullptr;
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()) {
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);
}
@ -376,15 +473,6 @@ static void BM_HpackParserParseHeader(benchmark::State &state) {
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 {
public:
static std::vector<grpc_slice> GetInitSlices() { return {}; }
@ -572,6 +660,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 {
public:
static std::vector<grpc_slice> GetInitSlices() {
@ -625,6 +761,81 @@ class RepresentativeServerTrailingMetadata {
}
};
static void free_timeout(void *p) { gpr_free(p); }
// New implementation.
static void OnHeaderNew(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_mdelem md) {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis *cached_timeout =
static_cast<grpc_millis *>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout != NULL) {
timeout = *cached_timeout;
} else {
if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout)) {
char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
timeout = GRPC_MILLIS_INF_FUTURE;
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* not already parsed: parse it now, and store the
* result away */
cached_timeout = (grpc_millis *)gpr_malloc(sizeof(grpc_millis));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
}
benchmark::DoNotOptimize(timeout);
GRPC_MDELEM_UNREF(exec_ctx, md);
} else {
GPR_ASSERT(0);
}
}
// Current implementation.
static void OnHeaderOld(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_mdelem md) {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis *cached_timeout =
static_cast<grpc_millis *>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout == NULL) {
/* not already parsed: parse it now, and store the result away */
cached_timeout = (grpc_millis *)gpr_malloc(sizeof(grpc_millis));
if (!grpc_http2_decode_timeout(GRPC_MDVALUE(md), cached_timeout)) {
char *val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
*cached_timeout = GRPC_MILLIS_INF_FUTURE;
}
timeout = *cached_timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
} else {
timeout = *cached_timeout;
}
benchmark::DoNotOptimize(timeout);
GRPC_MDELEM_UNREF(exec_ctx, md);
} else {
GPR_ASSERT(0);
}
}
// Send the same deadline repeatedly
class SameDeadline {
public:
static std::vector<grpc_slice> GetInitSlices() {
return {
grpc_slice_from_static_string("@\x0cgrpc-timeout\x03"
"30S")};
}
static std::vector<grpc_slice> GetBenchmarkSlices() {
// Use saved key and literal value.
return {MakeSlice({0x0f, 0x2f, 0x03, '3', '0', 'S'})};
}
};
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, EmptyBatch);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, IndexedSingleStaticElem);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, AddIndexedSingleStaticElem);
@ -645,11 +856,16 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<31, true>);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, NonIndexedBinaryElem<100, true>);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeClientInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
MoreRepresentativeClientInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerTrailingMetadata);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderOld);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderNew);
} // namespace hpack_parser_fixtures
BENCHMARK_MAIN();

@ -26,14 +26,12 @@
#include <memory>
#include <queue>
#include <sstream>
extern "C" {
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/static_metadata.h"
}
#include "test/cpp/microbenchmarks/helpers.h"
#include "third_party/benchmark/include/benchmark/benchmark.h"
@ -430,9 +428,8 @@ static void BM_TransportStreamSend(benchmark::State &state) {
return;
}
// force outgoing window to be yuge
s->chttp2_stream()->flow_control.remote_window_delta =
1024 * 1024 * 1024;
f.chttp2_transport()->flow_control.remote_window = 1024 * 1024 * 1024;
s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0);
reset_op();
op.on_complete = c.get();
@ -562,22 +559,21 @@ static void BM_TransportStreamRecv(benchmark::State &state) {
std::unique_ptr<Closure> drain_continue;
grpc_slice recv_slice;
std::unique_ptr<Closure> c = MakeClosure([&](grpc_exec_ctx *exec_ctx,
grpc_error *error) {
if (!state.KeepRunning()) return;
// force outgoing window to be yuge
s.chttp2_stream()->flow_control.local_window_delta = 1024 * 1024 * 1024;
s.chttp2_stream()->flow_control.announced_window_delta = 1024 * 1024 * 1024;
f.chttp2_transport()->flow_control.announced_window = 1024 * 1024 * 1024;
received = 0;
reset_op();
op.on_complete = do_nothing.get();
op.recv_message = true;
op.payload->recv_message.recv_message = &recv_stream;
op.payload->recv_message.recv_message_ready = drain_start.get();
s.Op(exec_ctx, &op);
f.PushInput(grpc_slice_ref(incoming_data));
});
std::unique_ptr<Closure> c =
MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
if (!state.KeepRunning()) return;
// force outgoing window to be yuge
s.chttp2_stream()->flow_control->TestOnlyForceHugeWindow();
f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow();
received = 0;
reset_op();
op.on_complete = do_nothing.get();
op.recv_message = true;
op.payload->recv_message.recv_message = &recv_stream;
op.payload->recv_message.recv_message_ready = drain_start.get();
s.Op(exec_ctx, &op);
f.PushInput(grpc_slice_ref(incoming_data));
});
drain_start = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
if (recv_stream == NULL) {

@ -21,17 +21,15 @@
#include <benchmark/benchmark.h>
#include <gflags/gflags.h>
#include <fstream>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/profiling/timers.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/trickle_endpoint.h"
#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
#include "test/cpp/util/test_config.h"
extern "C" {
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "test/core/util/trickle_endpoint.h"
}
DEFINE_bool(log, false, "Log state to CSV files");
DEFINE_int32(
@ -144,15 +142,18 @@ class TrickledCHTTP2 : public EndpointPairFixture {
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_STREAM].head != nullptr,
client->flow_control.remote_window, server->flow_control.remote_window,
client->flow_control.announced_window,
server->flow_control.announced_window,
client_stream ? client_stream->flow_control.remote_window_delta : -1,
server_stream ? server_stream->flow_control.remote_window_delta : -1,
client_stream ? client_stream->flow_control.local_window_delta : -1,
server_stream ? server_stream->flow_control.local_window_delta : -1,
client_stream ? client_stream->flow_control.announced_window_delta : -1,
server_stream ? server_stream->flow_control.announced_window_delta : -1,
client->flow_control->remote_window(),
server->flow_control->remote_window(),
client->flow_control->announced_window(),
server->flow_control->announced_window(),
client_stream ? client_stream->flow_control->remote_window_delta() : -1,
server_stream ? server_stream->flow_control->remote_window_delta() : -1,
client_stream ? client_stream->flow_control->local_window_delta() : -1,
server_stream ? server_stream->flow_control->local_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]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
client->settings[GRPC_LOCAL_SETTINGS]

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save