Merge branch 'master' into fix_alarm

pull/11579/head
Sree Kuchibhotla 8 years ago
commit e70f3b2200
  1. 5
      .pylintrc
  2. 6
      BUILD
  3. 1160
      CMakeLists.txt
  4. 880
      Makefile
  5. 4
      bazel/grpc_build_system.bzl
  6. 697
      build.yaml
  7. 6
      doc/environment_variables.md
  8. 310
      gRPC-Core.podspec
  9. 169
      grpc.gemspec
  10. 6
      include/grpc/grpc.h
  11. 4
      include/grpc/impl/codegen/grpc_types.h
  12. 60
      include/grpc/support/avl.h
  13. 169
      package.xml
  14. 13
      setup.py
  15. 1
      src/compiler/node_generator.cc
  16. 2
      src/core/ext/filters/client_channel/channel_connectivity.c
  17. 1
      src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c
  18. 158
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
  19. 79
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c
  20. 27
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
  21. 44
      src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
  22. 2
      src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
  23. 22
      src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
  24. 48
      src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
  25. 29
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
  26. 2
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
  27. 22
      src/core/ext/filters/client_channel/retry_throttle.c
  28. 88
      src/core/ext/filters/client_channel/subchannel_index.c
  29. 514
      src/core/ext/filters/http/client/http_client_filter.c
  30. 202
      src/core/ext/filters/http/message_compress/message_compress_filter.c
  31. 195
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  32. 2
      src/core/ext/transport/chttp2/transport/frame_data.c
  33. 23
      src/core/ext/transport/chttp2/transport/internal.h
  34. 85
      src/core/ext/transport/chttp2/transport/writing.c
  35. 3
      src/core/ext/transport/cronet/transport/cronet_transport.c
  36. 33
      src/core/ext/transport/inproc/inproc_transport.c
  37. 4
      src/core/lib/iomgr/combiner.c
  38. 104
      src/core/lib/iomgr/nameser.h
  39. 5
      src/core/lib/iomgr/port.h
  40. 165
      src/core/lib/support/avl.c
  41. 3
      src/core/lib/surface/alarm.c
  42. 23
      src/core/lib/surface/call.c
  43. 2
      src/core/lib/surface/channel_ping.c
  44. 87
      src/core/lib/surface/completion_queue.c
  45. 5
      src/core/lib/surface/completion_queue.h
  46. 14
      src/core/lib/surface/server.c
  47. 128
      src/core/lib/transport/byte_stream.c
  48. 99
      src/core/lib/transport/byte_stream.h
  49. 24
      src/core/lib/transport/transport.c
  50. 9
      src/core/lib/transport/transport.h
  51. 2
      src/cpp/client/client_context.cc
  52. 50
      src/cpp/server/server_cc.cc
  53. 98
      src/csharp/Grpc.Core.Tests/ThreadingModelTest.cs
  54. 1
      src/csharp/Grpc.Core/Grpc.Core.csproj
  55. 22
      src/csharp/Grpc.Core/GrpcEnvironment.cs
  56. 31
      src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
  57. 5
      src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
  58. 1
      src/csharp/tests.json
  59. 11
      src/node/src/server.js
  60. 2
      src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
  61. 2
      src/objective-c/!ProtoCompiler.podspec
  62. 544
      src/objective-c/BoringSSL.podspec
  63. 2
      src/objective-c/GRPCClient/private/NSData+GRPC.m
  64. 8
      src/objective-c/RxLibrary/GRXBufferedPipe.m
  65. 70
      src/objective-c/tests/RxLibraryUnitTests.m
  66. 6
      src/objective-c/tests/build_one_example.sh
  67. 14
      src/objective-c/tests/run_tests.sh
  68. 42
      src/proto/grpc/lb/v1/load_balancer.proto
  69. 13
      src/python/grpcio_health_checking/setup.py
  70. 13
      src/python/grpcio_reflection/setup.py
  71. 119
      src/python/grpcio_testing/grpc_testing/__init__.py
  72. 224
      src/python/grpcio_testing/grpc_testing/_time.py
  73. 17
      src/python/grpcio_testing/grpc_version.py
  74. 44
      src/python/grpcio_testing/setup.py
  75. 13
      src/python/grpcio_tests/tests/testing/__init__.py
  76. 165
      src/python/grpcio_tests/tests/testing/_time_test.py
  77. 2
      src/python/grpcio_tests/tests/tests.json
  78. 12
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  79. 15
      src/ruby/lib/grpc/generic/active_call.rb
  80. 26
      src/ruby/spec/generic/client_stub_spec.rb
  81. 88
      src/ruby/spec/generic/rpc_server_spec.rb
  82. 2
      templates/Makefile.template
  83. 2
      templates/gRPC-Core.podspec.template
  84. 2
      templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template
  85. 30
      templates/tools/dockerfile/interoptest/grpc_interop_android_java/Dockerfile.template
  86. 5
      test/core/end2end/fuzzers/api_fuzzer.c
  87. BIN
      test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-4688823906729984
  88. 5
      test/core/end2end/fuzzers/server_fuzzer.c
  89. 8
      test/core/end2end/tests/cancel_with_status.c
  90. 6
      test/core/fling/server.c
  91. 3484
      test/core/support/avl_test.c
  92. 6
      test/core/surface/completion_queue_test.c
  93. 4
      test/core/surface/completion_queue_threading_test.c
  94. 12
      test/core/transport/BUILD
  95. 279
      test/core/transport/byte_stream_test.c
  96. 213
      test/cpp/end2end/grpclb_end2end_test.cc
  97. 16
      test/cpp/grpclb/grpclb_api_test.cc
  98. 7
      test/cpp/microbenchmarks/bm_cq.cc
  99. 2
      test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
  100. 7
      test/cpp/qps/server.h
  101. Some files were not shown because too many files have changed in this diff Show More

@ -41,6 +41,11 @@ disable=
# NOTE(nathaniel): We don't write doc strings for most private code
# elements.
missing-docstring,
# NOTE(nathaniel): In numeric comparisons it is better to have the
# lesser (or lesser-or-equal-to) quantity on the left when the
# expression is true than it is to worry about which is an identifier
# and which a literal value.
misplaced-comparison-constant,
# NOTE(nathaniel): Our completely abstract interface classes don't have
# constructors.
no-init,

@ -206,6 +206,7 @@ grpc_cc_library(
standalone = True,
deps = [
"grpc_common",
"grpc_lb_policy_grpclb",
],
)
@ -221,7 +222,6 @@ grpc_cc_library(
deps = [
"grpc_common",
"grpc_lb_policy_grpclb_secure",
"grpc_resolver_dns_ares",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_secure",
@ -287,6 +287,7 @@ grpc_cc_library(
"grpc++_base_unsecure",
"grpc++_codegen_base",
"grpc++_codegen_base_src",
"grpc++_codegen_proto",
"grpc_unsecure",
],
)
@ -725,6 +726,7 @@ grpc_cc_library(
"src/core/lib/iomgr/is_epollexclusive_available.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/lockfree_event.h",
"src/core/lib/iomgr/nameser.h",
"src/core/lib/iomgr/network_status_tracker.h",
"src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h",
@ -837,6 +839,8 @@ grpc_cc_library(
"grpc_load_reporting",
"grpc_max_age_filter",
"grpc_message_size_filter",
"grpc_resolver_dns_ares",
"grpc_resolver_fake",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
"grpc_transport_chttp2_client_insecure",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -80,7 +80,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
linkopts = ["-pthread"],
)
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False):
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = []):
copts = []
if language.upper() == "C":
copts = ["-std=c99"]
@ -93,7 +93,7 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da
linkshared = linkshared,
deps = deps + ["//external:" + dep for dep in external_deps],
copts = copts,
linkopts = ["-pthread"],
linkopts = ["-pthread"] + linkopts,
)
def grpc_generate_one_off_targets():

@ -59,52 +59,6 @@ filegroups:
- grpc_base
- nanopb
- name: gpr_base
public_headers:
- include/grpc/support/alloc.h
- include/grpc/support/atm.h
- include/grpc/support/atm_gcc_atomic.h
- include/grpc/support/atm_gcc_sync.h
- include/grpc/support/atm_windows.h
- include/grpc/support/avl.h
- include/grpc/support/cmdline.h
- include/grpc/support/cpu.h
- include/grpc/support/histogram.h
- include/grpc/support/host_port.h
- include/grpc/support/log.h
- include/grpc/support/log_windows.h
- include/grpc/support/port_platform.h
- include/grpc/support/string_util.h
- include/grpc/support/subprocess.h
- include/grpc/support/sync.h
- include/grpc/support/sync_generic.h
- include/grpc/support/sync_posix.h
- include/grpc/support/sync_windows.h
- include/grpc/support/thd.h
- include/grpc/support/time.h
- include/grpc/support/tls.h
- include/grpc/support/tls_gcc.h
- include/grpc/support/tls_msvc.h
- include/grpc/support/tls_pthread.h
- include/grpc/support/useful.h
headers:
- src/core/lib/profiling/timers.h
- src/core/lib/support/arena.h
- src/core/lib/support/atomic.h
- src/core/lib/support/atomic_with_atm.h
- src/core/lib/support/atomic_with_std.h
- src/core/lib/support/backoff.h
- src/core/lib/support/block_annotate.h
- src/core/lib/support/env.h
- src/core/lib/support/memory.h
- src/core/lib/support/mpscq.h
- src/core/lib/support/murmur_hash.h
- src/core/lib/support/spinlock.h
- src/core/lib/support/stack_lockfree.h
- src/core/lib/support/string.h
- src/core/lib/support/string_windows.h
- src/core/lib/support/thd_internal.h
- src/core/lib/support/time_precise.h
- src/core/lib/support/tmpfile.h
src:
- src/core/lib/profiling/basic_timers.c
- src/core/lib/profiling/stap_timers.c
@ -153,6 +107,55 @@ filegroups:
- src/core/lib/support/tmpfile_windows.c
- src/core/lib/support/wrap_memcpy.c
uses:
- gpr_base_headers
- name: gpr_base_headers
public_headers:
- include/grpc/support/alloc.h
- include/grpc/support/atm.h
- include/grpc/support/atm_gcc_atomic.h
- include/grpc/support/atm_gcc_sync.h
- include/grpc/support/atm_windows.h
- include/grpc/support/avl.h
- include/grpc/support/cmdline.h
- include/grpc/support/cpu.h
- include/grpc/support/histogram.h
- include/grpc/support/host_port.h
- include/grpc/support/log.h
- include/grpc/support/log_windows.h
- include/grpc/support/port_platform.h
- include/grpc/support/string_util.h
- include/grpc/support/subprocess.h
- include/grpc/support/sync.h
- include/grpc/support/sync_generic.h
- include/grpc/support/sync_posix.h
- include/grpc/support/sync_windows.h
- include/grpc/support/thd.h
- include/grpc/support/time.h
- include/grpc/support/tls.h
- include/grpc/support/tls_gcc.h
- include/grpc/support/tls_msvc.h
- include/grpc/support/tls_pthread.h
- include/grpc/support/useful.h
headers:
- src/core/lib/profiling/timers.h
- src/core/lib/support/arena.h
- src/core/lib/support/atomic.h
- src/core/lib/support/atomic_with_atm.h
- src/core/lib/support/atomic_with_std.h
- src/core/lib/support/backoff.h
- src/core/lib/support/block_annotate.h
- src/core/lib/support/env.h
- src/core/lib/support/memory.h
- src/core/lib/support/mpscq.h
- src/core/lib/support/murmur_hash.h
- src/core/lib/support/spinlock.h
- src/core/lib/support/stack_lockfree.h
- src/core/lib/support/string.h
- src/core/lib/support/string_windows.h
- src/core/lib/support/thd_internal.h
- src/core/lib/support/time_precise.h
- src/core/lib/support/tmpfile.h
uses:
- gpr_codegen
- name: gpr_codegen
public_headers:
@ -167,132 +170,19 @@ filegroups:
- include/grpc/impl/codegen/sync_generic.h
- include/grpc/impl/codegen/sync_posix.h
- include/grpc/impl/codegen/sync_windows.h
- name: grpc++_base
deps:
- grpc
uses:
- grpc++_common
- grpc++_codegen_base
- name: grpc++_base_unsecure
deps:
- grpc_unsecure
uses:
- grpc++_common
- grpc++_codegen_base
- name: grpc_base
public_headers:
- include/grpc/byte_buffer.h
- include/grpc/byte_buffer_reader.h
- include/grpc/compression.h
- include/grpc/grpc.h
- include/grpc/grpc_posix.h
- include/grpc/grpc_security_constants.h
- include/grpc/load_reporting.h
- include/grpc/slice.h
- include/grpc/slice_buffer.h
- include/grpc/status.h
- include/grpc/support/workaround_list.h
headers:
- src/core/lib/channel/channel_args.h
- src/core/lib/channel/channel_stack.h
- src/core/lib/channel/channel_stack_builder.h
- src/core/lib/channel/connected_channel.h
- src/core/lib/channel/context.h
- src/core/lib/channel/handshaker.h
- src/core/lib/channel/handshaker_factory.h
- src/core/lib/channel/handshaker_registry.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/message_compress.h
- src/core/lib/compression/stream_compression.h
- src/core/lib/http/format_request.h
- src/core/lib/http/httpcli.h
- src/core/lib/http/parser.h
- src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/combiner.h
- src/core/lib/iomgr/endpoint.h
- src/core/lib/iomgr/endpoint_pair.h
- src/core/lib/iomgr/error.h
- src/core/lib/iomgr/error_internal.h
- src/core/lib/iomgr/ev_epoll1_linux.h
- src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h
- src/core/lib/iomgr/ev_epoll_thread_pool_linux.h
- src/core/lib/iomgr/ev_epollex_linux.h
- src/core/lib/iomgr/ev_epollsig_linux.h
- src/core/lib/iomgr/ev_poll_posix.h
- src/core/lib/iomgr/ev_posix.h
- src/core/lib/iomgr/exec_ctx.h
- src/core/lib/iomgr/executor.h
- src/core/lib/iomgr/iocp_windows.h
- src/core/lib/iomgr/iomgr.h
- src/core/lib/iomgr/iomgr_internal.h
- src/core/lib/iomgr/iomgr_posix.h
- src/core/lib/iomgr/iomgr_uv.h
- src/core/lib/iomgr/is_epollexclusive_available.h
- src/core/lib/iomgr/load_file.h
- src/core/lib/iomgr/lockfree_event.h
- src/core/lib/iomgr/network_status_tracker.h
- src/core/lib/iomgr/polling_entity.h
- src/core/lib/iomgr/pollset.h
- src/core/lib/iomgr/pollset_set.h
- src/core/lib/iomgr/pollset_set_windows.h
- src/core/lib/iomgr/pollset_uv.h
- src/core/lib/iomgr/pollset_windows.h
- src/core/lib/iomgr/port.h
- src/core/lib/iomgr/resolve_address.h
- src/core/lib/iomgr/resource_quota.h
- src/core/lib/iomgr/sockaddr.h
- src/core/lib/iomgr/sockaddr_posix.h
- src/core/lib/iomgr/sockaddr_utils.h
- src/core/lib/iomgr/sockaddr_windows.h
- src/core/lib/iomgr/socket_factory_posix.h
- src/core/lib/iomgr/socket_mutator.h
- src/core/lib/iomgr/socket_utils.h
- src/core/lib/iomgr/socket_utils_posix.h
- src/core/lib/iomgr/socket_windows.h
- src/core/lib/iomgr/sys_epoll_wrapper.h
- src/core/lib/iomgr/tcp_client.h
- src/core/lib/iomgr/tcp_client_posix.h
- src/core/lib/iomgr/tcp_posix.h
- src/core/lib/iomgr/tcp_server.h
- src/core/lib/iomgr/tcp_server_utils_posix.h
- src/core/lib/iomgr/tcp_uv.h
- src/core/lib/iomgr/tcp_windows.h
- src/core/lib/iomgr/time_averaged_stats.h
- src/core/lib/iomgr/timer.h
- src/core/lib/iomgr/timer_generic.h
- src/core/lib/iomgr/timer_heap.h
- src/core/lib/iomgr/timer_manager.h
- src/core/lib/iomgr/timer_uv.h
- src/core/lib/iomgr/udp_server.h
- src/core/lib/iomgr/unix_sockets_posix.h
- src/core/lib/iomgr/wakeup_fd_cv.h
- src/core/lib/iomgr/wakeup_fd_pipe.h
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/json/json.h
- src/core/lib/json/json_common.h
- src/core/lib/json/json_reader.h
- src/core/lib/json/json_writer.h
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
- 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/surface/alarm_internal.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/call.h
- src/core/lib/surface/call_test_only.h
- src/core/lib/surface/channel.h
- src/core/lib/surface/channel_init.h
- src/core/lib/surface/channel_stack_type.h
- src/core/lib/surface/completion_queue.h
- src/core/lib/surface/completion_queue_factory.h
- src/core/lib/surface/event_string.h
- src/core/lib/surface/init.h
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/transport/bdp_estimator.h
- src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/error_utils.h
- src/core/lib/transport/http2_errors.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/pid_controller.h
- src/core/lib/transport/service_config.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/status_conversion.h
- src/core/lib/transport/timeout_encoding.h
- src/core/lib/transport/transport.h
- src/core/lib/transport/transport_impl.h
src:
- src/core/lib/channel/channel_args.c
- src/core/lib/channel/channel_stack.c
@ -421,9 +311,143 @@ filegroups:
- src/core/lib/transport/transport_op_string.c
deps:
- gpr
filegroups:
- grpc_base_headers
uses:
- grpc_codegen
- grpc_trace
- name: grpc_base_headers
public_headers:
- include/grpc/byte_buffer.h
- include/grpc/byte_buffer_reader.h
- include/grpc/compression.h
- include/grpc/grpc.h
- include/grpc/grpc_posix.h
- include/grpc/grpc_security_constants.h
- include/grpc/load_reporting.h
- include/grpc/slice.h
- include/grpc/slice_buffer.h
- include/grpc/status.h
- include/grpc/support/workaround_list.h
headers:
- src/core/lib/channel/channel_args.h
- src/core/lib/channel/channel_stack.h
- src/core/lib/channel/channel_stack_builder.h
- src/core/lib/channel/connected_channel.h
- src/core/lib/channel/context.h
- src/core/lib/channel/handshaker.h
- src/core/lib/channel/handshaker_factory.h
- src/core/lib/channel/handshaker_registry.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/message_compress.h
- src/core/lib/compression/stream_compression.h
- src/core/lib/http/format_request.h
- src/core/lib/http/httpcli.h
- src/core/lib/http/parser.h
- src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/combiner.h
- src/core/lib/iomgr/endpoint.h
- src/core/lib/iomgr/endpoint_pair.h
- src/core/lib/iomgr/error.h
- src/core/lib/iomgr/error_internal.h
- src/core/lib/iomgr/ev_epoll1_linux.h
- src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h
- src/core/lib/iomgr/ev_epoll_thread_pool_linux.h
- src/core/lib/iomgr/ev_epollex_linux.h
- src/core/lib/iomgr/ev_epollsig_linux.h
- src/core/lib/iomgr/ev_poll_posix.h
- src/core/lib/iomgr/ev_posix.h
- src/core/lib/iomgr/exec_ctx.h
- src/core/lib/iomgr/executor.h
- src/core/lib/iomgr/iocp_windows.h
- src/core/lib/iomgr/iomgr.h
- src/core/lib/iomgr/iomgr_internal.h
- src/core/lib/iomgr/iomgr_posix.h
- src/core/lib/iomgr/iomgr_uv.h
- src/core/lib/iomgr/is_epollexclusive_available.h
- src/core/lib/iomgr/load_file.h
- src/core/lib/iomgr/lockfree_event.h
- src/core/lib/iomgr/nameser.h
- src/core/lib/iomgr/network_status_tracker.h
- src/core/lib/iomgr/polling_entity.h
- src/core/lib/iomgr/pollset.h
- src/core/lib/iomgr/pollset_set.h
- src/core/lib/iomgr/pollset_set_windows.h
- src/core/lib/iomgr/pollset_uv.h
- src/core/lib/iomgr/pollset_windows.h
- src/core/lib/iomgr/port.h
- src/core/lib/iomgr/resolve_address.h
- src/core/lib/iomgr/resource_quota.h
- src/core/lib/iomgr/sockaddr.h
- src/core/lib/iomgr/sockaddr_posix.h
- src/core/lib/iomgr/sockaddr_utils.h
- src/core/lib/iomgr/sockaddr_windows.h
- src/core/lib/iomgr/socket_factory_posix.h
- src/core/lib/iomgr/socket_mutator.h
- src/core/lib/iomgr/socket_utils.h
- src/core/lib/iomgr/socket_utils_posix.h
- src/core/lib/iomgr/socket_windows.h
- src/core/lib/iomgr/sys_epoll_wrapper.h
- src/core/lib/iomgr/tcp_client.h
- src/core/lib/iomgr/tcp_client_posix.h
- src/core/lib/iomgr/tcp_posix.h
- src/core/lib/iomgr/tcp_server.h
- src/core/lib/iomgr/tcp_server_utils_posix.h
- src/core/lib/iomgr/tcp_uv.h
- src/core/lib/iomgr/tcp_windows.h
- src/core/lib/iomgr/time_averaged_stats.h
- src/core/lib/iomgr/timer.h
- src/core/lib/iomgr/timer_generic.h
- src/core/lib/iomgr/timer_heap.h
- src/core/lib/iomgr/timer_manager.h
- src/core/lib/iomgr/timer_uv.h
- src/core/lib/iomgr/udp_server.h
- src/core/lib/iomgr/unix_sockets_posix.h
- src/core/lib/iomgr/wakeup_fd_cv.h
- src/core/lib/iomgr/wakeup_fd_pipe.h
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/json/json.h
- src/core/lib/json/json_common.h
- src/core/lib/json/json_reader.h
- src/core/lib/json/json_writer.h
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
- 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/surface/alarm_internal.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/call.h
- src/core/lib/surface/call_test_only.h
- src/core/lib/surface/channel.h
- src/core/lib/surface/channel_init.h
- src/core/lib/surface/channel_stack_type.h
- src/core/lib/surface/completion_queue.h
- src/core/lib/surface/completion_queue_factory.h
- src/core/lib/surface/event_string.h
- src/core/lib/surface/init.h
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/transport/bdp_estimator.h
- src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/error_utils.h
- src/core/lib/transport/http2_errors.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/pid_controller.h
- src/core/lib/transport/service_config.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/status_conversion.h
- src/core/lib/transport/timeout_encoding.h
- src/core/lib/transport/transport.h
- src/core/lib/transport/transport_impl.h
deps:
- gpr
uses:
- grpc_codegen
- grpc_trace
- grpc_trace_headers
- name: grpc_client_channel
headers:
- src/core/ext/filters/client_channel/client_channel.h
@ -716,15 +740,23 @@ filegroups:
- test/core/util/slice_splitter.c
- test/core/util/trickle_endpoint.c
deps:
- grpc
- gpr_test_util
uses:
- grpc_base
- grpc_client_channel
- grpc_transport_chttp2
- name: grpc_trace
headers:
- src/core/lib/debug/trace.h
src:
- src/core/lib/debug/trace.c
deps:
- gpr
filegroups:
- grpc_trace_headers
- name: grpc_trace_headers
headers:
- src/core/lib/debug/trace.h
deps:
- gpr
- name: grpc_transport_chttp2
headers:
- src/core/ext/transport/chttp2/transport/bin_decoder.h
@ -848,14 +880,18 @@ filegroups:
- grpc_transport_chttp2
- grpc_http_filters
- name: grpc_transport_inproc
headers:
- src/core/ext/transport/inproc/inproc_transport.h
src:
- src/core/ext/transport/inproc/inproc_plugin.c
- src/core/ext/transport/inproc/inproc_transport.c
plugin: grpc_inproc_plugin
uses:
- grpc_transport_inproc_headers
- grpc_base
- name: grpc_transport_inproc_headers
headers:
- src/core/ext/transport/inproc/inproc_transport.h
uses:
- grpc_base_headers
- name: grpc_workaround_cronet_compression_filter
headers:
- src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
@ -866,15 +902,18 @@ filegroups:
- grpc_base
- grpc_server_backward_compatibility
- name: nanopb
src:
- third_party/nanopb/pb_common.c
- third_party/nanopb/pb_decode.c
- third_party/nanopb/pb_encode.c
filegroups:
- nanopb_headers
- name: nanopb_headers
headers:
- third_party/nanopb/pb.h
- third_party/nanopb/pb_common.h
- third_party/nanopb/pb_decode.h
- third_party/nanopb/pb_encode.h
src:
- third_party/nanopb/pb_common.c
- third_party/nanopb/pb_decode.c
- third_party/nanopb/pb_encode.c
- name: tsi
headers:
- src/core/tsi/fake_transport_security.h
@ -897,7 +936,54 @@ filegroups:
uses:
- grpc_trace
- grpc_base
- name: grpc++_base
- name: grpc++_codegen_base
language: c++
public_headers:
- include/grpc++/impl/codegen/async_stream.h
- include/grpc++/impl/codegen/async_unary_call.h
- include/grpc++/impl/codegen/call.h
- include/grpc++/impl/codegen/call_hook.h
- include/grpc++/impl/codegen/channel_interface.h
- include/grpc++/impl/codegen/client_context.h
- include/grpc++/impl/codegen/client_unary_call.h
- include/grpc++/impl/codegen/completion_queue.h
- include/grpc++/impl/codegen/completion_queue_tag.h
- include/grpc++/impl/codegen/config.h
- include/grpc++/impl/codegen/core_codegen_interface.h
- include/grpc++/impl/codegen/create_auth_context.h
- include/grpc++/impl/codegen/grpc_library.h
- include/grpc++/impl/codegen/metadata_map.h
- include/grpc++/impl/codegen/method_handler_impl.h
- include/grpc++/impl/codegen/rpc_method.h
- include/grpc++/impl/codegen/rpc_service_method.h
- include/grpc++/impl/codegen/security/auth_context.h
- include/grpc++/impl/codegen/serialization_traits.h
- include/grpc++/impl/codegen/server_context.h
- include/grpc++/impl/codegen/server_interface.h
- include/grpc++/impl/codegen/service_type.h
- include/grpc++/impl/codegen/slice.h
- include/grpc++/impl/codegen/status.h
- include/grpc++/impl/codegen/status_code_enum.h
- include/grpc++/impl/codegen/string_ref.h
- include/grpc++/impl/codegen/stub_options.h
- include/grpc++/impl/codegen/sync_stream.h
- include/grpc++/impl/codegen/time.h
uses:
- grpc_codegen
- name: grpc++_codegen_base_src
language: c++
src:
- src/cpp/codegen/codegen_init.cc
uses:
- grpc++_codegen_base
- name: grpc++_codegen_proto
language: c++
public_headers:
- include/grpc++/impl/codegen/proto_utils.h
uses:
- grpc++_codegen_base
- grpc++_config_proto
- name: grpc++_common
language: c++
public_headers:
- include/grpc++/alarm.h
@ -987,58 +1073,12 @@ filegroups:
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
deps:
- grpc
uses:
- grpc++_codegen_base
- nanopb
- name: grpc++_codegen_base
language: c++
public_headers:
- include/grpc++/impl/codegen/async_stream.h
- include/grpc++/impl/codegen/async_unary_call.h
- include/grpc++/impl/codegen/call.h
- include/grpc++/impl/codegen/call_hook.h
- include/grpc++/impl/codegen/channel_interface.h
- include/grpc++/impl/codegen/client_context.h
- include/grpc++/impl/codegen/client_unary_call.h
- include/grpc++/impl/codegen/completion_queue.h
- include/grpc++/impl/codegen/completion_queue_tag.h
- include/grpc++/impl/codegen/config.h
- include/grpc++/impl/codegen/core_codegen_interface.h
- include/grpc++/impl/codegen/create_auth_context.h
- include/grpc++/impl/codegen/grpc_library.h
- include/grpc++/impl/codegen/metadata_map.h
- include/grpc++/impl/codegen/method_handler_impl.h
- include/grpc++/impl/codegen/rpc_method.h
- include/grpc++/impl/codegen/rpc_service_method.h
- include/grpc++/impl/codegen/security/auth_context.h
- include/grpc++/impl/codegen/serialization_traits.h
- include/grpc++/impl/codegen/server_context.h
- include/grpc++/impl/codegen/server_interface.h
- include/grpc++/impl/codegen/service_type.h
- include/grpc++/impl/codegen/slice.h
- include/grpc++/impl/codegen/status.h
- include/grpc++/impl/codegen/status_code_enum.h
- include/grpc++/impl/codegen/string_ref.h
- include/grpc++/impl/codegen/stub_options.h
- include/grpc++/impl/codegen/sync_stream.h
- include/grpc++/impl/codegen/time.h
uses:
- grpc_codegen
- name: grpc++_codegen_base_src
language: c++
src:
- src/cpp/codegen/codegen_init.cc
uses:
- grpc++_codegen_base
- name: grpc++_codegen_proto
language: c++
public_headers:
- include/grpc++/impl/codegen/proto_utils.h
uses:
- gpr_base_headers
- grpc_base_headers
- grpc_transport_inproc_headers
- grpc++_codegen_base
- grpc++_config_proto
- nanopb_headers
- name: grpc++_config_proto
language: c++
public_headers:
@ -1166,7 +1206,6 @@ libs:
- grpc
filegroups:
- grpc_test_util_base
- grpc_base
vs_project_guid: '{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}'
- name: grpc_test_util_unsecure
build: private
@ -1363,6 +1402,32 @@ libs:
- grpc++_codegen_base_src
- grpc++_codegen_proto
- grpc++_config_proto
- name: grpc++_test_util_unsecure
build: private
language: c++
headers:
- test/cpp/end2end/test_service_impl.h
- test/cpp/util/byte_buffer_proto_helper.h
- test/cpp/util/string_ref_helper.h
- test/cpp/util/subprocess.h
src:
- src/proto/grpc/health/v1/health.proto
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/echo.proto
- src/proto/grpc/testing/duplicate/echo_duplicate.proto
- test/cpp/end2end/test_service_impl.cc
- test/cpp/util/byte_buffer_proto_helper.cc
- test/cpp/util/string_ref_helper.cc
- test/cpp/util/subprocess.cc
deps:
- grpc++_unsecure
- grpc_test_util_unsecure
- grpc_unsecure
filegroups:
- grpc++_codegen_base
- grpc++_codegen_base_src
- grpc++_codegen_proto
- grpc++_config_proto
- name: grpc++_unsecure
build: all
language: c++
@ -1376,7 +1441,7 @@ libs:
baselib: true
dll: true
filegroups:
- grpc++_base
- grpc++_base_unsecure
- grpc++_codegen_base
- grpc++_codegen_base_src
secure: false
@ -1392,9 +1457,9 @@ libs:
- test/cpp/microbenchmarks/helpers.cc
deps:
- benchmark
- grpc++
- grpc_test_util
- grpc
- grpc++_unsecure
- grpc_test_util_unsecure
- grpc_unsecure
defaults: benchmark
- name: grpc_cli_libs
build: private
@ -1703,6 +1768,16 @@ targets:
deps:
- grpc_test_util
- grpc
- name: byte_stream_test
build: test
language: c
src:
- test/core/transport/byte_stream_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: census_context_test
build: test
language: c
@ -3264,10 +3339,10 @@ targets:
src:
- test/cpp/common/alarm_cpp_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
- name: async_end2end_test
@ -3304,10 +3379,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3325,10 +3400,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3346,10 +3421,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3367,10 +3442,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3388,10 +3463,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3409,10 +3484,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3430,10 +3505,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3451,10 +3526,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3472,10 +3547,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3497,10 +3572,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3522,10 +3597,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3547,10 +3622,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3572,10 +3647,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -3593,10 +3668,10 @@ targets:
deps:
- grpc_benchmark
- benchmark
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
args:
@ -4339,11 +4414,11 @@ targets:
- src/proto/grpc/testing/echo.proto
- test/cpp/server/server_builder_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- gpr_test_util
- grpc++
- grpc
- grpc++_unsecure
- grpc_unsecure
- gpr
- name: server_context_test_spouse_test
gtest: true
@ -4399,11 +4474,11 @@ targets:
- src/proto/grpc/testing/echo.proto
- test/cpp/server/server_request_call_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- gpr_test_util
- grpc++
- grpc
- grpc++_unsecure
- grpc_unsecure
- gpr
- name: shutdown_test
gtest: true
@ -4479,8 +4554,8 @@ targets:
src:
- test/cpp/thread_manager/thread_manager_test.cc
deps:
- grpc++
- grpc
- grpc++_unsecure
- grpc_unsecure
- gpr
- grpc++_test_config
- name: thread_stress_test
@ -4491,10 +4566,10 @@ targets:
src:
- test/cpp/end2end/thread_stress_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- grpc++_test_util_unsecure
- grpc_test_util_unsecure
- grpc++_unsecure
- grpc_unsecure
- gpr_test_util
- gpr
timeout_seconds: 1200

@ -5,8 +5,7 @@ gRPC C core based implementations (those contained in this repository) expose
some configuration as environment variables that can be set.
* http_proxy
The URI of the proxy to use for HTTP CONNECT support. Does not currently
support username or password information in the URI.
The URI of the proxy to use for HTTP CONNECT support.
* GRPC_ABORT_ON_LEAKS
A debugging aid to cause a call to abort() when gRPC objects are leaked past
@ -103,6 +102,9 @@ some configuration as environment variables that can be set.
- INFO - log INFO and ERROR message
- ERROR - log only errors
* GRPC_TRACE_FUZZER
if set, the fuzzers will output trace (it is usually supressed).
* GRPC_DNS_RESOLVER
Declares which DNS resolver to use. The default is ares if gRPC is built with
c-ares support. Otherwise, the value of this environment variable is ignored.

@ -139,17 +139,6 @@ Pod::Spec.new do |s|
'include/grpc/impl/codegen/sync_generic.h',
'include/grpc/impl/codegen/sync_posix.h',
'include/grpc/impl/codegen/sync_windows.h',
'include/grpc/byte_buffer.h',
'include/grpc/byte_buffer_reader.h',
'include/grpc/compression.h',
'include/grpc/grpc.h',
'include/grpc/grpc_posix.h',
'include/grpc/grpc_security_constants.h',
'include/grpc/load_reporting.h',
'include/grpc/slice.h',
'include/grpc/slice_buffer.h',
'include/grpc/status.h',
'include/grpc/support/workaround_list.h',
'include/grpc/impl/codegen/byte_buffer_reader.h',
'include/grpc/impl/codegen/compression_types.h',
'include/grpc/impl/codegen/connectivity_state.h',
@ -170,13 +159,24 @@ Pod::Spec.new do |s|
'include/grpc/impl/codegen/sync_posix.h',
'include/grpc/impl/codegen/sync_windows.h',
'include/grpc/grpc_security.h',
'include/grpc/byte_buffer.h',
'include/grpc/byte_buffer_reader.h',
'include/grpc/compression.h',
'include/grpc/grpc.h',
'include/grpc/grpc_posix.h',
'include/grpc/grpc_security_constants.h',
'include/grpc/load_reporting.h',
'include/grpc/slice.h',
'include/grpc/slice_buffer.h',
'include/grpc/status.h',
'include/grpc/support/workaround_list.h',
'include/grpc/census.h'
end
s.subspec 'Implementation' do |ss|
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
ss.dependency 'BoringSSL', '~> 8.0'
ss.dependency 'BoringSSL', '~> 9.0'
ss.dependency 'nanopb', '~> 0.3'
# To save you from scrolling, this is the last part of the podspec.
@ -244,6 +244,77 @@ Pod::Spec.new do |s|
'src/core/lib/support/tmpfile_posix.c',
'src/core/lib/support/tmpfile_windows.c',
'src/core/lib/support/wrap_memcpy.c',
'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/frame.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',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/jwt/json_token.h',
'src/core/lib/security/credentials/jwt/jwt_credentials.h',
'src/core/lib/security/credentials/jwt/jwt_verifier.h',
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/gts_transport_security.h',
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/ssl_types.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_adapter.h',
'src/core/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/inproc/inproc_transport.h',
'src/core/lib/channel/channel_args.h',
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
@ -281,6 +352,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/is_epollexclusive_available.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/network_status_tracker.h',
'src/core/lib/iomgr/polling_entity.h',
'src/core/lib/iomgr/pollset.h',
@ -357,77 +429,6 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
'src/core/lib/debug/trace.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.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',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/jwt/json_token.h',
'src/core/lib/security/credentials/jwt/jwt_credentials.h',
'src/core/lib/security/credentials/jwt/jwt_verifier.h',
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/gts_transport_security.h',
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/ssl_types.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_adapter.h',
'src/core/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/inproc/inproc_transport.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@ -730,6 +731,77 @@ Pod::Spec.new do |s|
'src/core/lib/support/thd_internal.h',
'src/core/lib/support/time_precise.h',
'src/core/lib/support/tmpfile.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.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',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/jwt/json_token.h',
'src/core/lib/security/credentials/jwt/jwt_credentials.h',
'src/core/lib/security/credentials/jwt/jwt_verifier.h',
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/gts_transport_security.h',
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/ssl_types.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_adapter.h',
'src/core/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/inproc/inproc_transport.h',
'src/core/lib/channel/channel_args.h',
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
@ -767,6 +839,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/is_epollexclusive_available.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/network_status_tracker.h',
'src/core/lib/iomgr/polling_entity.h',
'src/core/lib/iomgr/pollset.h',
@ -843,77 +916,6 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
'src/core/lib/debug/trace.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.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',
'src/core/ext/transport/chttp2/transport/frame_ping.h',
'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
'src/core/ext/transport/chttp2/transport/varint.h',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/jwt/json_token.h',
'src/core/lib/security/credentials/jwt/jwt_credentials.h',
'src/core/lib/security/credentials/jwt/jwt_verifier.h',
'src/core/lib/security/credentials/oauth2/oauth2_credentials.h',
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/fake_transport_security.h',
'src/core/tsi/gts_transport_security.h',
'src/core/tsi/ssl_transport_security.h',
'src/core/tsi/ssl_types.h',
'src/core/tsi/transport_security.h',
'src/core/tsi/transport_security_adapter.h',
'src/core/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/http_connect_handshaker.h',
'src/core/ext/filters/client_channel/http_proxy.h',
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.h',
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/inproc/inproc_transport.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',

@ -144,17 +144,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/tmpfile_posix.c )
s.files += %w( src/core/lib/support/tmpfile_windows.c )
s.files += %w( src/core/lib/support/wrap_memcpy.c )
s.files += %w( include/grpc/byte_buffer.h )
s.files += %w( include/grpc/byte_buffer_reader.h )
s.files += %w( include/grpc/compression.h )
s.files += %w( include/grpc/grpc.h )
s.files += %w( include/grpc/grpc_posix.h )
s.files += %w( include/grpc/grpc_security_constants.h )
s.files += %w( include/grpc/load_reporting.h )
s.files += %w( include/grpc/slice.h )
s.files += %w( include/grpc/slice_buffer.h )
s.files += %w( include/grpc/status.h )
s.files += %w( include/grpc/support/workaround_list.h )
s.files += %w( include/grpc/impl/codegen/byte_buffer_reader.h )
s.files += %w( include/grpc/impl/codegen/compression_types.h )
s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
@ -175,7 +164,89 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/sync_posix.h )
s.files += %w( include/grpc/impl/codegen/sync_windows.h )
s.files += %w( include/grpc/grpc_security.h )
s.files += %w( include/grpc/byte_buffer.h )
s.files += %w( include/grpc/byte_buffer_reader.h )
s.files += %w( include/grpc/compression.h )
s.files += %w( include/grpc/grpc.h )
s.files += %w( include/grpc/grpc_posix.h )
s.files += %w( include/grpc/grpc_security_constants.h )
s.files += %w( include/grpc/load_reporting.h )
s.files += %w( include/grpc/slice.h )
s.files += %w( include/grpc/slice_buffer.h )
s.files += %w( include/grpc/status.h )
s.files += %w( include/grpc/support/workaround_list.h )
s.files += %w( include/grpc/census.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.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 )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_ping.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.h )
s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.h )
s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.h )
s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.h )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
s.files += %w( src/core/lib/security/context/security_context.h )
s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
s.files += %w( src/core/lib/security/credentials/credentials.h )
s.files += %w( src/core/lib/security/credentials/fake/fake_credentials.h )
s.files += %w( src/core/lib/security/credentials/google_default/google_default_credentials.h )
s.files += %w( src/core/lib/security/credentials/iam/iam_credentials.h )
s.files += %w( src/core/lib/security/credentials/jwt/json_token.h )
s.files += %w( src/core/lib/security/credentials/jwt/jwt_credentials.h )
s.files += %w( src/core/lib/security/credentials/jwt/jwt_verifier.h )
s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.h )
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/transport/auth_filters.h )
s.files += %w( src/core/lib/security/transport/lb_targets_info.h )
s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_connector.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.h )
s.files += %w( src/core/lib/security/transport/tsi_error.h )
s.files += %w( src/core/lib/security/util/json_util.h )
s.files += %w( src/core/tsi/fake_transport_security.h )
s.files += %w( src/core/tsi/gts_transport_security.h )
s.files += %w( src/core/tsi/ssl_transport_security.h )
s.files += %w( src/core/tsi/ssl_types.h )
s.files += %w( src/core/tsi/transport_security.h )
s.files += %w( src/core/tsi/transport_security_adapter.h )
s.files += %w( src/core/tsi/transport_security_interface.h )
s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/filters/client_channel/connector.h )
s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h )
s.files += %w( src/core/ext/filters/client_channel/http_proxy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
s.files += %w( src/core/ext/filters/client_channel/resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_factory.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
s.files += %w( src/core/lib/channel/channel_args.h )
s.files += %w( src/core/lib/channel/channel_stack.h )
s.files += %w( src/core/lib/channel/channel_stack_builder.h )
@ -213,6 +284,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/is_epollexclusive_available.h )
s.files += %w( src/core/lib/iomgr/load_file.h )
s.files += %w( src/core/lib/iomgr/lockfree_event.h )
s.files += %w( src/core/lib/iomgr/nameser.h )
s.files += %w( src/core/lib/iomgr/network_status_tracker.h )
s.files += %w( src/core/lib/iomgr/polling_entity.h )
s.files += %w( src/core/lib/iomgr/pollset.h )
@ -289,87 +361,12 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/transport.h )
s.files += %w( src/core/lib/transport/transport_impl.h )
s.files += %w( src/core/lib/debug/trace.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.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 )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_ping.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.h )
s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.h )
s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.h )
s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.h )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
s.files += %w( src/core/lib/security/context/security_context.h )
s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
s.files += %w( src/core/lib/security/credentials/credentials.h )
s.files += %w( src/core/lib/security/credentials/fake/fake_credentials.h )
s.files += %w( src/core/lib/security/credentials/google_default/google_default_credentials.h )
s.files += %w( src/core/lib/security/credentials/iam/iam_credentials.h )
s.files += %w( src/core/lib/security/credentials/jwt/json_token.h )
s.files += %w( src/core/lib/security/credentials/jwt/jwt_credentials.h )
s.files += %w( src/core/lib/security/credentials/jwt/jwt_verifier.h )
s.files += %w( src/core/lib/security/credentials/oauth2/oauth2_credentials.h )
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/transport/auth_filters.h )
s.files += %w( src/core/lib/security/transport/lb_targets_info.h )
s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_connector.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.h )
s.files += %w( src/core/lib/security/transport/tsi_error.h )
s.files += %w( src/core/lib/security/util/json_util.h )
s.files += %w( src/core/tsi/fake_transport_security.h )
s.files += %w( src/core/tsi/gts_transport_security.h )
s.files += %w( src/core/tsi/ssl_transport_security.h )
s.files += %w( src/core/tsi/ssl_types.h )
s.files += %w( src/core/tsi/transport_security.h )
s.files += %w( src/core/tsi/transport_security_adapter.h )
s.files += %w( src/core/tsi/transport_security_interface.h )
s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/filters/client_channel/connector.h )
s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h )
s.files += %w( src/core/ext/filters/client_channel/http_proxy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
s.files += %w( src/core/ext/filters/client_channel/resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_factory.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
s.files += %w( third_party/nanopb/pb.h )
s.files += %w( third_party/nanopb/pb_common.h )
s.files += %w( third_party/nanopb/pb_decode.h )
s.files += %w( third_party/nanopb/pb_encode.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )

@ -296,7 +296,11 @@ GRPCAPI grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved);
If a status has not been received for the call, set it to the status code
and description passed in.
Importantly, this function does not send status nor description to the
remote endpoint. */
remote endpoint.
Note that \a description doesn't need be a static string.
It doesn't need to be alive after the call to
grpc_call_cancel_with_status completes.
*/
GRPCAPI grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
grpc_status_code status,
const char *description,

@ -333,7 +333,9 @@ typedef enum grpc_call_error {
/** this batch of operations leads to more operations than allowed */
GRPC_CALL_ERROR_BATCH_TOO_BIG,
/** payload type requested is not the type registered */
GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH
GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH,
/** completion queue has been shutdown */
GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN
} grpc_call_error;
/** Default send/receive message size limits in bytes. -1 for unlimited. */

@ -31,18 +31,23 @@ typedef struct gpr_avl_node {
long height;
} gpr_avl_node;
/** vtable for the AVL tree
* The optional user_data is propagated from the top level gpr_avl_XXX API.
* From the same API call, multiple vtable functions may be called multiple
* times.
*/
typedef struct gpr_avl_vtable {
/** destroy a key */
void (*destroy_key)(void *key);
void (*destroy_key)(void *key, void *user_data);
/** copy a key, returning new value */
void *(*copy_key)(void *key);
void *(*copy_key)(void *key, void *user_data);
/** compare key1, key2; return <0 if key1 < key2,
>0 if key1 > key2, 0 if key1 == key2 */
long (*compare_keys)(void *key1, void *key2);
long (*compare_keys)(void *key1, void *key2, void *user_data);
/** destroy a value */
void (*destroy_value)(void *value);
void (*destroy_value)(void *value, void *user_data);
/** copy a value */
void *(*copy_value)(void *value);
void *(*copy_value)(void *value, void *user_data);
} gpr_avl_vtable;
/** "pointer" to an AVL tree - this is a reference
@ -53,29 +58,36 @@ typedef struct gpr_avl {
gpr_avl_node *root;
} gpr_avl;
/** create an immutable AVL tree */
/** Create an immutable AVL tree. */
GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable);
/** add a reference to an existing tree - returns
the tree as a convenience */
GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl);
/** remove a reference to a tree - destroying it if there
are no references left */
GPRAPI void gpr_avl_unref(gpr_avl avl);
/** return a new tree with (key, value) added to avl.
/** Add a reference to an existing tree - returns
the tree as a convenience. The optional user_data will be passed to vtable
functions. */
GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data);
/** Remove a reference to a tree - destroying it if there
are no references left. The optional user_data will be passed to vtable
functions. */
GPRAPI void gpr_avl_unref(gpr_avl avl, void *user_data);
/** Return a new tree with (key, value) added to avl.
implicitly unrefs avl to allow easy chaining.
if key exists in avl, the new tree's key entry updated
(i.e. a duplicate is not created) */
GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value);
/** return a new tree with key deleted
implicitly unrefs avl to allow easy chaining. */
GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key);
/** lookup key, and return the associated value.
does not mutate avl.
returns NULL if key is not found. */
GPRAPI void *gpr_avl_get(gpr_avl avl, void *key);
(i.e. a duplicate is not created). The optional user_data will be passed to
vtable functions. */
GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value,
void *user_data);
/** Return a new tree with key deleted
implicitly unrefs avl to allow easy chaining. The optional user_data will be
passed to vtable functions. */
GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data);
/** Lookup key, and return the associated value.
Does not mutate avl.
Returns NULL if key is not found. The optional user_data will be passed to
vtable functions.*/
GPRAPI void *gpr_avl_get(gpr_avl avl, void *key, void *user_data);
/** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to
its value*/
GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value);
its value. THe optional user_data will be passed to vtable functions. */
GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value,
void *user_data);
/** Return 1 if avl is empty, 0 otherwise */
GPRAPI int gpr_avl_is_empty(gpr_avl avl);

@ -158,17 +158,6 @@
<file baseinstalldir="/" name="src/core/lib/support/tmpfile_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/tmpfile_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/wrap_memcpy.c" role="src" />
<file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
<file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
<file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" />
<file baseinstalldir="/" name="include/grpc/load_reporting.h" role="src" />
<file baseinstalldir="/" name="include/grpc/slice.h" role="src" />
<file baseinstalldir="/" name="include/grpc/slice_buffer.h" role="src" />
<file baseinstalldir="/" name="include/grpc/status.h" role="src" />
<file baseinstalldir="/" name="include/grpc/support/workaround_list.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer_reader.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
@ -189,7 +178,89 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_security.h" role="src" />
<file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
<file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
<file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" />
<file baseinstalldir="/" name="include/grpc/load_reporting.h" role="src" />
<file baseinstalldir="/" name="include/grpc/slice.h" role="src" />
<file baseinstalldir="/" name="include/grpc/slice_buffer.h" role="src" />
<file baseinstalldir="/" name="include/grpc/status.h" role="src" />
<file baseinstalldir="/" name="include/grpc/support/workaround_list.h" role="src" />
<file baseinstalldir="/" name="include/grpc/census.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.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" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_ping.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_rst_stream.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/fake/fake_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/google_default/google_default_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/iam/iam_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/json_token.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/jwt_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/jwt_verifier.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/gts_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
@ -227,6 +298,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/is_epollexclusive_available.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/load_file.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/nameser.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/network_status_tracker.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" />
@ -303,87 +375,12 @@
<file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.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" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_ping.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_rst_stream.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/fake/fake_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/google_default/google_default_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/iam/iam_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/json_token.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/jwt_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/jwt/jwt_verifier.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/oauth2/oauth2_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/gts_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
<file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />

@ -60,6 +60,18 @@ _spawn_patch.monkeypatch_spawn()
LICENSE = 'Apache License 2.0'
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'License :: OSI Approved :: Apache Software License',
],
# Environment variable to determine whether or not the Cython extension should
# *use* Cython or use the generated C files. Note that this requires the C files
# to have been generated by building first *with* Cython support. Even if this
@ -283,6 +295,7 @@ setuptools.setup(
author_email='grpc-io@googlegroups.com',
url='https://grpc.io',
license=LICENSE,
classifiers=CLASSIFIERS,
long_description=open(README).read(),
ext_modules=CYTHON_EXTENSION_MODULES,
packages=list(PACKAGES),

@ -47,6 +47,7 @@ grpc::string ModuleAlias(const grpc::string filename) {
grpc::string basename = grpc_generator::StripProto(filename);
basename = grpc_generator::StringReplace(basename, "-", "$");
basename = grpc_generator::StringReplace(basename, "/", "_");
basename = grpc_generator::StringReplace(basename, ".", "_");
return basename + "_pb";
}

@ -208,7 +208,7 @@ void grpc_channel_watch_connectivity_state(
7, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec,
(int)deadline.clock_type, cq, tag));
grpc_cq_begin_op(cq, tag);
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
gpr_mu_init(&w->mu);
GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w,

@ -88,7 +88,6 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
// Record call finished, optionally setting client_failed_to_send and
// received.
grpc_grpclb_client_stats_add_call_finished(
false /* drop_for_rate_limiting */, false /* drop_for_load_balancing */,
!calld->send_initial_metadata_succeeded /* client_failed_to_send */,
calld->recv_initial_metadata_succeeded /* known_received */,
calld->client_stats);

@ -416,9 +416,7 @@ struct rr_connectivity_data {
static bool is_server_valid(const grpc_grpclb_server *server, size_t idx,
bool log) {
if (server->drop_for_rate_limiting || server->drop_for_load_balancing) {
return false;
}
if (server->drop) return false;
const grpc_grpclb_ip_address *ip = &server->ip_address;
if (server->port >> 16 != 0) {
if (log) {
@ -462,7 +460,7 @@ static const grpc_lb_user_data_vtable lb_token_vtable = {
static void parse_server(const grpc_grpclb_server *server,
grpc_resolved_address *addr) {
memset(addr, 0, sizeof(*addr));
if (server->drop_for_rate_limiting || server->drop_for_load_balancing) return;
if (server->drop) return;
const uint16_t netorder_port = htons((uint16_t)server->port);
/* the addresses are given in binary format (a in(6)_addr struct) in
* server->ip_address.bytes. */
@ -491,11 +489,8 @@ static grpc_lb_addresses *process_serverlist_locked(
for (size_t i = 0; i < serverlist->num_servers; ++i) {
if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid;
}
if (num_valid == 0) return NULL;
grpc_lb_addresses *lb_addresses =
grpc_lb_addresses_create(num_valid, &lb_token_vtable);
/* second pass: actually populate the addresses and LB tokens (aka user data
* to the outside world) to be read by the RR policy during its creation.
* Given that the validity tests are very cheap, they are performed again
@ -503,14 +498,12 @@ static grpc_lb_addresses *process_serverlist_locked(
* incurr in an allocation due to the arbitrary number of server */
size_t addr_idx = 0;
for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) {
GPR_ASSERT(addr_idx < num_valid);
const grpc_grpclb_server *server = serverlist->servers[sl_idx];
if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue;
GPR_ASSERT(addr_idx < num_valid);
/* address processing */
grpc_resolved_address addr;
parse_server(server, &addr);
/* lb token processing */
void *user_data;
if (server->has_load_balance_token) {
@ -596,7 +589,7 @@ static void update_lb_connectivity_status_locked(
grpc_connectivity_state_name(rr_state), (void *)glb_policy->rr_policy);
}
grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, rr_state,
GRPC_ERROR_REF(rr_state_error),
rr_state_error,
"update_lb_connectivity_status_locked");
}
@ -615,7 +608,7 @@ static bool pick_from_internal_rr_locked(
if (glb_policy->serverlist_index == glb_policy->serverlist->num_servers) {
glb_policy->serverlist_index = 0; // Wrap-around.
}
if (server->drop_for_rate_limiting || server->drop_for_load_balancing) {
if (server->drop) {
// Not using the RR policy, so unref it.
if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
gpr_log(GPR_INFO, "Unreffing RR for drop (0x%" PRIxPTR ")",
@ -627,11 +620,8 @@ static bool pick_from_internal_rr_locked(
// the client_load_reporting filter, because we do not create a
// subchannel call (and therefore no client_load_reporting filter)
// for dropped calls.
grpc_grpclb_client_stats_add_call_started(wc_arg->client_stats);
grpc_grpclb_client_stats_add_call_finished(
server->drop_for_rate_limiting, server->drop_for_load_balancing,
false /* failed_to_send */, false /* known_received */,
wc_arg->client_stats);
grpc_grpclb_client_stats_add_call_dropped_locked(server->load_balance_token,
wc_arg->client_stats);
grpc_grpclb_client_stats_unref(wc_arg->client_stats);
if (force_async) {
GPR_ASSERT(wc_arg->wrapped_closure != NULL);
@ -678,11 +668,12 @@ static bool pick_from_internal_rr_locked(
static grpc_lb_policy_args *lb_policy_args_create(grpc_exec_ctx *exec_ctx,
glb_lb_policy *glb_policy) {
grpc_lb_addresses *addresses =
process_serverlist_locked(exec_ctx, glb_policy->serverlist);
GPR_ASSERT(addresses != NULL);
grpc_lb_policy_args *args = gpr_zalloc(sizeof(*args));
args->client_channel_factory = glb_policy->cc_factory;
args->combiner = glb_policy->base.combiner;
grpc_lb_addresses *addresses =
process_serverlist_locked(exec_ctx, glb_policy->serverlist);
// Replace the LB addresses in the channel args that we pass down to
// the subchannel.
static const char *keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES};
@ -719,7 +710,6 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
return;
}
glb_policy->rr_policy = new_rr_policy;
grpc_error *rr_state_error = NULL;
const grpc_connectivity_state rr_state =
grpc_lb_policy_check_connectivity_locked(exec_ctx, glb_policy->rr_policy,
@ -727,7 +717,6 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
/* Connectivity state is a function of the RR policy updated/created */
update_lb_connectivity_status_locked(exec_ctx, glb_policy, rr_state,
rr_state_error);
/* Add the gRPC LB's interested_parties pollset_set to that of the newly
* created RR policy. This will make the RR policy progress upon activity on
* gRPC LB, which in turn is tied to the application's call */
@ -746,7 +735,7 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
rr_connectivity->state = rr_state;
/* Subscribe to changes to the connectivity of the new RR */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "rr_connectivity_sched");
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "glb_rr_connectivity_cb");
grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy,
&rr_connectivity->state,
&rr_connectivity->on_change);
@ -761,8 +750,8 @@ static void create_rr_locked(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
pp->wrapped_on_complete_arg.client_stats =
grpc_grpclb_client_stats_ref(glb_policy->client_stats);
if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "",
(intptr_t)glb_policy->rr_policy);
gpr_log(GPR_INFO, "Pending pick about to (async) PICK from %p",
(void *)glb_policy->rr_policy);
}
pick_from_internal_rr_locked(exec_ctx, glb_policy, &pp->pick_args,
true /* force_async */, pp->target,
@ -788,10 +777,9 @@ static void rr_handover_locked(grpc_exec_ctx *exec_ctx,
glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->serverlist != NULL &&
glb_policy->serverlist->num_servers > 0);
if (glb_policy->shutting_down) return;
grpc_lb_policy_args *args = lb_policy_args_create(exec_ctx, glb_policy);
GPR_ASSERT(args != NULL);
if (glb_policy->rr_policy != NULL) {
if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
gpr_log(GPR_DEBUG, "Updating Round Robin policy (%p)",
@ -812,32 +800,31 @@ static void glb_rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx,
void *arg, grpc_error *error) {
rr_connectivity_data *rr_connectivity = arg;
glb_lb_policy *glb_policy = rr_connectivity->glb_policy;
const bool shutting_down = glb_policy->shutting_down;
bool unref_needed = false;
GRPC_ERROR_REF(error);
if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN || shutting_down) {
/* RR policy shutting down. Don't renew subscription and free the arg of
* this callback. In addition we need to stash away the current policy to
* be UNREF'd after releasing the lock. Otherwise, if the UNREF is the last
* one, the policy would be destroyed, alongside the lock, which would
* result in a use-after-free */
unref_needed = true;
if (glb_policy->shutting_down) {
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"glb_rr_connectivity_cb");
gpr_free(rr_connectivity);
} else { /* rr state != SHUTDOWN && !shutting down: biz as usual */
update_lb_connectivity_status_locked(exec_ctx, glb_policy,
rr_connectivity->state, error);
/* Resubscribe. Reuse the "rr_connectivity_cb" weak ref. */
grpc_lb_policy_notify_on_state_change_locked(
exec_ctx, glb_policy->rr_policy, &rr_connectivity->state,
&rr_connectivity->on_change);
return;
}
if (unref_needed) {
if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN) {
/* An RR policy that has transitioned into the SHUTDOWN connectivity state
* should not be considered for picks or updates: the SHUTDOWN state is a
* sink, policies can't transition back from it. .*/
GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy,
"rr_connectivity_shutdown");
glb_policy->rr_policy = NULL;
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"rr_connectivity_cb");
"glb_rr_connectivity_cb");
gpr_free(rr_connectivity);
return;
}
GRPC_ERROR_UNREF(error);
/* rr state != SHUTDOWN && !glb_policy->shutting down: biz as usual */
update_lb_connectivity_status_locked(
exec_ctx, glb_policy, rr_connectivity->state, GRPC_ERROR_REF(error));
/* Resubscribe. Reuse the "glb_rr_connectivity_cb" weak ref. */
grpc_lb_policy_notify_on_state_change_locked(exec_ctx, glb_policy->rr_policy,
&rr_connectivity->state,
&rr_connectivity->on_change);
}
static void destroy_balancer_name(grpc_exec_ctx *exec_ctx,
@ -1001,7 +988,6 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
gpr_free(glb_policy);
return NULL;
}
GRPC_CLOSURE_INIT(&glb_policy->lb_channel_on_connectivity_changed,
glb_lb_channel_on_connectivity_changed_cb, glb_policy,
grpc_combiner_scheduler(args->combiner));
@ -1058,7 +1044,7 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
glb_policy->pending_picks = NULL;
pending_ping *pping = glb_policy->pending_pings;
glb_policy->pending_pings = NULL;
if (glb_policy->rr_policy) {
if (glb_policy->rr_policy != NULL) {
GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
}
// We destroy the LB channel here because
@ -1089,6 +1075,16 @@ static void glb_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
}
// Cancel a specific pending pick.
//
// A grpclb pick progresses as follows:
// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be
// handed over to the RR policy (in create_rr_locked()). From that point
// onwards, it'll be RR's responsibility. For cancellations, that implies the
// pick needs also be cancelled by the RR instance.
// - Otherwise, without an RR instance, picks stay pending at this policy's
// level (grpclb), inside the glb_policy->pending_picks list. To cancel these,
// we invoke the completion closure and set *target to NULL right here.
static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_connected_subchannel **target,
grpc_error *error) {
@ -1108,9 +1104,23 @@ static void glb_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
}
pp = next;
}
if (glb_policy->rr_policy != NULL) {
grpc_lb_policy_cancel_pick_locked(exec_ctx, glb_policy->rr_policy, target,
GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
// Cancel all pending picks.
//
// A grpclb pick progresses as follows:
// - If there's a Round Robin policy (glb_policy->rr_policy) available, it'll be
// handed over to the RR policy (in create_rr_locked()). From that point
// onwards, it'll be RR's responsibility. For cancellations, that implies the
// pick needs also be cancelled by the RR instance.
// - Otherwise, without an RR instance, picks stay pending at this policy's
// level (grpclb), inside the glb_policy->pending_picks list. To cancel these,
// we invoke the completion closure and set *target to NULL right here.
static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol,
uint32_t initial_metadata_flags_mask,
@ -1132,6 +1142,11 @@ static void glb_cancel_picks_locked(grpc_exec_ctx *exec_ctx,
}
pp = next;
}
if (glb_policy->rr_policy != NULL) {
grpc_lb_policy_cancel_picks_locked(
exec_ctx, glb_policy->rr_policy, initial_metadata_flags_mask,
initial_metadata_flags_eq, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
@ -1286,15 +1301,14 @@ static void do_send_client_load_report_locked(grpc_exec_ctx *exec_ctx,
}
static bool load_report_counters_are_zero(grpc_grpclb_request *request) {
grpc_grpclb_dropped_call_counts *drop_entries =
request->client_stats.calls_finished_with_drop.arg;
return request->client_stats.num_calls_started == 0 &&
request->client_stats.num_calls_finished == 0 &&
request->client_stats.num_calls_finished_with_drop_for_rate_limiting ==
0 &&
request->client_stats
.num_calls_finished_with_drop_for_load_balancing == 0 &&
request->client_stats.num_calls_finished_with_client_failed_to_send ==
0 &&
request->client_stats.num_calls_finished_known_received == 0;
request->client_stats.num_calls_finished_known_received == 0 &&
(drop_entries == NULL || drop_entries->num_entries == 0);
}
static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg,
@ -1309,7 +1323,7 @@ static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg,
// Construct message payload.
GPR_ASSERT(glb_policy->client_load_report_payload == NULL);
grpc_grpclb_request *request =
grpc_grpclb_load_report_request_create(glb_policy->client_stats);
grpc_grpclb_load_report_request_create_locked(glb_policy->client_stats);
// Skip client load report if the counters were all zero in the last
// report and they are still zero in this one.
if (load_report_counters_are_zero(request)) {
@ -1463,7 +1477,8 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx,
op++;
/* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref
* count goes to zero) to be unref'd in lb_on_sent_initial_request_locked() */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received");
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base,
"lb_on_sent_initial_request_locked");
call_error = grpc_call_start_batch_and_execute(
exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops),
&glb_policy->lb_on_sent_initial_request);
@ -1480,8 +1495,9 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx,
op->reserved = NULL;
op++;
/* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref
* count goes to zero) to be unref'd in lb_on_server_status_received */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received");
* count goes to zero) to be unref'd in lb_on_server_status_received_locked */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base,
"lb_on_server_status_received_locked");
call_error = grpc_call_start_batch_and_execute(
exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops),
&glb_policy->lb_on_server_status_received);
@ -1493,8 +1509,9 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx,
op->flags = 0;
op->reserved = NULL;
op++;
/* take another weak ref to be unref'd in lb_on_response_received */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received");
/* take another weak ref to be unref'd/reused in
* lb_on_response_received_locked */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received_locked");
call_error = grpc_call_start_batch_and_execute(
exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops),
&glb_policy->lb_on_response_received);
@ -1511,13 +1528,12 @@ static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx,
do_send_client_load_report_locked(exec_ctx, glb_policy);
}
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"lb_on_response_received_locked");
"lb_on_sent_initial_request_locked");
}
static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
glb_lb_policy *glb_policy = arg;
grpc_op ops[2];
memset(ops, 0, sizeof(ops));
grpc_op *op = ops;
@ -1548,7 +1564,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
}
/* take a weak ref (won't prevent calling of \a glb_shutdown() if the
* strong ref count goes to zero) to be unref'd in
* send_client_load_report() */
* send_client_load_report_locked() */
glb_policy->client_load_report_timer_pending = true;
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "client_load_report");
schedule_next_client_load_report(exec_ctx, glb_policy);
@ -1576,7 +1592,6 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(ipport);
}
}
/* update serverlist */
if (serverlist->num_servers > 0) {
if (grpc_grpclb_serverlist_equals(glb_policy->serverlist,
@ -1611,9 +1626,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
}
}
grpc_slice_unref_internal(exec_ctx, response_slice);
if (!glb_policy->shutting_down) {
/* keep listening for serverlist updates */
op->op = GRPC_OP_RECV_MESSAGE;
@ -1621,7 +1634,7 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
op->flags = 0;
op->reserved = NULL;
op++;
/* reuse the "lb_on_response_received" weak ref taken in
/* reuse the "lb_on_response_received_locked" weak ref taken in
* query_for_backends_locked() */
const grpc_call_error call_error = grpc_call_start_batch_and_execute(
exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops),
@ -1629,10 +1642,10 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(GRPC_CALL_OK == call_error);
}
} else { /* empty payload: call cancelled. */
/* dispose of the "lb_on_response_received" weak ref taken in
/* dispose of the "lb_on_response_received_locked" weak ref taken in
* query_for_backends_locked() and reused in every reception loop */
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"lb_on_response_received_empty_payload");
"lb_on_response_received_locked_empty_payload");
}
}
@ -1699,7 +1712,7 @@ static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx,
&glb_policy->lb_on_call_retry, now);
}
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"lb_on_server_status_received");
"lb_on_server_status_received_locked");
}
static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
@ -1756,7 +1769,8 @@ static void glb_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
if (!glb_policy->watching_lb_channel) {
// Watch the LB channel connectivity for connection.
glb_policy->lb_channel_connectivity = GRPC_CHANNEL_INIT;
glb_policy->lb_channel_connectivity = grpc_channel_check_connectivity_state(
glb_policy->lb_channel, true /* try to connect */);
grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(glb_policy->lb_channel));
GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter);

@ -18,8 +18,11 @@
#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
@ -29,10 +32,11 @@
struct grpc_grpclb_client_stats {
gpr_refcount refs;
// This field must only be accessed via *_locked() methods.
grpc_grpclb_dropped_call_counts* drop_token_counts;
// These fields may be accessed from multiple threads at a time.
gpr_atm num_calls_started;
gpr_atm num_calls_finished;
gpr_atm num_calls_finished_with_drop_for_rate_limiting;
gpr_atm num_calls_finished_with_drop_for_load_balancing;
gpr_atm num_calls_finished_with_client_failed_to_send;
gpr_atm num_calls_finished_known_received;
};
@ -51,6 +55,7 @@ grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref(
void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats) {
if (gpr_unref(&client_stats->refs)) {
grpc_grpclb_dropped_call_counts_destroy(client_stats->drop_token_counts);
gpr_free(client_stats);
}
}
@ -61,21 +66,9 @@ void grpc_grpclb_client_stats_add_call_started(
}
void grpc_grpclb_client_stats_add_call_finished(
bool finished_with_drop_for_rate_limiting,
bool finished_with_drop_for_load_balancing,
bool finished_with_client_failed_to_send, bool finished_known_received,
grpc_grpclb_client_stats* client_stats) {
gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1);
if (finished_with_drop_for_rate_limiting) {
gpr_atm_full_fetch_add(
&client_stats->num_calls_finished_with_drop_for_rate_limiting,
(gpr_atm)1);
}
if (finished_with_drop_for_load_balancing) {
gpr_atm_full_fetch_add(
&client_stats->num_calls_finished_with_drop_for_load_balancing,
(gpr_atm)1);
}
if (finished_with_client_failed_to_send) {
gpr_atm_full_fetch_add(
&client_stats->num_calls_finished_with_client_failed_to_send,
@ -87,32 +80,70 @@ void grpc_grpclb_client_stats_add_call_finished(
}
}
void grpc_grpclb_client_stats_add_call_dropped_locked(
char* token, grpc_grpclb_client_stats* client_stats) {
// Increment num_calls_started and num_calls_finished.
gpr_atm_full_fetch_add(&client_stats->num_calls_started, (gpr_atm)1);
gpr_atm_full_fetch_add(&client_stats->num_calls_finished, (gpr_atm)1);
// Record the drop.
if (client_stats->drop_token_counts == NULL) {
client_stats->drop_token_counts =
gpr_zalloc(sizeof(grpc_grpclb_dropped_call_counts));
}
grpc_grpclb_dropped_call_counts* drop_token_counts =
client_stats->drop_token_counts;
for (size_t i = 0; i < drop_token_counts->num_entries; ++i) {
if (strcmp(drop_token_counts->token_counts[i].token, token) == 0) {
++drop_token_counts->token_counts[i].count;
return;
}
}
// Not found, so add a new entry. We double the size of the array each time.
size_t new_num_entries = 2;
while (new_num_entries < drop_token_counts->num_entries + 1) {
new_num_entries *= 2;
}
drop_token_counts->token_counts =
gpr_realloc(drop_token_counts->token_counts,
new_num_entries * sizeof(grpc_grpclb_drop_token_count));
grpc_grpclb_drop_token_count* new_entry =
&drop_token_counts->token_counts[drop_token_counts->num_entries++];
new_entry->token = gpr_strdup(token);
new_entry->count = 1;
}
static void atomic_get_and_reset_counter(int64_t* value, gpr_atm* counter) {
*value = (int64_t)gpr_atm_acq_load(counter);
gpr_atm_full_fetch_add(counter, (gpr_atm)(-*value));
}
void grpc_grpclb_client_stats_get(
void grpc_grpclb_client_stats_get_locked(
grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started,
int64_t* num_calls_finished,
int64_t* num_calls_finished_with_drop_for_rate_limiting,
int64_t* num_calls_finished_with_drop_for_load_balancing,
int64_t* num_calls_finished_with_client_failed_to_send,
int64_t* num_calls_finished_known_received) {
int64_t* num_calls_finished_known_received,
grpc_grpclb_dropped_call_counts** drop_token_counts) {
atomic_get_and_reset_counter(num_calls_started,
&client_stats->num_calls_started);
atomic_get_and_reset_counter(num_calls_finished,
&client_stats->num_calls_finished);
atomic_get_and_reset_counter(
num_calls_finished_with_drop_for_rate_limiting,
&client_stats->num_calls_finished_with_drop_for_rate_limiting);
atomic_get_and_reset_counter(
num_calls_finished_with_drop_for_load_balancing,
&client_stats->num_calls_finished_with_drop_for_load_balancing);
atomic_get_and_reset_counter(
num_calls_finished_with_client_failed_to_send,
&client_stats->num_calls_finished_with_client_failed_to_send);
atomic_get_and_reset_counter(
num_calls_finished_known_received,
&client_stats->num_calls_finished_known_received);
*drop_token_counts = client_stats->drop_token_counts;
client_stats->drop_token_counts = NULL;
}
void grpc_grpclb_dropped_call_counts_destroy(
grpc_grpclb_dropped_call_counts* drop_entries) {
if (drop_entries != NULL) {
for (size_t i = 0; i < drop_entries->num_entries; ++i) {
gpr_free(drop_entries->token_counts[i].token);
}
gpr_free(drop_entries->token_counts);
gpr_free(drop_entries);
}
}

@ -25,6 +25,16 @@
typedef struct grpc_grpclb_client_stats grpc_grpclb_client_stats;
typedef struct {
char* token;
int64_t count;
} grpc_grpclb_drop_token_count;
typedef struct {
grpc_grpclb_drop_token_count* token_counts;
size_t num_entries;
} grpc_grpclb_dropped_call_counts;
grpc_grpclb_client_stats* grpc_grpclb_client_stats_create();
grpc_grpclb_client_stats* grpc_grpclb_client_stats_ref(
grpc_grpclb_client_stats* client_stats);
@ -33,18 +43,23 @@ void grpc_grpclb_client_stats_unref(grpc_grpclb_client_stats* client_stats);
void grpc_grpclb_client_stats_add_call_started(
grpc_grpclb_client_stats* client_stats);
void grpc_grpclb_client_stats_add_call_finished(
bool finished_with_drop_for_rate_limiting,
bool finished_with_drop_for_load_balancing,
bool finished_with_client_failed_to_send, bool finished_known_received,
grpc_grpclb_client_stats* client_stats);
void grpc_grpclb_client_stats_get(
// This method is not thread-safe; caller must synchronize.
void grpc_grpclb_client_stats_add_call_dropped_locked(
char* token, grpc_grpclb_client_stats* client_stats);
// This method is not thread-safe; caller must synchronize.
void grpc_grpclb_client_stats_get_locked(
grpc_grpclb_client_stats* client_stats, int64_t* num_calls_started,
int64_t* num_calls_finished,
int64_t* num_calls_finished_with_drop_for_rate_limiting,
int64_t* num_calls_finished_with_drop_for_load_balancing,
int64_t* num_calls_finished_with_client_failed_to_send,
int64_t* num_calls_finished_known_received);
int64_t* num_calls_finished_known_received,
grpc_grpclb_dropped_call_counts** drop_token_counts);
void grpc_grpclb_dropped_call_counts_destroy(
grpc_grpclb_dropped_call_counts* drop_entries);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H \
*/

@ -76,7 +76,33 @@ static void populate_timestamp(gpr_timespec timestamp,
timestamp_pb->nanos = timestamp.tv_nsec;
}
grpc_grpclb_request *grpc_grpclb_load_report_request_create(
static bool encode_string(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
char *str = *arg;
if (!pb_encode_tag_for_field(stream, field)) return false;
return pb_encode_string(stream, (uint8_t *)str, strlen(str));
}
static bool encode_drops(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
grpc_grpclb_dropped_call_counts *drop_entries = *arg;
if (drop_entries == NULL) return true;
for (size_t i = 0; i < drop_entries->num_entries; ++i) {
if (!pb_encode_tag_for_field(stream, field)) return false;
grpc_lb_v1_ClientStatsPerToken drop_message;
drop_message.load_balance_token.funcs.encode = encode_string;
drop_message.load_balance_token.arg = drop_entries->token_counts[i].token;
drop_message.has_num_calls = true;
drop_message.num_calls = drop_entries->token_counts[i].count;
if (!pb_encode_submessage(stream, grpc_lb_v1_ClientStatsPerToken_fields,
&drop_message)) {
return false;
}
}
return true;
}
grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked(
grpc_grpclb_client_stats *client_stats) {
grpc_grpclb_request *req = gpr_zalloc(sizeof(grpc_grpclb_request));
req->has_client_stats = true;
@ -84,18 +110,17 @@ grpc_grpclb_request *grpc_grpclb_load_report_request_create(
populate_timestamp(gpr_now(GPR_CLOCK_REALTIME), &req->client_stats.timestamp);
req->client_stats.has_num_calls_started = true;
req->client_stats.has_num_calls_finished = true;
req->client_stats.has_num_calls_finished_with_drop_for_rate_limiting = true;
req->client_stats.has_num_calls_finished_with_drop_for_load_balancing = true;
req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
req->client_stats.has_num_calls_finished_with_client_failed_to_send = true;
req->client_stats.has_num_calls_finished_known_received = true;
grpc_grpclb_client_stats_get(
req->client_stats.calls_finished_with_drop.funcs.encode = encode_drops;
grpc_grpclb_client_stats_get_locked(
client_stats, &req->client_stats.num_calls_started,
&req->client_stats.num_calls_finished,
&req->client_stats.num_calls_finished_with_drop_for_rate_limiting,
&req->client_stats.num_calls_finished_with_drop_for_load_balancing,
&req->client_stats.num_calls_finished_with_client_failed_to_send,
&req->client_stats.num_calls_finished_known_received);
&req->client_stats.num_calls_finished_known_received,
(grpc_grpclb_dropped_call_counts **)&req->client_stats
.calls_finished_with_drop.arg);
return req;
}
@ -117,6 +142,11 @@ grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) {
}
void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
if (request->has_client_stats) {
grpc_grpclb_dropped_call_counts *drop_entries =
request->client_stats.calls_finished_with_drop.arg;
grpc_grpclb_dropped_call_counts_destroy(drop_entries);
}
gpr_free(request);
}

@ -44,7 +44,7 @@ typedef struct {
/** Create a request for a gRPC LB service under \a lb_service_name */
grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name);
grpc_grpclb_request *grpc_grpclb_load_report_request_create(
grpc_grpclb_request *grpc_grpclb_load_report_request_create_locked(
grpc_grpclb_client_stats *client_stats);
/** Protocol Buffers v3-encode \a request */

@ -33,14 +33,19 @@ const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2] = {
PB_LAST_FIELD
};
const pb_field_t grpc_lb_v1_ClientStats_fields[8] = {
const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3] = {
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, grpc_lb_v1_ClientStatsPerToken, load_balance_token, load_balance_token, 0),
PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStatsPerToken, num_calls, load_balance_token, 0),
PB_LAST_FIELD
};
const pb_field_t grpc_lb_v1_ClientStats_fields[7] = {
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v1_ClientStats, timestamp, timestamp, &grpc_lb_v1_Timestamp_fields),
PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_started, timestamp, 0),
PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished, num_calls_started, 0),
PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_rate_limiting, num_calls_finished, 0),
PB_FIELD( 5, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_drop_for_load_balancing, num_calls_finished_with_drop_for_rate_limiting, 0),
PB_FIELD( 6, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished_with_drop_for_load_balancing, 0),
PB_FIELD( 6, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_with_client_failed_to_send, num_calls_finished, 0),
PB_FIELD( 7, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_ClientStats, num_calls_finished_known_received, num_calls_finished_with_client_failed_to_send, 0),
PB_FIELD( 8, MESSAGE , REPEATED, CALLBACK, OTHER, grpc_lb_v1_ClientStats, calls_finished_with_drop, num_calls_finished_known_received, &grpc_lb_v1_ClientStatsPerToken_fields),
PB_LAST_FIELD
};
@ -62,12 +67,11 @@ const pb_field_t grpc_lb_v1_ServerList_fields[3] = {
PB_LAST_FIELD
};
const pb_field_t grpc_lb_v1_Server_fields[6] = {
const pb_field_t grpc_lb_v1_Server_fields[5] = {
PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0),
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, port, ip_address, 0),
PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, load_balance_token, port, 0),
PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_for_rate_limiting, load_balance_token, 0),
PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_for_load_balancing, drop_for_rate_limiting, 0),
PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop, load_balance_token, 0),
PB_LAST_FIELD
};
@ -81,7 +85,7 @@ const pb_field_t grpc_lb_v1_Server_fields[6] = {
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
* field descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 65536 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v1_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
#endif
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
@ -92,7 +96,7 @@ PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request)
* numbers or field sizes that are larger than what can fit in the default
* 8 bit descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v1_ClientStats, timestamp) < 256 && pb_membersize(grpc_lb_v1_ClientStats, calls_finished_with_drop) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v1_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v1_ServerList, servers) < 256 && pb_membersize(grpc_lb_v1_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v1_Duration_grpc_lb_v1_Timestamp_grpc_lb_v1_LoadBalanceRequest_grpc_lb_v1_InitialLoadBalanceRequest_grpc_lb_v1_ClientStatsPerToken_grpc_lb_v1_ClientStats_grpc_lb_v1_LoadBalanceResponse_grpc_lb_v1_InitialLoadBalanceResponse_grpc_lb_v1_ServerList_grpc_lb_v1_Server)
#endif

@ -14,6 +14,13 @@ extern "C" {
#endif
/* Struct definitions */
typedef struct _grpc_lb_v1_ClientStatsPerToken {
pb_callback_t load_balance_token;
bool has_num_calls;
int64_t num_calls;
/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStatsPerToken) */
} grpc_lb_v1_ClientStatsPerToken;
typedef struct _grpc_lb_v1_Duration {
bool has_seconds;
int64_t seconds;
@ -36,10 +43,8 @@ typedef struct _grpc_lb_v1_Server {
int32_t port;
bool has_load_balance_token;
char load_balance_token[50];
bool has_drop_for_rate_limiting;
bool drop_for_rate_limiting;
bool has_drop_for_load_balancing;
bool drop_for_load_balancing;
bool has_drop;
bool drop;
/* @@protoc_insertion_point(struct:grpc_lb_v1_Server) */
} grpc_lb_v1_Server;
@ -58,14 +63,11 @@ typedef struct _grpc_lb_v1_ClientStats {
int64_t num_calls_started;
bool has_num_calls_finished;
int64_t num_calls_finished;
bool has_num_calls_finished_with_drop_for_rate_limiting;
int64_t num_calls_finished_with_drop_for_rate_limiting;
bool has_num_calls_finished_with_drop_for_load_balancing;
int64_t num_calls_finished_with_drop_for_load_balancing;
bool has_num_calls_finished_with_client_failed_to_send;
int64_t num_calls_finished_with_client_failed_to_send;
bool has_num_calls_finished_known_received;
int64_t num_calls_finished_known_received;
pb_callback_t calls_finished_with_drop;
/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */
} grpc_lb_v1_ClientStats;
@ -107,39 +109,41 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse {
#define grpc_lb_v1_Timestamp_init_default {false, 0, false, 0}
#define grpc_lb_v1_LoadBalanceRequest_init_default {false, grpc_lb_v1_InitialLoadBalanceRequest_init_default, false, grpc_lb_v1_ClientStats_init_default}
#define grpc_lb_v1_InitialLoadBalanceRequest_init_default {false, ""}
#define grpc_lb_v1_ClientStats_init_default {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define grpc_lb_v1_ClientStatsPerToken_init_default {{{NULL}, NULL}, false, 0}
#define grpc_lb_v1_ClientStats_init_default {false, grpc_lb_v1_Timestamp_init_default, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}}
#define grpc_lb_v1_LoadBalanceResponse_init_default {false, grpc_lb_v1_InitialLoadBalanceResponse_init_default, false, grpc_lb_v1_ServerList_init_default}
#define grpc_lb_v1_InitialLoadBalanceResponse_init_default {false, "", false, grpc_lb_v1_Duration_init_default}
#define grpc_lb_v1_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_default}
#define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0, false, 0}
#define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0}
#define grpc_lb_v1_Duration_init_zero {false, 0, false, 0}
#define grpc_lb_v1_Timestamp_init_zero {false, 0, false, 0}
#define grpc_lb_v1_LoadBalanceRequest_init_zero {false, grpc_lb_v1_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v1_ClientStats_init_zero}
#define grpc_lb_v1_InitialLoadBalanceRequest_init_zero {false, ""}
#define grpc_lb_v1_ClientStats_init_zero {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
#define grpc_lb_v1_ClientStatsPerToken_init_zero {{{NULL}, NULL}, false, 0}
#define grpc_lb_v1_ClientStats_init_zero {false, grpc_lb_v1_Timestamp_init_zero, false, 0, false, 0, false, 0, false, 0, {{NULL}, NULL}}
#define grpc_lb_v1_LoadBalanceResponse_init_zero {false, grpc_lb_v1_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v1_ServerList_init_zero}
#define grpc_lb_v1_InitialLoadBalanceResponse_init_zero {false, "", false, grpc_lb_v1_Duration_init_zero}
#define grpc_lb_v1_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_zero}
#define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0, false, 0}
#define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0}
/* Field tags (for use in manual encoding/decoding) */
#define grpc_lb_v1_ClientStatsPerToken_load_balance_token_tag 1
#define grpc_lb_v1_ClientStatsPerToken_num_calls_tag 2
#define grpc_lb_v1_Duration_seconds_tag 1
#define grpc_lb_v1_Duration_nanos_tag 2
#define grpc_lb_v1_InitialLoadBalanceRequest_name_tag 1
#define grpc_lb_v1_Server_ip_address_tag 1
#define grpc_lb_v1_Server_port_tag 2
#define grpc_lb_v1_Server_load_balance_token_tag 3
#define grpc_lb_v1_Server_drop_for_rate_limiting_tag 4
#define grpc_lb_v1_Server_drop_for_load_balancing_tag 5
#define grpc_lb_v1_Server_drop_tag 4
#define grpc_lb_v1_Timestamp_seconds_tag 1
#define grpc_lb_v1_Timestamp_nanos_tag 2
#define grpc_lb_v1_ClientStats_timestamp_tag 1
#define grpc_lb_v1_ClientStats_num_calls_started_tag 2
#define grpc_lb_v1_ClientStats_num_calls_finished_tag 3
#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_rate_limiting_tag 4
#define grpc_lb_v1_ClientStats_num_calls_finished_with_drop_for_load_balancing_tag 5
#define grpc_lb_v1_ClientStats_num_calls_finished_with_client_failed_to_send_tag 6
#define grpc_lb_v1_ClientStats_num_calls_finished_known_received_tag 7
#define grpc_lb_v1_ClientStats_calls_finished_with_drop_tag 8
#define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 1
#define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 2
#define grpc_lb_v1_ServerList_servers_tag 1
@ -154,22 +158,24 @@ extern const pb_field_t grpc_lb_v1_Duration_fields[3];
extern const pb_field_t grpc_lb_v1_Timestamp_fields[3];
extern const pb_field_t grpc_lb_v1_LoadBalanceRequest_fields[3];
extern const pb_field_t grpc_lb_v1_InitialLoadBalanceRequest_fields[2];
extern const pb_field_t grpc_lb_v1_ClientStats_fields[8];
extern const pb_field_t grpc_lb_v1_ClientStatsPerToken_fields[3];
extern const pb_field_t grpc_lb_v1_ClientStats_fields[7];
extern const pb_field_t grpc_lb_v1_LoadBalanceResponse_fields[3];
extern const pb_field_t grpc_lb_v1_InitialLoadBalanceResponse_fields[3];
extern const pb_field_t grpc_lb_v1_ServerList_fields[3];
extern const pb_field_t grpc_lb_v1_Server_fields[6];
extern const pb_field_t grpc_lb_v1_Server_fields[5];
/* Maximum encoded size of messages (where known) */
#define grpc_lb_v1_Duration_size 22
#define grpc_lb_v1_Timestamp_size 22
#define grpc_lb_v1_LoadBalanceRequest_size 226
#define grpc_lb_v1_LoadBalanceRequest_size (140 + grpc_lb_v1_ClientStats_size)
#define grpc_lb_v1_InitialLoadBalanceRequest_size 131
#define grpc_lb_v1_ClientStats_size 90
/* grpc_lb_v1_ClientStatsPerToken_size depends on runtime parameters */
/* grpc_lb_v1_ClientStats_size depends on runtime parameters */
#define grpc_lb_v1_LoadBalanceResponse_size (98 + grpc_lb_v1_ServerList_size)
#define grpc_lb_v1_InitialLoadBalanceResponse_size 90
/* grpc_lb_v1_ServerList_size depends on runtime parameters */
#define grpc_lb_v1_Server_size 85
#define grpc_lb_v1_Server_size 83
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID

@ -74,6 +74,9 @@ typedef struct round_robin_lb_policy {
bool started_picking;
/** are we shutting down? */
bool shutdown;
/** has the policy gotten into the GRPC_CHANNEL_SHUTDOWN? No picks can be
* service after this point, the policy will never transition out. */
bool in_connectivity_shutdown;
/** List of picks that are waiting on connectivity */
pending_pick *pending_picks;
@ -420,6 +423,8 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_call_context_element *context, void **user_data,
grpc_closure *on_complete) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
GPR_ASSERT(!p->shutdown);
GPR_ASSERT(!p->in_connectivity_shutdown);
if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO, "[RR %p] Trying to pick", (void *)pol);
}
@ -532,6 +537,7 @@ static grpc_connectivity_state update_lb_connectivity_status_locked(
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error),
"rr_shutdown");
p->in_connectivity_shutdown = true;
new_state = GRPC_CHANNEL_SHUTDOWN;
} else if (subchannel_list->num_transient_failures ==
p->subchannel_list->num_subchannels) { /* 4) TRANSIENT_FAILURE */
@ -584,10 +590,16 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg,
// Dispose of outdated subchannel lists.
if (sd->subchannel_list != p->subchannel_list &&
sd->subchannel_list != p->latest_pending_subchannel_list) {
// sd belongs to an outdated subchannel_list: get rid of it.
rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list,
"sl_outdated");
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "sl_outdated");
char *reason = NULL;
if (sd->subchannel_list->shutting_down) {
reason = "sl_outdated_straggler";
rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, reason);
} else {
reason = "sl_outdated";
rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list,
reason);
}
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, reason);
return;
}
// Now that we're inside the combiner, copy the pending connectivity
@ -753,6 +765,7 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
for (size_t i = 0; i < addresses->num_addresses; i++) {
if (!addresses->addresses[i].is_balancer) ++num_addrs;
}
rr_subchannel_list *subchannel_list = rr_subchannel_list_create(p, num_addrs);
if (num_addrs == 0) {
grpc_connectivity_state_set(
exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
@ -761,18 +774,16 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
if (p->subchannel_list != NULL) {
rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list,
"sl_shutdown_empty_update");
p->subchannel_list = NULL;
}
p->subchannel_list = subchannel_list; // empty list
return;
}
size_t subchannel_index = 0;
rr_subchannel_list *subchannel_list = rr_subchannel_list_create(p, num_addrs);
if (p->latest_pending_subchannel_list != NULL && p->started_picking) {
if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
gpr_log(GPR_DEBUG,
"[RR %p] Shutting down latest pending subchannel list %p, about "
"to be "
"replaced by newer latest %p",
"to be replaced by newer latest %p",
(void *)p, (void *)p->latest_pending_subchannel_list,
(void *)subchannel_list);
}
@ -876,10 +887,10 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_args *args) {
GPR_ASSERT(args->client_channel_factory != NULL);
round_robin_lb_policy *p = gpr_zalloc(sizeof(*p));
rr_update_locked(exec_ctx, &p->base, args);
grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner);
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"round_robin");
rr_update_locked(exec_ctx, &p->base, args);
if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
gpr_log(GPR_DEBUG, "[RR %p] Created with %lu subchannels", (void *)p,
(unsigned long)p->subchannel_list->num_subchannels);

@ -33,13 +33,13 @@
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include <nameser.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/nameser.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"

@ -130,24 +130,28 @@ static grpc_server_retry_throttle_data* grpc_server_retry_throttle_data_create(
// avl vtable for string -> server_retry_throttle_data map
//
static void* copy_server_name(void* key) { return gpr_strdup(key); }
static void* copy_server_name(void* key, void* unused) {
return gpr_strdup(key);
}
static long compare_server_name(void* key1, void* key2) {
static long compare_server_name(void* key1, void* key2, void* unused) {
return strcmp(key1, key2);
}
static void destroy_server_retry_throttle_data(void* value) {
static void destroy_server_retry_throttle_data(void* value, void* unused) {
grpc_server_retry_throttle_data* throttle_data = value;
grpc_server_retry_throttle_data_unref(throttle_data);
}
static void* copy_server_retry_throttle_data(void* value) {
static void* copy_server_retry_throttle_data(void* value, void* unused) {
grpc_server_retry_throttle_data* throttle_data = value;
return grpc_server_retry_throttle_data_ref(throttle_data);
}
static void destroy_server_name(void* key, void* unused) { gpr_free(key); }
static const gpr_avl_vtable avl_vtable = {
gpr_free /* destroy_key */, copy_server_name, compare_server_name,
destroy_server_name, copy_server_name, compare_server_name,
destroy_server_retry_throttle_data, copy_server_retry_throttle_data};
//
@ -164,19 +168,19 @@ void grpc_retry_throttle_map_init() {
void grpc_retry_throttle_map_shutdown() {
gpr_mu_destroy(&g_mu);
gpr_avl_unref(g_avl);
gpr_avl_unref(g_avl, NULL);
}
grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
const char* server_name, int max_milli_tokens, int milli_token_ratio) {
gpr_mu_lock(&g_mu);
grpc_server_retry_throttle_data* throttle_data =
gpr_avl_get(g_avl, (char*)server_name);
gpr_avl_get(g_avl, (char*)server_name, NULL);
if (throttle_data == NULL) {
// Entry not found. Create a new one.
throttle_data = grpc_server_retry_throttle_data_create(
max_milli_tokens, milli_token_ratio, NULL);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL);
} else {
if (throttle_data->max_milli_tokens != max_milli_tokens ||
throttle_data->milli_token_ratio != milli_token_ratio) {
@ -184,7 +188,7 @@ grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
// the original one.
throttle_data = grpc_server_retry_throttle_data_create(
max_milli_tokens, milli_token_ratio, throttle_data);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data);
g_avl = gpr_avl_add(g_avl, (char*)server_name, throttle_data, NULL);
} else {
// Entry found. Increase refcount.
grpc_server_retry_throttle_data_ref(throttle_data);

@ -38,26 +38,8 @@ struct grpc_subchannel_key {
grpc_subchannel_args args;
};
GPR_TLS_DECL(subchannel_index_exec_ctx);
static bool g_force_creation = false;
static void enter_ctx(grpc_exec_ctx *exec_ctx) {
GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0);
gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx);
}
static void leave_ctx(grpc_exec_ctx *exec_ctx) {
GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx);
gpr_tls_set(&subchannel_index_exec_ctx, 0);
}
static grpc_exec_ctx *current_ctx() {
grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx);
GPR_ASSERT(c != NULL);
return c;
}
static grpc_subchannel_key *create_key(
const grpc_subchannel_args *args,
grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) {
@ -104,21 +86,25 @@ void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
gpr_free(k);
}
static void sck_avl_destroy(void *p) {
grpc_subchannel_key_destroy(current_ctx(), p);
static void sck_avl_destroy(void *p, void *user_data) {
grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data;
grpc_subchannel_key_destroy(exec_ctx, p);
}
static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); }
static void *sck_avl_copy(void *p, void *unused) {
return subchannel_key_copy(p);
}
static long sck_avl_compare(void *a, void *b) {
static long sck_avl_compare(void *a, void *b, void *unused) {
return grpc_subchannel_key_compare(a, b);
}
static void scv_avl_destroy(void *p) {
GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index");
static void scv_avl_destroy(void *p, void *user_data) {
grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data;
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, p, "subchannel_index");
}
static void *scv_avl_copy(void *p) {
static void *scv_avl_copy(void *p, void *unused) {
GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index");
return p;
}
@ -133,38 +119,33 @@ static const gpr_avl_vtable subchannel_avl_vtable = {
void grpc_subchannel_index_init(void) {
g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable);
gpr_mu_init(&g_mu);
gpr_tls_init(&subchannel_index_exec_ctx);
}
void grpc_subchannel_index_shutdown(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
gpr_mu_destroy(&g_mu);
gpr_avl_unref(g_subchannel_index);
gpr_tls_destroy(&subchannel_index_exec_ctx);
gpr_avl_unref(g_subchannel_index, &exec_ctx);
grpc_exec_ctx_finish(&exec_ctx);
}
grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
grpc_subchannel_key *key) {
enter_ctx(exec_ctx);
// Lock, and take a reference to the subchannel index.
// We don't need to do the search under a lock as avl's are immutable.
gpr_mu_lock(&g_mu);
gpr_avl index = gpr_avl_ref(g_subchannel_index);
gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
gpr_mu_unlock(&g_mu);
grpc_subchannel *c =
GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find");
gpr_avl_unref(index);
grpc_subchannel *c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
gpr_avl_get(index, key, exec_ctx), "index_find");
gpr_avl_unref(index, exec_ctx);
leave_ctx(exec_ctx);
return c;
}
grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
grpc_subchannel_key *key,
grpc_subchannel *constructed) {
enter_ctx(exec_ctx);
grpc_subchannel *c = NULL;
bool need_to_unref_constructed;
@ -174,11 +155,11 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
// Compare and swap loop:
// - take a reference to the current index
gpr_mu_lock(&g_mu);
gpr_avl index = gpr_avl_ref(g_subchannel_index);
gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
gpr_mu_unlock(&g_mu);
// - Check to see if a subchannel already exists
c = gpr_avl_get(index, key);
c = gpr_avl_get(index, key, exec_ctx);
if (c != NULL) {
c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
}
@ -187,9 +168,9 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
need_to_unref_constructed = true;
} else {
// no -> update the avl and compare/swap
gpr_avl updated =
gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key),
GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"));
gpr_avl updated = gpr_avl_add(
gpr_avl_ref(index, exec_ctx), subchannel_key_copy(key),
GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), exec_ctx);
// it may happen (but it's expected to be unlikely)
// that some other thread has changed the index:
@ -201,13 +182,11 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
}
gpr_mu_unlock(&g_mu);
gpr_avl_unref(updated);
gpr_avl_unref(updated, exec_ctx);
}
gpr_avl_unref(index);
gpr_avl_unref(index, exec_ctx);
}
leave_ctx(exec_ctx);
if (need_to_unref_constructed) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register");
}
@ -218,27 +197,26 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
grpc_subchannel_key *key,
grpc_subchannel *constructed) {
enter_ctx(exec_ctx);
bool done = false;
while (!done) {
// Compare and swap loop:
// - take a reference to the current index
gpr_mu_lock(&g_mu);
gpr_avl index = gpr_avl_ref(g_subchannel_index);
gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
gpr_mu_unlock(&g_mu);
// Check to see if this key still refers to the previously
// registered subchannel
grpc_subchannel *c = gpr_avl_get(index, key);
grpc_subchannel *c = gpr_avl_get(index, key, exec_ctx);
if (c != constructed) {
gpr_avl_unref(index);
gpr_avl_unref(index, exec_ctx);
break;
}
// compare and swap the update (some other thread may have
// mutated the index behind us)
gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key);
gpr_avl updated =
gpr_avl_remove(gpr_avl_ref(index, exec_ctx), key, exec_ctx);
gpr_mu_lock(&g_mu);
if (index.root == g_subchannel_index.root) {
@ -247,11 +225,9 @@ void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
}
gpr_mu_unlock(&g_mu);
gpr_avl_unref(updated);
gpr_avl_unref(index);
gpr_avl_unref(updated, exec_ctx);
gpr_avl_unref(index, exec_ctx);
}
leave_ctx(exec_ctx);
}
void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {

@ -36,41 +36,29 @@
static const size_t kMaxPayloadSizeForGet = 2048;
typedef struct call_data {
// State for handling send_initial_metadata ops.
grpc_linked_mdelem method;
grpc_linked_mdelem scheme;
grpc_linked_mdelem authority;
grpc_linked_mdelem te_trailers;
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
// State for handling recv_initial_metadata ops.
grpc_metadata_batch *recv_initial_metadata;
grpc_closure *original_recv_initial_metadata_ready;
grpc_closure recv_initial_metadata_ready;
// State for handling recv_trailing_metadata ops.
grpc_metadata_batch *recv_trailing_metadata;
uint8_t *payload_bytes;
/* Vars to read data off of send_message */
grpc_transport_stream_op_batch *send_op;
uint32_t send_length;
uint32_t send_flags;
grpc_slice incoming_slice;
grpc_slice_buffer_stream replacement_stream;
grpc_slice_buffer slices;
/* flag that indicates that all slices of send_messages aren't availble */
bool send_message_blocked;
/** Closure to call when finished with the hc_on_recv hook */
grpc_closure *on_done_recv_initial_metadata;
grpc_closure *on_done_recv_trailing_metadata;
grpc_closure *on_complete;
grpc_closure *post_send;
/** Receive closures are chained: we inject this closure as the on_done_recv
up-call on transport_op, and remember to call our on_done_recv member
after handling it. */
grpc_closure hc_on_recv_initial_metadata;
grpc_closure hc_on_recv_trailing_metadata;
grpc_closure hc_on_complete;
grpc_closure got_slice;
grpc_closure send_done;
grpc_closure *original_recv_trailing_metadata_on_complete;
grpc_closure recv_trailing_metadata_on_complete;
// State for handling send_message ops.
grpc_transport_stream_op_batch *send_message_batch;
size_t send_message_bytes_read;
grpc_byte_stream_cache send_message_cache;
grpc_caching_byte_stream send_message_caching_stream;
grpc_closure on_send_message_next_done;
grpc_closure *original_send_message_on_complete;
grpc_closure send_message_on_complete;
} call_data;
typedef struct channel_data {
@ -148,7 +136,7 @@ static grpc_error *client_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
return GRPC_ERROR_NONE;
}
static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
void *user_data, grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
@ -158,11 +146,13 @@ static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
} else {
GRPC_ERROR_REF(error);
}
GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv_initial_metadata, error);
GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready,
error);
}
static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
void *user_data, grpc_error *error) {
static void recv_trailing_metadata_on_complete(grpc_exec_ctx *exec_ctx,
void *user_data,
grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
if (error == GRPC_ERROR_NONE) {
@ -171,25 +161,131 @@ static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
} else {
GRPC_ERROR_REF(error);
}
GRPC_CLOSURE_RUN(exec_ctx, calld->on_done_recv_trailing_metadata, error);
GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_trailing_metadata_on_complete,
error);
}
static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
if (calld->payload_bytes) {
gpr_free(calld->payload_bytes);
calld->payload_bytes = NULL;
static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = (grpc_call_element *)arg;
call_data *calld = (call_data *)elem->call_data;
grpc_byte_stream_cache_destroy(exec_ctx, &calld->send_message_cache);
GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete,
GRPC_ERROR_REF(error));
}
// Pulls a slice from the send_message byte stream, updating
// calld->send_message_bytes_read.
static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx,
call_data *calld) {
grpc_slice incoming_slice;
grpc_error *error = grpc_byte_stream_pull(
exec_ctx, &calld->send_message_caching_stream.base, &incoming_slice);
if (error == GRPC_ERROR_NONE) {
calld->send_message_bytes_read += GRPC_SLICE_LENGTH(incoming_slice);
grpc_slice_unref_internal(exec_ctx, incoming_slice);
}
calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, error);
return error;
}
static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices);
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
// Reads as many slices as possible from the send_message byte stream.
// Upon successful return, if calld->send_message_bytes_read ==
// calld->send_message_caching_stream.base.length, then we have completed
// reading from the byte stream; otherwise, an async read has been dispatched
// and on_send_message_next_done() will be invoked when it is complete.
static grpc_error *read_all_available_send_message_data(grpc_exec_ctx *exec_ctx,
call_data *calld) {
while (grpc_byte_stream_next(exec_ctx,
&calld->send_message_caching_stream.base,
~(size_t)0, &calld->on_send_message_next_done)) {
grpc_error *error = pull_slice_from_send_message(exec_ctx, calld);
if (error != GRPC_ERROR_NONE) return error;
if (calld->send_message_bytes_read ==
calld->send_message_caching_stream.base.length) {
break;
}
}
return GRPC_ERROR_NONE;
}
// Async callback for grpc_byte_stream_next().
static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = (grpc_call_element *)arg;
call_data *calld = (call_data *)elem->call_data;
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, calld->send_message_batch, error);
return;
}
error = pull_slice_from_send_message(exec_ctx, calld);
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, calld->send_message_batch, error);
return;
}
// There may or may not be more to read, but we don't care. If we got
// here, then we know that all of the data was not available
// synchronously, so we were not able to do a cached call. Instead,
// we just reset the byte stream and then send down the batch as-is.
grpc_caching_byte_stream_reset(&calld->send_message_caching_stream);
grpc_call_next_op(exec_ctx, elem, calld->send_message_batch);
}
static char *slice_buffer_to_string(grpc_slice_buffer *slice_buffer) {
char *payload_bytes = gpr_malloc(slice_buffer->length + 1);
size_t offset = 0;
for (size_t i = 0; i < slice_buffer->count; ++i) {
memcpy(payload_bytes + offset,
GRPC_SLICE_START_PTR(slice_buffer->slices[i]),
GRPC_SLICE_LENGTH(slice_buffer->slices[i]));
offset += GRPC_SLICE_LENGTH(slice_buffer->slices[i]);
}
*(payload_bytes + offset) = '\0';
return payload_bytes;
}
// Modifies the path entry in the batch's send_initial_metadata to
// append the base64-encoded query for a GET request.
static grpc_error *update_path_for_get(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op_batch *batch) {
call_data *calld = (call_data *)elem->call_data;
grpc_slice path_slice =
GRPC_MDVALUE(batch->payload->send_initial_metadata.send_initial_metadata
->idx.named.path->md);
/* sum up individual component's lengths and allocate enough memory to
* hold combined path+query */
size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
estimated_len++; /* for the '?' */
estimated_len += grpc_base64_estimate_encoded_size(
batch->payload->send_message.send_message->length, true /* url_safe */,
false /* multi_line */);
grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len);
/* memcopy individual pieces into this slice */
char *write_ptr = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
char *original_path = (char *)GRPC_SLICE_START_PTR(path_slice);
memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
write_ptr += GRPC_SLICE_LENGTH(path_slice);
*write_ptr++ = '?';
char *payload_bytes =
slice_buffer_to_string(&calld->send_message_cache.cache_buffer);
grpc_base64_encode_core((char *)write_ptr, payload_bytes,
batch->payload->send_message.send_message->length,
true /* url_safe */, false /* multi_line */);
gpr_free(payload_bytes);
/* remove trailing unused memory and add trailing 0 to terminate string */
char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
/* safe to use strlen since base64_encode will always add '\0' */
path_with_query_slice =
grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t));
/* substitute previous path with the new path+query */
grpc_mdelem mdelem_path_and_query =
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
grpc_metadata_batch *b =
batch->payload->send_initial_metadata.send_initial_metadata;
return grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_and_query);
}
static void remove_if_present(grpc_exec_ctx *exec_ctx,
@ -200,273 +296,153 @@ static void remove_if_present(grpc_exec_ctx *exec_ctx,
}
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
static void hc_start_transport_stream_op_batch(
grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_transport_stream_op_batch *batch) {
call_data *calld = elem->call_data;
uint8_t *wrptr = calld->payload_bytes;
while (grpc_byte_stream_next(
exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0,
&calld->got_slice)) {
grpc_byte_stream_pull(exec_ctx,
calld->send_op->payload->send_message.send_message,
&calld->incoming_slice);
if (GRPC_SLICE_LENGTH(calld->incoming_slice) > 0) {
memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
GRPC_SLICE_LENGTH(calld->incoming_slice));
}
wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice);
grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
calld->send_message_blocked = false;
break;
}
}
}
channel_data *channeld = elem->channel_data;
GPR_TIMER_BEGIN("hc_start_transport_stream_op_batch", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, batch);
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
calld->send_message_blocked = false;
if (GRPC_ERROR_NONE !=
grpc_byte_stream_pull(exec_ctx,
calld->send_op->payload->send_message.send_message,
&calld->incoming_slice)) {
/* Should never reach here */
abort();
}
grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
/* Pass down the original send_message op that was blocked.*/
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
calld->send_op->payload->send_message.send_message =
&calld->replacement_stream.base;
calld->post_send = calld->send_op->on_complete;
calld->send_op->on_complete = &calld->send_done;
grpc_call_next_op(exec_ctx, elem, calld->send_op);
} else {
continue_send_message(exec_ctx, elem);
if (batch->recv_initial_metadata) {
/* substitute our callback for the higher callback */
calld->recv_initial_metadata =
batch->payload->recv_initial_metadata.recv_initial_metadata;
calld->original_recv_initial_metadata_ready =
batch->payload->recv_initial_metadata.recv_initial_metadata_ready;
batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
&calld->recv_initial_metadata_ready;
}
}
static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op_batch *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
grpc_error *error;
if (batch->recv_trailing_metadata) {
/* substitute our callback for the higher callback */
calld->recv_trailing_metadata =
batch->payload->recv_trailing_metadata.recv_trailing_metadata;
calld->original_recv_trailing_metadata_on_complete = batch->on_complete;
batch->on_complete = &calld->recv_trailing_metadata_on_complete;
}
if (op->send_initial_metadata) {
/* Decide which HTTP VERB to use. We use GET if the request is marked
cacheable, and the operation contains both initial metadata and send
message, and the payload is below the size threshold, and all the data
for this request is immediately available. */
grpc_error *error = GRPC_ERROR_NONE;
bool batch_will_be_handled_asynchronously = false;
if (batch->send_initial_metadata) {
// Decide which HTTP VERB to use. We use GET if the request is marked
// cacheable, and the operation contains both initial metadata and send
// message, and the payload is below the size threshold, and all the data
// for this request is immediately available.
grpc_mdelem method = GRPC_MDELEM_METHOD_POST;
if (op->send_message &&
(op->payload->send_initial_metadata.send_initial_metadata_flags &
if (batch->send_message &&
(batch->payload->send_initial_metadata.send_initial_metadata_flags &
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
op->payload->send_message.send_message->length <
batch->payload->send_message.send_message->length <
channeld->max_payload_size_for_get) {
method = GRPC_MDELEM_METHOD_GET;
/* The following write to calld->send_message_blocked isn't racy with
reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because
being here means ops->send_message is not NULL, which is primarily
guarding the read there. */
calld->send_message_blocked = true;
} else if (op->payload->send_initial_metadata.send_initial_metadata_flags &
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
method = GRPC_MDELEM_METHOD_PUT;
}
/* Attempt to read the data from send_message and create a header field. */
if (grpc_mdelem_eq(method, GRPC_MDELEM_METHOD_GET)) {
/* allocate memory to hold the entire payload */
calld->payload_bytes =
gpr_malloc(op->payload->send_message.send_message->length);
/* read slices of send_message and copy into payload_bytes */
calld->send_op = op;
calld->send_length = op->payload->send_message.send_message->length;
calld->send_flags = op->payload->send_message.send_message->flags;
continue_send_message(exec_ctx, elem);
if (calld->send_message_blocked == false) {
/* when all the send_message data is available, then modify the path
* MDELEM by appending base64 encoded query to the path */
const int k_url_safe = 1;
const int k_multi_line = 0;
const unsigned char k_query_separator = '?';
grpc_slice path_slice =
GRPC_MDVALUE(op->payload->send_initial_metadata
.send_initial_metadata->idx.named.path->md);
/* sum up individual component's lengths and allocate enough memory to
* hold combined path+query */
size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
estimated_len++; /* for the '?' */
estimated_len += grpc_base64_estimate_encoded_size(
op->payload->send_message.send_message->length, k_url_safe,
k_multi_line);
grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len);
/* memcopy individual pieces into this slice */
uint8_t *write_ptr =
(uint8_t *)GRPC_SLICE_START_PTR(path_with_query_slice);
uint8_t *original_path = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
write_ptr += GRPC_SLICE_LENGTH(path_slice);
*write_ptr = k_query_separator;
write_ptr++; /* for the '?' */
grpc_base64_encode_core((char *)write_ptr, calld->payload_bytes,
op->payload->send_message.send_message->length,
k_url_safe, k_multi_line);
/* remove trailing unused memory and add trailing 0 to terminate string
*/
char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
/* safe to use strlen since base64_encode will always add '\0' */
path_with_query_slice =
grpc_slice_sub_no_ref(path_with_query_slice, 0, strlen(t));
/* substitute previous path with the new path+query */
grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
grpc_metadata_batch *b =
op->payload->send_initial_metadata.send_initial_metadata;
error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
mdelem_path_and_query);
if (error != GRPC_ERROR_NONE) return error;
calld->on_complete = op->on_complete;
op->on_complete = &calld->hc_on_complete;
op->send_message = false;
calld->send_message_bytes_read = 0;
grpc_byte_stream_cache_init(&calld->send_message_cache,
batch->payload->send_message.send_message);
grpc_caching_byte_stream_init(&calld->send_message_caching_stream,
&calld->send_message_cache);
batch->payload->send_message.send_message =
&calld->send_message_caching_stream.base;
calld->original_send_message_on_complete = batch->on_complete;
batch->on_complete = &calld->send_message_on_complete;
calld->send_message_batch = batch;
error = read_all_available_send_message_data(exec_ctx, calld);
if (error != GRPC_ERROR_NONE) goto done;
// If all the data has been read, then we can use GET.
if (calld->send_message_bytes_read ==
calld->send_message_caching_stream.base.length) {
method = GRPC_MDELEM_METHOD_GET;
error = update_path_for_get(exec_ctx, elem, batch);
if (error != GRPC_ERROR_NONE) goto done;
batch->send_message = false;
grpc_byte_stream_destroy(exec_ctx,
&calld->send_message_caching_stream.base);
} else {
/* Not all data is available. Fall back to POST. */
// Not all data is available. The batch will be sent down
// asynchronously in on_send_message_next_done().
batch_will_be_handled_asynchronously = true;
// Fall back to POST.
gpr_log(GPR_DEBUG,
"Request is marked Cacheable but not all data is available.\
Falling back to POST");
method = GRPC_MDELEM_METHOD_POST;
"Request is marked Cacheable but not all data is available. "
"Falling back to POST");
}
} else if (batch->payload->send_initial_metadata
.send_initial_metadata_flags &
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
method = GRPC_MDELEM_METHOD_PUT;
}
remove_if_present(exec_ctx,
op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_METHOD);
remove_if_present(exec_ctx,
op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_SCHEME);
remove_if_present(exec_ctx,
op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_TE);
remove_if_present(exec_ctx,
op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_CONTENT_TYPE);
remove_if_present(exec_ctx,
op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_USER_AGENT);
remove_if_present(
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_METHOD);
remove_if_present(
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_SCHEME);
remove_if_present(
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_TE);
remove_if_present(
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_CONTENT_TYPE);
remove_if_present(
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_USER_AGENT);
/* Send : prefixed headers, which have to be before any application
layer headers. */
error = grpc_metadata_batch_add_head(
exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
&calld->method, method);
if (error != GRPC_ERROR_NONE) return error;
if (error != GRPC_ERROR_NONE) goto done;
error = grpc_metadata_batch_add_head(
exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
&calld->scheme, channeld->static_scheme);
if (error != GRPC_ERROR_NONE) return error;
if (error != GRPC_ERROR_NONE) goto done;
error = grpc_metadata_batch_add_tail(
exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
&calld->te_trailers, GRPC_MDELEM_TE_TRAILERS);
if (error != GRPC_ERROR_NONE) return error;
if (error != GRPC_ERROR_NONE) goto done;
error = grpc_metadata_batch_add_tail(
exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
&calld->content_type, GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
if (error != GRPC_ERROR_NONE) return error;
if (error != GRPC_ERROR_NONE) goto done;
error = grpc_metadata_batch_add_tail(
exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
exec_ctx, batch->payload->send_initial_metadata.send_initial_metadata,
&calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent));
if (error != GRPC_ERROR_NONE) return error;
if (error != GRPC_ERROR_NONE) goto done;
}
if (op->recv_initial_metadata) {
/* substitute our callback for the higher callback */
calld->recv_initial_metadata =
op->payload->recv_initial_metadata.recv_initial_metadata;
calld->on_done_recv_initial_metadata =
op->payload->recv_initial_metadata.recv_initial_metadata_ready;
op->payload->recv_initial_metadata.recv_initial_metadata_ready =
&calld->hc_on_recv_initial_metadata;
}
if (op->recv_trailing_metadata) {
/* substitute our callback for the higher callback */
calld->recv_trailing_metadata =
op->payload->recv_trailing_metadata.recv_trailing_metadata;
calld->on_done_recv_trailing_metadata = op->on_complete;
op->on_complete = &calld->hc_on_recv_trailing_metadata;
}
return GRPC_ERROR_NONE;
}
static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op_batch *op) {
GPR_TIMER_BEGIN("hc_start_transport_op", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
grpc_error *error = hc_mutate_op(exec_ctx, elem, op);
done:
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
} else {
call_data *calld = elem->call_data;
if (op->send_message && calld->send_message_blocked) {
/* Don't forward the op. send_message contains slices that aren't ready
yet. The call will be forwarded by the op_complete of slice read call.
*/
} else {
grpc_call_next_op(exec_ctx, elem, op);
}
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, calld->send_message_batch, error);
} else if (!batch_will_be_handled_asynchronously) {
grpc_call_next_op(exec_ctx, elem, batch);
}
GPR_TIMER_END("hc_start_transport_op", 0);
GPR_TIMER_END("hc_start_transport_stream_op_batch", 0);
}
/* Constructor for call_data */
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
const grpc_call_element_args *args) {
call_data *calld = elem->call_data;
calld->on_done_recv_initial_metadata = NULL;
calld->on_done_recv_trailing_metadata = NULL;
calld->on_complete = NULL;
calld->payload_bytes = NULL;
calld->send_message_blocked = false;
grpc_slice_buffer_init(&calld->slices);
GRPC_CLOSURE_INIT(&calld->hc_on_recv_initial_metadata,
hc_on_recv_initial_metadata, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->hc_on_recv_trailing_metadata,
hc_on_recv_trailing_metadata, elem,
call_data *calld = (call_data *)elem->call_data;
GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
recv_initial_metadata_ready, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->hc_on_complete, hc_on_complete, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->got_slice, got_slice, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->send_done, send_done, elem,
GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_on_complete,
recv_trailing_metadata_on_complete, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete,
elem, grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->on_send_message_next_done,
on_send_message_next_done, elem, grpc_schedule_on_exec_ctx);
return GRPC_ERROR_NONE;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
grpc_closure *ignored) {
call_data *calld = elem->call_data;
grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
}
grpc_closure *ignored) {}
static grpc_mdelem scheme_from_args(const grpc_channel_args *args) {
unsigned i;
@ -580,7 +556,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
}
const grpc_channel_filter grpc_http_client_filter = {
hc_start_transport_op,
hc_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,

@ -61,14 +61,11 @@ typedef struct call_data {
pointer | CANCELLED_BIT - request was cancelled with error pointed to */
gpr_atm send_initial_metadata_state;
grpc_transport_stream_op_batch *send_op;
uint32_t send_length;
uint32_t send_flags;
grpc_slice incoming_slice;
grpc_transport_stream_op_batch *send_message_batch;
grpc_slice_buffer_stream replacement_stream;
grpc_closure *post_send;
grpc_closure send_done;
grpc_closure got_slice;
grpc_closure *original_send_message_on_complete;
grpc_closure send_message_on_complete;
grpc_closure on_send_message_next_done;
} call_data;
typedef struct channel_data {
@ -164,24 +161,25 @@ static grpc_error *process_send_initial_metadata(
return error;
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem);
static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
static void send_message_on_complete(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = (grpc_call_element *)arg;
call_data *calld = (call_data *)elem->call_data;
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices);
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
GRPC_CLOSURE_RUN(exec_ctx, calld->original_send_message_on_complete,
GRPC_ERROR_REF(error));
}
static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
int did_compress;
call_data *calld = (call_data *)elem->call_data;
// Compress the data if appropriate.
grpc_slice_buffer tmp;
grpc_slice_buffer_init(&tmp);
did_compress = grpc_msg_compress(exec_ctx, calld->compression_algorithm,
&calld->slices, &tmp);
uint32_t send_flags =
calld->send_message_batch->payload->send_message.send_message->flags;
const bool did_compress = grpc_msg_compress(
exec_ctx, calld->compression_algorithm, &calld->slices, &tmp);
if (did_compress) {
if (GRPC_TRACER_ON(grpc_compression_trace)) {
char *algo_name;
@ -195,7 +193,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
algo_name, before_size, after_size, 100 * savings_ratio);
}
grpc_slice_buffer_swap(&calld->slices, &tmp);
calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
} else {
if (GRPC_TRACER_ON(grpc_compression_trace)) {
char *algo_name;
@ -207,83 +205,118 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
algo_name, calld->slices.length);
}
}
grpc_slice_buffer_destroy_internal(exec_ctx, &tmp);
// Swap out the original byte stream with our new one and send the
// batch down.
grpc_byte_stream_destroy(
exec_ctx, calld->send_message_batch->payload->send_message.send_message);
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
calld->send_op->payload->send_message.send_message =
send_flags);
calld->send_message_batch->payload->send_message.send_message =
&calld->replacement_stream.base;
calld->post_send = calld->send_op->on_complete;
calld->send_op->on_complete = &calld->send_done;
grpc_call_next_op(exec_ctx, elem, calld->send_op);
calld->original_send_message_on_complete =
calld->send_message_batch->on_complete;
calld->send_message_batch->on_complete = &calld->send_message_on_complete;
grpc_call_next_op(exec_ctx, elem, calld->send_message_batch);
}
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
if (GRPC_ERROR_NONE !=
grpc_byte_stream_pull(exec_ctx,
calld->send_op->payload->send_message.send_message,
&calld->incoming_slice)) {
/* Should never reach here */
abort();
}
grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
finish_send_message(exec_ctx, elem);
} else {
continue_send_message(exec_ctx, elem);
// Pulls a slice from the send_message byte stream and adds it to calld->slices.
static grpc_error *pull_slice_from_send_message(grpc_exec_ctx *exec_ctx,
call_data *calld) {
grpc_slice incoming_slice;
grpc_error *error = grpc_byte_stream_pull(
exec_ctx, calld->send_message_batch->payload->send_message.send_message,
&incoming_slice);
if (error == GRPC_ERROR_NONE) {
grpc_slice_buffer_add(&calld->slices, incoming_slice);
}
return error;
}
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
// Reads as many slices as possible from the send_message byte stream.
// If all data has been read, invokes finish_send_message(). Otherwise,
// an async call to grpc_byte_stream_next() has been started, which will
// eventually result in calling on_send_message_next_done().
static grpc_error *continue_reading_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = (call_data *)elem->call_data;
while (grpc_byte_stream_next(
exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0,
&calld->got_slice)) {
grpc_byte_stream_pull(exec_ctx,
calld->send_op->payload->send_message.send_message,
&calld->incoming_slice);
grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
exec_ctx, calld->send_message_batch->payload->send_message.send_message,
~(size_t)0, &calld->on_send_message_next_done)) {
grpc_error *error = pull_slice_from_send_message(exec_ctx, calld);
if (error != GRPC_ERROR_NONE) return error;
if (calld->slices.length ==
calld->send_message_batch->payload->send_message.send_message->length) {
finish_send_message(exec_ctx, elem);
break;
}
}
return GRPC_ERROR_NONE;
}
static void handle_send_message_batch(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op_batch *op,
bool has_compression_algorithm) {
call_data *calld = elem->call_data;
if (!skip_compression(elem, op->payload->send_message.send_message->flags,
// Async callback for grpc_byte_stream_next().
static void on_send_message_next_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_call_element *elem = (grpc_call_element *)arg;
call_data *calld = (call_data *)elem->call_data;
if (error != GRPC_ERROR_NONE) goto fail;
error = pull_slice_from_send_message(exec_ctx, calld);
if (error != GRPC_ERROR_NONE) goto fail;
if (calld->slices.length ==
calld->send_message_batch->payload->send_message.send_message->length) {
finish_send_message(exec_ctx, elem);
} else {
// This will either finish reading all of the data and invoke
// finish_send_message(), or else it will make an async call to
// grpc_byte_stream_next(), which will eventually result in calling
// this function again.
error = continue_reading_send_message(exec_ctx, elem);
if (error != GRPC_ERROR_NONE) goto fail;
}
return;
fail:
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, calld->send_message_batch, error);
}
static void start_send_message_batch(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op_batch *batch,
bool has_compression_algorithm) {
call_data *calld = (call_data *)elem->call_data;
if (!skip_compression(elem, batch->payload->send_message.send_message->flags,
has_compression_algorithm)) {
calld->send_op = op;
calld->send_length = op->payload->send_message.send_message->length;
calld->send_flags = op->payload->send_message.send_message->flags;
continue_send_message(exec_ctx, elem);
calld->send_message_batch = batch;
// This will either finish reading all of the data and invoke
// finish_send_message(), or else it will make an async call to
// grpc_byte_stream_next(), which will eventually result in calling
// on_send_message_next_done().
grpc_error *error = continue_reading_send_message(exec_ctx, elem);
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, calld->send_message_batch, error);
}
} else {
/* pass control down the stack */
grpc_call_next_op(exec_ctx, elem, op);
grpc_call_next_op(exec_ctx, elem, batch);
}
}
static void compress_start_transport_stream_op_batch(
grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_transport_stream_op_batch *op) {
grpc_transport_stream_op_batch *batch) {
call_data *calld = elem->call_data;
GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0);
if (op->cancel_stream) {
GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error);
if (batch->cancel_stream) {
// TODO(roth): As part of the upcoming call combiner work, change
// this to call grpc_byte_stream_shutdown() on the incoming byte
// stream, to cancel any in-flight calls to grpc_byte_stream_next().
GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
gpr_atm cur = gpr_atm_full_xchg(
&calld->send_initial_metadata_state,
CANCELLED_BIT | (gpr_atm)op->payload->cancel_stream.cancel_error);
CANCELLED_BIT | (gpr_atm)batch->payload->cancel_stream.cancel_error);
switch (cur) {
case HAS_COMPRESSION_ALGORITHM:
case NO_COMPRESSION_ALGORITHM:
@ -293,7 +326,7 @@ static void compress_start_transport_stream_op_batch(
if ((cur & CANCELLED_BIT) == 0) {
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, (grpc_transport_stream_op_batch *)cur,
GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error));
} else {
GRPC_ERROR_UNREF((grpc_error *)(cur & ~CANCELLED_BIT));
}
@ -301,14 +334,15 @@ static void compress_start_transport_stream_op_batch(
}
}
if (op->send_initial_metadata) {
if (batch->send_initial_metadata) {
bool has_compression_algorithm;
grpc_error *error = process_send_initial_metadata(
exec_ctx, elem,
op->payload->send_initial_metadata.send_initial_metadata,
batch->payload->send_initial_metadata.send_initial_metadata,
&has_compression_algorithm);
if (error != GRPC_ERROR_NONE) {
grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch,
error);
return;
}
gpr_atm cur;
@ -324,32 +358,32 @@ static void compress_start_transport_stream_op_batch(
goto retry_send_im;
}
if (cur != INITIAL_METADATA_UNSEEN) {
handle_send_message_batch(exec_ctx, elem,
(grpc_transport_stream_op_batch *)cur,
has_compression_algorithm);
start_send_message_batch(exec_ctx, elem,
(grpc_transport_stream_op_batch *)cur,
has_compression_algorithm);
}
}
}
if (op->send_message) {
if (batch->send_message) {
gpr_atm cur;
retry_send:
cur = gpr_atm_acq_load(&calld->send_initial_metadata_state);
switch (cur) {
case INITIAL_METADATA_UNSEEN:
if (!gpr_atm_rel_cas(&calld->send_initial_metadata_state, cur,
(gpr_atm)op)) {
(gpr_atm)batch)) {
goto retry_send;
}
break;
case HAS_COMPRESSION_ALGORITHM:
case NO_COMPRESSION_ALGORITHM:
handle_send_message_batch(exec_ctx, elem, op,
cur == HAS_COMPRESSION_ALGORITHM);
start_send_message_batch(exec_ctx, elem, batch,
cur == HAS_COMPRESSION_ALGORITHM);
break;
default:
if (cur & CANCELLED_BIT) {
grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, op,
exec_ctx, batch,
GRPC_ERROR_REF((grpc_error *)(cur & ~CANCELLED_BIT)));
} else {
/* >1 send_message concurrently */
@ -358,7 +392,7 @@ static void compress_start_transport_stream_op_batch(
}
} else {
/* pass control down the stack */
grpc_call_next_op(exec_ctx, elem, op);
grpc_call_next_op(exec_ctx, elem, batch);
}
GPR_TIMER_END("compress_start_transport_stream_op_batch", 0);
@ -373,10 +407,10 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
/* initialize members */
grpc_slice_buffer_init(&calld->slices);
GRPC_CLOSURE_INIT(&calld->got_slice, got_slice, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->send_done, send_done, elem,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->on_send_message_next_done,
on_send_message_next_done, elem, grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete,
elem, grpc_schedule_on_exec_ctx);
return GRPC_ERROR_NONE;
}

@ -730,6 +730,14 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
grpc_slice_buffer_destroy_internal(exec_ctx,
&s->unprocessed_incoming_frames_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, &s->frame_storage);
if (s->compressed_data_buffer) {
grpc_slice_buffer_destroy_internal(exec_ctx, s->compressed_data_buffer);
gpr_free(s->compressed_data_buffer);
}
if (s->decompressed_data_buffer) {
grpc_slice_buffer_destroy_internal(exec_ctx, s->decompressed_data_buffer);
gpr_free(s->decompressed_data_buffer);
}
grpc_chttp2_list_remove_stalled_by_transport(t, s);
grpc_chttp2_list_remove_stalled_by_stream(t, s);
@ -780,6 +788,15 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
if (s->stream_compression_ctx != NULL) {
grpc_stream_compression_context_destroy(s->stream_compression_ctx);
s->stream_compression_ctx = NULL;
}
if (s->stream_decompression_ctx != NULL) {
grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
s->stream_decompression_ctx = NULL;
}
s->destroy_stream_arg = then_schedule_closure;
GRPC_CLOSURE_SCHED(
exec_ctx, GRPC_CLOSURE_INIT(&s->destroy_stream, destroy_stream_locked, s,
@ -1173,6 +1190,7 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx,
return; /* early out */
}
if (s->fetched_send_message_length == s->fetching_send_message->length) {
grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message);
int64_t notify_offset = s->next_message_end_offset;
if (notify_offset <= s->flow_controlled_bytes_written) {
grpc_chttp2_complete_closure_step(
@ -1195,9 +1213,14 @@ static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx,
return; /* early out */
} else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message,
UINT32_MAX, &s->complete_fetch_locked)) {
grpc_byte_stream_pull(exec_ctx, s->fetching_send_message,
&s->fetching_slice);
add_fetched_slice_locked(exec_ctx, t, s);
grpc_error *error = grpc_byte_stream_pull(
exec_ctx, s->fetching_send_message, &s->fetching_slice);
if (error != GRPC_ERROR_NONE) {
grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message);
grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
} else {
add_fetched_slice_locked(exec_ctx, t, s);
}
}
}
}
@ -1214,10 +1237,9 @@ static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs,
continue_fetching_send_locked(exec_ctx, t, s);
}
}
if (error != GRPC_ERROR_NONE) {
/* TODO(ctiller): what to do here */
abort();
grpc_byte_stream_destroy(exec_ctx, s->fetching_send_message);
grpc_chttp2_cancel_stream(exec_ctx, t, s, error);
}
}
@ -1362,8 +1384,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
"fetching_send_message_finished");
} else {
GPR_ASSERT(s->fetching_send_message == NULL);
uint8_t *frame_hdr =
grpc_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5);
uint8_t *frame_hdr = grpc_slice_buffer_tiny_add(
&s->flow_controlled_buffer, GRPC_HEADER_SIZE_IN_BYTES);
uint32_t flags = op_payload->send_message.send_message->flags;
frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
size_t len = op_payload->send_message.send_message->length;
@ -1454,14 +1476,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
s->recv_message_ready = op_payload->recv_message.recv_message_ready;
s->recv_message = op_payload->recv_message.recv_message;
if (s->id != 0) {
if (s->pending_byte_stream) {
already_received = s->frame_storage.length;
} else {
already_received = s->frame_storage.length +
s->unprocessed_incoming_frames_buffer.length;
}
incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5,
already_received);
already_received = s->frame_storage.length;
incoming_byte_stream_update_flow_control(
exec_ctx, t, s, GRPC_HEADER_SIZE_IN_BYTES, already_received);
}
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
}
@ -1698,10 +1715,43 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx,
if (s->unprocessed_incoming_frames_buffer.length == 0) {
grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer,
&s->frame_storage);
s->unprocessed_incoming_frames_decompressed = false;
}
if (s->stream_compression_recv_enabled &&
!s->unprocessed_incoming_frames_decompressed) {
GPR_ASSERT(s->decompressed_data_buffer->length == 0);
bool end_of_context;
if (!s->stream_decompression_ctx) {
s->stream_decompression_ctx =
grpc_stream_compression_context_create(
GRPC_STREAM_COMPRESSION_DECOMPRESS);
}
if (!grpc_stream_decompress(s->stream_decompression_ctx,
&s->unprocessed_incoming_frames_buffer,
s->decompressed_data_buffer, NULL,
GRPC_HEADER_SIZE_IN_BYTES,
&end_of_context)) {
grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
&s->frame_storage);
grpc_slice_buffer_reset_and_unref_internal(
exec_ctx, &s->unprocessed_incoming_frames_buffer);
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Stream decompression error.");
} else {
error = grpc_deframe_unprocessed_incoming_frames(
exec_ctx, &s->data_parser, s, s->decompressed_data_buffer, NULL,
s->recv_message);
if (end_of_context) {
grpc_stream_compression_context_destroy(
s->stream_decompression_ctx);
s->stream_decompression_ctx = NULL;
}
}
} else {
error = grpc_deframe_unprocessed_incoming_frames(
exec_ctx, &s->data_parser, s,
&s->unprocessed_incoming_frames_buffer, NULL, s->recv_message);
}
error = grpc_deframe_unprocessed_incoming_frames(
exec_ctx, &s->data_parser, s,
&s->unprocessed_incoming_frames_buffer, NULL, s->recv_message);
if (error != GRPC_ERROR_NONE) {
s->seen_error = true;
grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
@ -1739,7 +1789,37 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
}
bool pending_data = s->pending_byte_stream ||
s->unprocessed_incoming_frames_buffer.length > 0;
if (s->stream_compression_recv_enabled && s->read_closed &&
s->frame_storage.length > 0 &&
s->unprocessed_incoming_frames_buffer.length == 0 && !pending_data &&
!s->seen_error && s->recv_trailing_metadata_finished != NULL) {
/* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and
* maybe decompress the next 5 bytes in the stream. */
bool end_of_context;
if (!s->stream_decompression_ctx) {
s->stream_decompression_ctx = grpc_stream_compression_context_create(
GRPC_STREAM_COMPRESSION_DECOMPRESS);
}
if (!grpc_stream_decompress(s->stream_decompression_ctx,
&s->frame_storage,
&s->unprocessed_incoming_frames_buffer, NULL,
GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) {
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &s->frame_storage);
grpc_slice_buffer_reset_and_unref_internal(
exec_ctx, &s->unprocessed_incoming_frames_buffer);
s->seen_error = true;
} else {
if (s->unprocessed_incoming_frames_buffer.length > 0) {
s->unprocessed_incoming_frames_decompressed = true;
}
if (end_of_context) {
grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
s->stream_decompression_ctx = NULL;
}
}
}
if (s->read_closed && s->frame_storage.length == 0 &&
s->unprocessed_incoming_frames_buffer.length == 0 &&
(!pending_data || s->seen_error) &&
s->recv_trailing_metadata_finished != NULL) {
grpc_chttp2_incoming_metadata_buffer_publish(
@ -2607,6 +2687,7 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
if (s->frame_storage.length > 0) {
grpc_slice_buffer_swap(&s->frame_storage,
&s->unprocessed_incoming_frames_buffer);
s->unprocessed_incoming_frames_decompressed = false;
GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE);
} else if (s->byte_stream_error != GRPC_ERROR_NONE) {
GRPC_CLOSURE_SCHED(exec_ctx, bs->next_action.on_complete,
@ -2668,17 +2749,41 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs =
(grpc_chttp2_incoming_byte_stream *)byte_stream;
grpc_chttp2_stream *s = bs->stream;
grpc_error *error;
if (s->unprocessed_incoming_frames_buffer.length > 0) {
grpc_error *error = grpc_deframe_unprocessed_incoming_frames(
if (s->stream_compression_recv_enabled &&
!s->unprocessed_incoming_frames_decompressed) {
bool end_of_context;
if (!s->stream_decompression_ctx) {
s->stream_decompression_ctx = grpc_stream_compression_context_create(
GRPC_STREAM_COMPRESSION_DECOMPRESS);
}
if (!grpc_stream_decompress(s->stream_decompression_ctx,
&s->unprocessed_incoming_frames_buffer,
s->decompressed_data_buffer, NULL, MAX_SIZE_T,
&end_of_context)) {
error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream decompression error.");
return error;
}
GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0);
grpc_slice_buffer_swap(&s->unprocessed_incoming_frames_buffer,
s->decompressed_data_buffer);
s->unprocessed_incoming_frames_decompressed = true;
if (end_of_context) {
grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
s->stream_decompression_ctx = NULL;
}
}
error = grpc_deframe_unprocessed_incoming_frames(
exec_ctx, &s->data_parser, s, &s->unprocessed_incoming_frames_buffer,
slice, NULL);
if (error != GRPC_ERROR_NONE) {
return error;
}
} else {
grpc_error *error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Truncated message");
GRPC_CLOSURE_SCHED(exec_ctx, &s->reset_byte_stream, GRPC_ERROR_REF(error));
return error;
}
@ -2686,22 +2791,9 @@ static grpc_error *incoming_byte_stream_pull(grpc_exec_ctx *exec_ctx,
return GRPC_ERROR_NONE;
}
static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream);
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
void *byte_stream,
grpc_error *error_ignored) {
grpc_chttp2_incoming_byte_stream *bs = byte_stream;
grpc_chttp2_stream *s = bs->stream;
grpc_chttp2_transport *t = s->t;
GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy);
incoming_byte_stream_unref(exec_ctx, bs);
s->pending_byte_stream = false;
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
grpc_error *error_ignored);
static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {
@ -2768,6 +2860,33 @@ grpc_error *grpc_chttp2_incoming_byte_stream_finished(
return error;
}
static void incoming_byte_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_error *error) {
grpc_chttp2_incoming_byte_stream *bs =
(grpc_chttp2_incoming_byte_stream *)byte_stream;
GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
exec_ctx, bs, error, true /* reset_on_error */));
}
static const grpc_byte_stream_vtable grpc_chttp2_incoming_byte_stream_vtable = {
incoming_byte_stream_next, incoming_byte_stream_pull,
incoming_byte_stream_shutdown, incoming_byte_stream_destroy};
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
void *byte_stream,
grpc_error *error_ignored) {
grpc_chttp2_incoming_byte_stream *bs = byte_stream;
grpc_chttp2_stream *s = bs->stream;
grpc_chttp2_transport *t = s->t;
GPR_ASSERT(bs->base.vtable == &grpc_chttp2_incoming_byte_stream_vtable);
incoming_byte_stream_unref(exec_ctx, bs);
s->pending_byte_stream = false;
grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
uint32_t frame_size, uint32_t flags) {
@ -2776,9 +2895,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
incoming_byte_stream->base.length = frame_size;
incoming_byte_stream->remaining_bytes = frame_size;
incoming_byte_stream->base.flags = flags;
incoming_byte_stream->base.next = incoming_byte_stream_next;
incoming_byte_stream->base.pull = incoming_byte_stream_pull;
incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
incoming_byte_stream->base.vtable = &grpc_chttp2_incoming_byte_stream_vtable;
gpr_ref_init(&incoming_byte_stream->refs, 2);
incoming_byte_stream->transport = t;
incoming_byte_stream->stream = s;

@ -293,7 +293,6 @@ grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
grpc_slice slice, int is_last) {
/* grpc_error *error = parse_inner_buffer(exec_ctx, p, t, s, slice); */
if (!s->pending_byte_stream) {
grpc_slice_ref_internal(slice);
grpc_slice_buffer_add(&s->frame_storage, slice);
@ -304,6 +303,7 @@ grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_slice_buffer_add(&s->unprocessed_incoming_frames_buffer, slice);
GRPC_CLOSURE_SCHED(exec_ctx, s->on_next, GRPC_ERROR_NONE);
s->on_next = NULL;
s->unprocessed_incoming_frames_decompressed = false;
} else {
grpc_slice_ref_internal(slice);
grpc_slice_buffer_add(&s->frame_storage, slice);

@ -526,6 +526,26 @@ struct grpc_chttp2_stream {
grpc_chttp2_write_cb *on_write_finished_cbs;
grpc_chttp2_write_cb *finish_after_write;
size_t sending_bytes;
/** Whether stream compression send is enabled */
bool stream_compression_recv_enabled;
/** Whether stream compression recv is enabled */
bool stream_compression_send_enabled;
/** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed
*/
bool unprocessed_incoming_frames_decompressed;
/** Stream compression decompress context */
grpc_stream_compression_context *stream_decompression_ctx;
/** Stream compression compress context */
grpc_stream_compression_context *stream_compression_ctx;
/** Buffer storing data that is compressed but not sent */
grpc_slice_buffer *compressed_data_buffer;
/** Amount of uncompressed bytes sent out when compressed_data_buffer is
* emptied */
size_t uncompressed_data_size;
/** Temporary buffer storing decompressed data */
grpc_slice_buffer *decompressed_data_buffer;
};
/** Transport writing call flow:
@ -621,6 +641,9 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
grpc_closure **pclosure,
grpc_error *error, const char *desc);
#define GRPC_HEADER_SIZE_IN_BYTES 5
#define MAX_SIZE_T (~(size_t)0)
#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
(sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)

@ -303,7 +303,9 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
}
if (sent_initial_metadata) {
/* send any body bytes, if allowed by flow control */
if (s->flow_controlled_buffer.length > 0) {
if (s->flow_controlled_buffer.length > 0 ||
(s->stream_compression_send_enabled &&
s->compressed_data_buffer->length > 0)) {
uint32_t stream_outgoing_window = (uint32_t)GPR_MAX(
0,
s->outgoing_window_delta +
@ -314,21 +316,63 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
GPR_MIN(stream_outgoing_window, t->outgoing_window));
if (max_outgoing > 0) {
uint32_t send_bytes =
(uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length);
bool is_last_data_frame =
s->fetching_send_message == NULL &&
send_bytes == s->flow_controlled_buffer.length;
bool is_last_frame =
is_last_data_frame && s->send_trailing_metadata != NULL &&
grpc_metadata_batch_is_empty(s->send_trailing_metadata);
grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes,
is_last_frame, &s->stats.outgoing,
&t->outbuf);
GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta,
send_bytes);
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window,
send_bytes);
bool is_last_data_frame = false;
bool is_last_frame = false;
if (s->stream_compression_send_enabled) {
while ((s->flow_controlled_buffer.length > 0 ||
s->compressed_data_buffer->length > 0) &&
max_outgoing > 0) {
if (s->compressed_data_buffer->length > 0) {
uint32_t send_bytes = (uint32_t)GPR_MIN(
max_outgoing, s->compressed_data_buffer->length);
is_last_data_frame =
(send_bytes == s->compressed_data_buffer->length &&
s->flow_controlled_buffer.length == 0 &&
s->fetching_send_message == NULL);
is_last_frame =
is_last_data_frame && s->send_trailing_metadata != NULL &&
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_FLOW_DEBIT_STREAM(
"write", t, s, outgoing_window_delta, send_bytes);
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window,
send_bytes);
max_outgoing -= send_bytes;
if (s->compressed_data_buffer->length == 0) {
s->sending_bytes += s->uncompressed_data_size;
}
} else {
if (s->stream_compression_ctx == NULL) {
s->stream_compression_ctx =
grpc_stream_compression_context_create(
GRPC_STREAM_COMPRESSION_COMPRESS);
}
s->uncompressed_data_size = s->flow_controlled_buffer.length;
GPR_ASSERT(grpc_stream_compress(
s->stream_compression_ctx, &s->flow_controlled_buffer,
s->compressed_data_buffer, NULL, MAX_SIZE_T,
GRPC_STREAM_COMPRESSION_FLUSH_SYNC));
}
}
} else {
uint32_t send_bytes = (uint32_t)GPR_MIN(
max_outgoing, s->flow_controlled_buffer.length);
is_last_data_frame = s->fetching_send_message == NULL &&
send_bytes == s->flow_controlled_buffer.length;
is_last_frame =
is_last_data_frame && s->send_trailing_metadata != NULL &&
grpc_metadata_batch_is_empty(s->send_trailing_metadata);
grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer,
send_bytes, is_last_frame,
&s->stats.outgoing, &t->outbuf);
GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window_delta,
send_bytes);
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window,
send_bytes);
s->sending_bytes += send_bytes;
}
t->ping_state.pings_before_data_required =
t->ping_policy.max_pings_without_data;
if (!t->is_client) {
@ -345,9 +389,10 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
&s->stats.outgoing));
}
}
s->sending_bytes += send_bytes;
now_writing = true;
if (s->flow_controlled_buffer.length > 0) {
if (s->flow_controlled_buffer.length > 0 ||
(s->stream_compression_send_enabled &&
s->compressed_data_buffer->length > 0)) {
GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork");
grpc_chttp2_list_add_writable_stream(t, s);
}
@ -361,7 +406,9 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write(
}
if (s->send_trailing_metadata != NULL &&
s->fetching_send_message == NULL &&
s->flow_controlled_buffer.length == 0) {
s->flow_controlled_buffer.length == 0 &&
(!s->stream_compression_send_enabled ||
s->compressed_data_buffer->length == 0)) {
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata"));
if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) {
grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true,

@ -968,6 +968,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
s->header_array.capacity = s->header_array.count;
CRONET_LOG(GPR_DEBUG, "bidirectional_stream_start(%p, %s)", s->cbs, url);
bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array, false);
if (url) {
gpr_free(url);
}
unsigned int header_index;
for (header_index = 0; header_index < s->header_array.count;
header_index++) {

@ -72,6 +72,7 @@ typedef struct sb_list_entry {
typedef struct {
grpc_byte_stream base;
sb_list_entry *le;
grpc_error *shutdown_error;
} inproc_slice_byte_stream;
typedef struct {
@ -201,24 +202,39 @@ static grpc_error *inproc_slice_byte_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *bs,
grpc_slice *slice) {
inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
if (stream->shutdown_error != GRPC_ERROR_NONE) {
return GRPC_ERROR_REF(stream->shutdown_error);
}
*slice = grpc_slice_buffer_take_first(&stream->le->sb);
return GRPC_ERROR_NONE;
}
static void inproc_slice_byte_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *bs,
grpc_error *error) {
inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
GRPC_ERROR_UNREF(stream->shutdown_error);
stream->shutdown_error = error;
}
static void inproc_slice_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *bs) {
inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
sb_list_entry_destroy(exec_ctx, stream->le);
GRPC_ERROR_UNREF(stream->shutdown_error);
}
static const grpc_byte_stream_vtable inproc_slice_byte_stream_vtable = {
inproc_slice_byte_stream_next, inproc_slice_byte_stream_pull,
inproc_slice_byte_stream_shutdown, inproc_slice_byte_stream_destroy};
void inproc_slice_byte_stream_init(inproc_slice_byte_stream *s,
sb_list_entry *le) {
s->base.length = (uint32_t)le->sb.length;
s->base.flags = 0;
s->base.next = inproc_slice_byte_stream_next;
s->base.pull = inproc_slice_byte_stream_pull;
s->base.destroy = inproc_slice_byte_stream_destroy;
s->base.vtable = &inproc_slice_byte_stream_vtable;
s->le = le;
s->shutdown_error = GRPC_ERROR_NONE;
}
static void ref_transport(inproc_transport *t) {
@ -956,11 +972,18 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
GPR_ASSERT(grpc_byte_stream_next(exec_ctx,
op->payload->send_message.send_message,
SIZE_MAX, &unused));
grpc_byte_stream_pull(exec_ctx, op->payload->send_message.send_message,
&message_slice);
error = grpc_byte_stream_pull(
exec_ctx, op->payload->send_message.send_message, &message_slice);
if (error != GRPC_ERROR_NONE) {
cancel_stream_locked(exec_ctx, s, GRPC_ERROR_REF(error));
break;
}
GPR_ASSERT(error == GRPC_ERROR_NONE);
remaining -= GRPC_SLICE_LENGTH(message_slice);
grpc_slice_buffer_add(dest, message_slice);
} while (remaining != 0);
grpc_byte_stream_destroy(exec_ctx,
op->payload->send_message.send_message);
}
if (error == GRPC_ERROR_NONE && op->send_trailing_metadata) {
grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md

@ -73,10 +73,8 @@ static const grpc_closure_scheduler_vtable finally_scheduler = {
static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
grpc_combiner *grpc_combiner_create(void) {
grpc_combiner *lock = gpr_malloc(sizeof(*lock));
grpc_combiner *lock = gpr_zalloc(sizeof(*lock));
gpr_ref_init(&lock->refs, 1);
lock->next_combiner_on_this_exec_ctx = NULL;
lock->time_to_execute_final_list = false;
lock->scheduler.vtable = &scheduler;
lock->finally_scheduler.vtable = &finally_scheduler;
gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED);

@ -0,0 +1,104 @@
/*
*
* 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_IOMGR_NAMESER_H
#define GRPC_CORE_LIB_IOMGR_NAMESER_H
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_HAVE_ARPA_NAMESER
#include <arpa/nameser.h>
#else /* GRPC_HAVE_ARPA_NAMESER */
typedef enum __ns_class {
ns_c_invalid = 0, /* Cookie. */
ns_c_in = 1, /* Internet. */
ns_c_2 = 2, /* unallocated/unsupported. */
ns_c_chaos = 3, /* MIT Chaos-net. */
ns_c_hs = 4, /* MIT Hesiod. */
/* Query class values which do not appear in resource records */
ns_c_none = 254, /* for prereq. sections in update requests */
ns_c_any = 255, /* Wildcard match. */
ns_c_max = 65536
} ns_class;
typedef enum __ns_type {
ns_t_invalid = 0, /* Cookie. */
ns_t_a = 1, /* Host address. */
ns_t_ns = 2, /* Authoritative server. */
ns_t_md = 3, /* Mail destination. */
ns_t_mf = 4, /* Mail forwarder. */
ns_t_cname = 5, /* Canonical name. */
ns_t_soa = 6, /* Start of authority zone. */
ns_t_mb = 7, /* Mailbox domain name. */
ns_t_mg = 8, /* Mail group member. */
ns_t_mr = 9, /* Mail rename name. */
ns_t_null = 10, /* Null resource record. */
ns_t_wks = 11, /* Well known service. */
ns_t_ptr = 12, /* Domain name pointer. */
ns_t_hinfo = 13, /* Host information. */
ns_t_minfo = 14, /* Mailbox information. */
ns_t_mx = 15, /* Mail routing information. */
ns_t_txt = 16, /* Text strings. */
ns_t_rp = 17, /* Responsible person. */
ns_t_afsdb = 18, /* AFS cell database. */
ns_t_x25 = 19, /* X_25 calling address. */
ns_t_isdn = 20, /* ISDN calling address. */
ns_t_rt = 21, /* Router. */
ns_t_nsap = 22, /* NSAP address. */
ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
ns_t_sig = 24, /* Security signature. */
ns_t_key = 25, /* Security key. */
ns_t_px = 26, /* X.400 mail mapping. */
ns_t_gpos = 27, /* Geographical position (withdrawn). */
ns_t_aaaa = 28, /* Ip6 Address. */
ns_t_loc = 29, /* Location Information. */
ns_t_nxt = 30, /* Next domain (security). */
ns_t_eid = 31, /* Endpoint identifier. */
ns_t_nimloc = 32, /* Nimrod Locator. */
ns_t_srv = 33, /* Server Selection. */
ns_t_atma = 34, /* ATM Address */
ns_t_naptr = 35, /* Naming Authority PoinTeR */
ns_t_kx = 36, /* Key Exchange */
ns_t_cert = 37, /* Certification record */
ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
ns_t_sink = 40, /* Kitchen sink (experimentatl) */
ns_t_opt = 41, /* EDNS0 option (meta-RR) */
ns_t_apl = 42, /* Address prefix list (RFC3123) */
ns_t_ds = 43, /* Delegation Signer (RFC4034) */
ns_t_sshfp = 44, /* SSH Key Fingerprint (RFC4255) */
ns_t_rrsig = 46, /* Resource Record Signature (RFC4034) */
ns_t_nsec = 47, /* Next Secure (RFC4034) */
ns_t_dnskey = 48, /* DNS Public Key (RFC4034) */
ns_t_tkey = 249, /* Transaction key */
ns_t_tsig = 250, /* Transaction signature. */
ns_t_ixfr = 251, /* Incremental zone transfer. */
ns_t_axfr = 252, /* Transfer zone of authority. */
ns_t_mailb = 253, /* Transfer mailbox records. */
ns_t_maila = 254, /* Transfer mail agent records. */
ns_t_any = 255, /* Wildcard match. */
ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
ns_t_max = 65536
} ns_type;
#endif /* GRPC_HAVE_ARPA_NAMESER */
#endif /* GRPC_CORE_LIB_IOMGR_NAMESER_H */

@ -24,6 +24,7 @@
#if defined(GRPC_UV)
// Do nothing
#elif defined(GPR_MANYLINUX1)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1
@ -51,6 +52,7 @@
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_LINUX)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1
@ -82,6 +84,7 @@
#define GRPC_POSIX_SOCKETUTILS
#endif
#elif defined(GPR_APPLE)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1
@ -93,6 +96,7 @@
#define GRPC_POSIX_WAKEUP_FD 1
#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_FREEBSD)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_SO_NOSIGPIPE 1
@ -104,6 +108,7 @@
#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
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1

@ -39,15 +39,16 @@ static gpr_avl_node *ref_node(gpr_avl_node *node) {
return node;
}
static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) {
static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *user_data) {
if (node == NULL) {
return;
}
if (gpr_unref(&node->refs)) {
vtable->destroy_key(node->key);
vtable->destroy_value(node->value);
unref_node(vtable, node->left);
unref_node(vtable, node->right);
vtable->destroy_key(node->key, user_data);
vtable->destroy_value(node->value, user_data);
unref_node(vtable, node->left, user_data);
unref_node(vtable, node->right, user_data);
gpr_free(node);
}
}
@ -87,30 +88,30 @@ gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left,
}
static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *key) {
void *key, void *user_data) {
long cmp;
if (node == NULL) {
return NULL;
}
cmp = vtable->compare_keys(node->key, key);
cmp = vtable->compare_keys(node->key, key, user_data);
if (cmp == 0) {
return node;
} else if (cmp > 0) {
return get(vtable, node->left, key);
return get(vtable, node->left, key, user_data);
} else {
return get(vtable, node->right, key);
return get(vtable, node->right, key, user_data);
}
}
void *gpr_avl_get(gpr_avl avl, void *key) {
gpr_avl_node *node = get(avl.vtable, avl.root, key);
void *gpr_avl_get(gpr_avl avl, void *key, void *user_data) {
gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data);
return node ? node->value : NULL;
}
int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) {
gpr_avl_node *node = get(avl.vtable, avl.root, key);
int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data) {
gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data);
if (node != NULL) {
*value = node->value;
return 1;
@ -120,70 +121,75 @@ int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) {
static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *n =
new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
new_node(key, value, left, ref_node(right->left)),
ref_node(right->right));
unref_node(vtable, right);
gpr_avl_node *right, void *user_data) {
gpr_avl_node *n = new_node(vtable->copy_key(right->key, user_data),
vtable->copy_value(right->value, user_data),
new_node(key, value, left, ref_node(right->left)),
ref_node(right->right));
unref_node(vtable, right, user_data);
return n;
}
static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *n = new_node(
vtable->copy_key(left->key), vtable->copy_value(left->value),
ref_node(left->left), new_node(key, value, ref_node(left->right), right));
unref_node(vtable, left);
gpr_avl_node *right, void *user_data) {
gpr_avl_node *n =
new_node(vtable->copy_key(left->key, user_data),
vtable->copy_value(left->value, user_data), ref_node(left->left),
new_node(key, value, ref_node(left->right), right));
unref_node(vtable, left, user_data);
return n;
}
static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *right, void *user_data) {
/* rotate_right(..., rotate_left(left), right) */
gpr_avl_node *n = new_node(
vtable->copy_key(left->right->key),
vtable->copy_value(left->right->value),
new_node(vtable->copy_key(left->key), vtable->copy_value(left->value),
ref_node(left->left), ref_node(left->right->left)),
new_node(key, value, ref_node(left->right->right), right));
unref_node(vtable, left);
gpr_avl_node *n =
new_node(vtable->copy_key(left->right->key, user_data),
vtable->copy_value(left->right->value, user_data),
new_node(vtable->copy_key(left->key, user_data),
vtable->copy_value(left->value, user_data),
ref_node(left->left), ref_node(left->right->left)),
new_node(key, value, ref_node(left->right->right), right));
unref_node(vtable, left, user_data);
return n;
}
static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *right, void *user_data) {
/* rotate_left(..., left, rotate_right(right)) */
gpr_avl_node *n = new_node(
vtable->copy_key(right->left->key),
vtable->copy_value(right->left->value),
new_node(key, value, left, ref_node(right->left->left)),
new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
ref_node(right->left->right), ref_node(right->right)));
unref_node(vtable, right);
gpr_avl_node *n =
new_node(vtable->copy_key(right->left->key, user_data),
vtable->copy_value(right->left->value, user_data),
new_node(key, value, left, ref_node(right->left->left)),
new_node(vtable->copy_key(right->key, user_data),
vtable->copy_value(right->value, user_data),
ref_node(right->left->right), ref_node(right->right)));
unref_node(vtable, right, user_data);
return n;
}
static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
gpr_avl_node *right, void *user_data) {
switch (node_height(left) - node_height(right)) {
case 2:
if (node_height(left->left) - node_height(left->right) == -1) {
return assert_invariants(
rotate_left_right(vtable, key, value, left, right));
rotate_left_right(vtable, key, value, left, right, user_data));
} else {
return assert_invariants(rotate_right(vtable, key, value, left, right));
return assert_invariants(
rotate_right(vtable, key, value, left, right, user_data));
}
case -2:
if (node_height(right->left) - node_height(right->right) == 1) {
return assert_invariants(
rotate_right_left(vtable, key, value, left, right));
rotate_right_left(vtable, key, value, left, right, user_data));
} else {
return assert_invariants(rotate_left(vtable, key, value, left, right));
return assert_invariants(
rotate_left(vtable, key, value, left, right, user_data));
}
default:
return assert_invariants(new_node(key, value, left, right));
@ -191,30 +197,32 @@ static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
}
static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node,
void *key, void *value) {
void *key, void *value, void *user_data) {
long cmp;
if (node == NULL) {
return new_node(key, value, NULL, NULL);
}
cmp = vtable->compare_keys(node->key, key);
cmp = vtable->compare_keys(node->key, key, user_data);
if (cmp == 0) {
return new_node(key, value, ref_node(node->left), ref_node(node->right));
} else if (cmp > 0) {
return rebalance(
vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
add_key(vtable, node->left, key, value), ref_node(node->right));
return rebalance(vtable, vtable->copy_key(node->key, user_data),
vtable->copy_value(node->value, user_data),
add_key(vtable, node->left, key, value, user_data),
ref_node(node->right), user_data);
} else {
return rebalance(vtable, vtable->copy_key(node->key),
vtable->copy_value(node->value), ref_node(node->left),
add_key(vtable, node->right, key, value));
return rebalance(
vtable, vtable->copy_key(node->key, user_data),
vtable->copy_value(node->value, user_data), ref_node(node->left),
add_key(vtable, node->right, key, value, user_data), user_data);
}
}
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) {
gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data) {
gpr_avl_node *old_root = avl.root;
avl.root = add_key(avl.vtable, avl.root, key, value);
avl.root = add_key(avl.vtable, avl.root, key, value, user_data);
assert_invariants(avl.root);
unref_node(avl.vtable, old_root);
unref_node(avl.vtable, old_root, user_data);
return avl;
}
@ -233,12 +241,13 @@ static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
}
static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
gpr_avl_node *node, void *key) {
gpr_avl_node *node, void *key,
void *user_data) {
long cmp;
if (node == NULL) {
return NULL;
}
cmp = vtable->compare_keys(node->key, key);
cmp = vtable->compare_keys(node->key, key, user_data);
if (cmp == 0) {
if (node->left == NULL) {
return ref_node(node->right);
@ -246,39 +255,45 @@ static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
return ref_node(node->left);
} else if (node->left->height < node->right->height) {
gpr_avl_node *h = in_order_head(node->right);
return rebalance(vtable, vtable->copy_key(h->key),
vtable->copy_value(h->value), ref_node(node->left),
remove_key(vtable, node->right, h->key));
return rebalance(
vtable, vtable->copy_key(h->key, user_data),
vtable->copy_value(h->value, user_data), ref_node(node->left),
remove_key(vtable, node->right, h->key, user_data), user_data);
} else {
gpr_avl_node *h = in_order_tail(node->left);
return rebalance(
vtable, vtable->copy_key(h->key), vtable->copy_value(h->value),
remove_key(vtable, node->left, h->key), ref_node(node->right));
return rebalance(vtable, vtable->copy_key(h->key, user_data),
vtable->copy_value(h->value, user_data),
remove_key(vtable, node->left, h->key, user_data),
ref_node(node->right), user_data);
}
} else if (cmp > 0) {
return rebalance(
vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
remove_key(vtable, node->left, key), ref_node(node->right));
return rebalance(vtable, vtable->copy_key(node->key, user_data),
vtable->copy_value(node->value, user_data),
remove_key(vtable, node->left, key, user_data),
ref_node(node->right), user_data);
} else {
return rebalance(vtable, vtable->copy_key(node->key),
vtable->copy_value(node->value), ref_node(node->left),
remove_key(vtable, node->right, key));
return rebalance(
vtable, vtable->copy_key(node->key, user_data),
vtable->copy_value(node->value, user_data), ref_node(node->left),
remove_key(vtable, node->right, key, user_data), user_data);
}
}
gpr_avl gpr_avl_remove(gpr_avl avl, void *key) {
gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) {
gpr_avl_node *old_root = avl.root;
avl.root = remove_key(avl.vtable, avl.root, key);
avl.root = remove_key(avl.vtable, avl.root, key, user_data);
assert_invariants(avl.root);
unref_node(avl.vtable, old_root);
unref_node(avl.vtable, old_root, user_data);
return avl;
}
gpr_avl gpr_avl_ref(gpr_avl avl) {
gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) {
ref_node(avl.root);
return avl;
}
void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); }
void gpr_avl_unref(gpr_avl avl, void *user_data) {
unref_node(avl.vtable, avl.root, user_data);
}
int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; }

@ -19,6 +19,7 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/surface/completion_queue.h"
@ -109,7 +110,7 @@ grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
alarm->cq = cq;
alarm->tag = tag;
grpc_cq_begin_op(cq, tag);
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
GRPC_CLOSURE_INIT(&alarm->on_alarm, alarm_cb, alarm,
grpc_schedule_on_exec_ctx);
grpc_timer_init(&exec_ctx, &alarm->alarm,

@ -644,6 +644,8 @@ static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
static grpc_error *error_from_status(grpc_status_code status,
const char *description) {
// copying 'description' is needed to ensure the grpc_call_cancel_with_status
// guarantee that can be short-lived.
return grpc_error_set_int(
grpc_error_set_str(GRPC_ERROR_CREATE_FROM_COPIED_STRING(description),
GRPC_ERROR_STR_GRPC_MESSAGE,
@ -823,7 +825,7 @@ uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
return encodings_accepted_by_peer;
}
static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
static grpc_linked_mdelem *linked_from_md(const grpc_metadata *md) {
return (grpc_linked_mdelem *)&md->internal_data;
}
@ -847,7 +849,7 @@ static int prepare_application_metadata(
for (i = 0; i < total_count; i++) {
const grpc_metadata *md =
get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
grpc_linked_mdelem *l = linked_from_md(md);
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
if (!GRPC_LOG_IF_ERROR("validate_metadata",
grpc_validate_header_key_is_legal(md->key))) {
@ -864,7 +866,7 @@ static int prepare_application_metadata(
for (int j = 0; j < i; j++) {
const grpc_metadata *md =
get_md_elem(metadata, additional_metadata, j, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
grpc_linked_mdelem *l = linked_from_md(md);
GRPC_MDELEM_UNREF(exec_ctx, l->md);
}
return 0;
@ -882,9 +884,12 @@ static int prepare_application_metadata(
}
for (i = 0; i < total_count; i++) {
grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
GRPC_LOG_IF_ERROR(
"prepare_application_metadata",
grpc_metadata_batch_link_tail(exec_ctx, batch, linked_from_md(md)));
grpc_linked_mdelem *l = linked_from_md(md);
grpc_error *error = grpc_metadata_batch_link_tail(exec_ctx, batch, l);
if (error != GRPC_ERROR_NONE) {
GRPC_MDELEM_UNREF(exec_ctx, l->md);
}
GRPC_LOG_IF_ERROR("prepare_application_metadata", error);
}
call->send_extra_metadata_count = 0;
@ -1422,7 +1427,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (nops == 0) {
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag));
grpc_cq_end_op(exec_ctx, call->cq, notify_tag, GRPC_ERROR_NONE,
free_no_op_completion, NULL,
gpr_malloc(sizeof(grpc_cq_completion)));
@ -1723,7 +1728,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
GRPC_CALL_INTERNAL_REF(call, "completion");
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag));
}
gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
@ -1844,6 +1849,8 @@ const char *grpc_call_error_to_string(grpc_call_error error) {
return "GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH";
case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS:
return "GRPC_CALL_ERROR_TOO_MANY_OPERATIONS";
case GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN:
return "GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN";
case GRPC_CALL_OK:
return "GRPC_CALL_OK";
}

@ -59,7 +59,7 @@ void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
GRPC_CLOSURE_INIT(&pr->closure, ping_done, pr, grpc_schedule_on_exec_ctx);
op->send_ping = &pr->closure;
op->bind_pollset = grpc_cq_pollset(cq);
grpc_cq_begin_op(cq, tag);
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
top_elem->filter->start_transport_op(&exec_ctx, top_elem, op);
grpc_exec_ctx_finish(&exec_ctx);
}

@ -196,7 +196,7 @@ typedef struct cq_vtable {
void (*init)(void *data);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq);
void (*destroy)(void *data);
void (*begin_op)(grpc_completion_queue *cq, void *tag);
bool (*begin_op)(grpc_completion_queue *cq, void *tag);
void (*end_op)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, void *tag,
grpc_error *error,
void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
@ -288,8 +288,8 @@ static void cq_shutdown_next(grpc_exec_ctx *exec_ctx,
static void cq_shutdown_pluck(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq);
static void cq_begin_op_for_next(grpc_completion_queue *cq, void *tag);
static void cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag);
static bool cq_begin_op_for_next(grpc_completion_queue *cq, void *tag);
static bool cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag);
static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq, void *tag,
@ -522,33 +522,6 @@ void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx,
}
}
static void cq_begin_op_for_next(grpc_completion_queue *cq, void *tag) {
cq_next_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(!cqd->shutdown_called);
gpr_atm_no_barrier_fetch_add(&cqd->pending_events, 1);
}
static void cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag) {
cq_pluck_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(!cqd->shutdown_called);
gpr_ref(&cqd->pending_events);
}
void grpc_cq_begin_op(grpc_completion_queue *cq, void *tag) {
#ifndef NDEBUG
gpr_mu_lock(cq->mu);
if (cq->outstanding_tag_count == cq->outstanding_tag_capacity) {
cq->outstanding_tag_capacity = GPR_MAX(4, 2 * cq->outstanding_tag_capacity);
cq->outstanding_tags =
gpr_realloc(cq->outstanding_tags, sizeof(*cq->outstanding_tags) *
cq->outstanding_tag_capacity);
}
cq->outstanding_tags[cq->outstanding_tag_count++] = tag;
gpr_mu_unlock(cq->mu);
#endif
cq->vtable->begin_op(cq, tag);
}
#ifndef NDEBUG
static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) {
int found = 0;
@ -576,6 +549,41 @@ static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) {
static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) {}
#endif
static bool cq_begin_op_for_next(grpc_completion_queue *cq, void *tag) {
cq_next_data *cqd = DATA_FROM_CQ(cq);
while (true) {
gpr_atm count = gpr_atm_no_barrier_load(&cqd->pending_events);
if (count == 0) {
return false;
} else if (gpr_atm_no_barrier_cas(&cqd->pending_events, count, count + 1)) {
break;
}
}
return true;
}
static bool cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag) {
cq_pluck_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(!cqd->shutdown_called);
gpr_ref(&cqd->pending_events);
return true;
}
bool grpc_cq_begin_op(grpc_completion_queue *cq, void *tag) {
#ifndef NDEBUG
gpr_mu_lock(cq->mu);
if (cq->outstanding_tag_count == cq->outstanding_tag_capacity) {
cq->outstanding_tag_capacity = GPR_MAX(4, 2 * cq->outstanding_tag_capacity);
cq->outstanding_tags =
gpr_realloc(cq->outstanding_tags, sizeof(*cq->outstanding_tags) *
cq->outstanding_tag_capacity);
}
cq->outstanding_tags[cq->outstanding_tag_count++] = tag;
gpr_mu_unlock(cq->mu);
#endif
return cq->vtable->begin_op(cq, tag);
}
/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
* completion
* type of GRPC_CQ_NEXT) */
@ -855,8 +863,7 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
inconsistent state. If it is the latter, we shold do a 0-timeout poll
so that the thread comes back quickly from poll to make a second
attempt at popping. Not doing this can potentially deadlock this
thread
forever (if the deadline is infinity) */
thread forever (if the deadline is infinity) */
if (cq_event_queue_num_items(&cqd->queue) > 0) {
iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
}
@ -869,10 +876,8 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
if (cq_event_queue_num_items(&cqd->queue) > 0) {
/* Go to the beginning of the loop. No point doing a poll because
(cq->shutdown == true) is only possible when there is no pending
work
(i.e cq->pending_events == 0) and any outstanding
grpc_cq_completion
events are already queued on this cq */
work (i.e cq->pending_events == 0) and any outstanding completion
events should have already been queued on this cq */
continue;
}
@ -909,11 +914,6 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
is_finished_arg.first_loop = false;
}
GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret);
GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "next");
grpc_exec_ctx_finish(&exec_ctx);
GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
if (cq_event_queue_num_items(&cqd->queue) > 0 &&
gpr_atm_no_barrier_load(&cqd->pending_events) > 0) {
gpr_mu_lock(cq->mu);
@ -921,6 +921,11 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
gpr_mu_unlock(cq->mu);
}
GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, &ret);
GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "next");
grpc_exec_ctx_finish(&exec_ctx);
GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
GPR_TIMER_END("grpc_completion_queue_next", 0);
return ret;

@ -72,8 +72,9 @@ void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc);
/* Flag that an operation is beginning: the completion channel will not finish
shutdown until a corrensponding grpc_cq_end_* call is made.
\a tag is currently used only in debug builds. */
void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
\a tag is currently used only in debug builds. Return true on success, and
false if completion_queue has been shutdown. */
bool grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
grpc_cq_begin_op */

@ -1259,7 +1259,7 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
}
/* stay locked, and gather up some stuff to do */
grpc_cq_begin_op(cq, tag);
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
if (server->shutdown_published) {
grpc_cq_end_op(&exec_ctx, cq, tag, GRPC_ERROR_NONE, done_published_shutdown,
NULL, gpr_malloc(sizeof(grpc_cq_completion)));
@ -1446,7 +1446,11 @@ grpc_call_error grpc_server_request_call(
error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
goto done;
}
grpc_cq_begin_op(cq_for_notification, tag);
if (grpc_cq_begin_op(cq_for_notification, tag) == false) {
gpr_free(rc);
error = GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN;
goto done;
}
details->reserved = NULL;
rc->cq_idx = cq_idx;
rc->type = BATCH_CALL;
@ -1496,7 +1500,11 @@ grpc_call_error grpc_server_request_registered_call(
error = GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH;
goto done;
}
grpc_cq_begin_op(cq_for_notification, tag);
if (grpc_cq_begin_op(cq_for_notification, tag) == false) {
gpr_free(rc);
error = GRPC_CALL_ERROR_COMPLETION_QUEUE_SHUTDOWN;
goto done;
}
rc->cq_idx = cq_idx;
rc->type = REGISTERED_CALL;
rc->server = server;

@ -19,29 +19,37 @@
#include "src/core/lib/transport/byte_stream.h"
#include <stdlib.h>
#include <string.h>
#include <grpc/support/log.h>
#include "src/core/lib/slice/slice_internal.h"
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream, size_t max_size_hint,
grpc_closure *on_complete) {
return byte_stream->next(exec_ctx, byte_stream, max_size_hint, on_complete);
bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream, size_t max_size_hint,
grpc_closure *on_complete) {
return byte_stream->vtable->next(exec_ctx, byte_stream, max_size_hint,
on_complete);
}
grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_slice *slice) {
return byte_stream->pull(exec_ctx, byte_stream, slice);
return byte_stream->vtable->pull(exec_ctx, byte_stream, slice);
}
void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_error *error) {
byte_stream->vtable->shutdown(exec_ctx, byte_stream, error);
}
void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {
byte_stream->destroy(exec_ctx, byte_stream);
byte_stream->vtable->destroy(exec_ctx, byte_stream);
}
/* slice_buffer_stream */
// grpc_slice_buffer_stream
static bool slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
@ -56,6 +64,9 @@ static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_slice *slice) {
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
if (stream->shutdown_error != GRPC_ERROR_NONE) {
return GRPC_ERROR_REF(stream->shutdown_error);
}
GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
*slice =
grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]);
@ -63,8 +74,23 @@ static grpc_error *slice_buffer_stream_pull(grpc_exec_ctx *exec_ctx,
return GRPC_ERROR_NONE;
}
static void slice_buffer_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_error *error) {
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
GRPC_ERROR_UNREF(stream->shutdown_error);
stream->shutdown_error = error;
}
static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {}
grpc_byte_stream *byte_stream) {
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
GRPC_ERROR_UNREF(stream->shutdown_error);
}
static const grpc_byte_stream_vtable slice_buffer_stream_vtable = {
slice_buffer_stream_next, slice_buffer_stream_pull,
slice_buffer_stream_shutdown, slice_buffer_stream_destroy};
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
grpc_slice_buffer *slice_buffer,
@ -72,9 +98,89 @@ void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
stream->base.length = (uint32_t)slice_buffer->length;
stream->base.flags = flags;
stream->base.next = slice_buffer_stream_next;
stream->base.pull = slice_buffer_stream_pull;
stream->base.destroy = slice_buffer_stream_destroy;
stream->base.vtable = &slice_buffer_stream_vtable;
stream->backing_buffer = slice_buffer;
stream->cursor = 0;
stream->shutdown_error = GRPC_ERROR_NONE;
}
// grpc_caching_byte_stream
void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache,
grpc_byte_stream *underlying_stream) {
cache->underlying_stream = underlying_stream;
grpc_slice_buffer_init(&cache->cache_buffer);
}
void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream_cache *cache) {
grpc_byte_stream_destroy(exec_ctx, cache->underlying_stream);
grpc_slice_buffer_destroy_internal(exec_ctx, &cache->cache_buffer);
}
static bool caching_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
size_t max_size_hint,
grpc_closure *on_complete) {
grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream;
if (stream->shutdown_error != GRPC_ERROR_NONE) return true;
if (stream->cursor < stream->cache->cache_buffer.count) return true;
return grpc_byte_stream_next(exec_ctx, stream->cache->underlying_stream,
max_size_hint, on_complete);
}
static grpc_error *caching_byte_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_slice *slice) {
grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream;
if (stream->shutdown_error != GRPC_ERROR_NONE) {
return GRPC_ERROR_REF(stream->shutdown_error);
}
if (stream->cursor < stream->cache->cache_buffer.count) {
*slice = grpc_slice_ref_internal(
stream->cache->cache_buffer.slices[stream->cursor]);
++stream->cursor;
return GRPC_ERROR_NONE;
}
grpc_error *error =
grpc_byte_stream_pull(exec_ctx, stream->cache->underlying_stream, slice);
if (error == GRPC_ERROR_NONE) {
++stream->cursor;
grpc_slice_buffer_add(&stream->cache->cache_buffer,
grpc_slice_ref_internal(*slice));
}
return error;
}
static void caching_byte_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_error *error) {
grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream;
GRPC_ERROR_UNREF(stream->shutdown_error);
stream->shutdown_error = GRPC_ERROR_REF(error);
grpc_byte_stream_shutdown(exec_ctx, stream->cache->underlying_stream, error);
}
static void caching_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {
grpc_caching_byte_stream *stream = (grpc_caching_byte_stream *)byte_stream;
GRPC_ERROR_UNREF(stream->shutdown_error);
}
static const grpc_byte_stream_vtable caching_byte_stream_vtable = {
caching_byte_stream_next, caching_byte_stream_pull,
caching_byte_stream_shutdown, caching_byte_stream_destroy};
void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream,
grpc_byte_stream_cache *cache) {
memset(stream, 0, sizeof(*stream));
stream->base.length = cache->underlying_stream->length;
stream->base.flags = cache->underlying_stream->flags;
stream->base.vtable = &caching_byte_stream_vtable;
stream->cache = cache;
stream->shutdown_error = GRPC_ERROR_NONE;
}
void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream) {
stream->cursor = 0;
}

@ -28,52 +28,109 @@
/** Mask of all valid internal flags. */
#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
struct grpc_byte_stream;
typedef struct grpc_byte_stream grpc_byte_stream;
struct grpc_byte_stream {
uint32_t length;
uint32_t flags;
typedef struct {
bool (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
size_t max_size_hint, grpc_closure *on_complete);
grpc_error *(*pull)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
grpc_slice *slice);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
grpc_error *error);
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream);
} grpc_byte_stream_vtable;
struct grpc_byte_stream {
uint32_t length;
uint32_t flags;
const grpc_byte_stream_vtable *vtable;
};
/* returns 1 if the bytes are available immediately (in which case
* on_complete will not be called), 0 if the bytes will be available
* asynchronously.
*
* max_size_hint can be set as a hint as to the maximum number
* of bytes that would be acceptable to read.
*/
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream, size_t max_size_hint,
grpc_closure *on_complete);
// Returns true if the bytes are available immediately (in which case
// on_complete will not be called), false if the bytes will be available
// asynchronously.
//
// max_size_hint can be set as a hint as to the maximum number
// of bytes that would be acceptable to read.
bool grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream, size_t max_size_hint,
grpc_closure *on_complete);
/* returns the next slice in the byte stream when it is ready (indicated by
* either grpc_byte_stream_next returning 1 or on_complete passed to
* grpc_byte_stream_next is called).
*
* once a slice is returned into *slice, it is owned by the caller.
*/
// Returns the next slice in the byte stream when it is ready (indicated by
// either grpc_byte_stream_next returning true or on_complete passed to
// grpc_byte_stream_next is called).
//
// Once a slice is returned into *slice, it is owned by the caller.
grpc_error *grpc_byte_stream_pull(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_slice *slice);
// Shuts down the byte stream.
//
// If there is a pending call to on_complete from grpc_byte_stream_next(),
// it will be invoked with the error passed to grpc_byte_stream_shutdown().
//
// The next call to grpc_byte_stream_pull() (if any) will return the error
// passed to grpc_byte_stream_shutdown().
void grpc_byte_stream_shutdown(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
grpc_error *error);
void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream);
/* grpc_byte_stream that wraps a slice buffer */
// grpc_slice_buffer_stream
//
// A grpc_byte_stream that wraps a slice buffer.
typedef struct grpc_slice_buffer_stream {
grpc_byte_stream base;
grpc_slice_buffer *backing_buffer;
size_t cursor;
grpc_error *shutdown_error;
} grpc_slice_buffer_stream;
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
grpc_slice_buffer *slice_buffer,
uint32_t flags);
// grpc_caching_byte_stream
//
// A grpc_byte_stream that that wraps an underlying byte stream but caches
// the resulting slices in a slice buffer. If an initial attempt fails
// without fully draining the underlying stream, a new caching stream
// can be created from the same underlying cache, in which case it will
// return whatever is in the backing buffer before continuing to read the
// underlying stream.
//
// NOTE: No synchronization is done, so it is not safe to have multiple
// grpc_caching_byte_streams simultaneously drawing from the same underlying
// grpc_byte_stream_cache at the same time.
typedef struct {
grpc_byte_stream *underlying_stream;
grpc_slice_buffer cache_buffer;
} grpc_byte_stream_cache;
// Takes ownership of underlying_stream.
void grpc_byte_stream_cache_init(grpc_byte_stream_cache *cache,
grpc_byte_stream *underlying_stream);
// Must not be called while still in use by a grpc_caching_byte_stream.
void grpc_byte_stream_cache_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream_cache *cache);
typedef struct {
grpc_byte_stream base;
grpc_byte_stream_cache *cache;
size_t cursor;
grpc_error *shutdown_error;
} grpc_caching_byte_stream;
void grpc_caching_byte_stream_init(grpc_caching_byte_stream *stream,
grpc_byte_stream_cache *cache);
// Resets the byte stream to the start of the underlying stream.
void grpc_caching_byte_stream_reset(grpc_caching_byte_stream *stream);
#endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */

@ -207,27 +207,35 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx,
return transport->vtable->get_endpoint(exec_ctx, transport);
}
// This comment should be sung to the tune of
// "Supercalifragilisticexpialidocious":
//
// grpc_transport_stream_op_batch_finish_with_failure
// is a function that must always unref cancel_error
// though it lives in lib, it handles transport stream ops sure
// it's grpc_transport_stream_op_batch_finish_with_failure
void grpc_transport_stream_op_batch_finish_with_failure(
grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *batch,
grpc_error *error) {
if (op->recv_message) {
GRPC_CLOSURE_SCHED(exec_ctx, op->payload->recv_message.recv_message_ready,
if (batch->send_message) {
grpc_byte_stream_destroy(exec_ctx,
batch->payload->send_message.send_message);
}
if (batch->recv_message) {
GRPC_CLOSURE_SCHED(exec_ctx,
batch->payload->recv_message.recv_message_ready,
GRPC_ERROR_REF(error));
}
if (op->recv_initial_metadata) {
if (batch->recv_initial_metadata) {
GRPC_CLOSURE_SCHED(
exec_ctx,
op->payload->recv_initial_metadata.recv_initial_metadata_ready,
batch->payload->recv_initial_metadata.recv_initial_metadata_ready,
GRPC_ERROR_REF(error));
}
GRPC_CLOSURE_SCHED(exec_ctx, op->on_complete, error);
if (op->cancel_stream) {
GRPC_ERROR_UNREF(op->payload->cancel_stream.cancel_error);
GRPC_CLOSURE_SCHED(exec_ctx, batch->on_complete, error);
if (batch->cancel_stream) {
GRPC_ERROR_UNREF(batch->payload->cancel_stream.cancel_error);
}
}

@ -159,6 +159,11 @@ struct grpc_transport_stream_op_batch_payload {
} send_trailing_metadata;
struct {
// The transport (or a filter that decides to return a failure before
// the op gets down to the transport) is responsible for calling
// grpc_byte_stream_destroy() on this.
// The batch's on_complete will not be called until after the byte
// stream is destroyed.
grpc_byte_stream *send_message;
} send_message;
@ -174,6 +179,10 @@ struct grpc_transport_stream_op_batch_payload {
} recv_initial_metadata;
struct {
// Will be set by the transport to point to the byte stream
// containing a received message.
// The caller is responsible for calling grpc_byte_stream_destroy()
// on this byte stream.
grpc_byte_stream **recv_message;
/** Should be enqueued when one message is ready to be processed. */
grpc_closure *recv_message_ready;

@ -24,6 +24,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/security/credentials.h>
#include <grpc++/server_context.h>
#include <grpc++/support/time.h>
@ -38,6 +39,7 @@ class DefaultGlobalClientCallbacks final
void Destructor(ClientContext* context) override {}
};
static internal::GrpcLibraryInitializer g_gli_initializer;
static DefaultGlobalClientCallbacks g_default_client_callbacks;
static ClientContext::GlobalCallbacks* g_client_callbacks =
&g_default_client_callbacks;

@ -151,19 +151,25 @@ class Server::SyncRequest final : public CompletionQueueTag {
GPR_ASSERT(cq_ && !in_flight_);
in_flight_ = true;
if (tag_) {
GPR_ASSERT(GRPC_CALL_OK ==
grpc_server_request_registered_call(
server, tag_, &call_, &deadline_, &request_metadata_,
has_request_payload_ ? &request_payload_ : nullptr, cq_,
notify_cq, this));
if (GRPC_CALL_OK !=
grpc_server_request_registered_call(
server, tag_, &call_, &deadline_, &request_metadata_,
has_request_payload_ ? &request_payload_ : nullptr, cq_,
notify_cq, this)) {
TeardownRequest();
return;
}
} else {
if (!call_details_) {
call_details_ = new grpc_call_details;
grpc_call_details_init(call_details_);
}
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
server, &call_, call_details_,
&request_metadata_, cq_, notify_cq, this));
if (grpc_server_request_call(server, &call_, call_details_,
&request_metadata_, cq_, notify_cq,
this) != GRPC_CALL_OK) {
TeardownRequest();
return;
}
}
}
@ -286,12 +292,10 @@ class Server::SyncRequestThreadManager : public ThreadManager {
if (ok) {
// Calldata takes ownership of the completion queue inside sync_req
SyncRequest::CallData cd(server_, sync_req);
{
// Prepare for the next request
if (!IsShutdown()) {
sync_req->SetupRequest(); // Create new completion queue for sync_req
sync_req->Request(server_->c_server(), server_cq_->cq());
}
// Prepare for the next request
if (!IsShutdown()) {
sync_req->SetupRequest(); // Create new completion queue for sync_req
sync_req->Request(server_->c_server(), server_cq_->cq());
}
GPR_TIMER_SCOPE("cd.Run()", 0);
@ -316,8 +320,8 @@ class Server::SyncRequestThreadManager : public ThreadManager {
}
void Shutdown() override {
server_cq_->Shutdown();
ThreadManager::Shutdown();
server_cq_->Shutdown();
}
void Wait() override {
@ -652,10 +656,11 @@ ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest(
void ServerInterface::RegisteredAsyncRequest::IssueRequest(
void* registered_method, grpc_byte_buffer** payload,
ServerCompletionQueue* notification_cq) {
grpc_server_request_registered_call(
server_->server(), registered_method, &call_, &context_->deadline_,
context_->client_metadata_.arr(), payload, call_cq_->cq(),
notification_cq->cq(), this);
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_registered_call(
server_->server(), registered_method, &call_,
&context_->deadline_,
context_->client_metadata_.arr(), payload,
call_cq_->cq(), notification_cq->cq(), this));
}
ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
@ -667,9 +672,10 @@ ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
grpc_call_details_init(&call_details_);
GPR_ASSERT(notification_cq);
GPR_ASSERT(call_cq);
grpc_server_request_call(server->server(), &call_, &call_details_,
context->client_metadata_.arr(), call_cq->cq(),
notification_cq->cq(), this);
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
server->server(), &call_, &call_details_,
context->client_metadata_.arr(), call_cq->cq(),
notification_cq->cq(), this));
}
bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,

@ -0,0 +1,98 @@
#region Copyright notice and license
// 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.
#endregion
using System;
using NUnit.Framework;
using System.Threading;
using System.Threading.Tasks;
namespace Grpc.Core.Tests
{
public class ThreadingModelTest
{
const string Host = "127.0.0.1";
MockServiceHelper helper;
Server server;
Channel channel;
[SetUp]
public void Init()
{
helper = new MockServiceHelper(Host);
server = helper.GetServer();
server.Start();
channel = helper.GetChannel();
}
[TearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
server.ShutdownAsync().Wait();
}
[Test]
public void BlockingCallInServerHandlerDoesNotDeadlock()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
int recursionDepth = int.Parse(request);
if (recursionDepth <= 0) {
return "SUCCESS";
}
return Calls.BlockingUnaryCall(helper.CreateUnaryCall(), (recursionDepth - 1).ToString());
});
int maxRecursionDepth = Environment.ProcessorCount * 2; // make sure we have more pending blocking calls than threads in GrpcThreadPool
Assert.AreEqual("SUCCESS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), maxRecursionDepth.ToString()));
}
[Test]
public void HandlerDoesNotRunOnGrpcThread()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
if (IsRunningOnGrpcThreadPool()) {
return "Server handler should not run on gRPC threadpool thread.";
}
return request;
});
Assert.AreEqual("ABC", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC"));
}
[Test]
public async Task ContinuationDoesNotRunOnGrpcThread()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
return request;
});
await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "ABC");
Assert.IsFalse(IsRunningOnGrpcThreadPool());
}
private static bool IsRunningOnGrpcThreadPool()
{
var threadName = Thread.CurrentThread.Name ?? "";
return threadName.Contains("grpc");
}
}
}

@ -64,6 +64,7 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' ">
<PackageReference Include="System.Runtime.Loader" Version="4.0.0" />
<PackageReference Include="System.Threading.Thread" Version="4.0.0" />
<PackageReference Include="System.Threading.ThreadPool" Version="4.0.0" />
</ItemGroup>
<Import Project="NativeDeps.csproj.include" />

@ -39,6 +39,7 @@ namespace Grpc.Core
static int refCount;
static int? customThreadPoolSize;
static int? customCompletionQueueCount;
static bool inlineHandlers;
static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>();
static readonly HashSet<Server> registeredServers = new HashSet<Server>();
@ -217,13 +218,32 @@ namespace Grpc.Core
}
}
/// <summary>
/// By default, gRPC's internal event handlers get offloaded to .NET default thread pool thread (<c>inlineHandlers=false</c>).
/// Setting <c>inlineHandlers</c> to <c>true</c> will allow scheduling the event handlers directly to
/// <c>GrpcThreadPool</c> internal threads. That can lead to significant performance gains in some situations,
/// but requires user to never block in async code (incorrectly written code can easily lead to deadlocks).
/// Inlining handlers is an advanced setting and you should only use it if you know what you are doing.
/// Most users should rely on the default value provided by gRPC library.
/// Note: this method is part of an experimental API that can change or be removed without any prior notice.
/// Note: <c>inlineHandlers=true</c> was the default in gRPC C# v1.4.x and earlier.
/// </summary>
public static void SetHandlerInlining(bool inlineHandlers)
{
lock (staticLock)
{
GrpcPreconditions.CheckState(instance == null, "Can only be set before GrpcEnvironment is initialized");
GrpcEnvironment.inlineHandlers = inlineHandlers;
}
}
/// <summary>
/// Creates gRPC environment.
/// </summary>
private GrpcEnvironment()
{
GrpcNativeInit();
threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault());
threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault(), inlineHandlers);
threadPool.Start();
}

@ -33,12 +33,15 @@ namespace Grpc.Core.Internal
internal class GrpcThreadPool
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<GrpcThreadPool>();
static readonly WaitCallback RunCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, true));
static readonly WaitCallback RunCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, false));
readonly GrpcEnvironment environment;
readonly object myLock = new object();
readonly List<Thread> threads = new List<Thread>();
readonly int poolSize;
readonly int completionQueueCount;
readonly bool inlineHandlers;
readonly List<BasicProfiler> threadProfilers = new List<BasicProfiler>(); // profilers assigned to threadpool threads
@ -52,11 +55,13 @@ namespace Grpc.Core.Internal
/// <param name="environment">Environment.</param>
/// <param name="poolSize">Pool size.</param>
/// <param name="completionQueueCount">Completion queue count.</param>
public GrpcThreadPool(GrpcEnvironment environment, int poolSize, int completionQueueCount)
/// <param name="inlineHandlers">Handler inlining.</param>
public GrpcThreadPool(GrpcEnvironment environment, int poolSize, int completionQueueCount, bool inlineHandlers)
{
this.environment = environment;
this.poolSize = poolSize;
this.completionQueueCount = completionQueueCount;
this.inlineHandlers = inlineHandlers;
GrpcPreconditions.CheckArgument(poolSize >= completionQueueCount,
"Thread pool size cannot be smaller than the number of completion queues used.");
}
@ -165,11 +170,19 @@ namespace Grpc.Core.Internal
try
{
var callback = cq.CompletionRegistry.Extract(tag);
callback(success);
// Use cached delegates to avoid unnecessary allocations
if (!inlineHandlers)
{
ThreadPool.QueueUserWorkItem(success ? RunCompletionQueueEventCallbackSuccess : RunCompletionQueueEventCallbackFailure, callback);
}
else
{
RunCompletionQueueEventCallback(callback, success);
}
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking completion delegate");
Logger.Error(e, "Exception occured while extracting event from completion registry.");
}
}
}
@ -186,5 +199,17 @@ namespace Grpc.Core.Internal
}
return list.AsReadOnly();
}
private static void RunCompletionQueueEventCallback(OpCompletionDelegate callback, bool success)
{
try
{
callback(success);
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking completion delegate");
}
}
}
}

@ -63,11 +63,6 @@ namespace Grpc.IntegrationTesting
private async Task RunAsync()
{
// (ThreadPoolSize == ProcessorCount) gives best throughput in benchmarks
// and doesn't seem to harm performance even when server and client
// are running on the same machine.
GrpcEnvironment.SetThreadPoolSize(Environment.ProcessorCount);
string host = "0.0.0.0";
int port = options.DriverPort;

@ -31,6 +31,7 @@
"Grpc.Core.Tests.ShutdownHookPendingCallTest",
"Grpc.Core.Tests.ShutdownHookServerTest",
"Grpc.Core.Tests.ShutdownTest",
"Grpc.Core.Tests.ThreadingModelTest",
"Grpc.Core.Tests.TimeoutsTest",
"Grpc.Core.Tests.UserAgentStringTest"
],

@ -919,11 +919,6 @@ Server.prototype.addService = function(service, implementation) {
});
};
var logAddProtoServiceDeprecationOnce = _.once(function() {
common.log(constants.logVerbosity.INFO,
'Server#addProtoService is deprecated. Use addService instead');
});
/**
* Add a proto service to the server, with a corresponding implementation
* @deprecated Use {@link grpc.Server#addService} instead
@ -931,11 +926,11 @@ var logAddProtoServiceDeprecationOnce = _.once(function() {
* @param {Object<String, grpc.Server~handleCall>} implementation Map of method
* names to method implementation for the provided service.
*/
Server.prototype.addProtoService = function(service, implementation) {
Server.prototype.addProtoService = util.deprecate(function(service,
implementation) {
var options;
var protobuf_js_5_common = require('./protobuf_js_5_common');
var protobuf_js_6_common = require('./protobuf_js_6_common');
logAddProtoServiceDeprecationOnce();
if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
this.addService(
@ -950,7 +945,7 @@ Server.prototype.addProtoService = function(service, implementation) {
// We assume that this is a service attributes object
this.addService(service, implementation);
}
};
}, 'Server#addProtoService: Use Server#addService instead');
/**
* Binds the server to the given port, with SSL disabled if creds is an

@ -101,7 +101,7 @@ Pod::Spec.new do |s|
s.preserve_paths = plugin
# Restrict the protoc version to the one supported by this plugin.
s.dependency '!ProtoCompiler', '3.2.0'
s.dependency '!ProtoCompiler', '3.3.0'
# For the Protobuf dependency not to complain:
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'

@ -36,7 +36,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler'
v = '3.2.0'
v = '3.3.0'
s.version = v
s.summary = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files'
s.description = <<-DESC

@ -31,7 +31,7 @@
Pod::Spec.new do |s|
s.name = 'BoringSSL'
version = '8.2'
version = '9.0'
s.version = version
s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
# Adapted from the homepage:
@ -69,9 +69,7 @@ Pod::Spec.new do |s|
s.source = {
:git => 'https://boringssl.googlesource.com/boringssl',
# Restore this version name hack in the next version!!
# :tag => "version_for_cocoapods_#{version}",
:tag => "version_for_cocoapods_8.0",
:tag => "version_for_cocoapods_#{version}",
}
name = 'openssl'
@ -169,7 +167,6 @@ Pod::Spec.new do |s|
#include "hkdf.h"
#include "md4.h"
#include "md5.h"
#include "newhope.h"
#include "obj_mac.h"
#include "objects.h"
#include "opensslv.h"
@ -183,7 +180,6 @@ Pod::Spec.new do |s|
#include "ripemd.h"
#include "safestack.h"
#include "srtp.h"
#include "time_support.h"
#include "x509.h"
#include "x509v3.h"
EOF
@ -389,42 +385,42 @@ Pod::Spec.new do |s|
0x28340c19,
0x283480ac,
0x283500ea,
0x2c3228ca,
0x2c32a8d8,
0x2c3328ea,
0x2c33a8fc,
0x2c342910,
0x2c34a922,
0x2c35293d,
0x2c35a94f,
0x2c362962,
0x2c3229b1,
0x2c32a9bf,
0x2c3329d1,
0x2c33a9e3,
0x2c3429f7,
0x2c34aa09,
0x2c352a24,
0x2c35aa36,
0x2c362a49,
0x2c36832d,
0x2c37296f,
0x2c37a981,
0x2c382994,
0x2c38a9ab,
0x2c3929b9,
0x2c39a9c9,
0x2c3a29db,
0x2c3aa9ef,
0x2c3b2a00,
0x2c3baa1f,
0x2c3c2a33,
0x2c3caa49,
0x2c3d2a62,
0x2c3daa7f,
0x2c3e2a90,
0x2c3eaa9e,
0x2c3f2ab6,
0x2c3faace,
0x2c402adb,
0x2c372a56,
0x2c37aa68,
0x2c382a7b,
0x2c38aa92,
0x2c392aa0,
0x2c39aab0,
0x2c3a2ac2,
0x2c3aaad6,
0x2c3b2ae7,
0x2c3bab06,
0x2c3c2b1a,
0x2c3cab30,
0x2c3d2b49,
0x2c3dab66,
0x2c3e2b77,
0x2c3eab85,
0x2c3f2b9d,
0x2c3fabb5,
0x2c402bc2,
0x2c4090e7,
0x2c412aec,
0x2c41aaff,
0x2c412bd3,
0x2c41abe6,
0x2c4210c0,
0x2c42ab10,
0x2c42abf7,
0x2c430720,
0x2c43aa11,
0x2c43aaf8,
0x30320000,
0x30328015,
0x3033001f,
@ -577,180 +573,189 @@ Pod::Spec.new do |s|
0x403b9861,
0x403c0064,
0x403c8083,
0x403d18aa,
0x403d98c0,
0x403e18cf,
0x403e98e2,
0x403f18fc,
0x403f990a,
0x4040191f,
0x40409933,
0x40411950,
0x4041996b,
0x40421984,
0x40429997,
0x404319ab,
0x404399c3,
0x404419da,
0x403d18c1,
0x403d98d7,
0x403e18e6,
0x403e98f9,
0x403f1913,
0x403f9921,
0x40401936,
0x4040994a,
0x40411967,
0x40419982,
0x4042199b,
0x404299ae,
0x404319c2,
0x404399da,
0x404419f1,
0x404480ac,
0x404519ef,
0x40459a01,
0x40461a25,
0x40469a45,
0x40471a53,
0x40479a7a,
0x40481ab7,
0x40489ad0,
0x40491ae7,
0x40499b01,
0x404a1b18,
0x404a9b36,
0x404b1b4e,
0x404b9b65,
0x404c1b7b,
0x404c9b8d,
0x404d1bae,
0x404d9bd0,
0x404e1be4,
0x404e9bf1,
0x404f1c1e,
0x404f9c47,
0x40501c71,
0x40509c85,
0x40511ca0,
0x40519cb0,
0x40521cc7,
0x40529ceb,
0x40531d03,
0x40539d16,
0x40541d2b,
0x40549d4e,
0x40551d5c,
0x40559d79,
0x40561d86,
0x40569d9f,
0x40571db7,
0x40579dca,
0x40581ddf,
0x40589e06,
0x40591e35,
0x40599e62,
0x405a1e76,
0x405a9e86,
0x405b1e9e,
0x405b9eaf,
0x405c1ec2,
0x405c9ed3,
0x405d1ee0,
0x405d9ef7,
0x405e1f17,
0x40451a06,
0x40459a18,
0x40461a3c,
0x40469a5c,
0x40471a6a,
0x40479a91,
0x40481ace,
0x40489ae7,
0x40491afe,
0x40499b18,
0x404a1b2f,
0x404a9b4d,
0x404b1b65,
0x404b9b7c,
0x404c1b92,
0x404c9ba4,
0x404d1bc5,
0x404d9be7,
0x404e1bfb,
0x404e9c08,
0x404f1c35,
0x404f9c5e,
0x40501c99,
0x40509cad,
0x40511cc8,
0x40519cd8,
0x40521cef,
0x40529d13,
0x40531d2b,
0x40539d3e,
0x40541d53,
0x40549d76,
0x40551d84,
0x40559da1,
0x40561dae,
0x40569dc7,
0x40571ddf,
0x40579df2,
0x40581e07,
0x40589e2e,
0x40591e5d,
0x40599e8a,
0x405a1e9e,
0x405a9eae,
0x405b1ec6,
0x405b9ed7,
0x405c1eea,
0x405c9f0b,
0x405d1f18,
0x405d9f2f,
0x405e1f6d,
0x405e8a95,
0x405f1f38,
0x405f9f45,
0x40601f53,
0x40609f75,
0x40611f9d,
0x40619fb2,
0x40621fc9,
0x40629fda,
0x40631feb,
0x4063a000,
0x40642017,
0x4064a043,
0x4065205e,
0x4065a075,
0x4066208d,
0x4066a0b7,
0x406720e2,
0x4067a103,
0x40682116,
0x4068a137,
0x40692169,
0x4069a197,
0x406a21b8,
0x406aa1d8,
0x406b2360,
0x406ba383,
0x406c2399,
0x406ca5c5,
0x406d25f4,
0x406da61c,
0x406e264a,
0x406ea662,
0x406f2681,
0x406fa696,
0x407026a9,
0x4070a6c6,
0x405f1f8e,
0x405f9f9b,
0x40601fa9,
0x40609fcb,
0x4061200f,
0x4061a047,
0x4062205e,
0x4062a06f,
0x40632080,
0x4063a095,
0x406420ac,
0x4064a0d8,
0x406520f3,
0x4065a10a,
0x40662122,
0x4066a14c,
0x40672177,
0x4067a198,
0x406821ab,
0x4068a1cc,
0x406921fe,
0x4069a22c,
0x406a224d,
0x406aa26d,
0x406b23f5,
0x406ba418,
0x406c242e,
0x406ca690,
0x406d26bf,
0x406da6e7,
0x406e2715,
0x406ea749,
0x406f2768,
0x406fa77d,
0x40702790,
0x4070a7ad,
0x40710800,
0x4071a6d8,
0x407226eb,
0x4072a704,
0x4073271c,
0x4071a7bf,
0x407227d2,
0x4072a7eb,
0x40732803,
0x4073936d,
0x40742730,
0x4074a74a,
0x4075275b,
0x4075a76f,
0x4076277d,
0x40742817,
0x4074a831,
0x40752842,
0x4075a856,
0x40762864,
0x407691aa,
0x407727a2,
0x4077a7c4,
0x407827df,
0x4078a818,
0x4079282f,
0x4079a845,
0x407a2851,
0x407aa864,
0x407b2879,
0x407ba88b,
0x407c28a0,
0x407ca8a9,
0x407d2152,
0x407d9c57,
0x407e27f4,
0x407e9e16,
0x407f1a67,
0x40772889,
0x4077a8ab,
0x407828c6,
0x4078a8ff,
0x40792916,
0x4079a92c,
0x407a2938,
0x407aa94b,
0x407b2960,
0x407ba972,
0x407c2987,
0x407ca990,
0x407d21e7,
0x407d9c6e,
0x407e28db,
0x407e9e3e,
0x407f1a7e,
0x407f9887,
0x40801c2e,
0x40809a8f,
0x40811cd9,
0x40819c08,
0x40822635,
0x40801c45,
0x40809aa6,
0x40811d01,
0x40819c1f,
0x40822700,
0x4082986d,
0x40831df1,
0x4083a028,
0x40841aa3,
0x40849e4e,
0x41f4228b,
0x41f9231d,
0x41fe2210,
0x41fea3ec,
0x41ff24dd,
0x420322a4,
0x420822c6,
0x4208a302,
0x420921f4,
0x4209a33c,
0x420a224b,
0x420aa22b,
0x420b226b,
0x420ba2e4,
0x420c24f9,
0x420ca3b9,
0x420d23d3,
0x420da40a,
0x42122424,
0x421724c0,
0x4217a466,
0x421c2488,
0x421f2443,
0x42212510,
0x422624a3,
0x422b25a9,
0x422ba572,
0x422c2591,
0x422ca54c,
0x422d252b,
0x40831e19,
0x4083a0bd,
0x40841aba,
0x40849e76,
0x40851efb,
0x40859ff3,
0x40861f4f,
0x40869c88,
0x4087272d,
0x4087a024,
0x408818aa,
0x41f42320,
0x41f923b2,
0x41fe22a5,
0x41fea481,
0x41ff2572,
0x42032339,
0x4208235b,
0x4208a397,
0x42092289,
0x4209a3d1,
0x420a22e0,
0x420aa2c0,
0x420b2300,
0x420ba379,
0x420c258e,
0x420ca44e,
0x420d2468,
0x420da49f,
0x421224b9,
0x42172555,
0x4217a4fb,
0x421c251d,
0x421f24d8,
0x422125a5,
0x42262538,
0x422b2674,
0x422ba622,
0x422c265c,
0x422ca5e1,
0x422d25c0,
0x422da641,
0x422e2607,
0x4432072b,
0x4432873a,
0x44330746,
@ -793,69 +798,69 @@ Pod::Spec.new do |s|
0x4c3d136d,
0x4c3d937c,
0x4c3e1389,
0x50322b22,
0x5032ab31,
0x50332b3c,
0x5033ab4c,
0x50342b65,
0x5034ab7f,
0x50352b8d,
0x5035aba3,
0x50362bb5,
0x5036abcb,
0x50372be4,
0x5037abf7,
0x50382c0f,
0x5038ac20,
0x50392c35,
0x5039ac49,
0x503a2c69,
0x503aac7f,
0x503b2c97,
0x503baca9,
0x503c2cc5,
0x503cacdc,
0x503d2cf5,
0x503dad0b,
0x503e2d18,
0x503ead2e,
0x503f2d40,
0x50322c09,
0x5032ac18,
0x50332c23,
0x5033ac33,
0x50342c4c,
0x5034ac66,
0x50352c74,
0x5035ac8a,
0x50362c9c,
0x5036acb2,
0x50372ccb,
0x5037acde,
0x50382cf6,
0x5038ad07,
0x50392d1c,
0x5039ad30,
0x503a2d50,
0x503aad66,
0x503b2d7e,
0x503bad90,
0x503c2dac,
0x503cadc3,
0x503d2ddc,
0x503dadf2,
0x503e2dff,
0x503eae15,
0x503f2e27,
0x503f8382,
0x50402d53,
0x5040ad63,
0x50412d7d,
0x5041ad8c,
0x50422da6,
0x5042adc3,
0x50432dd3,
0x5043ade3,
0x50442df2,
0x50402e3a,
0x5040ae4a,
0x50412e64,
0x5041ae73,
0x50422e8d,
0x5042aeaa,
0x50432eba,
0x5043aeca,
0x50442ed9,
0x5044843f,
0x50452e06,
0x5045ae24,
0x50462e37,
0x5046ae4d,
0x50472e5f,
0x5047ae74,
0x50482e9a,
0x5048aea8,
0x50492ebb,
0x5049aed0,
0x504a2ee6,
0x504aaef6,
0x504b2f16,
0x504baf29,
0x504c2f4c,
0x504caf7a,
0x504d2f8c,
0x504dafa9,
0x504e2fc4,
0x504eafe0,
0x504f2ff2,
0x504fb009,
0x50503018,
0x50452eed,
0x5045af0b,
0x50462f1e,
0x5046af34,
0x50472f46,
0x5047af5b,
0x50482f81,
0x5048af8f,
0x50492fa2,
0x5049afb7,
0x504a2fcd,
0x504aafdd,
0x504b2ffd,
0x504bb010,
0x504c3033,
0x504cb061,
0x504d3073,
0x504db090,
0x504e30ab,
0x504eb0c7,
0x504f30d9,
0x504fb0f0,
0x505030ff,
0x505086ef,
0x5051302b,
0x50513112,
0x58320ec9,
0x68320e8b,
0x68328c25,
@ -1218,6 +1223,7 @@ Pod::Spec.new do |s|
"BIO_NOT_SET\\0"
"BLOCK_CIPHER_PAD_IS_WRONG\\0"
"BUFFERED_MESSAGES_ON_CIPHER_CHANGE\\0"
"CANNOT_PARSE_LEAF_CERT\\0"
"CA_DN_LENGTH_MISMATCH\\0"
"CA_DN_TOO_LONG\\0"
"CCS_RECEIVED_EARLY\\0"
@ -1261,6 +1267,7 @@ Pod::Spec.new do |s|
"INVALID_COMPRESSION_LIST\\0"
"INVALID_MESSAGE\\0"
"INVALID_OUTER_RECORD_TYPE\\0"
"INVALID_SCT_LIST\\0"
"INVALID_SSL_SESSION\\0"
"INVALID_TICKET_KEYS_LENGTH\\0"
"LENGTH_MISMATCH\\0"
@ -1290,15 +1297,19 @@ Pod::Spec.new do |s|
"NO_RENEGOTIATION\\0"
"NO_REQUIRED_DIGEST\\0"
"NO_SHARED_CIPHER\\0"
"NO_SHARED_GROUP\\0"
"NULL_SSL_CTX\\0"
"NULL_SSL_METHOD_PASSED\\0"
"OLD_SESSION_CIPHER_NOT_RETURNED\\0"
"OLD_SESSION_PRF_HASH_MISMATCH\\0"
"OLD_SESSION_VERSION_NOT_RETURNED\\0"
"PARSE_TLSEXT\\0"
"PATH_TOO_LONG\\0"
"PEER_DID_NOT_RETURN_A_CERTIFICATE\\0"
"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0"
"PRE_SHARED_KEY_MUST_BE_LAST\\0"
"PROTOCOL_IS_SHUTDOWN\\0"
"PSK_IDENTITY_BINDER_COUNT_MISMATCH\\0"
"PSK_IDENTITY_NOT_FOUND\\0"
"PSK_NO_CLIENT_CB\\0"
"PSK_NO_SERVER_CB\\0"
@ -1350,7 +1361,9 @@ Pod::Spec.new do |s|
"TLSV1_ALERT_USER_CANCELLED\\0"
"TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0"
"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0"
"TLSV1_CERTIFICATE_REQUIRED\\0"
"TLSV1_CERTIFICATE_UNOBTAINABLE\\0"
"TLSV1_UNKNOWN_PSK_IDENTITY\\0"
"TLSV1_UNRECOGNIZED_NAME\\0"
"TLSV1_UNSUPPORTED_EXTENSION\\0"
"TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0"
@ -1358,6 +1371,7 @@ Pod::Spec.new do |s|
"TOO_MANY_EMPTY_FRAGMENTS\\0"
"TOO_MANY_KEY_UPDATES\\0"
"TOO_MANY_WARNING_ALERTS\\0"
"TOO_MUCH_SKIPPED_EARLY_DATA\\0"
"UNABLE_TO_FIND_ECDH_PARAMETERS\\0"
"UNEXPECTED_EXTENSION\\0"
"UNEXPECTED_MESSAGE\\0"

@ -47,6 +47,8 @@ static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer,
grpc_slice_unref(slice);
*array = result;
*length = uncompressed_length;
grpc_byte_buffer_reader_destroy(&reader);
}
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array,

@ -110,4 +110,12 @@
self.state = GRXWriterStateFinished;
}
- (void)dealloc {
GRXWriterState state = self.state;
if (state == GRXWriterStateNotStarted ||
state == GRXWriterStatePaused) {
dispatch_resume(_writeQueue);
}
}
@end

@ -213,4 +213,74 @@
XCTAssertEqualObjects(handler.errorOrNil, nil);
}
#define WRITE_ROUNDS (1000)
- (void)testBufferedPipeResumeWhenDealloc {
id anyValue = @7;
id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) {
}];
// Release after alloc;
GRXBufferedPipe *pipe = [GRXBufferedPipe pipe];
pipe = nil;
// Release after write but before start
pipe = [GRXBufferedPipe pipe];
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
pipe = nil;
// Release after start but not write
pipe = [GRXBufferedPipe pipe];
[pipe startWithWriteable:writeable];
pipe = nil;
// Release after start and write
pipe = [GRXBufferedPipe pipe];
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
[pipe startWithWriteable:writeable];
pipe = nil;
// Release after start, write and pause
pipe = [GRXBufferedPipe pipe];
[pipe startWithWriteable:writeable];
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
pipe.state = GRXWriterStatePaused;
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
pipe = nil;
// Release after start, write, pause and finish
pipe = [GRXBufferedPipe pipe];
[pipe startWithWriteable:writeable];
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
pipe.state = GRXWriterStatePaused;
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
[pipe finishWithError:nil];
pipe = nil;
// Release after start, write, pause, finish and resume
pipe = [GRXBufferedPipe pipe];
[pipe startWithWriteable:writeable];
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
pipe.state = GRXWriterStatePaused;
for (int i = 0; i < WRITE_ROUNDS; i++) {
[pipe writeValue:anyValue];
}
[pipe finishWithError:nil];
pipe.state = GRXWriterStateStarted;
pipe = nil;
}
@end

@ -37,9 +37,11 @@ rm -f Podfile.lock
pod install
set -o pipefail
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)'
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail|\bpassed\b)'
xcodebuild \
build \
-workspace *.xcworkspace \
-scheme $SCHEME \
-destination name="iPhone 6" | xcpretty
-destination name="iPhone 6" \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -

@ -70,7 +70,7 @@ trap 'kill -9 `jobs -p` ; echo "EXIT TIME: $(date)"' EXIT
# element of the pipe fails.
# TODO(jcanizales): Use xctool instead? Issue #2540.
set -o pipefail
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail)'
XCODEBUILD_FILTER='(^===|^\*\*|\bfatal\b|\berror\b|\bwarning\b|\bfail|\bpassed\b)'
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
@ -79,14 +79,18 @@ xcodebuild \
HOST_PORT_LOCALSSL=localhost:5051 \
HOST_PORT_LOCAL=localhost:5050 \
HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
test | xcpretty
test \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CoreCronetEnd2EndTests \
-destination name="iPhone 6" \
test | xcpretty
test \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -
# Temporarily disabled for (possible) flakiness on Jenkins.
# Fix or reenable after confirmation/disconfirmation that it is the source of
@ -105,4 +109,6 @@ xcodebuild \
-scheme InteropTestsRemoteWithCronet \
-destination name="iPhone 6" \
HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
test | xcpretty
test \
| egrep "$XCODEBUILD_FILTER" \
| egrep -v "(GPBDictionary|GPBArray)" -

@ -67,6 +67,15 @@ message InitialLoadBalanceRequest {
string name = 1;
}
// Contains the number of calls finished for a particular load balance token.
message ClientStatsPerToken {
// See Server.load_balance_token.
string load_balance_token = 1;
// The total number of RPCs that finished associated with the token.
int64 num_calls = 2;
}
// Contains client level statistics that are useful to load balancing. Each
// count except the timestamp should be reset to zero after reporting the stats.
message ClientStats {
@ -79,20 +88,17 @@ message ClientStats {
// The total number of RPCs that finished.
int64 num_calls_finished = 3;
// The total number of RPCs that were dropped by the client because of rate
// limiting.
int64 num_calls_finished_with_drop_for_rate_limiting = 4;
// The total number of RPCs that were dropped by the client because of load
// balancing.
int64 num_calls_finished_with_drop_for_load_balancing = 5;
// The total number of RPCs that failed to reach a server except dropped RPCs.
int64 num_calls_finished_with_client_failed_to_send = 6;
// The total number of RPCs that finished and are known to have been received
// by a server.
int64 num_calls_finished_known_received = 7;
// The list of dropped calls.
repeated ClientStatsPerToken calls_finished_with_drop = 8;
reserved 4, 5;
}
message LoadBalanceResponse {
@ -134,10 +140,8 @@ message ServerList {
Duration expiration_interval = 3;
}
// Contains server information. When none of the [drop_for_*] fields are true,
// use the other fields. When drop_for_rate_limiting is true, ignore all other
// fields. Use drop_for_load_balancing only when it is true and
// drop_for_rate_limiting is false.
// Contains server information. When the drop field is not true, use the other
// fields.
message Server {
// A resolved address for the server, serialized in network-byte-order. It may
// either be an IPv4 or IPv6 address.
@ -149,16 +153,16 @@ message Server {
// An opaque but printable token given to the frontend for each pick. All
// frontend requests for that pick must include the token in its initial
// metadata. The token is used by the backend to verify the request and to
// allow the backend to report load to the gRPC LB system.
// allow the backend to report load to the gRPC LB system. The token is also
// used in client stats for reporting dropped calls.
//
// Its length is variable but less than 50 bytes.
string load_balance_token = 3;
// Indicates whether this particular request should be dropped by the client
// for rate limiting.
bool drop_for_rate_limiting = 4;
// Indicates whether this particular request should be dropped by the client.
// If the request is dropped, there will be a corresponding entry in
// ClientStats.calls_finished_with_drop.
bool drop = 4;
// Indicates whether this particular request should be dropped by the client
// for load balancing.
bool drop_for_load_balancing = 5;
reserved 5;
}

@ -24,6 +24,18 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
import health_commands
import grpc_version
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'License :: OSI Approved :: Apache Software License',
],
PACKAGE_DIRECTORIES = {
'': '.',
}
@ -48,6 +60,7 @@ setuptools.setup(
author_email='grpc-io@googlegroups.com',
url='https://grpc.io',
license='Apache License 2.0',
classifiers=CLASSIFIERS,
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages('.'),
install_requires=INSTALL_REQUIRES,

@ -25,6 +25,18 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
import reflection_commands
import grpc_version
CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'License :: OSI Approved :: Apache Software License',
],
PACKAGE_DIRECTORIES = {
'': '.',
}
@ -48,6 +60,7 @@ setuptools.setup(
description='Standard Protobuf Reflection Service for gRPC',
author='The gRPC Authors',
author_email='grpc-io@googlegroups.com',
classifiers=CLASSIFIERS,
url='https://grpc.io',
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages('.'),

@ -0,0 +1,119 @@
# 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.
"""Objects for use in testing gRPC Python-using application code."""
import abc
import six
import grpc
class Time(six.with_metaclass(abc.ABCMeta)):
"""A simulation of time.
Implementations needn't be connected with real time as provided by the
Python interpreter, but as long as systems under test use
RpcContext.is_active and RpcContext.time_remaining for querying RPC liveness
implementations may be used to change passage of time in tests.
"""
@abc.abstractmethod
def time(self):
"""Accesses the current test time.
Returns:
The current test time (over which this object has authority).
"""
raise NotImplementedError()
@abc.abstractmethod
def call_in(self, behavior, delay):
"""Adds a behavior to be called after some time.
Args:
behavior: A behavior to be called with no arguments.
delay: A duration of time in seconds after which to call the behavior.
Returns:
A grpc.Future with which the call of the behavior may be cancelled
before it is executed.
"""
raise NotImplementedError()
@abc.abstractmethod
def call_at(self, behavior, time):
"""Adds a behavior to be called at a specific time.
Args:
behavior: A behavior to be called with no arguments.
time: The test time at which to call the behavior.
Returns:
A grpc.Future with which the call of the behavior may be cancelled
before it is executed.
"""
raise NotImplementedError()
@abc.abstractmethod
def sleep_for(self, duration):
"""Blocks for some length of test time.
Args:
duration: A duration of test time in seconds for which to block.
"""
raise NotImplementedError()
@abc.abstractmethod
def sleep_until(self, time):
"""Blocks until some test time.
Args:
time: The test time until which to block.
"""
raise NotImplementedError()
def strict_real_time():
"""Creates a Time backed by the Python interpreter's time.
The returned instance will be "strict" with respect to callbacks
submitted to it: it will ensure that all callbacks registered to
be called at time t have been called before it describes the time
as having advanced beyond t.
Returns:
A Time backed by the "system" (Python interpreter's) time.
"""
from grpc_testing import _time
return _time.StrictRealTime()
def strict_fake_time(now):
"""Creates a Time that can be manipulated by test code.
The returned instance maintains an internal representation of time
independent of real time. This internal representation only advances
when user code calls the instance's sleep_for and sleep_until methods.
The returned instance will be "strict" with respect to callbacks
submitted to it: it will ensure that all callbacks registered to
be called at time t have been called before it describes the time
as having advanced beyond t.
Returns:
A Time that simulates the passage of time.
"""
from grpc_testing import _time
return _time.StrictFakeTime(now)

@ -0,0 +1,224 @@
# 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.
"""Test times."""
import collections
import logging
import threading
import time as _time
import grpc
import grpc_testing
def _call(behaviors):
for behavior in behaviors:
try:
behavior()
except Exception: # pylint: disable=broad-except
logging.exception('Exception calling behavior "%r"!', behavior)
def _call_in_thread(behaviors):
calling = threading.Thread(target=_call, args=(behaviors,))
calling.start()
# NOTE(nathaniel): Because this function is called from "strict" Time
# implementations, it blocks until after all behaviors have terminated.
calling.join()
class _State(object):
def __init__(self):
self.condition = threading.Condition()
self.times_to_behaviors = collections.defaultdict(list)
class _Delta(
collections.namedtuple('_Delta',
('mature_behaviors', 'earliest_mature_time',
'earliest_immature_time',))):
pass
def _process(state, now):
mature_behaviors = []
earliest_mature_time = None
while state.times_to_behaviors:
earliest_time = min(state.times_to_behaviors)
if earliest_time <= now:
if earliest_mature_time is None:
earliest_mature_time = earliest_time
earliest_mature_behaviors = state.times_to_behaviors.pop(
earliest_time)
mature_behaviors.extend(earliest_mature_behaviors)
else:
earliest_immature_time = earliest_time
break
else:
earliest_immature_time = None
return _Delta(mature_behaviors, earliest_mature_time,
earliest_immature_time)
class _Future(grpc.Future):
def __init__(self, state, behavior, time):
self._state = state
self._behavior = behavior
self._time = time
self._cancelled = False
def cancel(self):
with self._state.condition:
if self._cancelled:
return True
else:
behaviors_at_time = self._state.times_to_behaviors.get(
self._time)
if behaviors_at_time is None:
return False
else:
behaviors_at_time.remove(self._behavior)
if not behaviors_at_time:
self._state.times_to_behaviors.pop(self._time)
self._state.condition.notify_all()
self._cancelled = True
return True
def cancelled(self):
with self._state.condition:
return self._cancelled
def running(self):
raise NotImplementedError()
def done(self):
raise NotImplementedError()
def result(self, timeout=None):
raise NotImplementedError()
def exception(self, timeout=None):
raise NotImplementedError()
def traceback(self, timeout=None):
raise NotImplementedError()
def add_done_callback(self, fn):
raise NotImplementedError()
class StrictRealTime(grpc_testing.Time):
def __init__(self):
self._state = _State()
self._active = False
self._calling = None
def _activity(self):
while True:
with self._state.condition:
while True:
now = _time.time()
delta = _process(self._state, now)
self._state.condition.notify_all()
if delta.mature_behaviors:
self._calling = delta.earliest_mature_time
break
self._calling = None
if delta.earliest_immature_time is None:
self._active = False
return
else:
timeout = max(0, delta.earliest_immature_time - now)
self._state.condition.wait(timeout=timeout)
_call(delta.mature_behaviors)
def _ensure_called_through(self, time):
with self._state.condition:
while ((self._state.times_to_behaviors and
min(self._state.times_to_behaviors) < time) or
(self._calling is not None and self._calling < time)):
self._state.condition.wait()
def _call_at(self, behavior, time):
with self._state.condition:
self._state.times_to_behaviors[time].append(behavior)
if self._active:
self._state.condition.notify_all()
else:
activity = threading.Thread(target=self._activity)
activity.start()
self._active = True
return _Future(self._state, behavior, time)
def time(self):
return _time.time()
def call_in(self, behavior, delay):
return self._call_at(behavior, _time.time() + delay)
def call_at(self, behavior, time):
return self._call_at(behavior, time)
def sleep_for(self, duration):
time = _time.time() + duration
_time.sleep(duration)
self._ensure_called_through(time)
def sleep_until(self, time):
_time.sleep(max(0, time - _time.time()))
self._ensure_called_through(time)
class StrictFakeTime(grpc_testing.Time):
def __init__(self, time):
self._state = _State()
self._time = time
def time(self):
return self._time
def call_in(self, behavior, delay):
if delay <= 0:
_call_in_thread((behavior,))
else:
with self._state.condition:
time = self._time + delay
self._state.times_to_behaviors[time].append(behavior)
return _Future(self._state, behavior, time)
def call_at(self, behavior, time):
with self._state.condition:
if time <= self._time:
_call_in_thread((behavior,))
else:
self._state.times_to_behaviors[time].append(behavior)
return _Future(self._state, behavior, time)
def sleep_for(self, duration):
if 0 < duration:
with self._state.condition:
self._time += duration
delta = _process(self._state, self._time)
_call_in_thread(delta.mature_behaviors)
def sleep_until(self, time):
with self._state.condition:
if self._time < time:
self._time = time
delta = _process(self._state, self._time)
_call_in_thread(delta.mature_behaviors)

@ -0,0 +1,17 @@
# 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.
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
VERSION = '1.5.0.dev0'

@ -0,0 +1,44 @@
# 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.
"""Setup module for gRPC Python's testing package."""
import os
import sys
import setuptools
# Ensure we're in the proper directory whether or not we're being used by pip.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import style to ensure that we can find same-directory modules.
import grpc_version
PACKAGE_DIRECTORIES = {
'': '.',
}
INSTALL_REQUIRES = ('protobuf>=3.3.0',
'grpcio>={version}'.format(version=grpc_version.VERSION),)
setuptools.setup(
name='grpcio-testing',
version=grpc_version.VERSION,
license='Apache License 2.0',
description='Testing utilities for gRPC Python',
author='The gRPC Authors',
author_email='grpc-io@googlegroups.com',
url='https://grpc.io',
package_dir=PACKAGE_DIRECTORIES,
packages=setuptools.find_packages('.'),
install_requires=INSTALL_REQUIRES)

@ -0,0 +1,13 @@
# 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.

@ -0,0 +1,165 @@
# 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.
import random
import threading
import time
import unittest
import grpc_testing
_QUANTUM = 0.3
_MANY = 10000
# Tests that run in real time can either wait for the scheduler to
# eventually run what needs to be run (and risk timing out) or declare
# that the scheduler didn't schedule work reasonably fast enough. We
# choose the latter for this test.
_PATHOLOGICAL_SCHEDULING = 'pathological thread scheduling!'
class _TimeNoter(object):
def __init__(self, time):
self._condition = threading.Condition()
self._time = time
self._call_times = []
def __call__(self):
with self._condition:
self._call_times.append(self._time.time())
def call_times(self):
with self._condition:
return tuple(self._call_times)
class TimeTest(object):
def test_sleep_for(self):
start_time = self._time.time()
self._time.sleep_for(_QUANTUM)
end_time = self._time.time()
self.assertLessEqual(start_time + _QUANTUM, end_time)
def test_sleep_until(self):
start_time = self._time.time()
self._time.sleep_until(start_time + _QUANTUM)
end_time = self._time.time()
self.assertLessEqual(start_time + _QUANTUM, end_time)
def test_call_in(self):
time_noter = _TimeNoter(self._time)
start_time = self._time.time()
self._time.call_in(time_noter, _QUANTUM)
self._time.sleep_for(_QUANTUM * 2)
call_times = time_noter.call_times()
self.assertTrue(call_times, msg=_PATHOLOGICAL_SCHEDULING)
self.assertLessEqual(start_time + _QUANTUM, call_times[0])
def test_call_at(self):
time_noter = _TimeNoter(self._time)
start_time = self._time.time()
self._time.call_at(time_noter, self._time.time() + _QUANTUM)
self._time.sleep_for(_QUANTUM * 2)
call_times = time_noter.call_times()
self.assertTrue(call_times, msg=_PATHOLOGICAL_SCHEDULING)
self.assertLessEqual(start_time + _QUANTUM, call_times[0])
def test_cancel(self):
time_noter = _TimeNoter(self._time)
future = self._time.call_in(time_noter, _QUANTUM * 2)
self._time.sleep_for(_QUANTUM)
cancelled = future.cancel()
self._time.sleep_for(_QUANTUM * 2)
call_times = time_noter.call_times()
self.assertFalse(call_times, msg=_PATHOLOGICAL_SCHEDULING)
self.assertTrue(cancelled)
self.assertTrue(future.cancelled())
def test_many(self):
test_events = tuple(threading.Event() for _ in range(_MANY))
possibly_cancelled_futures = {}
background_noise_futures = []
for test_event in test_events:
possibly_cancelled_futures[test_event] = self._time.call_in(
test_event.set, _QUANTUM * (2 + random.random()))
for _ in range(_MANY):
background_noise_futures.append(
self._time.call_in(threading.Event().set, _QUANTUM * 1000 *
random.random()))
self._time.sleep_for(_QUANTUM)
cancelled = set()
for test_event, test_future in possibly_cancelled_futures.items():
if bool(random.randint(0, 1)) and test_future.cancel():
cancelled.add(test_event)
self._time.sleep_for(_QUANTUM * 3)
for test_event in test_events:
(self.assertFalse if test_event in cancelled else
self.assertTrue)(test_event.is_set())
for background_noise_future in background_noise_futures:
background_noise_future.cancel()
def test_same_behavior_used_several_times(self):
time_noter = _TimeNoter(self._time)
start_time = self._time.time()
first_future_at_one = self._time.call_in(time_noter, _QUANTUM)
second_future_at_one = self._time.call_in(time_noter, _QUANTUM)
first_future_at_three = self._time.call_in(time_noter, _QUANTUM * 3)
second_future_at_three = self._time.call_in(time_noter, _QUANTUM * 3)
self._time.sleep_for(_QUANTUM * 2)
first_future_at_one_cancelled = first_future_at_one.cancel()
second_future_at_one_cancelled = second_future_at_one.cancel()
first_future_at_three_cancelled = first_future_at_three.cancel()
self._time.sleep_for(_QUANTUM * 2)
second_future_at_three_cancelled = second_future_at_three.cancel()
first_future_at_three_cancelled_again = first_future_at_three.cancel()
call_times = time_noter.call_times()
self.assertEqual(3, len(call_times), msg=_PATHOLOGICAL_SCHEDULING)
self.assertFalse(first_future_at_one_cancelled)
self.assertFalse(second_future_at_one_cancelled)
self.assertTrue(first_future_at_three_cancelled)
self.assertFalse(second_future_at_three_cancelled)
self.assertTrue(first_future_at_three_cancelled_again)
self.assertLessEqual(start_time + _QUANTUM, call_times[0])
self.assertLessEqual(start_time + _QUANTUM, call_times[1])
self.assertLessEqual(start_time + _QUANTUM * 3, call_times[2])
class StrictRealTimeTest(TimeTest, unittest.TestCase):
def setUp(self):
self._time = grpc_testing.strict_real_time()
class StrictFakeTimeTest(TimeTest, unittest.TestCase):
def setUp(self):
self._time = grpc_testing.strict_fake_time(
random.randint(0, int(time.time())))
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -9,6 +9,8 @@
"protoc_plugin._split_definitions_test.SplitSeparateTest",
"protoc_plugin.beta_python_plugin_test.PythonPluginTest",
"reflection._reflection_servicer_test.ReflectionServicerTest",
"testing._time_test.StrictFakeTimeTest",
"testing._time_test.StrictRealTimeTest",
"unit._api_test.AllTest",
"unit._api_test.ChannelConnectivityTest",
"unit._api_test.ChannelTest",

@ -644,22 +644,22 @@ extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable *vtable);
extern gpr_avl_create_type gpr_avl_create_import;
#define gpr_avl_create gpr_avl_create_import
typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl);
typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl, void *user_data);
extern gpr_avl_ref_type gpr_avl_ref_import;
#define gpr_avl_ref gpr_avl_ref_import
typedef void(*gpr_avl_unref_type)(gpr_avl avl);
typedef void(*gpr_avl_unref_type)(gpr_avl avl, void *user_data);
extern gpr_avl_unref_type gpr_avl_unref_import;
#define gpr_avl_unref gpr_avl_unref_import
typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value);
typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value, void *user_data);
extern gpr_avl_add_type gpr_avl_add_import;
#define gpr_avl_add gpr_avl_add_import
typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key);
typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key, void *user_data);
extern gpr_avl_remove_type gpr_avl_remove_import;
#define gpr_avl_remove gpr_avl_remove_import
typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key);
typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key, void *user_data);
extern gpr_avl_get_type gpr_avl_get_import;
#define gpr_avl_get gpr_avl_get_import
typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value);
typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value, void *user_data);
extern gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
#define gpr_avl_maybe_get gpr_avl_maybe_get_import
typedef int(*gpr_avl_is_empty_type)(gpr_avl avl);

@ -480,7 +480,20 @@ module GRPC
def bidi_streamer(requests, metadata: {}, &blk)
raise_error_if_already_executed
# Metadata might have already been sent if this is an operation view
merge_metadata_and_send_if_not_already_sent(metadata)
begin
merge_metadata_and_send_if_not_already_sent(metadata)
rescue GRPC::Core::CallError => e
batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
set_input_stream_done
set_output_stream_done
attach_status_results_and_complete_call(batch_result)
raise e
rescue => e
set_input_stream_done
set_output_stream_done
raise e
end
bd = BidiCall.new(@call,
@marshal,
@unmarshal,

@ -616,8 +616,22 @@ describe 'ClientStub' do
th.join
end
# TODO: add test for metadata-related ArgumentError in a bidi call once
# issue mentioned in https://github.com/grpc/grpc/issues/10526 is fixed
it 'should raise ArgumentError if metadata contains invalid values' do
@metadata.merge!(k3: 3)
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
expect do
get_responses(stub).collect { |r| r }
end.to raise_error(ArgumentError,
/Header values must be of type string or array/)
end
it 'terminates if the call fails to start' do
# don't start the server
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
expect do
get_responses(stub, deadline: from_relative_time(0)).collect { |r| r }
end.to raise_error(GRPC::BadStatus)
end
it 'should send metadata to the server ok' do
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true,
@ -630,9 +644,9 @@ describe 'ClientStub' do
end
describe 'without a call operation' do
def get_responses(stub)
def get_responses(stub, deadline: nil)
e = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
metadata: @metadata)
metadata: @metadata, deadline: deadline)
expect(e).to be_a(Enumerator)
e
end
@ -644,10 +658,10 @@ describe 'ClientStub' do
after(:each) do
@op.wait # make sure wait doesn't hang
end
def get_responses(stub, run_start_call_first: false)
def get_responses(stub, run_start_call_first: false, deadline: nil)
@op = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
return_op: true,
metadata: @metadata)
metadata: @metadata, deadline: deadline)
expect(@op).to be_a(GRPC::ActiveCall::Operation)
@op.start_call if run_start_call_first
e = @op.execute

@ -111,6 +111,32 @@ end
SlowStub = SlowService.rpc_stub_class
# A test service that allows a synchronized RPC cancellation
class SynchronizedCancellationService
include GRPC::GenericService
rpc :an_rpc, EchoMsg, EchoMsg
attr_reader :received_md, :delay
# notify_request_received and wait_until_rpc_cancelled are
# callbacks to synchronously allow the client to proceed with
# cancellation (after the unary request has been received),
# and to synchronously wait until the client has cancelled the
# current RPC.
def initialize(notify_request_received, wait_until_rpc_cancelled)
@notify_request_received = notify_request_received
@wait_until_rpc_cancelled = wait_until_rpc_cancelled
end
def an_rpc(req, _call)
GRPC.logger.info('starting a synchronusly cancelled rpc')
@notify_request_received.call(req)
@wait_until_rpc_cancelled.call
req # send back the req as the response
end
end
SynchronizedCancellationStub = SynchronizedCancellationService.rpc_stub_class
# a test service that hangs onto call objects
# and uses them after the server-side call has been
# finished
@ -384,20 +410,64 @@ describe GRPC::RpcServer do
end
it 'should handle cancellation correctly', server: true do
service = SlowService.new
request_received = false
request_received_mu = Mutex.new
request_received_cv = ConditionVariable.new
notify_request_received = proc do |req|
request_received_mu.synchronize do
fail 'req is nil' if req.nil?
expect(req.is_a?(EchoMsg)).to be true
fail 'test bug - already set' if request_received
request_received = true
request_received_cv.signal
end
end
rpc_cancelled = false
rpc_cancelled_mu = Mutex.new
rpc_cancelled_cv = ConditionVariable.new
wait_until_rpc_cancelled = proc do
rpc_cancelled_mu.synchronize do
loop do
break if rpc_cancelled
rpc_cancelled_cv.wait(rpc_cancelled_mu)
end
end
end
service = SynchronizedCancellationService.new(notify_request_received,
wait_until_rpc_cancelled)
@srv.handle(service)
t = Thread.new { @srv.run }
srv_thd = Thread.new { @srv.run }
@srv.wait_till_running
req = EchoMsg.new
stub = SlowStub.new(@host, :this_channel_is_insecure, **client_opts)
op = stub.an_rpc(req, metadata: { k1: 'v1', k2: 'v2' }, return_op: true)
Thread.new do # cancel the call
sleep 0.1
op.cancel
stub = SynchronizedCancellationStub.new(@host,
:this_channel_is_insecure,
**client_opts)
op = stub.an_rpc(req, return_op: true)
client_thd = Thread.new do
expect { op.execute }.to raise_error GRPC::Cancelled
end
expect { op.execute }.to raise_error GRPC::Cancelled
request_received_mu.synchronize do
loop do
break if request_received
request_received_cv.wait(request_received_mu)
end
end
op.cancel
rpc_cancelled_mu.synchronize do
fail 'test bug - already set' if rpc_cancelled
rpc_cancelled = true
rpc_cancelled_cv.signal
end
client_thd.join
@srv.stop
t.join
srv_thd.join
end
it 'should handle multiple parallel requests', server: true do

@ -1233,7 +1233,7 @@
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(GENDIR)/${p}.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=${pluginflags}$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<

@ -135,7 +135,7 @@
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
ss.dependency 'BoringSSL', '~> 8.0'
ss.dependency 'BoringSSL', '~> 9.0'
ss.dependency 'nanopb', '~> 0.3'
# To save you from scrolling, this is the last part of the podspec.

@ -103,7 +103,7 @@
s.preserve_paths = plugin
# Restrict the protoc version to the one supported by this plugin.
s.dependency '!ProtoCompiler', '3.2.0'
s.dependency '!ProtoCompiler', '3.3.0'
# For the Protobuf dependency not to complain:
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'

@ -57,22 +57,24 @@
apt-get update && apt-get install -y google-cloud-sdk && apt-get clean && ${'\\'}
gcloud config set component_manager/disable_update_check true
# Download and install grpc-java
# Install Android SDK
WORKDIR /
RUN git clone https://github.com/grpc/grpc-java.git
WORKDIR /grpc-java
RUN ./gradlew install
RUN mkdir android-sdk
WORKDIR android-sdk
RUN wget -q https://dl.google.com/android/repository/tools_r25.2.5-linux.zip && ${'\\'}
unzip -qq tools_r25.2.5-linux.zip && ${'\\'}
rm tools_r25.2.5-linux.zip && ${'\\'}
echo y | tools/bin/sdkmanager "platforms;android-22" && ${'\\'}
echo y | tools/bin/sdkmanager "build-tools;25.0.2" && ${'\\'}
echo y | tools/bin/sdkmanager "extras;android;m2repository" && ${'\\'}
echo y | tools/bin/sdkmanager "extras;google;google_play_services" && ${'\\'}
echo y | tools/bin/sdkmanager "extras;google;m2repository" && ${'\\'}
echo y | tools/bin/sdkmanager "patcher;v4" && ${'\\'}
echo y | tools/bin/sdkmanager "platform-tools"
ENV ANDROID_HOME "/android-sdk"
# Setup the Android SDK licenses
ENV ANDROID_HOME "/grpc-java/android-interop-testing/.android"
RUN mkdir -p "<%text>${ANDROID_HOME}</%text>/licenses"
RUN echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "<%text>${ANDROID_HOME}</%text>/licenses/android-sdk-license"
RUN echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "<%text>${ANDROID_HOME}</%text>/licenses/android-sdk-preview-license"
# Build the Android interop apks
WORKDIR /grpc-java/android-interop-testing
RUN ../gradlew assembleDebug
RUN ../gradlew assembleDebugAndroidTest
# Reset the working directory
WORKDIR /
# Define the default command.
CMD ["bash"]

@ -34,6 +34,7 @@
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/metadata.h"
#include "test/core/end2end/data/ssl_test_data.h"
@ -731,7 +732,9 @@ static validator *make_finished_batch_validator(call_state *cs,
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_test_only_set_slice_hash_seed(0);
if (squelch) gpr_set_log_function(dont_log);
char *grpc_trace_fuzzer = gpr_getenv("GRPC_TRACE_FUZZER");
if (squelch && grpc_trace_fuzzer == NULL) gpr_set_log_function(dont_log);
gpr_free(grpc_trace_fuzzer);
input_stream inp = {data, data + size};
grpc_tcp_client_connect_impl = my_tcp_client_connect;
gpr_now_impl = now_impl;

@ -72,8 +72,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_metadata_array_init(&request_metadata1);
int requested_calls = 0;
grpc_server_request_call(server, &call1, &call_details1, &request_metadata1,
cq, cq, tag(1));
GPR_ASSERT(GRPC_CALL_OK ==
grpc_server_request_call(server, &call1, &call_details1,
&request_metadata1, cq, cq, tag(1)));
requested_calls++;
grpc_event ev;

@ -25,6 +25,7 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include <grpc/support/useful.h>
#include "src/core/lib/support/string.h"
@ -138,7 +139,12 @@ static void simple_request_body(grpc_end2end_test_config config,
error = grpc_call_start_batch(c, ops, num_ops, tag(1), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
grpc_call_cancel_with_status(c, GRPC_STATUS_UNIMPLEMENTED, "xyz", NULL);
char *dynamic_string = gpr_strdup("xyz");
grpc_call_cancel_with_status(c, GRPC_STATUS_UNIMPLEMENTED,
(const char *)dynamic_string, NULL);
// The API of \a description allows for it to be a dynamic/non-const
// string, test this guarantee.
gpr_free(dynamic_string);
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);

@ -77,8 +77,10 @@ typedef struct {
static void request_call(void) {
grpc_metadata_array_init(&request_metadata_recv);
grpc_server_request_call(server, &call, &call_details, &request_metadata_recv,
cq, cq, tag(FLING_SERVER_NEW_REQUEST));
GPR_ASSERT(GRPC_CALL_OK ==
grpc_server_request_call(server, &call, &call_details,
&request_metadata_recv, cq, cq,
tag(FLING_SERVER_NEW_REQUEST)));
}
static void handle_unary_method(void) {

File diff suppressed because it is too large Load Diff

@ -144,7 +144,7 @@ static void test_cq_end_op(void) {
cc = grpc_completion_queue_create(
grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
grpc_cq_begin_op(cc, tag);
GPR_ASSERT(grpc_cq_begin_op(cc, tag));
grpc_cq_end_op(&exec_ctx, cc, tag, GRPC_ERROR_NONE,
do_nothing_end_completion, NULL, &completion);
@ -233,7 +233,7 @@ static void test_pluck(void) {
grpc_completion_queue_factory_lookup(&attr), &attr, NULL);
for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
grpc_cq_begin_op(cc, tags[i]);
GPR_ASSERT(grpc_cq_begin_op(cc, tags[i]));
grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
do_nothing_end_completion, NULL, &completions[i]);
}
@ -245,7 +245,7 @@ static void test_pluck(void) {
}
for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
grpc_cq_begin_op(cc, tags[i]);
GPR_ASSERT(grpc_cq_begin_op(cc, tags[i]));
grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
do_nothing_end_completion, NULL, &completions[i]);
}

@ -107,7 +107,7 @@ static void test_too_many_plucks(void) {
GPR_ASSERT(ev.type == GRPC_QUEUE_TIMEOUT);
for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
grpc_cq_begin_op(cc, tags[i]);
GPR_ASSERT(grpc_cq_begin_op(cc, tags[i]));
grpc_cq_end_op(&exec_ctx, cc, tags[i], GRPC_ERROR_NONE,
do_nothing_end_completion, NULL, &completions[i]);
}
@ -153,7 +153,7 @@ static void producer_thread(void *arg) {
gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
for (i = 0; i < TEST_THREAD_EVENTS; i++) {
grpc_cq_begin_op(opt->cc, (void *)(intptr_t)1);
GPR_ASSERT(grpc_cq_begin_op(opt->cc, (void *)(intptr_t)1));
}
gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);

@ -35,6 +35,18 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "byte_stream_test",
srcs = ["byte_stream_test.c"],
language = "C",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "connectivity_state_test",
srcs = ["connectivity_state_test.c"],

@ -0,0 +1,279 @@
/*
*
* 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/transport/byte_stream.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
//
// grpc_slice_buffer_stream tests
//
static void not_called_closure(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
GPR_ASSERT(false);
}
static void test_slice_buffer_stream_basic(void) {
gpr_log(GPR_DEBUG, "test_slice_buffer_stream_basic");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
// Create and populate slice buffer.
grpc_slice_buffer buffer;
grpc_slice_buffer_init(&buffer);
grpc_slice input[] = {
grpc_slice_from_static_string("foo"),
grpc_slice_from_static_string("bar"),
};
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
grpc_slice_buffer_add(&buffer, input[i]);
}
// Create byte stream.
grpc_slice_buffer_stream stream;
grpc_slice_buffer_stream_init(&stream, &buffer, 0);
GPR_ASSERT(stream.base.length == 6);
grpc_closure closure;
GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL,
grpc_schedule_on_exec_ctx);
// Read each slice. Note that next() always returns synchronously.
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
grpc_slice output;
grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[i], output));
grpc_slice_unref_internal(&exec_ctx, output);
}
// Clean up.
grpc_byte_stream_destroy(&exec_ctx, &stream.base);
grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_slice_buffer_stream_shutdown(void) {
gpr_log(GPR_DEBUG, "test_slice_buffer_stream_shutdown");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
// Create and populate slice buffer.
grpc_slice_buffer buffer;
grpc_slice_buffer_init(&buffer);
grpc_slice input[] = {
grpc_slice_from_static_string("foo"),
grpc_slice_from_static_string("bar"),
};
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
grpc_slice_buffer_add(&buffer, input[i]);
}
// Create byte stream.
grpc_slice_buffer_stream stream;
grpc_slice_buffer_stream_init(&stream, &buffer, 0);
GPR_ASSERT(stream.base.length == 6);
grpc_closure closure;
GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL,
grpc_schedule_on_exec_ctx);
// Read the first slice.
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
grpc_slice output;
grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[0], output));
grpc_slice_unref_internal(&exec_ctx, output);
// Now shutdown.
grpc_error *shutdown_error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown error");
grpc_byte_stream_shutdown(&exec_ctx, &stream.base,
GRPC_ERROR_REF(shutdown_error));
// After shutdown, the next pull() should return the error.
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == shutdown_error);
GRPC_ERROR_UNREF(error);
GRPC_ERROR_UNREF(shutdown_error);
// Clean up.
grpc_byte_stream_destroy(&exec_ctx, &stream.base);
grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
grpc_exec_ctx_finish(&exec_ctx);
}
//
// grpc_caching_byte_stream tests
//
static void test_caching_byte_stream_basic(void) {
gpr_log(GPR_DEBUG, "test_caching_byte_stream_basic");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
// Create and populate slice buffer byte stream.
grpc_slice_buffer buffer;
grpc_slice_buffer_init(&buffer);
grpc_slice input[] = {
grpc_slice_from_static_string("foo"),
grpc_slice_from_static_string("bar"),
};
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
grpc_slice_buffer_add(&buffer, input[i]);
}
grpc_slice_buffer_stream underlying_stream;
grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
// Create cache and caching stream.
grpc_byte_stream_cache cache;
grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
grpc_caching_byte_stream stream;
grpc_caching_byte_stream_init(&stream, &cache);
grpc_closure closure;
GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL,
grpc_schedule_on_exec_ctx);
// Read each slice. Note that next() always returns synchronously,
// because the underlying byte stream always does.
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
grpc_slice output;
grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[i], output));
grpc_slice_unref_internal(&exec_ctx, output);
}
// Clean up.
grpc_byte_stream_destroy(&exec_ctx, &stream.base);
grpc_byte_stream_cache_destroy(&exec_ctx, &cache);
grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_caching_byte_stream_reset(void) {
gpr_log(GPR_DEBUG, "test_caching_byte_stream_reset");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
// Create and populate slice buffer byte stream.
grpc_slice_buffer buffer;
grpc_slice_buffer_init(&buffer);
grpc_slice input[] = {
grpc_slice_from_static_string("foo"),
grpc_slice_from_static_string("bar"),
};
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
grpc_slice_buffer_add(&buffer, input[i]);
}
grpc_slice_buffer_stream underlying_stream;
grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
// Create cache and caching stream.
grpc_byte_stream_cache cache;
grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
grpc_caching_byte_stream stream;
grpc_caching_byte_stream_init(&stream, &cache);
grpc_closure closure;
GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL,
grpc_schedule_on_exec_ctx);
// Read one slice.
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
grpc_slice output;
grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[0], output));
grpc_slice_unref_internal(&exec_ctx, output);
// Reset the caching stream. The reads should start over from the
// first slice.
grpc_caching_byte_stream_reset(&stream);
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream.base, ~(size_t)0, &closure));
error = grpc_byte_stream_pull(&exec_ctx, &stream.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[i], output));
grpc_slice_unref_internal(&exec_ctx, output);
}
// Clean up.
grpc_byte_stream_destroy(&exec_ctx, &stream.base);
grpc_byte_stream_cache_destroy(&exec_ctx, &cache);
grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
grpc_exec_ctx_finish(&exec_ctx);
}
static void test_caching_byte_stream_shared_cache(void) {
gpr_log(GPR_DEBUG, "test_caching_byte_stream_shared_cache");
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
// Create and populate slice buffer byte stream.
grpc_slice_buffer buffer;
grpc_slice_buffer_init(&buffer);
grpc_slice input[] = {
grpc_slice_from_static_string("foo"),
grpc_slice_from_static_string("bar"),
};
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
grpc_slice_buffer_add(&buffer, input[i]);
}
grpc_slice_buffer_stream underlying_stream;
grpc_slice_buffer_stream_init(&underlying_stream, &buffer, 0);
// Create cache and two caching streams.
grpc_byte_stream_cache cache;
grpc_byte_stream_cache_init(&cache, &underlying_stream.base);
grpc_caching_byte_stream stream1;
grpc_caching_byte_stream_init(&stream1, &cache);
grpc_caching_byte_stream stream2;
grpc_caching_byte_stream_init(&stream2, &cache);
grpc_closure closure;
GRPC_CLOSURE_INIT(&closure, not_called_closure, NULL,
grpc_schedule_on_exec_ctx);
// Read one slice from stream1.
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream1.base, ~(size_t)0, &closure));
grpc_slice output;
grpc_error *error = grpc_byte_stream_pull(&exec_ctx, &stream1.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[0], output));
grpc_slice_unref_internal(&exec_ctx, output);
// Read all slices from stream2.
for (size_t i = 0; i < GPR_ARRAY_SIZE(input); ++i) {
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream2.base, ~(size_t)0, &closure));
error = grpc_byte_stream_pull(&exec_ctx, &stream2.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[i], output));
grpc_slice_unref_internal(&exec_ctx, output);
}
// Now read the second slice from stream1.
GPR_ASSERT(
grpc_byte_stream_next(&exec_ctx, &stream1.base, ~(size_t)0, &closure));
error = grpc_byte_stream_pull(&exec_ctx, &stream1.base, &output);
GPR_ASSERT(error == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_slice_eq(input[1], output));
grpc_slice_unref_internal(&exec_ctx, output);
// Clean up.
grpc_byte_stream_destroy(&exec_ctx, &stream1.base);
grpc_byte_stream_destroy(&exec_ctx, &stream2.base);
grpc_byte_stream_cache_destroy(&exec_ctx, &cache);
grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
grpc_exec_ctx_finish(&exec_ctx);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_slice_buffer_stream_basic();
test_slice_buffer_stream_shutdown();
test_caching_byte_stream_basic();
test_caching_byte_stream_reset();
test_caching_byte_stream_shared_cache();
return 0;
}

@ -45,6 +45,7 @@ extern "C" {
#include "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
// TODO(dgq): Other scenarios in need of testing:
@ -73,8 +74,8 @@ extern "C" {
using std::chrono::system_clock;
using grpc::lb::v1::LoadBalanceResponse;
using grpc::lb::v1::LoadBalanceRequest;
using grpc::lb::v1::LoadBalanceResponse;
using grpc::lb::v1::LoadBalancer;
namespace grpc {
@ -131,6 +132,19 @@ class BackendServiceImpl : public BackendService {
IncreaseResponseCount();
return status;
}
// Returns true on its first invocation, false otherwise.
bool Shutdown() {
std::unique_lock<std::mutex> lock(mu_);
const bool prev = !shutdown_;
shutdown_ = true;
gpr_log(GPR_INFO, "Backend: shut down");
return prev;
}
private:
std::mutex mu_;
bool shutdown_ = false;
};
grpc::string Ip4ToPackedString(const char* ip_str) {
@ -142,22 +156,20 @@ grpc::string Ip4ToPackedString(const char* ip_str) {
struct ClientStats {
size_t num_calls_started = 0;
size_t num_calls_finished = 0;
size_t num_calls_finished_with_drop_for_rate_limiting = 0;
size_t num_calls_finished_with_drop_for_load_balancing = 0;
size_t num_calls_finished_with_client_failed_to_send = 0;
size_t num_calls_finished_known_received = 0;
std::map<grpc::string, size_t> drop_token_counts;
ClientStats& operator+=(const ClientStats& other) {
num_calls_started += other.num_calls_started;
num_calls_finished += other.num_calls_finished;
num_calls_finished_with_drop_for_rate_limiting +=
other.num_calls_finished_with_drop_for_rate_limiting;
num_calls_finished_with_drop_for_load_balancing +=
other.num_calls_finished_with_drop_for_load_balancing;
num_calls_finished_with_client_failed_to_send +=
other.num_calls_finished_with_client_failed_to_send;
num_calls_finished_known_received +=
other.num_calls_finished_known_received;
for (const auto& p : other.drop_token_counts) {
drop_token_counts[p.first] += p.second;
}
return *this;
}
};
@ -173,11 +185,12 @@ class BalancerServiceImpl : public BalancerService {
shutdown_(false) {}
Status BalanceLoad(ServerContext* context, Stream* stream) override {
gpr_log(GPR_INFO, "LB: BalanceLoad");
gpr_log(GPR_INFO, "LB[%p]: BalanceLoad", this);
LoadBalanceRequest request;
stream->Read(&request);
IncreaseRequestCount();
gpr_log(GPR_INFO, "LB: recv msg '%s'", request.DebugString().c_str());
gpr_log(GPR_INFO, "LB[%p]: recv msg '%s'", this,
request.DebugString().c_str());
if (client_load_reporting_interval_seconds_ > 0) {
LoadBalanceResponse initial_response;
@ -208,7 +221,7 @@ class BalancerServiceImpl : public BalancerService {
if (client_load_reporting_interval_seconds_ > 0) {
request.Clear();
stream->Read(&request);
gpr_log(GPR_INFO, "LB: recv client load report msg: '%s'",
gpr_log(GPR_INFO, "LB[%p]: recv client load report msg: '%s'", this,
request.DebugString().c_str());
GPR_ASSERT(request.has_client_stats());
// We need to acquire the lock here in order to prevent the notify_one
@ -218,21 +231,21 @@ class BalancerServiceImpl : public BalancerService {
request.client_stats().num_calls_started();
client_stats_.num_calls_finished +=
request.client_stats().num_calls_finished();
client_stats_.num_calls_finished_with_drop_for_rate_limiting +=
request.client_stats()
.num_calls_finished_with_drop_for_rate_limiting();
client_stats_.num_calls_finished_with_drop_for_load_balancing +=
request.client_stats()
.num_calls_finished_with_drop_for_load_balancing();
client_stats_.num_calls_finished_with_client_failed_to_send +=
request.client_stats()
.num_calls_finished_with_client_failed_to_send();
client_stats_.num_calls_finished_known_received +=
request.client_stats().num_calls_finished_known_received();
for (const auto& drop_token_count :
request.client_stats().calls_finished_with_drop()) {
client_stats_
.drop_token_counts[drop_token_count.load_balance_token()] +=
drop_token_count.num_calls();
}
load_report_cond_.notify_one();
}
done:
gpr_log(GPR_INFO, "LB: done");
gpr_log(GPR_INFO, "LB[%p]: done", this);
return Status::OK;
}
@ -247,21 +260,20 @@ class BalancerServiceImpl : public BalancerService {
std::unique_lock<std::mutex> lock(mu_);
const bool prev = !shutdown_;
shutdown_ = true;
gpr_log(GPR_INFO, "LB: shut down");
gpr_log(GPR_INFO, "LB[%p]: shut down", this);
return prev;
}
static LoadBalanceResponse BuildResponseForBackends(
const std::vector<int>& backend_ports, int num_drops_for_rate_limiting,
int num_drops_for_load_balancing) {
const std::vector<int>& backend_ports,
const std::map<grpc::string, size_t>& drop_token_counts) {
LoadBalanceResponse response;
for (int i = 0; i < num_drops_for_rate_limiting; ++i) {
auto* server = response.mutable_server_list()->add_servers();
server->set_drop_for_rate_limiting(true);
}
for (int i = 0; i < num_drops_for_load_balancing; ++i) {
auto* server = response.mutable_server_list()->add_servers();
server->set_drop_for_load_balancing(true);
for (const auto& drop_token_count : drop_token_counts) {
for (size_t i = 0; i < drop_token_count.second; ++i) {
auto* server = response.mutable_server_list()->add_servers();
server->set_drop(true);
server->set_load_balance_token(drop_token_count.first);
}
}
for (const int& backend_port : backend_ports) {
auto* server = response.mutable_server_list()->add_servers();
@ -285,13 +297,13 @@ class BalancerServiceImpl : public BalancerService {
private:
void SendResponse(Stream* stream, const LoadBalanceResponse& response,
int delay_ms) {
gpr_log(GPR_INFO, "LB: sleeping for %d ms...", delay_ms);
gpr_log(GPR_INFO, "LB[%p]: sleeping for %d ms...", this, delay_ms);
if (delay_ms > 0) {
gpr_sleep_until(
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(delay_ms, GPR_TIMESPAN)));
}
gpr_log(GPR_INFO, "LB: Woke up! Sending response '%s'",
gpr_log(GPR_INFO, "LB[%p]: Woke up! Sending response '%s'", this,
response.DebugString().c_str());
IncreaseResponseCount();
stream->Write(response);
@ -341,7 +353,7 @@ class GrpclbEnd2endTest : public ::testing::Test {
void TearDown() override {
for (size_t i = 0; i < backends_.size(); ++i) {
backend_servers_[i].Shutdown();
if (backends_[i]->Shutdown()) backend_servers_[i].Shutdown();
}
for (size_t i = 0; i < balancers_.size(); ++i) {
if (balancers_[i]->Shutdown()) balancer_servers_[i].Shutdown();
@ -499,7 +511,7 @@ class SingleBalancerTest : public GrpclbEnd2endTest {
TEST_F(SingleBalancerTest, Vanilla) {
const size_t kNumRpcsPerAddress = 100;
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0),
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
0);
// Make sure that trying to connect works without a call.
channel_->GetState(true /* try_to_connect */);
@ -538,7 +550,7 @@ TEST_F(SingleBalancerTest, InitiallyEmptyServerlist) {
ScheduleResponseForBalancer(0, LoadBalanceResponse(), 0);
// Send non-empty serverlist only after kServerlistDelayMs
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0),
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
kServerlistDelayMs);
const auto t0 = system_clock::now();
@ -580,11 +592,11 @@ TEST_F(SingleBalancerTest, RepeatedServerlist) {
// Send a serverlist right away.
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0),
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
0);
// ... and the same one a bit later.
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0),
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
kServerlistDelayMs);
// Send num_backends/2 requests.
@ -639,6 +651,61 @@ TEST_F(SingleBalancerTest, RepeatedServerlist) {
EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
}
TEST_F(SingleBalancerTest, BackendsRestart) {
const size_t kNumRpcsPerAddress = 100;
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
0);
// Make sure that trying to connect works without a call.
channel_->GetState(true /* try_to_connect */);
// Send 100 RPCs per server.
auto statuses_and_responses =
SendRpc(kMessage_, kNumRpcsPerAddress * num_backends_);
for (const auto& status_and_response : statuses_and_responses) {
const Status& status = status_and_response.first;
const EchoResponse& response = status_and_response.second;
EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
<< " message=" << status.error_message();
EXPECT_EQ(response.message(), kMessage_);
}
// Each backend should have gotten 100 requests.
for (size_t i = 0; i < backends_.size(); ++i) {
EXPECT_EQ(kNumRpcsPerAddress,
backend_servers_[i].service_->request_count());
}
balancers_[0]->NotifyDoneWithServerlists();
// The balancer got a single request.
EXPECT_EQ(1U, balancer_servers_[0].service_->request_count());
// and sent a single response.
EXPECT_EQ(1U, balancer_servers_[0].service_->response_count());
for (size_t i = 0; i < backends_.size(); ++i) {
if (backends_[i]->Shutdown()) backend_servers_[i].Shutdown();
}
statuses_and_responses = SendRpc(kMessage_, 1);
for (const auto& status_and_response : statuses_and_responses) {
const Status& status = status_and_response.first;
EXPECT_FALSE(status.ok());
}
for (size_t i = 0; i < num_backends_; ++i) {
backends_.emplace_back(new BackendServiceImpl());
backend_servers_.emplace_back(ServerThread<BackendService>(
"backend", server_host_, backends_.back().get()));
}
// The following RPC will fail due to the backend ports having changed. It
// will nonetheless exercise the grpclb-roundrobin handling of the RR policy
// having gone into shutdown.
// TODO(dgq): implement the "backend restart" component as well. We need extra
// machinery to either update the LB responses "on the fly" or instruct
// backends which ports to restart on.
statuses_and_responses = SendRpc(kMessage_, 1);
for (const auto& status_and_response : statuses_and_responses) {
const Status& status = status_and_response.first;
EXPECT_FALSE(status.ok());
}
// Check LB policy name for the channel.
EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName());
}
class UpdatesTest : public GrpclbEnd2endTest {
public:
UpdatesTest() : GrpclbEnd2endTest(4, 3, 0) {}
@ -647,12 +714,10 @@ class UpdatesTest : public GrpclbEnd2endTest {
TEST_F(UpdatesTest, UpdateBalancers) {
const std::vector<int> first_backend{GetBackendPorts()[0]};
const std::vector<int> second_backend{GetBackendPorts()[1]};
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0);
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0);
ScheduleResponseForBalancer(
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0),
0);
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
// Start servers and send 10 RPCs per server.
gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
@ -727,10 +792,9 @@ TEST_F(UpdatesTest, UpdateBalancersRepeated) {
const std::vector<int> second_backend{GetBackendPorts()[0]};
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0);
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0);
ScheduleResponseForBalancer(
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0),
0);
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
// Start servers and send 10 RPCs per server.
gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
@ -810,10 +874,9 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) {
const std::vector<int> second_backend{GetBackendPorts()[1]};
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, 0, 0), 0);
0, BalancerServiceImpl::BuildResponseForBackends(first_backend, {}), 0);
ScheduleResponseForBalancer(
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, 0, 0),
0);
1, BalancerServiceImpl::BuildResponseForBackends(second_backend, {}), 0);
// Start servers and send 10 RPCs per server.
gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
@ -902,7 +965,8 @@ TEST_F(UpdatesTest, UpdateBalancersDeadUpdate) {
TEST_F(SingleBalancerTest, Drop) {
const size_t kNumRpcsPerAddress = 100;
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 1, 2),
0, BalancerServiceImpl::BuildResponseForBackends(
GetBackendPorts(), {{"rate_limiting", 1}, {"load_balancing", 2}}),
0);
// Send 100 RPCs for each server and drop address.
const auto& statuses_and_responses =
@ -934,6 +998,49 @@ TEST_F(SingleBalancerTest, Drop) {
EXPECT_EQ(1U, balancer_servers_[0].service_->response_count());
}
TEST_F(SingleBalancerTest, DropAllFirst) {
// All registered addresses are marked as "drop".
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(
{}, {{"rate_limiting", 1}, {"load_balancing", 1}}),
0);
const auto& statuses_and_responses = SendRpc(kMessage_, 1);
for (const auto& status_and_response : statuses_and_responses) {
const Status& status = status_and_response.first;
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
}
}
TEST_F(SingleBalancerTest, DropAll) {
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
0);
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(
{}, {{"rate_limiting", 1}, {"load_balancing", 1}}),
1000);
// First call succeeds.
auto statuses_and_responses = SendRpc(kMessage_, 1);
for (const auto& status_and_response : statuses_and_responses) {
const Status& status = status_and_response.first;
const EchoResponse& response = status_and_response.second;
EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
<< " message=" << status.error_message();
EXPECT_EQ(response.message(), kMessage_);
}
// But eventually, the update with only dropped servers is processed and calls
// fail.
do {
statuses_and_responses = SendRpc(kMessage_, 1);
ASSERT_EQ(statuses_and_responses.size(), 1UL);
} while (statuses_and_responses[0].first.ok());
const Status& status = statuses_and_responses[0].first;
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_message(), "Call dropped by load balancing policy");
}
class SingleBalancerWithClientLoadReportingTest : public GrpclbEnd2endTest {
public:
SingleBalancerWithClientLoadReportingTest() : GrpclbEnd2endTest(4, 1, 2) {}
@ -942,7 +1049,7 @@ class SingleBalancerWithClientLoadReportingTest : public GrpclbEnd2endTest {
TEST_F(SingleBalancerWithClientLoadReportingTest, Vanilla) {
const size_t kNumRpcsPerAddress = 100;
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 0, 0),
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), {}),
0);
// Send 100 RPCs per server.
const auto& statuses_and_responses =
@ -971,17 +1078,17 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Vanilla) {
EXPECT_EQ(kNumRpcsPerAddress * num_backends_, client_stats.num_calls_started);
EXPECT_EQ(kNumRpcsPerAddress * num_backends_,
client_stats.num_calls_finished);
EXPECT_EQ(0U, client_stats.num_calls_finished_with_drop_for_rate_limiting);
EXPECT_EQ(0U, client_stats.num_calls_finished_with_drop_for_load_balancing);
EXPECT_EQ(0U, client_stats.num_calls_finished_with_client_failed_to_send);
EXPECT_EQ(kNumRpcsPerAddress * num_backends_,
client_stats.num_calls_finished_known_received);
EXPECT_THAT(client_stats.drop_token_counts, ::testing::ElementsAre());
}
TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) {
const size_t kNumRpcsPerAddress = 3;
ScheduleResponseForBalancer(
0, BalancerServiceImpl::BuildResponseForBackends(GetBackendPorts(), 2, 1),
0, BalancerServiceImpl::BuildResponseForBackends(
GetBackendPorts(), {{"rate_limiting", 2}, {"load_balancing", 1}}),
0);
// Send 100 RPCs for each server and drop address.
const auto& statuses_and_responses =
@ -1018,13 +1125,13 @@ TEST_F(SingleBalancerWithClientLoadReportingTest, Drop) {
client_stats.num_calls_started);
EXPECT_EQ(kNumRpcsPerAddress * (num_backends_ + 3),
client_stats.num_calls_finished);
EXPECT_EQ(kNumRpcsPerAddress * 2,
client_stats.num_calls_finished_with_drop_for_rate_limiting);
EXPECT_EQ(kNumRpcsPerAddress,
client_stats.num_calls_finished_with_drop_for_load_balancing);
EXPECT_EQ(0U, client_stats.num_calls_finished_with_client_failed_to_send);
EXPECT_EQ(kNumRpcsPerAddress * num_backends_,
client_stats.num_calls_finished_known_received);
EXPECT_THAT(client_stats.drop_token_counts,
::testing::ElementsAre(
::testing::Pair("load_balancing", kNumRpcsPerAddress),
::testing::Pair("rate_limiting", kNumRpcsPerAddress * 2)));
}
} // namespace

@ -91,13 +91,13 @@ TEST_F(GrpclbTest, ParseResponseServerList) {
auto* server = serverlist->add_servers();
server->set_ip_address(Ip4ToPackedString("127.0.0.1"));
server->set_port(12345);
server->set_drop_for_rate_limiting(true);
server->set_drop_for_load_balancing(false);
server->set_load_balance_token("rate_limting");
server->set_drop(true);
server = response.mutable_server_list()->add_servers();
server->set_ip_address(Ip4ToPackedString("10.0.0.1"));
server->set_port(54321);
server->set_drop_for_rate_limiting(false);
server->set_drop_for_load_balancing(true);
server->set_load_balance_token("load_balancing");
server->set_drop(true);
auto* expiration_interval = serverlist->mutable_expiration_interval();
expiration_interval->set_seconds(888);
expiration_interval->set_nanos(999);
@ -112,14 +112,14 @@ TEST_F(GrpclbTest, ParseResponseServerList) {
EXPECT_EQ(PackedStringToIp(c_serverlist->servers[0]->ip_address),
"127.0.0.1");
EXPECT_EQ(c_serverlist->servers[0]->port, 12345);
EXPECT_TRUE(c_serverlist->servers[0]->drop_for_rate_limiting);
EXPECT_FALSE(c_serverlist->servers[0]->drop_for_load_balancing);
EXPECT_STREQ(c_serverlist->servers[0]->load_balance_token, "rate_limting");
EXPECT_TRUE(c_serverlist->servers[0]->drop);
EXPECT_TRUE(c_serverlist->servers[1]->has_ip_address);
EXPECT_EQ(PackedStringToIp(c_serverlist->servers[1]->ip_address), "10.0.0.1");
EXPECT_EQ(c_serverlist->servers[1]->port, 54321);
EXPECT_FALSE(c_serverlist->servers[1]->drop_for_rate_limiting);
EXPECT_TRUE(c_serverlist->servers[1]->drop_for_load_balancing);
EXPECT_STREQ(c_serverlist->servers[1]->load_balance_token, "load_balancing");
EXPECT_TRUE(c_serverlist->servers[1]->drop);
EXPECT_TRUE(c_serverlist->expiration_interval.has_seconds);
EXPECT_EQ(c_serverlist->expiration_interval.seconds, 888);

@ -23,6 +23,7 @@
#include <grpc++/completion_queue.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "test/cpp/microbenchmarks/helpers.h"
extern "C" {
@ -82,7 +83,7 @@ static void BM_Pass1Cpp(benchmark::State& state) {
grpc_cq_completion completion;
DummyTag dummy_tag;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_cq_begin_op(c_cq, &dummy_tag);
GPR_ASSERT(grpc_cq_begin_op(c_cq, &dummy_tag));
grpc_cq_end_op(&exec_ctx, c_cq, &dummy_tag, GRPC_ERROR_NONE,
DoneWithCompletionOnStack, NULL, &completion);
grpc_exec_ctx_finish(&exec_ctx);
@ -102,7 +103,7 @@ static void BM_Pass1Core(benchmark::State& state) {
while (state.KeepRunning()) {
grpc_cq_completion completion;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_cq_begin_op(cq, NULL);
GPR_ASSERT(grpc_cq_begin_op(cq, NULL));
grpc_cq_end_op(&exec_ctx, cq, NULL, GRPC_ERROR_NONE,
DoneWithCompletionOnStack, NULL, &completion);
grpc_exec_ctx_finish(&exec_ctx);
@ -121,7 +122,7 @@ static void BM_Pluck1Core(benchmark::State& state) {
while (state.KeepRunning()) {
grpc_cq_completion completion;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_cq_begin_op(cq, NULL);
GPR_ASSERT(grpc_cq_begin_op(cq, NULL));
grpc_cq_end_op(&exec_ctx, cq, NULL, GRPC_ERROR_NONE,
DoneWithCompletionOnStack, NULL, &completion);
grpc_exec_ctx_finish(&exec_ctx);

@ -78,7 +78,7 @@ static grpc_error* pollset_work(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
}
gpr_mu_unlock(&ps->mu);
grpc_cq_begin_op(g_cq, g_tag);
GPR_ASSERT(grpc_cq_begin_op(g_cq, g_tag));
grpc_cq_end_op(exec_ctx, g_cq, g_tag, GRPC_ERROR_NONE, cq_done_cb, NULL,
(grpc_cq_completion*)gpr_malloc(sizeof(grpc_cq_completion)));
grpc_exec_ctx_flush(exec_ctx);

@ -80,8 +80,11 @@ class Server {
return false;
}
payload->set_type(type);
std::unique_ptr<char[]> body(new char[size]());
payload->set_body(body.get(), size);
// Don't waste time creating a new payload of identical size.
if (payload->body().length() != (size_t)size) {
std::unique_ptr<char[]> body(new char[size]());
payload->set_body(body.get(), size);
}
return true;
}

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

Loading…
Cancel
Save